Files
jobtrackingapp/docs/implementation-roadmap.md
T
cesnimda c08232b9d7
CI and Deploy / test (push) Failing after 58s
CI and Deploy / deploy (push) Has been skipped
feat: meter AI usage
2026-07-30 22:39:24 +02:00

29 KiB
Raw Blame History

Jobjakt — Implementation Roadmap

Date: 2026-07-17 · Updated after Phase 0 (see docs/phase-0-foundation-report.md) Companion to docs/application-discovery-report.md. Every task below traces to a verified finding there.

Phase 0 is complete. Architecture docs restored, AI sidecar locked down to backend-only and verified live, pipeline expanded beyond Applied (10 stages, 3 board groups), Job entity introduced. Phase 1 below has been re-scoped against the actual architecture rather than the assumptions the original plan carried. Product decisions from 2026-07-17 are folded in throughout.

Product decisions now settled (were open questions):

  1. Career profile storage — relational for Experience/Education/Skills/Projects; JSON blob for the long tail. Phase 3 is unblocked.
  2. AI providers — fix the docs to match the code; do not build the multi-provider abstraction. Task 5.1 is now S, not L.
  3. Job discovery order — manual URL import → browser extension → official APIs. Scraping is not a starting point. Phase 6 re-ordered.
  4. Geography — Norway first, but no hardcoding Norway; market is a data dimension. New task 6.6, and Job.CountryCode/Job.Source already exist.
  5. Free vs Premium — Free: job tracking, basic career profile, basic CV. Premium: advanced AI, more themes, automation, analytics, more storage. Not count-based. Phase 7 scoped.
  6. MockupsF:\Pictures\website\jobtracker\new is the source of truth only where a mockup exists; do not invent pages from them.

Legend Priority: P0 blocker · P1 high · P2 medium · P3 later Difficulty: XS <½day · S ~1day · M 24days · L ~12wk · XL 2wk+

Ordering principle: the guide names "Excellent Job Tracking" and "Excellent Application Workflow" as goals #1 and #2. Phase 1 exists because the data model currently cannot represent goal #2 at all. Nothing in Phases 37 is worth building before that is true.


Phase 0 — Foundation corrections DONE (2026-07-17)

Delivered: architecture docs restored and corrected; AI sidecar authenticated + de-published; JobPipeline gained Saved/Interested/Preparing under a new Prospect category; DateApplied nullable + SavedAt added; Job entity introduced additively; ADR-002 written. Full record in docs/phase-0-foundation-report.md.

Original tasks 1.1, 1.2, 1.3 (backend half), 1.5, 1.7, 1.8, 1.9, 1.10 are complete and removed from Phase 1 below.


Phase 1 — Critical fixes (re-scoped after Phase 0)

Goal: finish surfacing the pre-application workflow in the UI, and close the security findings that need an operator.

# Task Priority Difficulty Dependencies Expected value
1.1 Surface prospect stages in the UI — add Saved/Interested/Preparing to src/pipeline.ts (PIPELINE_STATUSES), the Kanban columns, the status filter and the status menus. P0 M Phase 0 The backend supports the workflow; the UI does not yet expose it. Phase 0 deliberately changed no UI behaviour. Until this lands, users still cannot save an unapplied job. Note the Kanban already has 6 columns — 9 stages needs a layout decision.
1.2 Point the add-job wizard at Saved/Preparing P0 XS 1.1 Completes the workflow end to end. The 6-step wizard already exists (components/AddJobModal.tsx:368); this is a default-value change once 1.1 makes the stage selectable.
1.3 Drag-and-drop on the Kanban P2 M 1.1 Board is drop-target-only today. Table stakes at every competitor. Deferred: not blocking.
1.4 Rotate DataProtection keys P1 XS none Needs an operator — cannot be done from here. Keys remain recoverable from git history (519c32e, 955cae6). Open since 2026-07-03.
1.5 Fix the CORS wildcard landmineCors:Origins="*" triggers SetIsOriginAllowed(_ => true) with AllowCredentials() (Program.cs:96-102): any site could make authenticated requests with the user's session cookie. Not currently active (compose never sets Cors__Origins), but it is one config value away. Reject the *+credentials combination outright. P1 XS none Found during Phase 0. Cheap fix, severe if ever triggered. Was out of Phase 0's 5-item scope.
1.6 Resolve the dead careerView prop — either wire it or remove the tab P1 XS none Ships a visible "CV Builder" tab that does nothing (views/ProfilePage.tsx:231). Removing it until Phase 4 is honest; leaving it is not. Both files are uncommitted WIP — confirm intent before touching.
1.7 Fix the onboarding CV check — read the structured profile, not profileCvText P2 XS none components/OnboardingChecklist.tsx:31 tells users with a parsed profile to upload a CV again.
1.8 Fix the 5 pre-existing frontend test failures in profile-page.test.tsx and settings-view.test.tsx P1 S none Failing on main before Phase 0 (verified by stashing all changes and re-running). CI runs the whole suite, so main is red — every future change lands on a broken baseline.
1.9 Decide what to do with the feature/career-workspace branch. Investigated 2026-07-17 — see below. The orphan tables are not an abandoned prototype: they are the local footprint of 10 unmerged commits (local + origin, last touched 2026-07-12) containing working, tested code and 1,100 lines of research/strategy. All 7 tables are empty in dev, so there is no data to migrate. Branch is 29 commits behind main. P0 M none Blocks Phases 3 and 4 from being planned honestly. Re-deriving this work would waste weeks; ignoring it leaves a rebase debt that grows every day main moves. See docs/career-workspace-branch-assessment.md.
1.10 Dev DB is missing 2 migrations (AddCorrespondenceEmailFields, AddShortSummary) yet has SyncModelSnapshot — the reconciler patched the columns instead. P2 S none Local-only inconsistency, but it means the dev DB is not a faithful rehearsal for a prod migration. Worth reconciling before the Phase 1 cutover.

Phase 1 exit: a user can save a job they have not applied to, walk the wizard, prepare materials, and then mark it applied — visibly, in the UI. CI is green.


Phase 2 — UX improvements DONE (2026-07-30)

Goal: the guide's "users should always understand where they are, what they can do, what happens next."

# Task Priority Difficulty Dependencies Expected value
2.1 Split /profile and /career DONE (2026-07-17, commit 66cc6a7)/profile = identity + security + preferences; /career = master career profile. The two saves are now scoped (partial-update-safe PUT /auth/profile) so neither wipes the other; the inert CV-Builder tab and dead careerView prop are gone. The master profile is the source of truth; generated docs reference snapshots (not built yet). P1 M none Fixed the guide's "everything should have one obvious place". Functional separation via the existing careerOnly fork + scoped saves.
2.2 DONE (2026-07-30) — decomposed identity/security and Career Workspace into separate ProfilePage and CareerProfilePage components, with career sections extracted into focused presentational components. P1 M 2.1 Phase 2 delivered the functional split via the careerOnly fork + scoped saves, but it is still one file behind a boolean. Extracting ProfilePage (identity/security) and a CareerWorkspace content component (master profile) is the remaining cleanup — mechanical, deferred so Phase 2 stayed low-risk. Blocks nothing; do before heavy Phase 3/4 edits.
2.3 DONE (2026-07-30)Signup → Verify → Profile → Import CV → Connect email → First job; the dashboard progress flow reuses existing signup/verification screens, reads structured career data, detects Gmail/Outlook/IMAP connections, and disappears when complete. P1 M 2.1 Currently a dismissible checkbox pair. Surface the Gmail connect step — the strongest differentiator is buried in /settings/connected-accounts.
2.4 DONE (2026-07-30) — dedicated /register route reuses the hardened auth form and clearly disables submission when registration is unavailable. P2 S none Endpoint exists but returns 403 by default and has no route; signup is hidden inside LoginPage. Required for Phase 7; harmless now.
2.5 DONE — incremental cache equivalents ship through useViewResource for shared server state and useWorkspaceTabCache for expensive workspace tabs; no dependency added. P2 M none Root cause of the 6001400-line components and the hand-rolled refreshToken prop-threading. Pays for itself across Phases 36. Adopt incrementally, not as a rewrite.
2.6 DONE (2026-07-30) — extracted shared presentation cards and four intelligence tab panels into JobDetailsPanels and JobInsightTabs; the dialog remains the orchestration boundary. P2 M 2.5 A dialog carrying an entire workspace.
2.7 DONE — user-owned interview preparation is exposed in ApplicationWorkspacePage, reachable from workflow signals and reminders, with grouped editable prep items. P2 S none /jobapplications/{id}/interview-prep already works and is invisible. Cheap win — a shipped feature nobody can reach.
2.8 DONE (2026-07-30) — direct Jest + Babel configuration replaces react-scripts; packages were promoted from the existing lockfile without a new download. P2 M none Removes one of three frontend toolchains. Do not touch the router in the same change.
2.9 DONE — dashboard analytics include funnel, response rate by source, top companies, and time-in-stage backed by AnalyticsService. P3 M 1.3 The paid feature at Teal/Huntr. Needs correct prospect-vs-applied accounting from 1.3 first.

Phase 3 — Career Workspace

Goal: one professional source of truth that can actually feed outputs.

Foundation SHIPPED 2026-07-18 (commits 9c8644ea1dd447). The relational master career profile is built, tested (23 backend + frontend tests), migrated (verified on the live DB), wired to /career, with completeness overview + version-history restore. See docs/architecture/career-profile-model.md (Implementation status). Phase 3 completed 2026-07-30: the workspace, Master CV separation, variants, long-tail sections, extraction retention, and file-backed avatars are delivered.

# Task Priority Difficulty Dependencies Expected value
3.1 DONE — Experience/Education/Skills/Projects/Certifications/Languages are relational children of CareerProfile; long tail is JSON. Projection service keeps the blob as a derived read-model; lazy backfill from existing data. P1 L 1.9 Delivered. Queryable structured career data is now the source of truth; the blob is derived.
3.2 DONE (2026-07-30) — added Awards, Publications, Organisations, and References across extraction, review/merge, JSON storage, editing, and rendering. P1 S 3.1 The guide names them; StructuredCvProfile has no home for them beyond generic OtherSections. These are the blob half of 3.1.
3.3 DONE (2026-07-30) — dedicated Career Workspace page and focused section components. P1 M 2.1, 2.2 Currently a wrapper around ProfilePage.
3.4 DONE (2026-07-30) — Career Profile is the source of truth; Master CV is a generated representation. P1 M 3.1 The glossary is explicit — "The career profile is NOT a CV"; Master CV is a generated representation. Code has one blob. Getting this wrong makes Phase 4 impossible.
3.5 DONE (2026-07-30) — named CV variants with stable profile-item references. P2 M 3.4 In the glossary; no code. Distinct from per-application TailoredCvDraft, which works correctly and must not be disturbed.
3.6 DONE (2026-07-30) — retain the newest 20 completed extraction runs per user; queued/running work is protected. P2 S none Three copies of every CV (raw/normalized/structured), unbounded.
3.7 DONE (2026-07-30) — new avatars live in persistent file storage; the DB stores only an internal file reference, with legacy data-URL compatibility. P3 S none Base64 blob on the /auth/me hot path.

Do not disturb: TailoredCvDraft correctly implements "the master CV must never be modified automatically" — the single most important documented invariant, and it already holds.


Phase 4 — CV Builder

Goal: Content Tab → Customise Tab → Preview → Export (guide :312). Completed 2026-07-30. The builder now covers content, customisation, preview, export, variants, and public sharing.

Foundation SHIPPED 2026-07-18 (commits a3e18e4 backend, 158dd02 frontend). Data-driven theme engine + variant model + 3-tab builder + live preview + public CV, all consuming the master profile (never duplicating it). See docs/architecture/cv-builder.md and docs/architecture/cv-theme-engine.md. Status: 4.1 CvTheme model. 4.2 one ThemedCvRenderer (the old CvTemplateRenderer stays only for the legacy tailored-draft flow). 4.3 8 themes as data. 4.4 Content tab reorder/hide/rename + custom sections (up/down controls with keyboard support; native drag-and-drop deferred — no dnd dependency added yet). 4.5 Customise tab (theme, accent, fonts, density, page size, photo/icons/page-numbers). 4.6 live preview (server render on a 350 ms debounce for export fidelity). 4.7 PDF export wired into the builder. Plus: autosave + version history/restore, AI-assist (suggestion-only), and public CV at /cv/{slug}.

Phase 4.5 — Builder Polish SHIPPED 2026-07-18 (commits 585047d, e3b255f, 582c4e0). Public-CV deep links fixed (optional catch-all app/[[...slug]]; direct nav/refresh/shared links work, no infra change). Native drag-and-drop reorder for sections + entries (keyboard arrows kept). Per-item editing via GET /api/cv/outline: hide, title/subtitle override, rich-text bullets (**bold** *italic* __underline__ [link], escaped-then-whitelisted server-side). ItemOrder reorders entries without touching the master profile. Preview: zoom presets, measured page count + page navigation + page-break indicators, "updating" state. Unsaved/Saving/Saved indicator, loading skeletons, better empty states, ATS-friendly theme badge, a11y (ARIA labels, keyboard theme cards, focus rings), print-quality page-break CSS, AA contrast fix. Docs: cv-builder.md, cv-theme-engine.md. Server-rendered preview remains intentional for export fidelity; the controller was split into endpoint, pipeline, and parsing partials on 2026-07-30.

# Task Priority Difficulty Dependencies Expected value
4.1 DONE — Design the CvTheme model — layout, columns, header position, font family, base size + per-element deltas, spacing, margins, accent + application targets, icon style, photo settings P1 M 3.4 The keystone. Everything else in Phase 4 depends on themes being data. Modelled on FlowCV's proven control set (report §7), trimmed to ~12 controls per the guide's "avoid excessive configuration".
4.2 DONE — Replace CvTemplateRenderer with one parameterized renderer P1 L 4.1 Current code is a C# switch over 6 hardcoded HTML-string functions with roundedPhoto/curvedHeader booleans (Services/CvTemplateRenderer.cs:22). A structural dead end — do not extend it.
4.3 DONE — Seed 35 themes as theme documents — ATS Professional, Modern Professional, Creative P1 M 4.2 The guide's explicit target. Cheap once 4.1/4.2 land; impossible before.
4.4 DONE — Content tab — section add/remove/reorder, entry editing, drag-and-drop with keyboard support P1 L 3.4 FlowCV's keyboard drag affordances are worth matching (report §7).
4.5 DONE — Customise tab — the ~12 controls from 4.1 P1 M 4.1, 4.2 Currently nothing is customisable.
4.6 DONE — Live server-rendered preview P1 L 4.2 Today: server round-trip. FlowCV: continuous, side-by-side. Hardest piece — the renderer must run client-side or stream fast enough to feel live.
4.7 DONE — Wire export into the builder P2 S 4.6 POST /profile-cv/export-pdf + Playwright already work. Make Download persistent, not a mode.
4.8 DONE (2026-07-30) — Split ProfileCvController (split from 2,379 lines) P2 M Do it while working here, not as a standalone refactor.
4.9 Research Reactive Resume / Novoresume / ElegantCV ALREADY DONE — on feature/career-workspace: docs/cv-builder-competitor-deep-research.md (327 lines, 8 teardowns incl. Novoresume + Reactive Resume, feature matrix, business-model analysis). Recover it; do not redo it. P1 XS 1.9 Its conclusions independently match this plan's §7/§10 reasoning — structured-form + live preview beats canvas; client-side preview is a hard requirement; themes must be declarative data. It also carries the pricing intelligence Phase 7 needs (Resume.io's F BBB rating for billing traps; Novoresume blocking re-download of already-paid CVs), which independently supports the "never gate on count" decision.

Phase 5 — AI improvements

Goal: polish. This is the healthiest area — grounding in the structured profile is already right, and "AI never has final control" already holds.

AI Career Assistant SHIPPED 2026-07-18 (commits f299d7b backend, bb0c0fe frontend). A unified per-application AI Workspace tab with five suggestion modules — job-analysis, career-match, cover-letter (6 tones), interview, application-review — each running through the existing ISummarizerService/ai-service provider abstraction and stored as append-only history (AiInteraction) with reuse / compare / copy / delete. Suggestion-only throughout; nothing auto-applies; Markdown renders React nodes (no HTML-injection surface). See docs/architecture/ai-career-assistant.md. Phase 5 completed 2026-07-30: provider-neutral usage metering and visible monthly totals now close the Phase 7 cost-control prerequisite. Per-request provider choice remains deliberately deferred by ADR-004.

# Task Priority Difficulty Dependencies Expected value
5.1 DONE (2026-07-30) — fixed docs/00-ai-context.md to match the code. Decided 2026-07-17: do NOT build the abstraction. P1 S none The doc describes a provider interface over OpenAI/Gemini/Claude/Ollama with admin control and per-user choice. Reality: one AI_PROVIDER env var over Ollama/Gemini/Groq. Multi-provider cloud AI also undermines the privacy moat (see docs/research/competitors.md §4). Revisit only if a customer asks. docs/architecture/current.md §9 already records the truth.
5.2 DONE (2026-07-30) — AI usage metering P1 M 1.5 No quota, no tracking, no ceiling. Hard blocker for Phase 7; a cost risk today with AI_PROVIDER=gemini.
5.3 DONE (2026-07-30) — surfaced optional CV generation inside the add-job wizard P2 S 1.4 The target workflow says "Generate CV if needed" at step 3. POST /generate-tailored-cv-draft exists but only post-save.
5.4 DONE — keyword-gap analysis on match score P2 M none JobCvMatchService + /match-score exist. Gap analysis is the specific thing people pay Jobscan $49.95/mo for.
5.5 DONE (2026-07-30) — wrote ADR-004 (AI provider system) P2 S 5.1 0-byte file naming a real decision.

Phase 6 — Job discovery

Goal: help users find opportunities. Zero code exists. Explicitly an enhancement — the guide: "Job discovery supports tracking. It does not replace job boards."

Order decided 2026-07-17: (a) manual URL import → (b) browser extension → (c) official APIs where available. Scraping is explicitly not the starting point. This reorders the original plan: the extension now comes before a search backend.

# Task Priority Difficulty Dependencies Expected value
6.1 (a) Harden manual URL importPOST /jobimport/preview is preview-only (a 27-line controller, no persistence, no import history, no dedup at import time). P2 M Phase 0 Step (a) of the decided order and already mostly built. Cheapest discovery win; the wizard already calls it.
6.2 (b) Browser extension / bookmarklet capture — reuse jobimport/preview; land captures in Saved. P2 L 6.1, 1.1 Step (b). Teal/Huntr/Simplify all ship one; Jobjakt is server-side parse only. Kills the single biggest friction (manual entry) and needs no search backend. Start with a bookmarklet — a full Chrome-store extension is high maintenance.
6.3 (c) Official job-board APIs where available P3 L 6.2, 6.6 Step (c). Legal and low-maintenance where an API exists.
6.4 Search UI + filters (title, location, remote, industry) P3 M 6.3 Only worth it once (c) supplies real data.
6.5 One-click import into tracker P3 S 6.3 Lands in Saved — which exists as of Phase 0.
6.6 Make market a data dimension, not an assumption — Finn/NAV/Jobbnorge/LinkedIn are Norway-specific. Decided: Norway first, but no hardcoding Norway. P2 M none Job.CountryCode and Job.Source already exist (added in Phase 0) — the entity is ready. The plugins, locale and currency handling still assume NO. Doing this before 6.3 stops each new market being a rewrite.
6.7 Explicitly out of scope: scraping. Recorded so it is not re-proposed. Also out: auto-apply bots (ToS/ethics/quality; contradicts "apply to more suitable jobs").

Phase 7 — SaaS preparation

Goal: commercialise. Last, per the guide's "do not over-engineer before needed. Excellent UX is more important." Good news: the hard part — multi-tenancy — is already done and tested. Everything below is additive.

Tiers decided 2026-07-17. Free: job tracking, basic career profile, basic CV. Premium: advanced AI, more themes, automation, analytics, more storage.

The gate is capability, never count. No CV-count or job-count caps — that is Huntr's 100-job limit, Teal's AI credits and FlowCV's 1-resume limit, i.e. the exact "free tier caps at the point of seriousness" frustration in docs/research/competitors.md §1.4. Jobjakt's moat is privacy + self-hosting + free local AI; a count-based paywall surrenders the moat while inheriting the complaint.

# Task Priority Difficulty Dependencies Expected value
7.1 Open registration + CAPTCHA P2 M 2.4, 7.3 Registration is 403 by default; no CAPTCHA exists (verified). Rate limiting alone is not enough for public signup.
7.2 **Plan / tier / entitlement model — capability flags (advancedAi, premiumThemes, automation, analytics, storageBytes), not counters. P3 M none No concept of a plan exists anywhere. Shape it around the decided split so the free tier stays genuinely useful.
7.3 Usage quotas — AI + storage only P3 M 5.2, 7.2 Do not open registration before this lands. AI and storage are unmetered and unbounded; these are real cost, so they are legitimate limits. Job/CV counts are not.
7.4 Storage limits + attachment caps P3 S 7.2 The "more storage" premium lever.
7.5 Stripe billing P3 L 7.2 Still blocked on Stripe keys — the only remaining hard blocker. Tiers are now decided.
7.6 Public CV (/cv/{guid}) P3 M 3.4, 4.2 Documented in docs/00-ai-context.md; zero code — no route, no IsPublic, no slug. Privacy-first random GUID, no usernames.
7.7 Premium themes P3 S 4.3, 7.2 Trivial once themes are data. Impossible while they are C# methods. A decided premium lever.
7.8 Dependency CVE scanning in CI P2 S none CI explicitly disables audit (npm_config_audit: 'false'). No vulnerability scan runs anywhere.
7.9 Per-user AI provider cost controls P3 S 5.2, 7.2 With AI_PROVIDER=gemini the "advanced AI" tier spends real money per call. Metering (5.2) measures; this enforces.

Critical path

[Phase 0 DONE] pipeline stages · DateApplied nullable · Job entity · sidecar secured · docs restored

1.1 Prospect stages in UI ── 1.2 Wizard target        (finishes the workflow users can see)
1.8 Fix red CI            (independent — do first; everything lands on this baseline)
1.4 Rotate DP keys · 1.5 CORS fix    (independent security)
1.9 Orphan tables         ── informs 3.1

2.1 Split profile/career ── 2.2 Decompose ProfilePage ── 3.3 Career Workspace
                                                      └─ 3.4 Profile ≠ Master CV ──┬─ 4.1 CvTheme model ── 4.2 Renderer ──┬─ 4.3 Themes
                                                                                   │                                      ├─ 4.5 Customise tab
                                                                                   │                                      └─ 4.6 Live preview ── 4.7 Export
                                                                                   └─ 4.4 Content tab
4.9 Reactive Resume research ── must precede 4.1
6.6 Market as data ── 6.3 Official APIs
5.2 AI metering ── 7.3 Quotas ── 7.1 Open registration

Two things now gate everything: 3.4 (profile ≠ CV) and 4.1 (themes as data). The third — the workflow — was unblocked by Phase 0; only its UI surface (1.1) remains.


Effort summary

Phase Rough size Note
0 — Foundation done Delivered 2026-07-17.
1 — Critical fixes ~35 days Shrunk: Phase 0 absorbed most of it. Mostly UI surfacing + two operator tasks.
2 — UX ~23 wk 2.5 (data layer) is the multiplier.
3 — Career Workspace ~23 wk Grew slightly: relational profile (3.1) is now L, not a coin-flip.
4 — CV Builder ~46 wk The big one. Do not underestimate because a tab exists.
5 — AI ~1 wk Shrunk: 5.1 is a docs fix, not an abstraction build.
6 — Job discovery ~23 wk Shrunk: no scraping, and (a) is mostly built. The extension (6.2) carries most of the value.
7 — SaaS ~34 wk Tiers decided; needs Stripe keys.

Product decisions — settled 2026-07-17

All six of the original blocking questions are answered. Recorded here so they are not re-litigated.

# Question Decision Effect
1 Career profile storage Relational for Experience/Education/Skills/Projects; JSON blob for the long tail Phase 3 unblocked; 3.1 is now a task, not a question
2 AI providers Fix the docs, do not build the abstraction 5.1 drops from L to S
3 Job discovery (a) manual URL import → (b) browser extension → (c) official APIs. No scraping. Phase 6 reordered; extension promoted ahead of a search backend
4 Geography Norway first, no hardcoding Norway New task 6.6; Job.CountryCode/Source already added in Phase 0
5 Free vs Premium Free: tracking, basic profile, basic CV. Premium: advanced AI, more themes, automation, analytics, more storage. Capability-gated, never count-gated Phase 7 scoped; 7.2/7.3 reshaped
6 Mockups Source of truth only where a mockup exists; do not invent pages from them Phases 2 and 4 constrained

Remaining blockers

Only two things now block work, and both need you rather than a decision:

  1. Stripe keys (gates 7.5). Tiers are decided; the integration needs credentials.
  2. DataProtection key rotation (task 1.4). Needs an operator with production access.

Open questions raised by Phase 0

Not product decisions — engineering findings that need a call before the phase they touch:

  1. Orphan DB tables (task 1.9). The dev database carries CareerProfiles, CareerProfileVersions, CvVariants, CvVersions, TailoredApplications, InterviewPrepNotes, AiWorkspaceNotes — in no model, no migration. An abandoned Career Workspace attempt. Was there a previous design worth recovering, or is this dead weight to drop? Answer before Phase 3 re-treads the same ground.
  2. Kanban column count (task 1.1). The pipeline now has 9 stages; the board is built for 6. Do the three Prospect stages get their own columns, collapse into one "Not applied" column, or sit behind a toggle? A UI decision, needed to finish Phase 1.