Files
jobtrackingapp/docs/cv-redesign/research/06-phased-implementation-plan.md
T

21 KiB
Raw Blame History

Jobjakt application documents Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking. Execution method is subject to the user's later choice; this document authorises no implementation.

Goal: Improve the existing CV workflow and complete an application-scoped cover-letter preview, design-matching and PDF workflow without weakening recovery or ownership.

Architecture: Extend existing React/MUI editors and .NET services. Keep CV variants as lenses over career data; keep letters attached to applications. Share established rendering, pagination and export infrastructure where the contracts fit, while giving letters their own render model and complete revision coverage.

Tech Stack: Existing React, TypeScript, MUI, React Router, Axios, C#/.NET 9, EF Core, Playwright/Chromium, Jest/Testing Library and existing i18n. No new package is proposed initially.

Spec: Design proposal, wireframes, source constraints, acceptance criteria.

Global constraints

  • Research only until explicit user approval. No commands below have been run as implementation or verification.
  • Preserve /career/builder, /career/builder/:id, current application routes, MUI/theme, Archivo and English/Bokmål localisation.
  • Keep the existing 900px edit/preview breakpoint initially; verify 320, 390, 768, 899, 900, 1024 and 1440px layouts.
  • Preserve current owner scoping, plan checks, AI consent/review, HTML escaping, link restrictions and PDF resource limits.
  • Preserve CV save-before-export, expected-version conflicts, last-good preview and settings-only history semantics.
  • Letter Save/Discard remains explicit. Do not add autosave as a side effect of adding preview.
  • No FlowCV code, templates, graphics, branding or proprietary assets may be reused.
  • All repository paths below are relative to E:/Storage/Projects/Active/Job tracker. Newly proposed files are identified explicitly. No existing migrations are rewritten.
  • Approval of a future implementation does not authorise destructive or production migrations/deployment.

Review focus

  1. A late template response must not replace the currently selected candidate: Phase 1 task 2 stale-request test.
  2. A stale writer on any letter endpoint must not overwrite a newer letter: Phase 2 task 3 cross-endpoint concurrency tests.
  3. A new draft must not export an old saved document after save failure: Phase 3 task 5 held-save/export tests.
  4. Removing or changing the attached CV must not alter an already saved letter design: Phase 3 task 4 snapshot test.
  5. A restored CV settings revision must not be presented as a frozen historic profile: Phase 1 task 1 history-copy test and Phase 4 package checks.

File and dependency map

Responsibility Existing files to extend New files only when phase needs them
CV hierarchy, provenance, save/history wording job-tracker-ui/src/views/CvBuilderEditor.tsx, src/i18n/translations.ts None
Template candidate preview src/components/CvTemplateGallery.tsx, src/cvBuilder.ts, editor src/components/cv/CvTemplatePreviewDialog.tsx
Letter text/revision contract and all writers JobTrackerApi/Models/JobApplication.cs, Models/CoverLetterVersion.cs, Services/ApplicationAssetsService.cs, Controllers/ApplicationAssetsController.cs, Controllers/JobApplicationsController.cs, Controllers/JobApplicationDtos.cs, Data/JobTrackerContext.cs; frontend src/applicationWorkspace.ts, src/components/ApplicationAssets.tsx and all actual create/update callers Additive migration created only after schema design approval
Letter rendering and design snapshot Existing CV safe-rendering/normalisation and export infrastructure; existing letter controller/service JobTrackerApi/Models/CoverLetterDocumentSettings.cs, Services/CoverLetterRenderer.cs; frontend src/components/CoverLetterPreview.tsx
Saved letter PDF ApplicationAssetsController.cs, ApplicationAssetsService.cs, existing PDF admission/export registration in Program.cs Small letter export adapter only if existing exporter cannot accept rendered HTML cleanly
Frozen package and data exports Services/SubmittedApplicationPackageService.cs, Models/SubmittedApplicationPackage.cs, Services/AccountDataExportService.cs, Controllers/BackupController.cs, Controllers/ExportController.cs, documents listing Additive package artifact schema only when needed
Coverage Existing CV and application-assets unit/E2E suites Focused letter render/concurrency/PDF tests, not a parallel test framework

Paths abbreviated as src/... in this table belong to job-tracker-ui. No cross-cutting editor refactor is required before these phases.

Phase 1 — improve the CV workflow without a schema change

Task 1: clarify scope, history and mobile actions

Modify: job-tracker-ui/src/views/CvBuilderEditor.tsx, src/i18n/translations.ts; library view only where card labelling needs adjustment. Tests: existing src/cv-builder-page.test.tsx, e2e/cv-editor-frame.spec.ts, e2e/cv-responsive-workflow.spec.ts.

Interfaces: Consume current variant/job metadata and existing save/undo/history handlers. Produce labels and navigation only; do not change CV DTOs or persistence.

  • Add a failing assertion that restoring settings history is described as using the current career profile; assert new EN/NB labels and named overflow actions.
  • Run the focused unit file and confirm the new assertion fails for the missing behaviour, not setup failure.
  • Add context/provenance wording, keep existing retry/conflict controls and move controls reachable at mobile widths. Use existing handlers and semantic tokens.
  • Run focused tests; extend responsive workflow for inactive-pane focus exclusion, move-up/down focus retention and dirty mode switching. Confirm source facts remain unchanged.
  • Review and commit only the scoped change after the focused checks pass.

Exit: clearer document ownership, correct history semantics and accessible actions; no new backend contract. Covers AC-01, 03, 04, 11, 12.

Task 2: render a candidate before applying a theme

Modify: job-tracker-ui/src/components/CvTemplateGallery.tsx, src/views/CvBuilderEditor.tsx, src/i18n/translations.ts. Create: src/components/cv/CvTemplatePreviewDialog.tsx and a focused test. Reuse: cvBuilderApi.themePreview(themeId: string): Promise<CvRender> and applyCvTheme(settings, themeId) in src/cvBuilder.ts.

Proposed component interface: CvTemplatePreviewDialog({theme, open, onClose, onApply}), where theme: CvTheme | null, open: boolean, onClose: () => void, onApply: (themeId: string) => void. Consume existing API/render DTO; do not invent a new template payload.

  • Add tests named candidateSelectionDoesNotSave, cancelPreservesDraft, lateCandidateResponseIsIgnored, applyIsOneUndoStep and lockedCandidateCannotApply; assert actual request/write counts.
  • Run the focused tests and confirm the new behaviours fail before implementation.
  • Implement the dialog using the existing sample-preview API, with a visible Sample content label, loading/error/retry, focus trap/return, and explicit Apply. Reuse established preview readiness logic where its sample contract fits.
  • Preserve current visual-reset confirmation, capability filtering, availability rules and content metadata. Apply via the editor's normal settings update, not a second persistence path.
  • Run template gallery, document controls and editor tests. Exercise EN/NB, desktop/mobile, preview failure and late response. Commit the independently usable candidate-preview feature.

Exit: accurate sample preview before a reversible theme application. Covers AC-02, 05, 11. Depends on no schema or new dependency.

Phase 2 — make all letter writes revision-safe

Task 3: close the shared persistence gap before persistent design

Modify: the letter model/service/controller/DTO files in the map; all frontend callers of generic job create/update and application draft updates. Tests: JobTrackerApi.Tests/ApplicationAssetsTests.cs, new CoverLetterConcurrencyTests.cs, frontend src/application-assets.test.tsx, current job update tests. Schema: additive current-letter revision plus per-version snapshot fields only as required; no changes are authorised now.

Proposed contract: extend CoverLetterDto with revision: number (server Revision: int). Dedicated save and restore accept expectedRevision: number; successful content change returns the new revision and creates one history record. No-op content saves do not advance it. Use a dedicated EF concurrency token on the application letter revision so unrelated job edits are not needlessly conflicted.

All-writer policy:

Writer Required handling
Job create Initial nonblank text gets initial revision/history in the same transaction as job creation; blank remains empty
Dedicated letter save and restore Require expected revision; missing → 428, stale → 409; restore appends rather than rewinds
Generic job update Preserve existing null-clears behaviour. Any request that changes the letter must carry expected letter revision
Application draft update Preserve null-leaves-unchanged and whitespace-clears behaviour; require revision when a mutation is requested
AI generate/improve Continue returning proposals; no direct letter mutation until explicit Apply and Save

Legacy clients that attempt letter mutations without the revision receive 428 with a stable error code. Generic updates that do not change letter content continue to work. Audit serialized full-job clients so stale copies do not unintentionally request changes; update them to carry the correct revision or omit letter mutation through an explicit DTO contract. Do not silently convert clear into unchanged.

  • Find every CoverLetterText assignment and every call to save/restore across controllers, services, fixtures, import/restore flows and clients. Capture the inventory in implementation review; include backup/import semantics explicitly.
  • Write failing tests: dedicated-vs-generic concurrent writes; generic-vs-draft; save-vs-restore; unchanged job update; null/whitespace semantics; foreign owner; failed transaction; no-op save. Use two independent database contexts and the supported relational provider, not only EF InMemory.
  • Confirm the new tests fail on the unprotected behaviour before implementation.
  • Centralise revision validation and history staging in ApplicationAssetsService using the existing DbContext and a single transaction for job and letter changes. Existing controller calls must not save the letter independently before a later job update can fail. Map EF concurrency conflicts consistently to 409.
  • Add an additive migration after inspecting existing schema and version duplicates read-only. Seed revision from existing history/current text deterministically. Preserve every historic row. A duplicate-history preflight blocks uniqueness changes; it never deletes records automatically.
  • Update all mutation DTOs, frontend API callers, mock responses, fixtures and recovery UI in the same contract change. Hold migration execution and production rollout for their own approved step. Document old-client 428 compatibility and rollout order.
  • Run the focused .NET and frontend tests. Prove lost-update prevention on the supported relational database. Commit the contract and its migration source together once review is complete.

Exit: every normal letter writer participates in a consistent revision/history boundary. This phase is valuable without letter design. Covers AC-06, 07, 09. Phase 3 persistence depends on this gate; do not bypass it with UI-only version checking.

Phase 3 — letter presentation, matching and export

Task 4: persist explicit document details and a compatible design snapshot

Create: JobTrackerApi/Models/CoverLetterDocumentSettings.cs, Services/CoverLetterRenderer.cs; frontend src/components/CoverLetterPreview.tsx. Modify: letter current/version models and DTOs, ApplicationAssetsService, controller, src/applicationWorkspace.ts, src/components/ApplicationAssets.tsx, translations. Tests: new JobTrackerApi.Tests/CoverLetterRenderingTests.cs, existing assets tests plus focused preview tests.

Proposed settings DTO: versioned JSON with schemaVersion: 1; explicit sender/recipient/date/subject fields; design values for page size, permitted fonts, base font size, line height, margins, accent/text colours and compatible header style. Represent copied contact/design as snapshots with optional source CV id. Do not embed arbitrary CSS, raw HTML, remote font URLs or CV column definitions. Reuse current renderer allowlists and numeric clamps; define the compatible subset in this model and test every field. Do not invent broader numeric ranges than existing validated settings.

Proposed renderer contract: CoverLetterRenderer.Render(string? text, CoverLetterDocumentSettings settings, string language) -> string safe complete document HTML. Preview consumes unsaved draft text/settings without persisting. The saved letter DTO and every history snapshot carry both text and settings. Text-only old versions resolve to documented defaults. A change to either text or settings advances the shared revision once.

  • Write failing tests for script/link/CSS injection, supported Markdown, long Norwegian prose, empty text, old text-only versions, settings normalisation and two-page output readiness.
  • Add contact-copy tests asserting only approved core fields are selected by default; optional identity fields are excluded; copy cancellation leaves the draft unchanged.
  • Add design-match tests asserting compatible values are snapshotted, body/recipient preserved, and later CV edits/deletion cannot change saved letter presentation.
  • Implement safe letter HTML with existing escaping/Markdown semantics and established page metrics. Share only proven helpers; no universal document engine or new WYSIWYG library.
  • Extend the explicit Save DTO from Phase 2 to atomically persist text/settings/revision. Update history restore and account/export/backup serializers so presentation is not lost on restore or recovery. Missing legacy settings produce defaults, not failure.
  • Add the responsive preview and two copy-review dialogs inside the existing application letter component. Preserve Save/Discard, route protection, last-good preview and stale-request suppression. Do not mount duplicate active editors at mobile widths.
  • Run focused tests and the mobile letter workflow with a held request, a failed preview and a changed application. Commit after both contract and interaction checks pass.

Exit: safe local preview, explicit core-contact copy, compatible design matching and restorable letter presentation. Covers AC-07, 08, 10–13. Depends on Phase 2 for persistence. A body-only preview can be released earlier using existing data, but must not masquerade as saved document design.

Task 5: export the intended saved letter revision

Modify: ApplicationAssetsController.cs, letter service/renderer, PDF exporter integration and Program.cs registration as needed; frontend applicationWorkspace.ts and ApplicationAssets.tsx. Test: focused letter export tests and new job-tracker-ui/e2e/cover-letter-document.spec.ts.

Proposed routes: POST /api/jobapplications/{jobId}/cover-letter/preview for owner-scoped unsaved draft HTML; GET /api/jobapplications/{jobId}/cover-letter/export-pdf?expectedRevision={revision} for owner-scoped saved PDF. Stale revision is 409, unknown/foreign job follows current non-disclosure policy. Response is application/pdf; no document content in logs. Routes are proposals, not discovered endpoints.

  • Add failing tests that held/failed save prevents PDF export; expected-revision mismatch cannot export a different letter; foreign owner cannot preview/export; admission timeout and renderer failure preserve the draft.
  • Reuse current Chromium admission, cancellation, bounded work and cleanup. Avoid adding a second unmanaged browser pool. Serve preview/PDF from the same letter HTML contract and font readiness rules.
  • Implement Save-then-export for dirty letters with explicit Saving/Exporting/failure status. A failed save never silently downloads old text. Disable duplicate export submissions while work is pending.
  • Run renderer/export integration and E2E tests, then manually inspect local synthetic PDFs for A4/Letter sizing, text selection, fonts, links, page breaks, omissions and desktop/mobile preview consistency.
  • Commit the scoped workflow after evidence is recorded. Do not promise tagged PDF accessibility unless independently verified.

Exit: letter PDF feature with revision fidelity and safe resource handling. Covers AC-08, 09, 13, 15.

Phase 4 — preserve records and qualify the release

Task 6: snapshot designed letters and run the failure matrix

Modify: JobTrackerApi/Services/SubmittedApplicationPackageService.cs, Models/SubmittedApplicationPackage.cs, data/export/backup models and serializers only as required for the letter artifact; document metadata UI and translations. Tests: SubmittedApplicationPackageTests.cs, DocumentsControllerTests.cs, account export/backup tests and current document contracts.

Contract: a new package records the exact letter text, effective presentation snapshot and rendered artifact/hash for that capture. Existing records remain readable as text-only captures. No historic record is silently rerendered from today's CV settings. UI uses “Recorded application package”; capture is not proof of submission/delivery.

  • Write failing tests for old package readability, snapshot immutability after source changes, owner-scoped artifact access, interrupted capture and exact-byte hash consistency.
  • Implement the smallest additive artifact change; preserve existing retention/attachment rules and data portability. Document storage impact and cleanup policy rather than inventing an unbounded render archive.
  • Run document, package, account export and backup round-trip tests. Ensure all ordinary read/list endpoints remain read-only.
  • Run the Break Jobjakt matrix in a disposable local/test environment. Include real phone/keyboard, screen reader, EN/NB, light/dark, offline/reconnect, concurrency and long-document PDF checks.
  • Record exact commit, commands, results, screenshots, limitations and outstanding human checks. Obtain implementation/release review before any production action. Commit the qualified changes without unrelated refactoring.

Exit: document records and portable data remain faithful; a bounded release decision has reproducible evidence. Covers AC-10–15. No production deployment is part of this research plan.

Suggested verification commands for the future implementer

Run from the appropriate project directory; commands are examples for the inspected scripts, not results. Prefix shell calls with RTK per repository instructions. Reconfirm the SDK/package state at execution time. Database-dependent suites require a disposable approved test database; never aim them at production.

# job-tracker-ui
rtk proxy npm test -- --runInBand src/cv-template-gallery.test.tsx src/cv-document-controls.test.tsx
rtk proxy npm test -- --runInBand src/application-assets.test.tsx
rtk proxy npm run typecheck
rtk proxy npm run lint
rtk proxy npm run test:e2e -- e2e/cv-editor-frame.spec.ts e2e/cv-responsive-workflow.spec.ts
# repository root; use configured SDK 9.0.317
rtk proxy dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter "FullyQualifiedName~ApplicationAssetsTests|FullyQualifiedName~CvRevisionReadinessTests"

New files named in tasks must be included in the matching focused run; run the broad required repository gates once the final changes justify them. If system dotnet cannot resolve the pinned SDK, use C:/Users/Connor/.dotnet/dotnet.exe with the proper DOTNET_ROOT. Do not install/upgrade dependencies merely to start this plan.

Dependency order, rollback and stop conditions

Phase 1 can ship independently. Phase 2 is a separate persistence project and can ship without presentation changes. Phase 3 depends on Phase 2; Phase 4 depends on the designed-letter output. Keep schema changes additive and old snapshots readable. Before any future schema deployment, document backup, forward/backward application compatibility and a tested rollback of application code that does not discard new data. Do not assume reverting a migration is safe.

Stop a phase if it requires a second editor/state framework, a replacement CV renderer, an undocumented external endpoint, silent data conversion, or an unreviewed destructive schema step. Resolve the concrete scope issue in review. New AI providers, standalone letter documents, DOCX generation, touch-drag libraries, custom zoom and new font infrastructure remain deferred.

Plan self-review: all design requirements map to the six tasks and acceptance IDs; the five review-focus risks have named tests; proposed contracts are marked as proposed; current runtime and production claims remain Not Tested. No implementation, test execution or schema operation has occurred during this investigation.