3.8 KiB
3.8 KiB
v1.1 worker dispatch — wave B
Global v1 rules binding (see v1-tasks.md header). Wave A is merged into master: packages/matching exists (cluster(), keywords coverage()), llm-gateway has mocks for cv_tailor (STRONG) + deadline_extract (CHEAP) + email_classify, api has email_suggestion + notification_log tables and /suggestions + /notifications/log endpoints (125 api tests green).
WB1: apps/api — dedupe + tailor + deadline integration
Paths: apps/api/** ONLY (you own apps/api this wave).
Migration 004_dedupe_deadline.sql:
ALTER TABLE job_posting ADD COLUMN IF NOT EXISTS cluster_id text;
ALTER TABLE job_posting ADD COLUMN IF NOT EXISTS apply_by date;
Deliverables:
- Cluster assignment: on job_posting creation (manual POST /postings AND /postings/fetch), run packages/matching cluster() over the new posting + all existing postings (small N, fine at v1 scale); persist cluster_id; new clusters only when no match (cluster() output may re-group - reconcile: prefer stability, assign new posting into existing cluster_id when rule matches, else fresh id).
- Read:
GET /postingsgainscluster_id; newGET /clusters-> [{cluster_id, postings: [{id, title, company, source, url, score}]}] sorted by best score desc; UI uses this for "same role via 3 agencies". - Tailor CV:
POST /applications/{id}/tailor-cv-> gateway task cv_tailor (STRONG) with prompt = profile + sections + posting description; validate output schema {sections, change_log[]}; hallucination guard check: every tailored bullet must map to a source bullet id from input (reject + 502 on unmapped bullet); store artifact kind='cv' origin='ai_drafted' + render PDF via packages/artifacts (bytes -> hash -> storage); return {artifact_id, change_log, keyword_coverage: coverage(cv_text, posting.description)}. - Deadline: scoring endpoints (single + batch) additionally run deadline_extract (CHEAP) and persist apply_by when non-null; /today adds
deadlines: [{application_id, title, company, apply_by}]for apply_by within next 7 days. - Dockerfile.test: add
-e /app/packages/matchinginstall. - Tests (+ >= 20): cluster assignment on create, cluster stability across re-imports, clusters endpoint shape, tailor-cv happy path + hallucination rejection (fabricate mock returning bullet without source id -> 502), keyword coverage numbers vs fixture, deadline persisted + /today deadlines filter window.
docker compose run --rm api-testall green (125 + yours). Branch feat/WB1-dedupe-tailor, commit incrementally, push.
WB2: apps/web — v1.1 UI
Paths: apps/web/** + docs/user-guide.md (edit allowed, append section) ONLY.
Backend per docs/api-contract-v2.md + wave A/B adds: /suggestions (accept/dismiss), /notifications/log, /clusters, tailor-cv, /today.deadlines. Mock these in tests like before.
- Today view: new "Deadlines this week" strip (cards with company/title/date, red when <=2 days) from GET /today.deadlines; "Inbox insights" strip listing pending email_suggestion rows (from/subject/snippet/classification chip) with Accept/Dismiss buttons -> POST endpoints, then refresh; notifications mini-log (last 5) optional.
- Research/Postings: group rows by cluster; cluster rows show "also via N more" expandable alternates list (GET /clusters).
- Application detail: "Tailor CV for this job" button -> POST tailor-cv -> panel showing change_log bullets + keyword coverage bar + link to download artifact; variant appears in artifacts list.
- CostDisplay: add totals by provider (group /telemetry/tasks client-side).
- Vitest: +4 tests (deadlines strip render, suggestions accept flow, cluster alternates render, tailor panel render from fixture). Keep all existing green. npm run build + npm test green.
- docs/user-guide.md: append "v1.1: email radar, dedupe, tailor CV" short section (plain language, no em dashes).
- Branch feat/WB2-web-v11, commit incrementally, push.