30 KiB
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),Jobentity 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):
- Career profile storage — relational for Experience/Education/Skills/Projects; JSON blob for the long tail. Phase 3 is unblocked.
- AI providers — fix the docs to match the code; do not build the multi-provider abstraction. Task 5.1 is now S, not L.
- Job discovery order — manual URL import → browser extension → official APIs. Scraping is not a starting point. Phase 6 re-ordered.
- Geography — Norway first, but no hardcoding Norway; market is a data dimension. New task 6.6, and
Job.CountryCode/Job.Sourcealready exist.- 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.
- Mockups —
F:\Pictures\website\jobtracker\newis 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 ✅ 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 | /profile and /career66cc6a7) — /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 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 | ✅ 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
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. Seedocs/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
a3e18e4backend,158dd02frontend). Data-driven theme engine + variant model + 3-tab builder + live preview + public CV, all consuming the master profile (never duplicating it). Seedocs/architecture/cv-builder.mdanddocs/architecture/cv-theme-engine.md. Status: 4.1 ✅CvThememodel. 4.2 ✅ oneThemedCvRenderer(the oldCvTemplateRendererstays 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-allapp/[[...slug]]; direct nav/refresh/shared links work, no infra change). Native drag-and-drop reorder for sections + entries (keyboard arrows kept). Per-item editing viaGET /api/cv/outline: hide, title/subtitle override, rich-text bullets (**bold** *italic* __underline__ [link], escaped-then-whitelisted server-side).ItemOrderreorders 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 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 | ✅ 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 | 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
f299d7bbackend,bb0c0fefrontend). 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 existingISummarizerService/ai-service provider abstraction and stored as append-only history (AiInteraction) with reuse / compare / copy / delete. Suggestion-only throughout; nothing auto-applies;Markdownrenders React nodes (no HTML-injection surface). Seedocs/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. URL preview and bookmarklet/PWA capture are complete. 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 | DONE (2026-07-30) — manual URL import previews into the existing reviewed add-job flow, which persists through the normal create endpoint and warns on duplicate URLs. No second import-history store was added. | P2 | M | Phase 0 | The existing flow delivers the discovery win without another persistence model. |
| 6.2 | DONE (2026-07-30) — bookmarklet/PWA share capture reuses jobimport/preview and opens the reviewed add-job flow in Saved. A store extension remains deliberately unnecessary. |
P2 | L | 6.1, 1.1 | Capture is available without Chrome-store maintenance. |
| 6.3 | DONE (2026-07-30) — NAV Job Vacancy Feed integration uses the official authenticated API and rotating public experiment token; NavJobs:Token supports a stable private token later. FINN requires a business agreement, while Indeed and LinkedIn do not expose open discovery feeds. |
P3 | L | 6.2, 6.6 | Legal official Norway-first discovery without scraping. |
| 6.4 | DONE (2026-07-30) — discovery UI searches recent active NAV events by title/company and municipality. | P3 | M | 6.3 | Provides a usable official-feed search surface. |
| 6.5 | DONE (2026-07-30) — “Save to tracker” routes discoveries through the existing reviewed URL-import wizard and lands them in Saved. |
P3 | S | 6.3 | Reuses the established import and duplicate-warning flow. |
| 6.6 | PARTIAL — Job.CountryCode and Job.Source exist, but the live JobApplication create flow does not yet dual-write Job, and import results do not carry market metadata. Decided: Norway first, but no hardcoding Norway. |
P2 | M | none | Complete this with the first official API so its provider market contract drives the write path. |
| 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 | DONE (2026-07-30) — CI runs NuGet transitive vulnerability reporting and a production-only npm audit. The npm audit reports the existing no-fix advisory baseline without blocking unrelated deploys. | P2 | S | none | Vulnerable dependencies are now visible before deployment. |
| 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:
- Stripe keys (gates 7.5). Tiers are decided; the integration needs credentials.
- 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:
- 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. - 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.