--- estimated_steps: 4 estimated_files: 4 skills_used: - aspnet-core - test --- # T01: Add linked Gmail thread refresh to the backend contract **Slice:** S01 — Smarter Gmail import and matching **Milestone:** M001 ## Description Finish the backend half of S01 by making already-imported Gmail threads refreshable for a single job. The executor should build on the existing job-aware matching/import flow already present in `GmailController`, keep the scope bounded to known linked thread ids, and return a clear refresh result that distinguishes new imports from duplicate-only refreshes and disconnected/failure states. ## Steps 1. Inspect the current Gmail import code in `JobTrackerApi/Controllers/GmailController.cs`, the Gmail API wrapper in `JobTrackerApi/Services/GmailOAuthService.cs`, and the current `GmailControllerTests` coverage to identify the smallest thread-refresh contract that can satisfy R002. 2. Add a job-scoped linked-thread refresh path in `JobTrackerApi/Controllers/GmailController.cs` that loads one owned job, gathers distinct linked `ExternalThreadId` values from its correspondence, fetches Gmail messages for those known threads, and imports only unseen `ExternalMessageId` values into the same job. 3. Extend `JobTrackerApi/Services/GmailOAuthService.cs` with the thread-level retrieval helper(s) needed by that controller path, and keep diagnostics bounded to counts, ids, timestamps, and connection state rather than full message bodies. 4. Expand `JobTrackerApi.Tests/GmailControllerTests.cs` to cover successful refresh with a new inbound reply, successful refresh with a new user-sent reply, duplicate-only refresh, disconnected Gmail state, and invalid/inaccessible job handling. ## Must-Haves - [ ] The refresh path operates on already-linked Gmail thread ids for one owned job; it does not introduce inbox-wide watch/history infrastructure for this slice. - [ ] New Gmail replies import into the same `JobApplication` with existing duplicate protection based on `ExternalMessageId`. - [ ] The refresh contract exposes enough status to tell whether the run imported new messages, found only duplicates, or could not run because Gmail/job state was invalid. ## Verification - `dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter GmailControllerTests` - Confirm the updated tests assert at least one new-message refresh, one duplicate-only refresh, and one failure-path outcome. ## Observability Impact - Signals added/changed: linked-thread refresh result counts, last refresh/sync timestamp updates, and explicit disconnected/invalid-job outcomes. - How a future agent inspects this: read the refresh DTO and controller action in `JobTrackerApi/Controllers/GmailController.cs` and the focused assertions in `JobTrackerApi.Tests/GmailControllerTests.cs`. - Failure state exposed: the API should make it obvious whether nothing happened because there were no linked threads, Gmail was disconnected, every message was already imported, or the job was not accessible. ## Inputs - `JobTrackerApi/Controllers/GmailController.cs` — current job-aware Gmail matching and import endpoints. - `JobTrackerApi/Services/GmailOAuthService.cs` — current Gmail list/detail helpers and connection status updates. - `JobTrackerApi.Tests/GmailControllerTests.cs` — existing Gmail controller test coverage. - `JobTrackerApi/Program.cs` — existing Gmail/correspondence runtime wiring and compatibility guards. ## Expected Output - `JobTrackerApi/Controllers/GmailController.cs` — adds the linked-thread refresh contract for one job. - `JobTrackerApi/Services/GmailOAuthService.cs` — adds thread-fetch support used by refresh. - `JobTrackerApi.Tests/GmailControllerTests.cs` — proves refresh success, duplicate-only, and failure-path behavior. - `JobTrackerApi/Program.cs` — updates any wiring needed for the new refresh flow or diagnostics.