Core Concepts
Skill-Scoring System
The 5-tier evidence model HUBCV uses to score every skill — the same way across jobs, courses, events, and projects.
One evidence model, four posting kinds
Every skill's score comes from the same 5-tier weighted formula (Completion 1/0.1, Assessment 0.01, Task 0.01, Attendance 0.001, Community 0.0001 — reserved for phase 2), computed live in lib/skills.ts's computeSkillScores. What differs by posting kind is where the underlying evidence rows live, not how they're weighted.
| Kind | Completion | Assessment/Task | Attendance |
|---|---|---|---|
| Course | courseEnrollment.status | gradedItem (kind: test/assignment) | attendanceWeek |
| Job / Event / Project | postingParticipant.status | postingTask (kind: exam/task) | postingAttendance |
Courses keep their existing tables — nothing about existing grades or attendance was migrated, just reweighted under the new tiers. Job, event, and project Positions had no equivalent to gradedItem/attendanceWeek at all before this, so postingTask and postingAttendance are new, scoped to a user's specific postingParticipant assignment rather than a whole posting.
postingRole and postingParticipant
A Hub admin defines named positions on a posting — for example "Winner" on a hackathon, "Contributor" on a project, "Lead Software Engineer" on a job listing — each carrying a skills[] list and an optional capacity. Assigning a real user to that position creates a verified activityRecord crediting exactly those skills and shows up immediately in that user's dynamic resume. Marking the assignment "completed" (postingParticipant.status) is what triggers Completion-tier credit — being merely active in a position doesn't, since Completion specifically means the user finished their involvement.
export async function assignParticipant(orgId: string, postingRoleId: string, userId: string) {
await requireOrgAdmin(orgId);
// ...creates a verified activityRecord with the role's skills,
// inserts the postingParticipant row that links user to role
}Undoing it
removeParticipant reverses the assignment cleanly: deletes the linked activityRecord and removes the postingParticipant row. Nothing about it is soft-deleted or archived — the resume reflects the current state, not history.
Where you can see it
- •The Activity page's Timeline, Skills, and Reports tabs — the dedicated view for browsing every piece of evidence and its rolled-up scores; see Activity Tracking.
- •Inside the relevant Event/Project/Job chat room's info panel, with an assign control if you're a Hub admin.
- •On the posting's public Hub detail page, read-only — a roster and the defined positions with their skill tags, no assign control there.
- •In the resume, as a normal activity-record entry under Projects & Social Activity or Experience, and in the Skills section's per-skill score.
Score-band labels
A raw skill score is also mapped to a 5-band label via proficiencyLabel() in lib/skills.ts: Learning (below 20), Beginner (20-39), Amateur (40-59), Advanced (60-79), Pro (80+). The same thresholds drive the Activity page's Skills-tab progress bars and the Reports tab's proficiency breakdown.