# Remaster Proposal — Job Tracker **Companion to:** [SYSTEM_AUDIT_REPORT.md](SYSTEM_AUDIT_REPORT.md) · **Decision:** [REBUILD_DECISION.md](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 `.gsd` D003). 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](DATA_MODEL_REVIEW.md): - **Jobs:** split `JobApplication` (core+workflow) from a 1:1 `JobImportContent` (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 inline `TailoredCvText`; keep `StructuredCvProfile` as 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 inline `CoverLetterText` string, enabling versions/history. - **Timeline events:** keep `JobEvent`; ensure it and `Correspondence` render 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` + `CoverLetter` history; 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](MIGRATION_PLAN.md). Order: indexes → controller extraction → data-model splits → AI provider router + hardening → UX polish → (decide) frontend migration.