CV Screening
AI-powered candidate filtering that scores every résumé against configurable criteria — so your recruiting team sees who clears the bar before opening a single CV manually.
Overview
CV Screening is TotalApp's AI-powered candidate filtering screen inside the HR module. It reads the résumé text uploaded through the Careers page application form, evaluates each applicant against a configurable scoring rubric, and surfaces a numeric match score so recruiters can immediately see which candidates clear the bar — without opening a single CV manually.
The screen is built around two primitives:
- Scoring criteria — five weighted dimensions (Education, Experience, Technical Skills, Soft Skills, Language Match) plus a pass/fail threshold.
- Hard Gatekeeper rules — a set of must-have tags that act as non-negotiable gates. If a candidate is missing any must-have, their score is hard-capped at 30 regardless of how well they score across other dimensions.
Every result is stored back into the applicant's record in career-manager.json. Candidates who pass are auto-promoted into the Recruitment pipeline and their score badge appears on Recruitment applicant cards.
AI-Powered, Not AI-Decided
CV Screening surfaces ranked scores to help your team prioritize — it does not make hiring decisions. All pass/fail thresholds are set by you, and you can override any result by clicking into the Detail Panel and choosing to advance or skip a candidate manually.
Quick Start
- Switch to HR mode in the header.
- Open CV Screening from the left sidebar (ScanSearch icon, between Recruitment and HR Reports).
- Use the job selector dropdown in the top bar to pick an open position.
- Go to the Criteria tab — review the pre-loaded department template, adjust the threshold slider if needed, and click Save Criteria.
- Switch to the Pool tab and click Bulk Analyze (N) to queue all pending applicants for AI analysis.
- Rows update in real time as each result arrives. Green rows passed; red rows failed.
- Click any passing row to open the Detail Panel and hit Move to Recruitment to advance the candidate.
Under Two Minutes
A full screening run from criteria setup to the first candidate in Recruitment takes under two minutes for a typical batch of ten applicants.
Core Concepts
Match Threshold
A number between 0 and 100 (default 60). An applicant must score at or above this value to be marked Passed. Applicants below it are marked Failed. The threshold is stored per job posting so different positions can have different bars — a junior role might use 50 while a senior role uses 75.
Scoring Dimensions
Every AI analysis returns a score for each of five dimensions. The overall score is a weighted average:
| Dimension | What the AI looks for |
|---|---|
| Education | Degree level, field of study, institution, certifications |
| Experience | Years in relevant roles, seniority level, sector alignment |
| Technical Skills | Specific tools, languages, frameworks, methodologies listed in the job requirements |
| Soft Skills | Communication, leadership, teamwork signals from the résumé narrative |
| Language Match | Required languages and proficiency levels |
Weights default to 20 / 30 / 30 / 15 / 5 and must sum to exactly 100. You can adjust them per position in the Criteria tab.
Score Tiers
Once a result is in, each candidate row is colour-coded based on how their score relates to the threshold:
The same tiers drive the filter tabs at the top of the Pool table.
Hard Gatekeeper (Must-Have)
Any tag added to the Must-Have list is a non-negotiable requirement. The AI checks whether the résumé demonstrates each must-have criterion. If any one is missing:
- The overall score is capped at maximum 30.
passedis set tofalse.- A
mustHaveFailedflag is stored with the result. - An ⚠ warning triangle appears next to the score badge in the table.
- The Detail Panel shows a "Must-Have Failed" alert banner.
Hard Gate Is Absolute
A candidate who otherwise scores 92 across the five dimensions will still be eliminated if they lack a single must-have — for example, "Security Clearance" or "5+ years Python". Use must-have tags only for genuinely non-negotiable requirements.
Nice-to-Have
Tags added to the Nice-to-Have list boost the score when present but do not gate candidates. Use them for preferred extras such as "Docker", "Agile certification", or "industry-specific experience".
Department Templates
Six ready-made templates pre-fill sensible weights and a suggested threshold for common hiring scenarios:
| Template | Suggested Threshold | Weight Emphasis |
|---|---|---|
| Engineering | 65% | Technical Skills (40%), Experience (30%) |
| Marketing | 60% | Soft Skills (25%), Experience (25%), Technical Skills (25%) |
| Sales | 55% | Soft Skills (30%), Experience (30%) |
| Finance | 65% | Technical Skills (35%), Experience (30%) |
| HR | 55% | Soft Skills (30%), Experience (25%) |
| Operations | 60% | Experience (35%), Technical Skills (25%) |
Applying a template overwrites the current weights and threshold but leaves your existing must-have / nice-to-have tags intact. You can fine-tune after applying.
Concurrent Analysis Limit
Bulk analysis runs at most 5 candidates simultaneously. This prevents the browser from locking during large batches. The remaining candidates queue automatically and are picked up as each slot frees. A spinner counter in the Bulk Analyze button shows how many are still queued.
Auto-Promotion
When the AI marks a candidate as passed and their pipeline status is still new, they are automatically moved to initial-qualification in the Recruitment Kanban. No manual step is needed for the happy path.
UI Walkthrough
Top Bar
| Element | Description |
|---|---|
| Eyebrow text | HR / CV SCREENING — identifies the screen context |
| Page title | CV Screening |
| Job selector | Dropdown listing all open and closed job postings pulled from Career Manager. Switching it reloads the Pool and Criteria tabs for the selected position. |
| Bulk Analyze (N) | Queues all pending candidates (those without a result, or with a previous error) for AI analysis. The number in parentheses shows how many will be processed. Disabled when there are no pending candidates. Turns into a spinner + counter while running. |
Pool Tab
The main candidate table. Each row is one applicant who submitted through the Careers page for the selected job.
Filter Row
| Control | Purpose |
|---|---|
| Search input | Free-text filter on name and email |
| All / Pending / Passed / Near / Failed | Filter tabs — click to narrow the table. Each tab shows its count in parentheses. |
| Hide Filtered toggle | When on, collapses rows that failed screening out of the visible table. Useful during bulk review to focus on passing candidates. |
| Candidate count | Right-aligned, shows how many rows are currently visible. |
Table Columns
| Column | Content |
|---|---|
| Candidate | Avatar initials + full name + email |
| Source | How the applicant arrived (e.g. careers-page, referral, linkedin) |
| Applied | ISO date of the application |
| Score | Score badge in tier colour. An ⚠ triangle appears if mustHaveFailed. While analyzing: a spinner. Before analysis: —. On error: Error. |
| Status | Recruitment pipeline stage (New, Initial Qualification, Hired, Refused, etc.) |
| Actions | ⚡ Analyze single candidate. → Move to Recruitment (only shown when passed and still new). |
Click anywhere on a row (except the action buttons) to open the Detail Panel for that candidate. Click the row again, or click ✕ in the panel, to close it.
Summary Bar
A fixed strip at the bottom of the Pool tab showing aggregate tier counts for the entire job:
12 Total 4 Pending 5 Passed 2 Near 1 Failed Threshold: %65
The threshold value in the bottom-right corner reflects the current Criteria setting in real time.
Criteria Tab
All configuration for how the AI evaluates candidates for the selected job. An amber dot appears on the tab label if you have unsaved changes.
Department Templates
Six preset buttons. Click one to apply default weights and threshold for that department type. Changes are not saved until you click Save Criteria.
Threshold Slider
Drag to set the pass/fail cutoff (0–100, step 5). The current value is shown in indigo on the right. The summary bar updates immediately when you save.
Scoring Weights
Five sliders, one per dimension. Each slider runs from 0 to 60 (step 5). A running total appears in the top-right corner of this section — it turns red when the total is not exactly 100, and the Save Criteria button is disabled until you fix it.
Must-Have Tags
Free-text tag input for hard-gate requirements.
- Type the criterion and press Enter or click +.
- Tags appear as rose-coloured pills.
- Click the × on a tag to remove it.
- Examples: "React Native", "Series B+ startup experience", "Active security clearance".
Nice-to-Have Tags
Same interaction as Must-Have, but sky-blue pills. These influence the score but never eliminate a candidate.
Save Criteria Button
Persists the current settings to the job posting record. Disabled when the weight total ≠ 100 or while saving. After saving, the amber unsaved-changes dot on the tab label disappears.
Criteria Changes Are Not Retroactive
Changing criteria does not retroactively update already-analyzed candidates. Re-run analysis on individual candidates using the single-analyze ⚡ button to refresh results against the new criteria.
Detail Panel
A right slide-out panel that opens when you click a candidate row. It overlays the table without collapsing it.
Score Summary
Score badge with tier colour, "Must-Have Failed" banner if applicable, two-line AI-generated fit summary, and breakdown bars — one per dimension — with raw score, weight, and an AI note.
Not Analyzed State
Clock icon with a prompt to run analysis. The candidate has not yet been through the AI screener — click ⚡ or use Bulk Analyze.
Résumé Preview
Collapsible section showing the raw résumé text in a monospace box. Click the eye button to expand or collapse. If no résumé text was captured, a placeholder message is shown.
Application Details
Label/value grid showing Source, Applied date, Degree, Availability, and Expected Salary from the original application form.
Footer Actions
- Re-analyze — runs the AI on this candidate again with the current criteria. Useful after updating must-have tags or weights.
- Move to Recruitment — only shown when the candidate has
passed === trueand their status is stillnew. Advances them to Initial Qualification in the Recruitment pipeline.
Score Breakdown Bars
Each dimension bar in the Detail Panel shows a coloured progress bar plus the AI's notes about that dimension:
| Bar Colour | Score Range | Meaning |
|---|---|---|
| Emerald | ≥ 70 | Strong match on this dimension |
| Amber | 50–69 | Partial match — some relevant signals present |
| Red | < 50 | Weak or missing signals for this dimension |
The weight displayed next to each dimension name (e.g. 30%) shows how much that dimension contributes to the overall score. A threshold reference line at the bottom of the breakdown section shows where the pass/fail bar sits.
Recruitment Integration
Automatic Pipeline Promotion
When bulk or single analysis completes and result.passed === true and the applicant's current status is new, the system automatically:
- Updates the applicant's status to
initial-qualification. - The change is reflected immediately in the Pool table (Status column).
- The applicant's Kanban card in the Recruitment screen moves to the Initial Qualification column.
Score Badge on Recruitment Cards
Every applicant card in the Recruitment Kanban that has been through CV Screening shows a small score badge in the card footer (next to the star rating). The badge is:
- Emerald with the score percentage when
passed === true - Rose with the score percentage when
passed === false
This gives recruiters a quick signal about AI-screened quality without opening the CV Screening screen.
AI Assistant
CV Screening includes a built-in AI Assistant, opened from the collapsed AI Assistant tab anchored to the right edge of the screen (click it to slide the panel open; click the tab on the panel's own left edge, or its header X, to close it again). It answers questions grounded in the candidate pool for the currently selected job posting, such as:
- A summary of how the candidate pool is trending — pass rate, average score, common gaps
- A comparison of two or more candidates and why one scored higher than another
- Which sourcing channels (LinkedIn, referral, careers page, etc.) are producing the strongest candidates
- Which pending or near-threshold candidates deserve a closer manual look
The assistant only sees the candidates currently visible under the active filter tab and search — narrow the pool first (e.g. to "Near Threshold") to focus its answer on that subset.
Step-by-Step Examples
Screening a Senior Backend Engineer Role
- Select "Senior Backend Engineer" from the job dropdown.
- Go to Criteria → click Engineering template (weights: Technical 40, Experience 30, Education 15, Soft 10, Language 5; threshold 65%).
- Add "5+ years production Python" and "Distributed systems experience" to Must-Have.
- Add "Kubernetes", "Postgres", "Redis" to Nice-to-Have.
- Click Save Criteria.
- Switch to Pool → click Bulk Analyze (18).
- After a minute, 4 candidates show emerald rows (score ≥ 80%), 6 show green (score 65–79%), 3 show amber (near threshold), and 5 show red (failed). Two red rows carry the ⚠ triangle — they lacked the Python or distributed systems must-have.
- Click the top emerald row → Detail Panel → Move to Recruitment.
- Repeat for the other passing candidates, or let auto-promotion handle it.
Quick-Check a Referral
A referral walks in outside the normal application cycle. An HR admin manually adds them to the career-manager as an applicant.
- Select the relevant job from the dropdown.
- Find the new applicant row in the Pool table (Status:
new, Score:—). - Click ⚡ in the Actions column.
- The row updates within seconds. Click the row to review the Detail Panel breakdown.
- If they pass, click → to move to Recruitment.
Re-Analyzing After Criteria Change
A recruiter tightens the threshold from 60% to 70% after seeing too many mediocre profiles pass.
- Go to Criteria → drag the Threshold slider to 70% → Save Criteria.
- Switch to Pool. The score badges and tier colours update immediately (score values don't change, but tier classification does because the cutoff moved).
- To re-run the AI against updated must-have tags: click Bulk Analyze (0) — this only re-runs candidates with no result or errors. For already-analyzed candidates, open the Detail Panel and click Re-analyze.
Eliminating a Candidate Who Passed Scoring But Lacks a Certification
- Add "PMP Certification" to the Must-Have list → Save Criteria.
- Open the Detail Panel for a candidate who previously scored 78%.
- Click Re-analyze. The AI detects no PMP in the résumé →
mustHaveFailed = true→ score is capped at 30 → candidate is re-marked Failed. - The row colour shifts from green to red, and the ⚠ triangle appears.
Data Persistence
CV Screening does not introduce a new JSON file. All results are stored directly in the existing career-manager.json under server/data/tenants/<tenantId>/:
"applicants": {
"app_...": {
"id": "app_...",
"firstName": "Elif",
"lastName": "Kaya",
"screeningStatus": "done",
"screeningResult": {
"score": 82,
"threshold": 65,
"passed": true,
"mustHaveFailed": false,
"analyzedAt": "2026-06-12T10:42:13.000Z",
"summary": "Strong backend candidate with 7 years Python experience...",
"breakdown": [
{ "category": "Technical Skills", "score": 88, "weight": 40, "notes": "Python, FastAPI, PostgreSQL confirmed..." },
{ "category": "Experience", "score": 85, "weight": 30, "notes": "Senior roles at two scale-ups..." }
]
}
}
}
}
Service Functions
| Function | Location | What it does |
|---|---|---|
analyzeCV(req) | cvScreeningService.ts | Calls POST /api/hr/cv-screening/analyze → returns raw AI result |
analyzeAndSaveApplicant(applicant, job, criteria) | cvScreeningService.ts | Sets status to analyzing → calls AI → saves result to career manager → auto-promotes if passed |
bulkAnalyze(applicants, job, criteria, onProgress) | cvScreeningService.ts | Processes applicants in batches of 5 with real-time onProgress callbacks |
getScoreTier(score, threshold) | cvScreeningService.ts | Returns 'high' | 'pass' | 'near' | 'fail' | 'pending' |
scoreTierClasses(tier) | cvScreeningService.ts | Returns Tailwind class string for badge colour |
scoreTierRowBg(tier) | cvScreeningService.ts | Returns rgba background for the table row |
updateApplicantScreening(id, status, result?) | careerManagerService.ts | Writes screeningStatus and screeningResult back to the JSON store |
updateJobScreeningCriteria(jobId, criteria) | careerManagerService.ts | Persists the ScreeningCriteria object on the JobPosting record |
getTemplateForDepartment(department) | careerManagerService.ts | Returns the matching SCREENING_TEMPLATES entry or the default criteria |
Server Endpoint
POST /api/hr/cv-screening/analyze — accepts applicant details, résumé text, job requirements, and criteria. Returns a scored result. The handler uses Anthropic's claude-sonnet-4-6 when ANTHROPIC_API_KEY is set; otherwise falls back to the Claude CLI.
Limitations
ScreeningCriteria. If you need to experiment with different weight configurations, save a copy of your results before changing criteria.resumeText field). Original file download is managed in Career Manager, not CV Screening.