- JobTrackerApi/Controllers/GmailController.cs - JobTrackerApi/Services/GmailOAuthService.cs - JobTrackerApi.Tests/GmailControllerTests.cs - .gsd/milestones/M001/slices/S01/S01-PLAN.md - .gsd/KNOWLEDGE.md
8.6 KiB
id: S01 parent: M001 milestone: M001 provides:
- Job-aware Gmail matching and import inside the job workspace, with ranked thread suggestions, duplicate-aware imports, and persisted Gmail message/thread metadata. requires: [] affects:
- S02
- S03
- S04 key_files:
JobTrackerApi/Controllers/GmailController.csJobTrackerApi/Services/GmailOAuthService.csModels/Correspondence.csJobTrackerApi/Program.csjob-tracker-ui/src/components/Correspondence.tsxjob-tracker-ui/src/components/JobDetailsDialog.tsxjob-tracker-ui/src/types.tsjob-tracker-ui/src/correspondence-gmail-import.test.tsxkey_decisions:- Backend, not the browser, is now the source of truth for Gmail candidate ranking.
- Gmail-imported correspondence now persists thread identity plus raw sender/recipient metadata for downstream context reuse. patterns_established:
- Job-scoped Gmail endpoints that load owned
JobApplicationcontext before querying Gmail. - Explicit import result payloads with imported/skipped counts instead of ambiguous duplicate behavior.
- Workspace UI consumes ranked backend suggestions and only uses manual search as an override. observability_surfaces:
GET /api/gmail/job-candidatesGET /api/gmail/statusPOST /api/gmail/importPOST /api/gmail/import-threadCI=true npm --prefix job-tracker-ui test -- --watch=false --runTestsByPath src/correspondence-gmail-import.test.tsx- isolated
GmailControllerTestsdrill_down_paths: .gsd/milestones/M001/slices/S01/tasks/T01-SUMMARY.md.gsd/milestones/M001/slices/S01/tasks/T02-SUMMARY.md.gsd/milestones/M001/slices/S01/tasks/T03-SUMMARY.mdduration: one execution pass verification_result: passed completed_at: 2026-03-24
S01: Smarter Gmail import and matching
Shipped a job-aware Gmail import loop that ranks likely correspondence for a specific job, imports it with clearer duplicate behavior, and persists thread-aware metadata for later slices.
What Happened
S01 moved Gmail import from a generic inbox search experience toward a job-scoped workflow. On the backend, GmailController now exposes GET /api/gmail/job-candidates, which builds queries from the owned job, company, recruiter, and prior correspondence state, then returns ranked threads/messages with confidence and match reasons. GmailOAuthService gained multi-query candidate retrieval so Gmail request plumbing stays in the service layer rather than leaking into the UI.
The slice also hardened import continuity. Correspondence records now store ExternalThreadId, ExternalFrom, and ExternalTo in addition to ExternalMessageId, and import responses explicitly report imported vs skipped work. Program.cs was updated so the runtime schema repair path adds those columns for older SQLite and MySQL databases instead of breaking startup.
On the frontend, the job workspace now passes the loaded job into Correspondence, and the Gmail tab consumes the new backend match contract directly. The tab shows ranked thread/message suggestions, confidence, reasons, already-linked state, and still supports manual query override through the same job-aware endpoint. After import, the correspondence list and Gmail suggestions both refresh so the user can see what changed immediately.
Verification
- Backend API compiled successfully with
$HOME/.dotnet/dotnet build JobTrackerApi/JobTrackerApi.csproj. - Focused Gmail backend coverage passed in an isolated harness after the repo-wide test project proved to have unrelated compile drift.
- Focused frontend Gmail UI coverage passed:
CI=true npm --prefix job-tracker-ui test -- --watch=false --runTestsByPath src/correspondence-gmail-import.test.tsx
- Manual/UAT verification is still required for the roadmap’s live Gmail trust bar: connect Gmail, review ranked suggestions for a real job, import a message and a thread, and confirm the result feels materially cleaner than the old manual search flow.
Requirements Advanced
- R001 — The imported job is now the anchor for Gmail discovery and correspondence import inside the workspace rather than a detached generic inbox search.
- R002 — Gmail matching/import now uses job/company/recruiter context, exposes confidence/reasons, skips duplicates explicitly, and persists thread-aware metadata for lower-cleanup correspondence import.
- R010 — The slice now preserves more job-linked correspondence continuity by storing message/thread identity and sender/recipient metadata that later timeline/follow-up work can reuse.
Requirements Validated
- R001 — S01 proved the job-specific Gmail import loop is wired into the actual job workspace and uses the job as the context boundary for import actions.
- R002 — Backend and frontend verification now prove ranked job-aware suggestions, explicit duplicate handling, and correspondence refresh after import.
New Requirements Surfaced
- none
Requirements Invalidated or Re-scoped
- none — the slice matched the planned requirement shape.
Deviations
The planned backend verification command (dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter GmailControllerTests) could not run cleanly because the broader JobTrackerApi.Tests project already contains unrelated compile errors outside Gmail. Instead of expanding slice scope to repair unrelated tests, Gmail controller coverage was verified in an isolated harness and the frontend path was verified with a focused React test.
Known Limitations
- The roadmap’s live Gmail trust bar still needs real-account UAT; automated tests prove the contract and UI behavior, not inbox quality on actual mail.
- The main
JobTrackerApi.Testsproject still has unrelated compile drift that prevents direct filtered execution of Gmail tests without isolation. - Draft-generation and follow-up slices still need to consume the new correspondence metadata before the full milestone loop is truly integrated.
Follow-ups
- S02 should consume the imported correspondence and persisted Gmail metadata as trusted application-context input instead of re-deriving it from raw snippets.
- S03 should use
ExternalThreadId,ExternalFrom, andExternalTowhen assembling reply/follow-up context so thread continuity stays explicit. - After S02/S03 wiring, run live Gmail UAT again to confirm ranking heuristics still feel trustworthy once downstream flows depend on them.
Files Created/Modified
JobTrackerApi/Controllers/GmailController.cs— added job-aware candidate discovery, ranked match DTOs, and explicit import result payloads.JobTrackerApi/Services/GmailOAuthService.cs— added multi-query Gmail candidate retrieval support.Models/Correspondence.cs— added persisted Gmail thread and sender/recipient metadata.JobTrackerApi/Controllers/CorrespondenceController.cs— exposed optional external Gmail metadata on correspondence creation.JobTrackerApi/Program.cs— added SQLite/MySQL compatibility guards for the new correspondence fields.JobTrackerApi.Tests/GmailControllerTests.cs— expanded Gmail controller coverage for ranking, ownership scope, duplicate imports, and import payloads.job-tracker-ui/src/components/JobDetailsDialog.tsx— passes job context into the correspondence tab.job-tracker-ui/src/components/Correspondence.tsx— consumes ranked backend Gmail suggestions and refreshes correspondence after import.job-tracker-ui/src/types.ts— added contracts for Gmail match/import payloads and enriched correspondence data.job-tracker-ui/src/correspondence-gmail-import.test.tsx— verifies ranked suggestion rendering, manual override, and post-import refresh.
Forward Intelligence
What the next slice should know
- S02 can treat imported correspondence as job-trusted context now; the Gmail tab already returns ranked candidates and the stored correspondence now preserves message/thread identity cleanly enough for downstream draft context assembly.
What's fragile
- Repo-wide backend test health is fragile — unrelated test drift in
JobTrackerApi.Testsstill blocks direct filtered test execution, so future slices should either repair that debt deliberately or keep focused verification isolated.
Authoritative diagnostics
GET /api/gmail/job-candidatesplusjob-tracker-ui/src/correspondence-gmail-import.test.tsxare the fastest trustworthy checks for whether Gmail matching and UI wiring are still aligned.
What assumptions changed
- Original assumption: the existing Gmail integration mostly needed UI polish. Actually, the trust problem sat in backend ranking ownership and persistence continuity, so the slice had to move matching logic server-side and enrich stored correspondence metadata.