Files
jobtrackingapp/.gsd/milestones/M001/slices/S01/S01-PLAN.md
T
2026-03-24 09:25:41 +01:00

72 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# S01: Smarter Gmail import and matching
**Goal:** Make Gmail import job-aware enough that a user reviewing one imported job sees the right candidate messages/threads first, can import them with clearer confidence signals, and ends up with job-linked correspondence that needs materially less cleanup.
**Demo:** From a job opened in the workspace, the user connects Gmail, sees ranked thread/message suggestions built from that jobs company/recruiter context, imports either one message or a full thread, and immediately sees the imported correspondence reflected on that job without any auto-send behavior.
S01 directly advances active requirements **R001** and **R002**, and it also lays the continuity foundation S04 will later rely on for **R010**. The work is split backend-first because the highest risk is the matching contract itself: if ranking, dedupe, and metadata stay client-only, the UI can look nicer while the import loop still feels untrustworthy. Once that contract exists, the frontend task can focus on presenting the ranked results cleanly instead of inventing its own heuristics.
## Must-Haves
- A job-scoped Gmail matching API ranks candidate messages/threads for a specific `JobApplication` using company, recruiter, title, and existing correspondence signals rather than a generic inbox search alone.
- Gmail import persists enough metadata to preserve message/thread identity, expose already-imported state, and reduce duplicate cleanup when the user imports single messages or whole threads into a job.
- The job workspace `Correspondence` tab shows ranked Gmail suggestions with match reasons/confidence, keeps a manual search override, and refreshes the job-linked correspondence list after import.
## Proof Level
- This slice proves: integration
- Real runtime required: yes
- Human/UAT required: yes
## Verification
- `dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter GmailControllerTests`
- `CI=true npm --prefix job-tracker-ui test -- --watch=false --runTestsByPath src/correspondence-gmail-import.test.tsx`
- Manual UAT: run the app, connect a real Gmail account, open one job in the workspace, confirm ranked Gmail suggestions appear before manual search, import one message and one full thread, and verify the imported correspondence appears on that same job with duplicates skipped and no send/apply automation.
## Observability / Diagnostics
- Runtime signals: ranked match reasons/confidence returned per candidate, import result counts for imported/skipped messages, and existing request logs with trace ids around Gmail endpoints.
- Inspection surfaces: `api/gmail/status`, the new job-scoped Gmail matching response in `JobTrackerApi/Controllers/GmailController.cs`, the correspondence list in `job-tracker-ui/src/components/Correspondence.tsx`, and backend/frontend tests covering duplicate and failure paths.
- Failure visibility: Gmail connection state, empty/noisy candidate lists, duplicate-skip counts, and per-candidate imported/already-linked flags should remain visible enough to tell whether failure came from query construction, Gmail retrieval, dedupe, or UI wiring.
- Redaction constraints: never expose OAuth tokens or full message bodies in logs; diagnostics should stay at message metadata, ranking reasons, and import counts.
## Integration Closure
- Upstream surfaces consumed: `JobTrackerApi/Services/GmailOAuthService.cs`, `Data/JobTrackerContext.cs`, `Models/JobApplication.cs`, `Models/Company.cs`, `Models/Correspondence.cs`, `job-tracker-ui/src/components/JobDetailsDialog.tsx`, and `job-tracker-ui/src/components/Correspondence.tsx`.
- New wiring introduced in this slice: a job-aware Gmail candidate contract in the API, correspondence persistence that retains Gmail thread/message identity, and job-context-driven rendering in the workspace Gmail import UI.
- What remains before the milestone is truly usable end-to-end: later slices still need to consume the imported correspondence for stronger drafting and daily workflow surfaces, but Gmail import itself should be trustworthy after this slice.
## Tasks
- [ ] **T01: Add a job-aware Gmail matching contract and backend ranking tests** `est:3h`
- Why: The slice risk sits in matching quality, so the backend needs to own candidate discovery, ranking, and duplicate awareness before the UI can present trustworthy suggestions.
- Files: `JobTrackerApi/Controllers/GmailController.cs`, `JobTrackerApi/Services/GmailOAuthService.cs`, `JobTrackerApi.Tests/GmailControllerTests.cs`
- Do: Add a job-scoped Gmail candidate endpoint that loads the owned job plus company context, builds multiple Gmail queries from recruiter/company/title/correspondence signals, dedupes messages and groups them by thread, and returns ranked suggestions with match reasons, confidence inputs, and already-imported flags; cover the contract with focused controller/service tests instead of leaving ranking in `Correspondence.tsx`.
- Verify: `dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter GmailControllerTests`
- Done when: the API can return ranked Gmail candidates for one job with explicit reasons and duplicate state, and backend tests prove owned-job lookup plus ranking/dedupe behavior.
- [ ] **T02: Persist Gmail thread metadata and harden import continuity** `est:3h`
- Why: Smarter matching is not enough if imported correspondence still loses thread identity or forces downstream slices to re-derive sender/thread information later.
- Files: `Models/Correspondence.cs`, `JobTrackerApi/Controllers/GmailController.cs`, `JobTrackerApi/Controllers/CorrespondenceController.cs`, `JobTrackerApi/Program.cs`, `JobTrackerApi.Tests/GmailControllerTests.cs`
- Do: Extend correspondence persistence and import logic so Gmail imports store thread/message identity plus sender/recipient metadata, update import responses and duplicate handling to reflect imported vs skipped outcomes clearly, and update startup schema guards so older SQLite/MySQL dev databases remain bootable when the new fields land.
- Verify: `dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter GmailControllerTests`
- Done when: imported correspondence keeps enough Gmail metadata for thread continuity and dedupe, compatibility guards are planned with the schema change, and tests prove single-message/thread imports behave correctly on repeat imports.
- [ ] **T03: Wire ranked Gmail suggestions into the job workspace UI** `est:3h`
- Why: The slice is only complete when the user can act on the smarter backend contract inside the actual job workspace rather than through a generic inbox search UI.
- Files: `job-tracker-ui/src/components/JobDetailsDialog.tsx`, `job-tracker-ui/src/components/Correspondence.tsx`, `job-tracker-ui/src/types.ts`, `job-tracker-ui/src/correspondence-gmail-import.test.tsx`
- Do: Pass job context from `JobDetailsDialog` into `Correspondence`, replace client-side primary ranking with the server-provided candidate contract, show match reasons/confidence/import state and thread actions, keep manual query/search as a fallback override, and add a React test that proves ranked suggestions and import refresh behavior in the dialog.
- Verify: `CI=true npm --prefix job-tracker-ui test -- --watch=false --runTestsByPath src/correspondence-gmail-import.test.tsx`
- Done when: the Correspondence Gmail tab opens on ranked job-aware suggestions, still supports manual search overrides, refreshes the correspondence list after import, and the new UI test passes.
## Files Likely Touched
- `JobTrackerApi/Controllers/GmailController.cs`
- `JobTrackerApi/Services/GmailOAuthService.cs`
- `Models/Correspondence.cs`
- `JobTrackerApi/Controllers/CorrespondenceController.cs`
- `JobTrackerApi/Program.cs`
- `JobTrackerApi.Tests/GmailControllerTests.cs`
- `job-tracker-ui/src/components/JobDetailsDialog.tsx`
- `job-tracker-ui/src/components/Correspondence.tsx`
- `job-tracker-ui/src/types.ts`
- `job-tracker-ui/src/correspondence-gmail-import.test.tsx`