--- id: S02 parent: M001 milestone: M001 provides: - stronger application-package generation that uses imported correspondence, recruiter/job context, profile CV structure, and attachment signals - a persisted package workspace inside the job dialog for tailored CV, cover letter, recruiter message, and application-answer draft material requires: - slice: S01 provides: imported and auto-refreshed job-linked correspondence plus trusted thread metadata for package context assembly affects: - S03 key_files: - JobTrackerApi/Controllers/JobApplicationsController.cs - JobTrackerApi.Tests/JobApplicationsApplicationPackageTests.cs - job-tracker-ui/src/components/JobDetailsDialog.tsx - job-tracker-ui/src/job-details-generated-drafts.test.tsx key_decisions: - D006: persist the application-answer draft as a replaceable marker-delimited notes block until a dedicated field exists patterns_established: - assemble AI package context from persisted job, recruiter, correspondence, saved-draft, profile-CV, and attachment signals before prompting - treat generated artifacts as editable workspace state with explicit saved/generated/unsaved status rather than disposable preview output observability_surfaces: - POST /api/jobapplications/{id}/generate-application-package - PUT /api/jobapplications/{id}/tailored-cv - PUT /api/jobapplications/{id}/application-drafts - job-tracker-ui/src/job-details-generated-drafts.test.tsx - JobTrackerApi.Tests/JobApplicationsApplicationPackageTests.cs duration: 2 tasks verification_result: passed completed_at: 2026-03-24 --- # S02: Stronger AI application package drafting **Imported Gmail/job context now feeds a persisted application-package workspace that generates, edits, saves, and reloads job-specific draft material instead of one-shot generic previews.** ## What Happened S02 closed the main draft-quality gap by wiring S01’s imported correspondence into application-package generation and then making the Tailored CV tab behave like a real working surface. On the backend, `JobTrackerApi/Controllers/JobApplicationsController.cs` now builds package context from more than the job description. Generation explicitly pulls in recruiter identity, job URL, imported correspondence, saved package material already tied to the job, profile CV structure, and selected attachment signals. That context is reused across tailored CV, cover letter, application answer, recruiter message, and package key points so the returned artifacts can react to real recruiter/thread context instead of defaulting to generic role-summary language. On the frontend, `job-tracker-ui/src/components/JobDetailsDialog.tsx` now treats tailored CV, cover letter, recruiter message, and application-answer text as one package workspace. Reopening the job loads the saved copy back into the editors, generation replaces the current working copy for all package artifacts, save persists the package back to the job, and reset restores the last saved state. Status chips make the persistence state legible by distinguishing `Saved to job`, `Generated only`, and `Unsaved edits`. S02 also established a temporary but stable persistence contract for the application-answer draft: until a dedicated field exists, it lives in a marker-delimited block inside `JobApplication.Notes`, and save replaces that block rather than appending indefinitely. That keeps the workspace trustworthy and gives S03 a reliable place to read package context back from. The net effect is that S01 correspondence is no longer just imported and displayed; it now materially influences package drafting, and the resulting artifacts persist as reusable job workspace material. ## Verification - `$HOME/.dotnet/dotnet build JobTrackerApi/JobTrackerApi.csproj` — passed - `$HOME/.dotnet/dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter JobApplicationsApplicationPackageTests` — passed (2 tests) - `CI=true npm --prefix job-tracker-ui test -- --watch=false --runTestsByPath src/job-details-generated-drafts.test.tsx` — passed (2 tests) - Observability surfaces confirmed by implementation/tests: - `POST /api/jobapplications/{id}/generate-application-package` now emits package artifacts grounded in correspondence/recruiter/job context - `PUT /api/jobapplications/{id}/tailored-cv` and `PUT /api/jobapplications/{id}/application-drafts` form the durable save loop the workspace depends on - focused backend/frontend tests cover package generation specificity, notes replacement, saved-state load, edit, save, and redisplay behavior ## New Requirements Surfaced - none ## Deviations - The plan did not call out storage for the application-answer draft, but execution required a concrete persistence strategy before the workspace could be trustworthy. S02 therefore adopted the marker-delimited notes-block approach captured in D006 instead of introducing a new schema field mid-slice. ## Known Limitations - The application-answer draft is still stored inside `JobApplication.Notes` rather than a first-class field, so downstream work must keep honoring the marker-block contract. - Automated verification proves context wiring and persistence loops, but it does not replace human judgment on whether the generated writing feels genuinely strong enough for a real application; that still needs live UAT with real imported correspondence and AI output. - Draft quality still depends on the quality of the imported correspondence, recruiter metadata, profile CV structure, and selected attachments available on the job. ## Follow-ups - S03 should consume the saved package workspace artifacts, including the marker-delimited application-answer block, instead of reconstructing package context from scratch. - A later milestone can promote the application-answer draft to a dedicated persisted field if the notes-block workaround starts constraining editing, analytics, or downstream composition. - Milestone-level live UAT should include at least one job with strong imported Gmail context to judge whether the upgraded generator actually feels specific enough to start from. ## Files Created/Modified - `JobTrackerApi/Controllers/JobApplicationsController.cs` — strengthened package-context assembly, notes replacement behavior, and generation/save contracts - `JobTrackerApi.Tests/JobApplicationsApplicationPackageTests.cs` — focused backend proof for correspondence-aware package output and notes replacement - `job-tracker-ui/src/components/JobDetailsDialog.tsx` — converted the Tailored CV tab into a coherent generate/edit/save/reset package workspace - `job-tracker-ui/src/job-details-generated-drafts.test.tsx` — verified saved-state load, generation, editing, coherent save payload, and redisplay behavior - `.gsd/REQUIREMENTS.md` — refreshed R003 validation to reflect the direct filtered backend test plus frontend workspace proof - `.gsd/KNOWLEDGE.md` — recorded the marker-delimited application-answer persistence contract and the authoritative direct S02 test command ## Forward Intelligence ### What the next slice should know - S03 can now assume package context lives in durable job fields: `tailoredCvText`, `coverLetterText`, `recruiterMessageDraft`, and the marker-delimited application-answer block inside `notes`; use those saved values as the baseline context for reply/follow-up generation. ### What's fragile - Application-answer persistence via the `<<>> ... <<>>` notes block — downstream code must replace/parse that block consistently or the workspace will drift back into duplicate or stale-answer behavior. ### Authoritative diagnostics - `JobTrackerApi.Tests/JobApplicationsApplicationPackageTests.cs` and `job-tracker-ui/src/job-details-generated-drafts.test.tsx` — these are the tightest trustworthy checks for whether package generation is context-aware and whether the workspace save/reload loop still works end to end. ### What assumptions changed - Earlier task execution assumed the filtered backend verification might still need an isolated harness because of broader test-project drift — in this worktree, `dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter JobApplicationsApplicationPackageTests` now passes directly and should be treated as the primary S02 regression check.