Give the candidate route a dedicated dark workspace layout with overview actions, while keeping the drawer profile flow unchanged.
Co-authored-by: Cursor <cursoragent@cursor.com>
Deploy to S3 / checks (push) Failing after 2m24sDetails
Deploy to S3 / deploy (push) Has been skippedDetails
The bank used to be write-only: a CV uploaded with no job carried only its
full text, so nothing could search or rank it. Now the employment agent's
extraction (title, company, education, plus new skills and years_experience,
both clamped to what the resume actually states) is stored on the row, and
the bank is ranked against a job the moment that job opens.
- New CV Bank screen at /cvbank replaces Talent Pool; the inline bank card
moves out of CV Import. One table, two populations: speculative uploads,
and silver medalists (rejected applicants scoring >= CV_BANK_SILVER_FLOOR,
read live from their application rather than copied).
- matching/ranking.py: the tier-1 keyword ranker moves out of
talent/plugins.py so Find Talent and the bank share one implementation;
talent/plugins.py re-exports it and its numbers are unchanged.
- Taskiq tasks in job.candidate.bank_tasks: backfill profiles for CVs
banked before extraction existed, and rank the bank when a job opens so
recruiters are told about matches above CV_BANK_SUGGEST_THRESHOLD.
Retention (CV_BANK_RETENTION_MONTHS) is stamped on the row at upload; the
sweep flags expired rows and never deletes.
- Migrations 029 (bank profile columns) and 030 (per-job bank matches).
- Routes: POST /candidate/cv-bank/score, GET /candidate/cv-bank/suggestions.
- README: The CV Bank, plus the retention and deletion policy.
Also in this change:
- Inbox, Sheet Forms: has_linkedin / has_resume filters, tri-valued so
"no link" is a real filter and NULL rows are kept in it; tab badge counts
now narrow with the list and the search box.
- Hiring-manager candidate rows carry the ATS score and band.
- Tests: analytics dashboard merge logic, employment extraction clamps,
form-data filters, manager candidate serializer, CV Bank mapper.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- Added methods to retrieve application history by email across various sources (inbox, manual uploads, form data).
- Introduced new serializers for application history items and overall history.
- Updated candidate and inbox views to include application history in responses.
- Enhanced frontend components to display reapplication badges and previous application details.
- Adjusted API endpoints to support fetching application history based on email input.
Deploy to S3 / deploy (push) Successful in 34sDetails
The recruiter table was user-centric (GET /candidate/fetch/users), so it could
only ever render account fields - name, email, created date. Everything a
recruiter actually triages on lives on the application, not the user.
Point the table at GET /candidate/fetch and map application rows through a new
toApplicationListView, adding Job, ATS (score + band chip), Stage and Recruiter
columns. Stage and band become real filters; the dead Department facet is gone.
Manual uploads came back unscored because the list path never joined the ATS
results, so attach scores there and expose ai_score/recommendation from the
manager serializer, deriving the band from the score when the model omitted it.
Co-authored-by: Cursor <cursoragent@cursor.com>
The recruiter table was user-centric (GET /candidate/fetch/users), so it could
only ever render account fields - name, email, created date. Everything a
recruiter actually triages on lives on the application, not the user.
Point the table at GET /candidate/fetch and map application rows through a new
toApplicationListView, adding Job, ATS (score + band chip), Stage and Recruiter
columns. Stage and band become real filters; the dead Department facet is gone.
Manual uploads came back unscored because the list path never joined the ATS
results, so attach scores there and expose ai_score/recommendation from the
manager serializer, deriving the band from the score when the model omitted it.
Co-authored-by: Cursor <cursoragent@cursor.com>