f0f178d77e
Deep, code-grounded audit of Job Tracker producing the mission deliverables under docs/remaster/: system audit, bug report, architecture/data-model/AI/UX reviews, remaster proposal, migration plan, competitor research, and the gated REBUILD_DECISION. Verdict: Incremental Refactor (no full rebuild). Evidence: no Critical defects; hardened cookie/CSRF auth (token never in JS storage), real SSRF defence, enforced multi-tenancy via global query filters, decoupled provider-swappable AI service, 135 backend tests. Debt is localised (god controllers/entity, missing hot-path indexes, prompt-injection hardening, CRA build debt) and reachable by in-place, test-guarded refactors. Also harden .gitignore: exclude agent tooling (.claude/, .bg-shell/, .agent.md) and restore/broaden the runtime-secrets block (**/keys/, **/backups/, exports, CV artifacts) so nested DataProtection keys can't be committed accidentally. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4.6 KiB
4.6 KiB
Migration / Remaster Plan — Job Tracker
Companion to: REMASTER_PROPOSAL.md · Decision: REBUILD_DECISION.md
Strategy: incremental, test-guarded, feature-branch per unit (matches .gsd D017 slice discipline and
the project's no-direct-main / conventional-commit rule). The 135 backend integration tests + 23 frontend
suites are the safety net that makes internal change low-risk. No big-bang.
Guardrails per slice
- Branch off
main; conventional commit; no direct main pushes; no auto-merge. dotnet build -c Release+dotnet test JobTrackerApi.Testsgreen before commit.- Frontend: full Jest suite green.
- One PR per slice → one CI run on the Pi (single-capacity runner).
- Behaviour preserved; add a targeted test if a slice exposes a coverage gap.
Wave 1 — Performance (lowest risk, highest ROI) — this was the paused Phase 7 work
- P1. Hot-path indexes (
Data/JobTrackerContext.cs+ one migration):IsDeleted,(IsDeleted,Status),FollowUpAt,Correspondence.JobApplicationId,JobEvent.JobApplicationId. SQLite+MySQL safe. - P2. Server-side aggregation for
GetStats/GetAnalyticsOverview(no full-tableToListAsync). - P3. Gmail N+1 batch fixes (:646, :701, :893) +
FirstOrDefaultAsyncfor review decisions. - P4.
RuleSettingscache inIMemoryCache(short TTL, per user). - AI provider router in
app.py(AI_PROVIDER={ollama|gemini|groq}) +/healthreports provider; default staysollama(keyless). Prod.envsetsAI_PROVIDER=gemini+ rotated key → offloads the 1060.
Wave 2 — Safe refactors (behaviour-preserving)
- R1. Extract services from
JobApplicationsController:AnalyticsService,JobStatsService,CvContextBuilder. Controller shrinks to a thin adapter. - R2. Extract
GmailImportService+GmailThreadRefresherfromGmailController. - R3. DTO extraction for
JobApplicationsController/ProfileCvController/GmailController. - New files under
Controllers//Services/so theJobTrackerBackendglob picks them up; noProgram.csDI churn beyond registering the new services.
Wave 3 — Data-model evolution (additive migrations + backfill)
- D1. Attachment booleans → computed. Migration + backfill verification test; then drop stored columns.
- D2. Single tailored-CV source. Migrate
TailoredCvText→TailoredCvDraft; deprecate the string. - D3. Split
JobImportContent1:1 offJobApplication. - D4.
CvVersion+CoverLetterfirst-class tables (enables real versioning promised by the product). Each is a reversible EF migration; run against a SQLite dev DB and a MariaDB staging copy before prod.
Wave 4 — AI hardening + UX
- A1. Prompt-injection delimiters + input normalisation; factuality diff vs
StructuredCvProfile. - A2. Match-score synonym map + relabel; matched/missing breakdown in the UI.
- U1. Import partial-parse state; dedicated application-answer field; AI-fabrication confirm UI.
Wave 5 — Frontend platform (decide first)
Resolve the .gsd "use next.js" override deliberately:
- Least churn: CRA → Vite (drops most transitive-vuln debt, keeps React/MUI, fast).
- If public/SEO product: Next.js (honours the override; SSR/routing/metadata) — larger effort. Do this as its own milestone, not coupled to backend work.
Risk assessment
| Risk | Likelihood | Mitigation |
|---|---|---|
| Migration data loss (Wave 3) | Low | additive + backfill + staging dry-run on MariaDB copy + backups (already automated) |
| Behaviour regression in extraction | Low | 135 integration tests lock the API contract |
| Single-runner CI bottleneck | Medium | one PR per slice; keep slices small |
| Provider-router auth leak | Low | key from env only; never logged/committed; rotate the pasted key |
| Frontend migration churn | Medium | isolate as its own milestone; feature-flag if needed |
Preserve vs discard
- Preserve unchanged: auth (cookie+CSRF), SSRF ingestion guard, global query filters, deterministic services, AI HTTP boundary, background-service model (single-node), test suites, deploy pipeline.
- Refactor before reuse: the three god controllers,
JobApplicationentity, prompt construction. - Discard: attachment boolean columns (after backfill), inline
TailoredCvText/CoverLetterTextstrings (after migration), scraper reliance as a guarantee (keep as best-effort). .gsdlogic: treat as historical design intent (already mostly realised); resolve the two open items (next.js override, notes-block workaround). The.gsdfolder is git-ignored and stays out of the repo.