F0-F2 fully shipped this session; F3 and F5 partially shipped. Each
phase section now states exactly what landed (with commit
references), what was deliberately deferred and why, and what a
future session should pick up next -- so the roadmap stays a source
of truth instead of drifting from the actual repo state.
Notable corrections made while auditing: JobCvMatchService already
reads a structured+text hybrid (the F5 "retarget" line item was based
on a stale assumption, resolved as not-needed rather than deferred);
F1's read-path cutover and F2's pre-existing-row backfill are
explicitly still open, not silently done.
Four discovery documents backing the Career Workspace redesign:
- cv-builder-competitor-deep-research.md: teardown of Novoresume,
Reactive Resume, FlowCV, Teal, Enhancv, Canva, Resume.io, Kickresume
-- positioning, UX patterns, pricing/trust failures, technical
architecture lessons (esp. Reactive Resume's content/theme
separation and PDF pipeline history).
- cv-builder-product-teardown.md: critical as-is audit of this app's
CV builder -- data model, editor UX, AI workflow, rendering
pipeline, feature gaps -- including the OAuth CV lockout bug fixed
in a prior commit.
- career-workspace-product-strategy.md: product vision, positioning,
personas, core object model, feature roadmap (MVP/V2/future),
AI/monetization strategy, and the first 10 engineering tasks.
- career-workspace-implementation-roadmap.md: the execution plan --
product boundary (Career Workspace is a bounded domain supporting
job tracking, not replacing it), phased sequencing (F0-F6), and the
migration mechanics specific to this repo's raw-SQL schema
reconciler.
Resolve conflicts from main's Wave 0 (PR #1) landing after this branch was cut:
- useViewResource.ts: main's e352aae already fixes the render loop the same way
(load in a ref, dropped from deps) — took main's canonical version. My
independent fix is superseded (my branch predated e352aae, which is why the
loop reproduced live).
- JobApplicationsController.cs: keep BOTH main's IJobCvMatchService and my
AnalyticsService (ctor gets both optional params). GetAnalyticsOverview stays
delegated to AnalyticsService.
- Fold main's H3 additions into the extracted AnalyticsService: pipeline-driven
funnel (JobPipeline.Normalize/Stages) + time-in-stage (StageAnalytics) and add
StageDurationDto + TimeInStage to Models/AnalyticsDtos.cs, preserving the API
contract the frontend expects.
Build clean; backend suite 135/135 green.
useViewResource built `reload` with `load` in its useCallback deps, and the
fetch effect depended on `reload`. Callers routinely pass an inline `load`
closure (e.g. JobTable), so `load` — and therefore `reload` and the effect —
changed every render, calling setState and re-rendering: an unbounded
"Maximum update depth exceeded" loop that froze the renderer on /jobs and every
other list view (DashboardView, RemindersView, CompaniesTable).
Fix: hold `load` in a ref (like the existing hasLoadedRef) and drop it from the
dependency arrays. Re-fetching is still driven by `deps`/`enabled`; the ref
always points at the latest closure. No API/behaviour change for callers.
Runtime-verified live: /jobs went from a render storm (frozen renderer, 100s of
console errors) to 0 errors in a 2s window and a clean render. Suites that drive
JobTable→useViewResource pass in isolation; the remaining full-run flakiness is
pre-existing (state-pollution/timing in the heavy RTL suites, unrelated).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The axios 401 interceptor calls clearAuthClientState() on every 401, which
dispatched "auth-changed"; the App handler re-fetched /auth/me, which 401'd
again → interceptor → clearAuthClientState() → "auth-changed" → ... an unbounded
request storm (observed live: 100+ GET /auth/me and climbing) that ran whenever
the user was logged out (login page, expired session) — burning CPU, network and
battery and flooding the server.
Fix: make clearAuthClientState idempotent — only emit "auth-changed" when it
actually removes a stored user key (a real signed-in→out transition), so
repeated 401s can no longer re-trigger the fetch.
Runtime-verified in a live stack: /auth/me went from 100+ & growing to 0 &
stable. login-page/settings tests green. Documented in
docs/performance/PERFORMANCE_IMPROVEMENTS.md (Phase 3.5 runtime finding).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Evidence-based investigation across every leak vector (timers, listeners, object
URLs, observers, websockets, static server collections, IMemoryCache, Python
caches). Verdict: no confirmed memory leak — the codebase has disciplined
cleanup. One resource-release correctness bug (over-eager blob-URL revocation in
the CV carousel) was found and fixed (eed9b1f).
Adds docs/performance/: MEMORY_LEAK_REPORT.md, ROOT_CAUSE_ANALYSIS.md,
PERFORMANCE_IMPROVEMENTS.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 1-3 deliverables: full architecture/security/tech-debt map,
2026 market research with feature matrix, and tiered execution roadmap.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>