Core Concepts

Dynamic Resume

How a resume is generated from verified activity, not typed by hand.

The core idea

Most resumes are a document you edit by hand and hope stays current. HUBCV's resume is generated on demand from a record of things that actually happened — completed jobs and courses, graded assessments and tasks, attendance, and credited social activity (events, projects, leadership). The generation logic lives in lib/resume-generator.ts and lib/skills.ts, and computes a skill level from a 5-tier weighted evidence model, originally inspired by a patent claim (US2020/0074567, referenced in the code comments) that's since evolved into something broader.

The 5 evidence tiers

This is the scoring model — see Skill-Scoring System for the full mechanics. It applies uniformly across all four Hub posting kinds (job, course, event, project), not just courses.

TierWeightEvidence
Completion1 (job/course) or 0.1 (project/event)the user finishes their involvement
Assessment0.01scaled by score — a failed assessment contributes ~0, not the full weight
Task0.01same scaling as Assessment
Attendance0.001% present
Community0.0001reserved for phase 2 — no evidence built yet, always 0

Each tier is normalized to a 0–100 score, then combined with its fixed weight to produce a single overall skill level — the same shape the old system used, just with 5 tiers instead of 4 modules, and computed live from real evidence rows instead of a counters table that could drift out of sync.

Resume sections are a separate, unrelated concern

The resume's SECTIONS (Experience, Academics, Online Training & Certifications, Projects & Social Activity) are still grouped by each activityRecord's module field — a kind-based tag (job→Experience, course→Academics, etc.) that has nothing to do with the 5 scoring tiers above. A completed job contributes to both the Completion tier's score AND the Experience section, but those are two independent effects of the same event, not the same mechanism.

Where the content comes from

Every section is backed by activityRecord rows — one per credited thing, each carrying a title, a bullet description, a skills[] list, a verified flag, and a per-target-role relevance score (0–1, one entry per target role like "Software Engineer" or "Product Manager"). generateResume() filters activity by relevance to the resume's selected target role, sorts it, and groups it into sections by module: Experience, Academics, Online Training & Certifications, Projects & Social Activity.

Skills shown at the top of the resume are the deduped union of every credited activity's skills, backfilled with the user's own manually-listed skills if there's room, capped at 10. The per-skill score list (skillScores) comes from the same 5-tier evidence model — see Skill-Scoring System for exactly how it's computed.

Real-time, computed on every view

The resume isn't regenerated on a schedule — it's computed fresh from the current state of your evidence every time it's viewed (the Resume page fetches activity records and skill evidence on every request and runs generateResume() against whatever it gets back), so a position marked complete this morning is already reflected the next time the page loads.

Every activity record carries a verified flag. Today, every activity record that HUBCV itself creates is written as verified from the moment it's created — a Hub admin assigning someone to a position (see Skill-Scoring System) is the one live pathway, and it writes verified: true immediately, with no separate approval step. Course-linked activity (the "Machine Learning (A-)" style entries) isn't produced by a grading feature at all yet — there's no in-product way for Faculty to enter a grade that turns into a resume entry; those rows are seed/demo data today. A record that starts unverified and later gets confirmed by a Hub — the flow the Onboarding page describes for uploaded documents — doesn't exist in the product yet either; see the note there.

Exporting

The Resume page renders the generated resume live and lets you export it as a real PDF via @react-pdf/renderer, server-rendered so the export always matches what's on screen.