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>
5.5 KiB
Remaster Proposal — Job Tracker
Companion to: SYSTEM_AUDIT_REPORT.md · Decision: REBUILD_DECISION.md
This is an evolution proposal, delivered as an incremental remaster of the existing system (the audit found no justification for a from-scratch rebuild). It reshapes internals and data model while preserving the working boundaries that already earn their keep.
1. The one decision that gates everything: product identity
Answer this first — it changes the roadmap:
- (A) Personal power-tool (matches
.gsdD003). Optimise for one serious job seeker: depth, automation, no billing/onboarding overhead. Multi-tenant stays a nicety. - (B) Multi-tenant SaaS. Then onboarding, plans/billing, quotas, per-tenant AI cost control, and abuse-resistance become first-class — and the polling background services need an outbox/queue.
Everything below is written to be true for both, with SaaS-only items flagged [SaaS].
2. Architecture redesign (target)
Keep the topology; move logic out of controllers into services.
Frontend (Vite+React or Next.js — resolve the override) API (thin controllers → services)
feature-sliced modules JobApplicationService / AnalyticsService
│ CvContextBuilder / GmailImportService
▼ JobPipeline / StageAnalytics (keep)
typed API client (generated from OpenAPI) │
EF Core (SQLite dev / MySQL prod, +indexes)
AI gateway (unchanged HTTP boundary) ──▶ FastAPI: provider router {ollama|gemini|groq}
/summarize local · /cv/* cloud
[SaaS] outbox + queue for reminders/enrichment; per-tenant AI budget guard
Modules/services to extract (behaviour-preserving, test-guarded):
JobApplicationService, AnalyticsService (server-side aggregation), CvContextBuilder,
GmailImportService + GmailThreadRefresher, RuleSettingsCache. Controllers become thin HTTP adapters.
3. Data model redesign
Per DATA_MODEL_REVIEW.md:
- Jobs: split
JobApplication(core+workflow) from a 1:1JobImportContent(description/translation/ summary/tags) so hot list queries don't drag import blobs. - CVs (versioned): introduce
CvVersion(id, ownerUserId, sourceProfileId, jobApplicationId?, label, content, structuredJson, createdAt)— immutable snapshots. Deprecate inlineTailoredCvText; keepStructuredCvProfileas the source of truth for factuality checks. - Cover letters: promote to first-class
CoverLetter(id, jobApplicationId, source{manual|upload|ai}, content, createdAt)instead of the inlineCoverLetterTextstring, enabling versions/history. - Timeline events: keep
JobEvent; ensure it andCorrespondencerender as one interleaved timeline. - AI outputs: persist as versioned artifacts with provenance (provider, model, prompt hash) for audit and regeneration — supports the factuality-check feature.
- Attachments: drop the drift-prone booleans; compute from the collection.
- Indexes: add the five hot-path indexes first (highest ROI, lowest risk).
4. UX redesign
- Import: explicit partial-parse state ("we read X, confirm/fill the rest"); never a silent dead end.
- Match score: show matched vs missing keywords; relabel as "keyword coverage".
- CV flow: dedicated application-answer field (retire the notes-block workaround); version picker per job.
- CV review: surface "AI added: — confirm" (factuality guardrail).
- Dashboard/timeline: one chronological story (events + emails); keep time-in-stage + funnel.
5. AI strategy
- Keep deterministic scoring; add synonym normalisation + honest labelling.
- Keep generative work behind the HTTP gateway; add a provider router (
AI_PROVIDER) so prod offloads the GTX 1060 to Gemini/Groq while dev uses local Ollama on the 3080. - Harden prompts: delimit untrusted inputs, add a post-gen factuality diff against
StructuredCvProfile. - Strict separation: deterministic = anything the user trusts as a fact/number; generative = drafts only.
6. Email + automation redesign
- Reminders: keep, but make event-driven where possible (status change → schedule follow-up) instead of pure polling; [SaaS] move to an outbox + worker.
- Gmail: keep the job-scoped linked-thread refresh (D007/D008 works); add health/telemetry.
- Optional inbound parsing stays opt-in and deterministic (
EmailStatusClassifier) — no auto-send (D002).
7. Optional features
Must-have
- Hot-path indexes; god-controller extraction; attachment-boolean fix; tailored-CV single source.
- Provider router for AI (unblocks prod on the 1060).
- Import partial-parse UX; match-score gap breakdown.
Nice-to-have
- Real
CvVersion+CoverLetterhistory; factuality guardrail; funnel drill-downs; scraper health board. - Frontend migration off CRA (Vite easiest; Next.js if SEO/SSR for a public product).
Experimental
- Embedding-based advisory match second-opinion; auto-suggested follow-up timing from response-rate data; [SaaS] per-tenant AI budget + BYO-key.
8. Sequencing
See MIGRATION_PLAN.md. Order: indexes → controller extraction → data-model splits → AI provider router + hardening → UX polish → (decide) frontend migration.