# 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. **Mockups** — `F:\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` 2–4days · `L` ~1–2wk · `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 3–7 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 landmine** — `Cors: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 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 | **Decompose `ProfilePage.tsx` (still ~1370 lines) into two real 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 | **Real onboarding flow** — `Signup → Verify → Profile → Import CV → Connect email → First job` replacing the 2-item checklist | **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 | **Dedicated `/register` screen** | **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 | **Introduce a server-cache layer** (React Query or equivalent) | **P2** | **M** | none | Root cause of the 600–1400-line components and the hand-rolled `refreshToken` prop-threading. Pays for itself across Phases 3–6. Adopt incrementally, not as a rewrite. | | 2.6 | **Decompose `JobDetailsDialog.tsx` (1400 lines)** | **P2** | **M** | 2.5 | A dialog carrying an entire workspace. | | 2.7 | **Interview prep hub screen** | **P2** | **S** | none | `/jobapplications/{id}/interview-prep` already works and is invisible. Cheap win — a shipped feature nobody can reach. | | 2.8 | **Retire `react-scripts` as test runner** (move to Jest+SWC or Vitest) | **P2** | **M** | none | Removes one of three frontend toolchains. Do not touch the router in the same change. | | 2.9 | **Expand analytics** — funnel, response rate, time-in-stage | **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 `9c8644e`…`a1dd447`). 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). Tasks 3.1, 3.3, 3.4 and the > versioning/validation goals are delivered. Remaining below: 3.2 (long-tail-as-relational, deferred > — currently JSON), 3.5 (CV variants — Phase 4), 3.6 (retention), plus a full section-by-section UX > redesign of the editor (polish; the functional workspace exists). | # | 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 | **Add the missing profile sections** — Awards, Publications, Organisations, References | **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 | **Real Career Workspace page** — replace the 36-line tab facade | **P1** | **M** | 2.1, 2.2 | Currently a wrapper around `ProfilePage`. | | 3.4 | **Separate Career Profile from Master CV** | **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 | **CV variants** (Software Engineer CV / Management CV) | **P2** | **M** | 3.4 | In the glossary; no code. Distinct from per-application `TailoredCvDraft`, which works correctly and must not be disturbed. | | 3.6 | **Retention policy for `CvExtractionRun`** | **P2** | **S** | none | Three copies of every CV (raw/normalized/structured), unbounded. | | 3.7 | **Move avatars out of the DB column** | **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`). **This is the largest item in the plan.** The existing inert tab makes it look nearly done; it is not started. > **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; **not yet client-side** — see below). 4.7 ✅ PDF > export wired into the builder. Plus: autosave + version history/restore, AI-assist (suggestion-only), > public CV at `/cv/{slug}`. **Remaining polish:** 4.8 split `ProfileCvController`; client-side preview > (4.6 currently server round-trip); native drag-and-drop; rich-text bullets; PDF page-number footer; > per-item override UI in the Content tab (the API + resolver support it; the editor exposes section- > level controls). **Known limitation:** external direct loads of `/cv/{slug}` bounce to root (SPA > deep-link issue, app-wide) — fix in the frontend static-export/routing config. > > **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`. **Still open:** PDF page-number footer (Playwright `footerTemplate`); > client-side preview (kept server-rendered for fidelity); `ProfileCvController` split. | # | Task | Priority | Difficulty | Dependencies | Expected value | |---|---|---|---|---|---| | 4.1 | **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 | **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 | **Seed 3–5 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 | **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 | **Customise tab** — the ~12 controls from 4.1 | **P1** | **M** | 4.1, 4.2 | Currently **nothing** is customisable. | | 4.6 | **Live client-side 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 | **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 | **Split `ProfileCvController` (2249 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`. **Still open:** per-request user-selectable providers > (needs an ai-service per-request override + a configured key per provider — deployment/credential > work, documented as an extension point); 5.2 AI usage metering (Phase 7 blocker) remains. | # | Task | Priority | Difficulty | Dependencies | Expected value | |---|---|---|---|---|---| | 5.1 | **Fix `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 | **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 | **Surface 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 | **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 | **Write 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 import** — `POST /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 | ~3–5 days | Shrunk: Phase 0 absorbed most of it. Mostly UI surfacing + two operator tasks. | | 2 — UX | ~2–3 wk | 2.5 (data layer) is the multiplier. | | 3 — Career Workspace | ~2–3 wk | Grew slightly: relational profile (3.1) is now L, not a coin-flip. | | 4 — CV Builder | **~4–6 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 | ~2–3 wk | Shrunk: no scraping, and (a) is mostly built. The extension (6.2) carries most of the value. | | 7 — SaaS | ~3–4 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.