Files
jobtrackingapp/docs/remaster/REBUILD_DECISION.md
T
cesnimda f0f178d77e docs(remaster): full-system audit + rebuild-vs-refactor decision
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>
2026-07-05 10:04:03 +02:00

84 lines
6.0 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.
# Rebuild Decision — Job Tracker
**Companion to:** [SYSTEM_AUDIT_REPORT.md](SYSTEM_AUDIT_REPORT.md)
**This is the gate.** Per the mission, because the recommendation is **Incremental Refactor**, work STOPS
here pending your approval — no `JobTrackerV2` is created.
## Executive summary
The audit examined product logic, architecture, data model, AI, security, UX, testing, and deployment
against the actual code. The system is a **mature, working, production-deployed brownfield** with correct
architectural bones (hardened cookie/CSRF auth, real SSRF defence, enforced multi-tenancy, a cleanly
decoupled AI service, deterministic scoring, 135 backend integration tests + 23 frontend suites, live at
`jobs.cesnimda.uk`). Its problems are **concentrated and fixable** — god controllers, a god entity, missing
indexes, prompt-injection hardening, and CRA build debt — none of which are load-bearing architectural
failures. A rebuild would discard substantial correct, tested work to re-solve problems that are already
solved, while re-introducing risk. **The evidence points clearly to incremental refactor.**
## Recommendation
### ✅ Continue with Incremental Refactor
(A full rebuild is **not** justified.)
## Evidence
**Against rebuild / for refactor:**
1. **No Critical defects.** No auth bypass, tenant-isolation break, or SSRF hole in audited paths. Rebuilds
are justified when the foundation is unsafe; this foundation is sound.
2. **The hard, easy-to-get-wrong things are already right:** SSRF blocklist (post-DNS, all private/CGNAT/
link-local/IPv6-ULA ranges), HttpOnly-cookie + CSRF auth (token never in JS storage — test-asserted),
global query-filter tenancy, and a provider-swappable AI boundary that needs **zero** app changes to move
off the weak prod GPU.
3. **Strong test harness.** 135 integration tests exercise controllers against a real in-memory DB — they
lock behaviour so internals can move safely. A rebuild throws this safety net away.
4. **Debt is localised.** 3 god controllers (~6.7k of ~9k controller lines) and 1 god entity account for
most of the maintainability pain. Both are reachable by in-place extraction.
5. **Live in production with a working CI/CD pipeline.** Discarding a deployed, observable system for a
greenfield reset trades known, bounded debt for unknown, unbounded schedule risk.
**Acknowledged weaknesses (all refactorable):** god classes; `JobApplication` god entity + denormalised
attachment booleans + dual CV source; missing hot-path indexes + load-all analytics + Gmail N+1; prompt
injection (capped by human-review); CRA transitive-vuln debt; the unexecuted "use next.js" override.
## Estimated effort
| | Incremental Refactor | Full Rebuild |
|---|---|---|
| Perf wave (indexes, aggregation, N+1, AI router) | ~1 focused pass | included, re-derived |
| Safe refactors (extract services/DTOs) | ~12 passes | rebuilt from scratch |
| Data-model evolution (versioning, splits) | ~12 passes, additive migrations | rebuilt + data migration anyway |
| Frontend platform (Vite/Next) | 1 isolated milestone | rebuilt |
| **Re-earning current parity (auth, SSRF, tenancy, 135 tests, deploy)** | **£0 — already have it** | **large, high-risk, re-tested** |
| **Total** | **Weeks of bounded, shippable slices** | **Months, mostly to get back to today** |
**Long-term maintenance:** after the refactor waves, maintenance cost is *lower than a rebuild's* because
the domain knowledge, tests, and ops are retained and improved rather than reconstructed.
## Risks
- **Continuing (current architecture):** god classes slow features and invite merge conflicts; unindexed
hot paths degrade as data grows; prompt injection can mislead drafts; CRA debt ages. **All mitigated by
the planned waves.**
- **Rebuilding:** re-introducing already-solved security bugs; long no-value-delivery window; data migration
is required *either way*; loss of the test harness during transition; opportunity cost.
- **Migration (refactor path):** additive migrations with backfill checks + staging dry-run on a MariaDB
copy + already-automated backups keep data-loss risk low.
- **User impact:** refactor path keeps the app live throughout; rebuild path risks a freeze or a parallel
system to maintain.
- **Operational:** single-capacity CI runner → keep slices small, one PR at a time (already the practice).
## Reuse analysis
| Verdict | Items |
|---|---|
| **Reuse unchanged** | Cookie/CSRF auth, SSRF ingestion guard, global query filters, `JobCvMatchService`/`JobPipeline`/`StageAnalytics`/`EmailStatusClassifier`, AI HTTP boundary, background-service model (single-node), test suites, deploy pipeline, docs from prior phases |
| **Refactor before reuse** | `JobApplicationsController`, `ProfileCvController`, `GmailController`, `JobApplication` entity, `tools/summarizer` prompt construction, CRA build setup |
| **Rewrite** | attachment-boolean logic → computed; tailored-CV/cover-letter storage → versioned tables; analytics read paths → server-side aggregation |
| **Remove** | denormalised attachment columns (post-backfill), inline `TailoredCvText`/`CoverLetterText` (post-migration), dead `Controller/` folder, scratch files (`temp_job.json`, `temp_post_job.py`) |
| **Keep out of repo** | `.gsd/`, `.claude/`, keys, backups, exports (all git-ignored — verify `.claude` is added) |
## Long-term recommendation
**Incrementally remaster.** It delivers the best balance of maintainability (retain tests + knowledge),
scalability (indexes + service extraction + optional queue), engineering velocity (shippable slices, no
freeze), reliability (behaviour-locked by tests, app stays live), and product quality (UX/AI fixes land
continuously). Reserve "rebuild" language for the *frontend platform* only, and only if you choose Next.js
for a public SEO product — that is a scoped migration, not a system rebuild.
## Gate
➡️ **Awaiting your approval.** On approval, I proceed with [MIGRATION_PLAN.md](MIGRATION_PLAN.md) Wave 1
(the paused Phase 7 performance work) as the first slice. No `JobTrackerV2` will be created.