docs(redesign): complete Phase 1 source audit

This commit is contained in:
cesnimda
2026-09-09 19:29:39 +02:00
parent 23cc250c64
commit 0b932da4a5
13 changed files with 10775 additions and 0 deletions
+2
View File
@@ -38,3 +38,5 @@ AI should support this flow naturally and contextually. It must never invent fac
## Status
These documents define the intended target state. They should be updated as the remaining functional work is completed. The full redesign implementation should begin only after a stable pre-redesign baseline has been created and protected by tests.
2026-09-09: [Phase 1 source audit](audit/README.md) completed on `codex/ui-redesign-audit`: current routes, protected functionality, component/test/API inventories, identity/storage boundaries and proposed migration gates. No redesign implementation or B07 started. Required release checks and F04 production verification remain separate from this audit's completion.
+59
View File
@@ -0,0 +1,59 @@
# API integration and identity boundaries
## Transport
[api.ts](../../../job-tracker-ui/src/api.ts) is the shared Axios transport. Production uses `/api`; local development defaults to port 5202 unless `NEXT_PUBLIC_API_BASE_URL` overrides it. The value is embedded in the static build. All discovered direct frontend `api`/`axios` calls are in [API_CALL_SITES](API_CALL_SITES.md); UI wrappers such as `cvBuilder`, `aiWorkspace` and `applicationWorkspace` are included. SDK OAuth/navigation and server-to-server provider calls are separate from that census.
Credentialed requests use the HttpOnly auth cookie and XSRF handling. B02 adds immutable session provenance, cancellation and late-response rejection. Downloads use authorized blob requests where required; B05 CSV bytes must not be decoded/re-encoded through `Blob.text()`. Error handling uses shared extraction plus screen-specific recovery. A new fetch/cache/form abstraction must preserve all of these behaviors.
## Domain contract map
Paths are relative to `/api`. See the linked census for each method, interpolated ID and exact source line. DTOs are in [frontend types](../../../job-tracker-ui/src/types.ts), domain wrappers, and [API controllers](../../../JobTrackerApi/Controllers).
| Frontend owner | API groups | Identity / mutation contract |
|---|---|---|
| Login/account/security cards | `/auth/config`, `/auth/me`, login/register/reset/verification, `/auth/profile`, avatar, email-change, 2FA, sessions, language preferences | Public challenge/setup entry versus authenticated self-account actions; client never chooses authoritative owner |
| Table/Kanban/edit/add | `/jobapplications`, `/board`, choices, duplicate-check, status, restore; `/companies` and relationship | Owner-scoped job/company lookup and associations; status changes and soft deletion distinct from creation intent |
| Capture/discovery | `/jobimport/preview`, `/job-discovery/search`, saved-searches/results, Gmail suggested jobs | Review/preview and create separate; B01 connection enforcement; saved searches belong to account |
| Personal analytics/reminders | Dashboard/statistics call sites, reminders/rules, notification-settings | Current-account reporting and dates; global/admin reporting separate |
| Full/overlay job workspace | `/jobapplications/:id/workspace`, timeline, analysis, match, CV, tailoring, cover-letter, drafts, submitted-packages, checklist, interview-prep, follow-up | Job owner boundary plus nested artifact IDs; workspace aggregate reads do not authorize child writes |
| Profile/evidence | `/career/profile`, versions/restore, `/career/evidence`, `/profile-cv/*` | Principal-owned singleton; extraction proposal review; history/projection distinct from CV overrides |
| CV library/editor | `/cv/*` through `cvBuilderApi`, themes, outline, variant save/copy/history/publish/preview/export | Private owner + resource ID; job association validates same owner; B03 admission shared with other PDF callers |
| Public CV | Public-CV slug endpoints | Anonymous access only through explicitly published variant; not arbitrary private ID download |
| Contextual AI | `/ai/usage`, `/jobapplications/:id/ai/modules`, generate/history; profile and CV AI endpoints | Server entitlement, context ownership/consent and quotas; UI accept step does not replace backend authorization |
| Documents | `/attachments/*`, submitted-package attachments, PDF export | Authorized upload/download/delete and scoped references; preserve content disposition and blob handling |
| Correspondence/mail | `/correspondence/*`, `/gmail/*`, `/microsoft-graph/*`, `/imap/*`, `/email/providers`, message, drafts, send | OAuth mailbox distinct from login; owner/job association, draft revision, send attempt/delivery state |
| Calendar | `/calendar/status`, `/calendar/jobs/:id/events`, `events.ics` | Owned job dates + provider permission; date-only and UTC timestamp semantics remain distinct |
| Operations/notifications | `/operations`, cancel/retry, `/notifications`, read/dismiss | Owner-scoped asynchronous work; rerender does not mean enqueue again |
| Export/lifecycle/billing | `/export/jobs`, `/export/account`, `/backup/encrypted`, `/account-lifecycle/*`, `/billing/status`, checkout/portal | Owner data; recent-auth/destructive/provider constraints; B05 at CSV boundary |
| Admin | `/users`, `/admin/audit`, `/admin/system` and maintenance/email/AI subroutes | Server Admin role; sensitive system views kept separate from personal workspace |
No backend contract changes are proposed for Phase 1. API endpoint names and old route query values are compatibility surface even if new screen labels differ.
## Authentication and authorization
[Program.cs](../../../JobTrackerApi/Program.cs#L299) configures the smart authentication selector and local/provider validation. Local bearer or cookie JWT validation includes issuer/audience/signature/lifetime and a live local-session validation step. Production account-aware policies resolve authenticated identity before limiting. Relevant middleware order is forwarded headers/security/routing/CORS and CSRF handling, then [authentication → authorization → rate limiter → B02 SessionContextMiddleware → controllers](../../../JobTrackerApi/Program.cs#L654). Do not move owner limiting ahead of authentication during shell/API cleanup.
[CurrentUserService](../../../JobTrackerApi/Services/CurrentUserService.cs) derives local owner identity from the principal. Its background-owner scope cannot replace an HTTP request identity. [JobTrackerContext](../../../JobTrackerApi/Data/JobTrackerContext.cs#L132) uses live owner evaluation and fail-closed query filters. These are additional guards; not a license to remove explicit ownership checks from services or to introduce unscoped `IgnoreQueryFilters()` calls.
The [CV service](../../../JobTrackerApi/Services/CvVariantService.cs#L74) looks up `id + owner` and validates job associations with `jobId + owner`. Its explicit public lookup bypasses ordinary filters only for the published-slug path. Career Profile PUT derives the owner from current authentication and updates that singleton, explaining why B02 session provenance is separate from ID-based authorization. The old retained A form replay under B was not simply an IDOR. B02 now rejects retained/missing/forged session provenance server-side; the client also unmounts/aborts private state.
Admin controllers enforce Admin roles; Pro operations have server entitlement checks. The permissive default in `AccountPlanContext` is for isolated previews, while routed App supplies server-backed values. It is not proof that an ordinary user can obtain Pro server access. The frontend's auth/config and role-based navigation are presentation logic; a stale or crafted frontend must remain constrained by the API.
This is an integration map with targeted service verification, not a fresh claim that every authorization path in the application has been penetration-tested. Keep the permanent B01–B06 tests and original independent audit evidence.
## State and storage map
| State | Current scope | Preservation condition |
|---|---|---|
| Auth credential | HttpOnly cookie; CSRF companion cookie | Do not move tokens into browser storage or let client headers select owner |
| `authUserKey`, auth persistence preferences | Browser identity marker/preferences | Not an authoritative server identity; B02 handles account-generation change |
| `authSessionContext` storage signal | Cross-tab change notification | Immutable per page context; stale work aborts/reauthenticates, it does not adopt B's identity |
| Form/editor state and workspace tab cache | React/component memory | Dispose on B02 invalidation; preserve unsaved-navigation guard within one identity |
| Dashboard visibility | `dashboardPrefs:<owner>` localStorage | Owner-scoped, five booleans; not cross-device persistence |
| Saved job views, headline fallback, onboarding dismissal | Owner-keyed localStorage | Never rehydrate A's private view/draft data into B's page |
| Theme/language/sidebar collapse/table page size and columns | Device/browser preferences (language also server-hydrated) | These are presentation preferences, not private document caches |
| Pro notice dismissal | Feature-keyed sessionStorage | Presentation-only; no CV/account content, entitlement still server-derived |
| Mail drafts / application drafts / CV history | Server persistence with domain-specific APIs | Preserve each existing contract; do not replace with a generic browser draft mechanism |
Sources: [auth.ts](../../../job-tracker-ui/src/auth.ts), [sessionBoundary.ts](../../../job-tracker-ui/src/sessionBoundary.ts), [App.tsx](../../../job-tracker-ui/src/App.tsx), `SavedViewsMenu`, `DashboardView`, `ProfilePage`, `ProFeatureNotice`. Any future cache must be account-scoped and must not replay mutations after the page's identity generation changes. Record revision conflicts, identity isolation and duplicate-creation idempotency remain **three distinct contracts**.
+272
View File
@@ -0,0 +1,272 @@
# API call-site inventory
Generated with the installed TypeScript AST from the committed baseline. Each row is an actual `api`/`axios` call expression, not a claim of runtime test coverage. Paths are relative to the shared `/api` base; interpolations are preserved. Domain wrappers are included. Companion technical audit maps contracts and authorization.
| Source | Method | URL expression |
|---|---|---|
| [src/App.tsx:189](../../../job-tracker-ui/src/App.tsx#L189) | GET | "/auth/config" |
| [src/App.tsx:206](../../../job-tracker-ui/src/App.tsx#L206) | GET | "/auth/me" |
| [src/App.tsx:229](../../../job-tracker-ui/src/App.tsx#L229) | GET | "/jobapplications/reminders" |
| [src/App.tsx:237](../../../job-tracker-ui/src/App.tsx#L237) | GET | "/notifications/unread-count" |
| [src/App.tsx:250](../../../job-tracker-ui/src/App.tsx#L250) | GET | "/auth/me" |
| [src/App.tsx:374](../../../job-tracker-ui/src/App.tsx#L374) | POST | "/auth/logout" |
| [src/aiWorkspace.ts:29](../../../job-tracker-ui/src/aiWorkspace.ts#L29) | GET | "/ai/usage" |
| [src/aiWorkspace.ts:30](../../../job-tracker-ui/src/aiWorkspace.ts#L30) | GET | `/jobapplications/${jobId}/ai/modules` |
| [src/aiWorkspace.ts:32](../../../job-tracker-ui/src/aiWorkspace.ts#L32) | POST | `/jobapplications/${jobId}/ai/generate` |
| [src/aiWorkspace.ts:34](../../../job-tracker-ui/src/aiWorkspace.ts#L34) | GET | `/jobapplications/${jobId}/ai/history` |
| [src/aiWorkspace.ts:35](../../../job-tracker-ui/src/aiWorkspace.ts#L35) | DELETE | `/jobapplications/${jobId}/ai/history/${id}` |
| [src/applicationWorkspace.ts:114](../../../job-tracker-ui/src/applicationWorkspace.ts#L114) | GET | `/jobapplications/${jobId}/workspace` |
| [src/applicationWorkspace.ts:188](../../../job-tracker-ui/src/applicationWorkspace.ts#L188) | GET | `/jobapplications/${jobId}/timeline` |
| [src/applicationWorkspace.ts:194](../../../job-tracker-ui/src/applicationWorkspace.ts#L194) | GET | `/jobapplications/${jobId}/analysis` |
| [src/applicationWorkspace.ts:195](../../../job-tracker-ui/src/applicationWorkspace.ts#L195) | GET | `/jobapplications/${jobId}/match` |
| [src/applicationWorkspace.ts:279](../../../job-tracker-ui/src/applicationWorkspace.ts#L279) | GET | `/jobapplications/${jobId}/cv` |
| [src/applicationWorkspace.ts:281](../../../job-tracker-ui/src/applicationWorkspace.ts#L281) | PUT | `/jobapplications/${jobId}/cv` |
| [src/applicationWorkspace.ts:283](../../../job-tracker-ui/src/applicationWorkspace.ts#L283) | GET | `/jobapplications/${jobId}/tailoring` |
| [src/applicationWorkspace.ts:285](../../../job-tracker-ui/src/applicationWorkspace.ts#L285) | GET | `/jobapplications/${jobId}/cover-letter` |
| [src/applicationWorkspace.ts:287](../../../job-tracker-ui/src/applicationWorkspace.ts#L287) | PUT | `/jobapplications/${jobId}/cover-letter` |
| [src/applicationWorkspace.ts:289](../../../job-tracker-ui/src/applicationWorkspace.ts#L289) | POST | `/jobapplications/${jobId}/cover-letter/versions/${version}/restore` |
| [src/applicationWorkspace.ts:291](../../../job-tracker-ui/src/applicationWorkspace.ts#L291) | GET | `/jobapplications/${jobId}/submitted-packages` |
| [src/applicationWorkspace.ts:293](../../../job-tracker-ui/src/applicationWorkspace.ts#L293) | POST | `/jobapplications/${jobId}/submitted-packages` |
| [src/applicationWorkspace.ts:295](../../../job-tracker-ui/src/applicationWorkspace.ts#L295) | GET | `/jobapplications/${jobId}/submitted-packages/${packageId}` |
| [src/applicationWorkspace.ts:297](../../../job-tracker-ui/src/applicationWorkspace.ts#L297) | GET | `/jobapplications/${jobId}/submitted-packages/${packageId}/attachments/${attachmentId}` |
| [src/applicationWorkspace.ts:299](../../../job-tracker-ui/src/applicationWorkspace.ts#L299) | PUT | `/jobapplications/${jobId}/application-drafts` |
| [src/applicationWorkspace.ts:345](../../../job-tracker-ui/src/applicationWorkspace.ts#L345) | GET | `/jobapplications/${jobId}/interview-prep` |
| [src/applicationWorkspace.ts:347](../../../job-tracker-ui/src/applicationWorkspace.ts#L347) | POST | `/jobapplications/${jobId}/interview-prep` |
| [src/applicationWorkspace.ts:349](../../../job-tracker-ui/src/applicationWorkspace.ts#L349) | PATCH | `/jobapplications/${jobId}/interview-prep/${itemId}` |
| [src/applicationWorkspace.ts:351](../../../job-tracker-ui/src/applicationWorkspace.ts#L351) | DELETE | `/jobapplications/${jobId}/interview-prep/${itemId}` |
| [src/applicationWorkspace.ts:353](../../../job-tracker-ui/src/applicationWorkspace.ts#L353) | GET | `/jobapplications/${jobId}/follow-up` |
| [src/applicationWorkspace.ts:355](../../../job-tracker-ui/src/applicationWorkspace.ts#L355) | PUT | `/jobapplications/${jobId}/follow-up` |
| [src/applicationWorkspace.ts:360](../../../job-tracker-ui/src/applicationWorkspace.ts#L360) | GET | `/jobapplications/${jobId}/checklist` |
| [src/applicationWorkspace.ts:362](../../../job-tracker-ui/src/applicationWorkspace.ts#L362) | POST | `/jobapplications/${jobId}/checklist` |
| [src/applicationWorkspace.ts:364](../../../job-tracker-ui/src/applicationWorkspace.ts#L364) | PATCH | `/jobapplications/${jobId}/checklist/${itemId}` |
| [src/applicationWorkspace.ts:366](../../../job-tracker-ui/src/applicationWorkspace.ts#L366) | DELETE | `/jobapplications/${jobId}/checklist/${itemId}` |
| [src/applicationWorkspace.ts:368](../../../job-tracker-ui/src/applicationWorkspace.ts#L368) | PUT | `/jobapplications/${jobId}/checklist/order` |
| [src/components/AddJobModal.tsx:224](../../../job-tracker-ui/src/components/AddJobModal.tsx#L224) | GET | "/jobapplications/duplicate-check" |
| [src/components/AddJobModal.tsx:247](../../../job-tracker-ui/src/components/AddJobModal.tsx#L247) | POST | "/companies" |
| [src/components/AddJobModal.tsx:271](../../../job-tracker-ui/src/components/AddJobModal.tsx#L271) | POST | "/jobimport/preview" |
| [src/components/AddJobModal.tsx:312](../../../job-tracker-ui/src/components/AddJobModal.tsx#L312) | POST | "/attachments" |
| [src/components/AddJobModal.tsx:331](../../../job-tracker-ui/src/components/AddJobModal.tsx#L331) | POST | "/jobapplications" |
| [src/components/AddJobModal.tsx:358](../../../job-tracker-ui/src/components/AddJobModal.tsx#L358) | POST | `/jobapplications/${response.data.id}/generate-tailored-cv-draft` |
| [src/components/AiPrivacySettingsCard.tsx:24](../../../job-tracker-ui/src/components/AiPrivacySettingsCard.tsx#L24) | GET | "/ai/settings" |
| [src/components/AiPrivacySettingsCard.tsx:35](../../../job-tracker-ui/src/components/AiPrivacySettingsCard.tsx#L35) | PUT | "/ai/settings" |
| [src/components/AiUsageCard.tsx:33](../../../job-tracker-ui/src/components/AiUsageCard.tsx#L33) | GET | "/ai/usage" |
| [src/components/AiUsageCard.tsx:36](../../../job-tracker-ui/src/components/AiUsageCard.tsx#L36) | GET | "/billing/status" |
| [src/components/AiUsageCard.tsx:46](../../../job-tracker-ui/src/components/AiUsageCard.tsx#L46) | POST | `/billing/${path}` |
| [src/components/ApplicationCalendarActions.tsx:23](../../../job-tracker-ui/src/components/ApplicationCalendarActions.tsx#L23) | GET | "/calendar/status" |
| [src/components/ApplicationCalendarActions.tsx:32](../../../job-tracker-ui/src/components/ApplicationCalendarActions.tsx#L32) | POST | `/calendar/jobs/${jobId}/events` |
| [src/components/ApplicationCalendarActions.tsx:41](../../../job-tracker-ui/src/components/ApplicationCalendarActions.tsx#L41) | GET | `/calendar/jobs/${jobId}/events.ics` |
| [src/components/ApplicationWorkflowAssist.tsx:23](../../../job-tracker-ui/src/components/ApplicationWorkflowAssist.tsx#L23) | GET | `/jobapplications/${jobId}/status-suggestion` |
| [src/components/ApplicationWorkflowAssist.tsx:34](../../../job-tracker-ui/src/components/ApplicationWorkflowAssist.tsx#L34) | PATCH | `/jobapplications/${jobId}/status` |
| [src/components/ApplicationWorkflowAssist.tsx:69](../../../job-tracker-ui/src/components/ApplicationWorkflowAssist.tsx#L69) | GET | `/jobapplications/${jobId}/focus-plan` |
| [src/components/ApplicationWorkflowAssist.tsx:81](../../../job-tracker-ui/src/components/ApplicationWorkflowAssist.tsx#L81) | GET | `/jobapplications/${jobId}/focus-plan/operation` |
| [src/components/ApplicationWorkflowAssist.tsx:91](../../../job-tracker-ui/src/components/ApplicationWorkflowAssist.tsx#L91) | GET | `/operations/${operation.id}` |
| [src/components/ApplicationWorkflowAssist.tsx:113](../../../job-tracker-ui/src/components/ApplicationWorkflowAssist.tsx#L113) | POST | `/jobapplications/${jobId}/focus-plan/operations` |
| [src/components/ApplicationWorkflowAssist.tsx:128](../../../job-tracker-ui/src/components/ApplicationWorkflowAssist.tsx#L128) | POST | `/operations/${operation.id}/${action}` |
| [src/components/Attachment.tsx:15](../../../job-tracker-ui/src/components/Attachment.tsx#L15) | POST | "/attachments" |
| [src/components/Attachments.tsx:98](../../../job-tracker-ui/src/components/Attachments.tsx#L98) | GET | `/attachments/${jobId}` |
| [src/components/Attachments.tsx:125](../../../job-tracker-ui/src/components/Attachments.tsx#L125) | POST | "/attachments" |
| [src/components/Attachments.tsx:143](../../../job-tracker-ui/src/components/Attachments.tsx#L143) | PATCH | `/attachments/${a.id}` |
| [src/components/Attachments.tsx:153](../../../job-tracker-ui/src/components/Attachments.tsx#L153) | PATCH | `/attachments/${a.id}` |
| [src/components/Attachments.tsx:164](../../../job-tracker-ui/src/components/Attachments.tsx#L164) | DELETE | `/attachments/${a.id}` |
| [src/components/Attachments.tsx:179](../../../job-tracker-ui/src/components/Attachments.tsx#L179) | GET | `/attachments/download/${id}` |
| [src/components/AuthStatusCard.tsx:32](../../../job-tracker-ui/src/components/AuthStatusCard.tsx#L32) | GET | "/auth/me" |
| [src/components/AuthStatusCard.tsx:73](../../../job-tracker-ui/src/components/AuthStatusCard.tsx#L73) | POST | "/auth/logout" |
| [src/components/BackupCard.tsx:28](../../../job-tracker-ui/src/components/BackupCard.tsx#L28) | GET | "/account-lifecycle/status" |
| [src/components/BackupCard.tsx:49](../../../job-tracker-ui/src/components/BackupCard.tsx#L49) | POST | "/export/account" |
| [src/components/BackupCard.tsx:62](../../../job-tracker-ui/src/components/BackupCard.tsx#L62) | POST | "/backup/encrypted" |
| [src/components/BackupCard.tsx:87](../../../job-tracker-ui/src/components/BackupCard.tsx#L87) | POST | "/account-lifecycle/delete" |
| [src/components/CompaniesTable.tsx:57](../../../job-tracker-ui/src/components/CompaniesTable.tsx#L57) | GET | "/companies" |
| [src/components/CompaniesTable.tsx:94](../../../job-tracker-ui/src/components/CompaniesTable.tsx#L94) | GET | `/companies/${company.id}/relationship` |
| [src/components/CompaniesTable.tsx:108](../../../job-tracker-ui/src/components/CompaniesTable.tsx#L108) | PUT | `/companies/${editing.id}` |
| [src/components/Correspondence.tsx:157](../../../job-tracker-ui/src/components/Correspondence.tsx#L157) | GET | `/correspondence/${jobId}` |
| [src/components/Correspondence.tsx:164](../../../job-tracker-ui/src/components/Correspondence.tsx#L164) | GET | "/gmail/status" |
| [src/components/Correspondence.tsx:176](../../../job-tracker-ui/src/components/Correspondence.tsx#L176) | GET | "/gmail/job-candidates" |
| [src/components/Correspondence.tsx:194](../../../job-tracker-ui/src/components/Correspondence.tsx#L194) | GET | "/jobapplications/choices" |
| [src/components/Correspondence.tsx:213](../../../job-tracker-ui/src/components/Correspondence.tsx#L213) | POST | "/gmail/refresh-linked-threads" |
| [src/components/Correspondence.tsx:311](../../../job-tracker-ui/src/components/Correspondence.tsx#L311) | POST | "/correspondence" |
| [src/components/Correspondence.tsx:327](../../../job-tracker-ui/src/components/Correspondence.tsx#L327) | POST | "/correspondence" |
| [src/components/Correspondence.tsx:348](../../../job-tracker-ui/src/components/Correspondence.tsx#L348) | GET | "/gmail/connect-url" |
| [src/components/Correspondence.tsx:358](../../../job-tracker-ui/src/components/Correspondence.tsx#L358) | DELETE | "/gmail/connection" |
| [src/components/Correspondence.tsx:371](../../../job-tracker-ui/src/components/Correspondence.tsx#L371) | DELETE | `/correspondence/${messageId}` |
| [src/components/Correspondence.tsx:382](../../../job-tracker-ui/src/components/Correspondence.tsx#L382) | POST | "/gmail/import" |
| [src/components/Correspondence.tsx:400](../../../job-tracker-ui/src/components/Correspondence.tsx#L400) | POST | "/gmail/import-thread" |
| [src/components/Correspondence.tsx:422](../../../job-tracker-ui/src/components/Correspondence.tsx#L422) | POST | "/gmail/unlink-thread" |
| [src/components/Correspondence.tsx:443](../../../job-tracker-ui/src/components/Correspondence.tsx#L443) | POST | "/gmail/relink-thread" |
| [src/components/DashboardView.tsx:133](../../../job-tracker-ui/src/components/DashboardView.tsx#L133) | GET | "/jobapplications/stats" |
| [src/components/DashboardView.tsx:134](../../../job-tracker-ui/src/components/DashboardView.tsx#L134) | GET | "/jobapplications/analytics-overview" |
| [src/components/DashboardView.tsx:135](../../../job-tracker-ui/src/components/DashboardView.tsx#L135) | GET | "/jobapplications/reminders" |
| [src/components/DashboardView.tsx:157](../../../job-tracker-ui/src/components/DashboardView.tsx#L157) | GET | "/jobapplications/analytics" |
| [src/components/DashboardView.tsx:158](../../../job-tracker-ui/src/components/DashboardView.tsx#L158) | GET | "/jobapplications/tags" |
| [src/components/DashboardView.tsx:159](../../../job-tracker-ui/src/components/DashboardView.tsx#L159) | GET | "/jobapplications/tag-trends" |
| [src/components/EditJobDialog.tsx:108](../../../job-tracker-ui/src/components/EditJobDialog.tsx#L108) | GET | `/jobapplications/${jobId}` |
| [src/components/EditJobDialog.tsx:147](../../../job-tracker-ui/src/components/EditJobDialog.tsx#L147) | PUT | `/jobapplications/${jobId}` |
| [src/components/EmailProviderConnections.tsx:28](../../../job-tracker-ui/src/components/EmailProviderConnections.tsx#L28) | GET | "/gmail/status" |
| [src/components/EmailProviderConnections.tsx:37](../../../job-tracker-ui/src/components/EmailProviderConnections.tsx#L37) | GET | "/microsoft-graph/status" |
| [src/components/EmailProviderConnections.tsx:46](../../../job-tracker-ui/src/components/EmailProviderConnections.tsx#L46) | GET | "/imap/status" |
| [src/components/EmailProviderConnections.tsx:85](../../../job-tracker-ui/src/components/EmailProviderConnections.tsx#L85) | GET | connectUrlPath |
| [src/components/EmailProviderConnections.tsx:95](../../../job-tracker-ui/src/components/EmailProviderConnections.tsx#L95) | DELETE | path |
| [src/components/EmailProviderConnections.tsx:110](../../../job-tracker-ui/src/components/EmailProviderConnections.tsx#L110) | POST | "/imap/connect" |
| [src/components/ErrorBoundary.tsx:30](../../../job-tracker-ui/src/components/ErrorBoundary.tsx#L30) | POST | "/client-errors" |
| [src/components/GoogleAuthCard.tsx:98](../../../job-tracker-ui/src/components/GoogleAuthCard.tsx#L98) | GET | "/auth/me" |
| [src/components/GoogleAuthCard.tsx:108](../../../job-tracker-ui/src/components/GoogleAuthCard.tsx#L108) | GET | "/auth/config" |
| [src/components/GoogleAuthCard.tsx:140](../../../job-tracker-ui/src/components/GoogleAuthCard.tsx#L140) | POST | "/auth/google/link" |
| [src/components/GoogleAuthCard.tsx:144](../../../job-tracker-ui/src/components/GoogleAuthCard.tsx#L144) | POST | "/auth/google/exchange" |
| [src/components/GoogleAuthCard.tsx:259](../../../job-tracker-ui/src/components/GoogleAuthCard.tsx#L259) | POST | "/auth/logout" |
| [src/components/GoogleAuthCard.tsx:277](../../../job-tracker-ui/src/components/GoogleAuthCard.tsx#L277) | DELETE | "/auth/google/link" |
| [src/components/ImportExportJobs.tsx:187](../../../job-tracker-ui/src/components/ImportExportJobs.tsx#L187) | GET | url |
| [src/components/ImportExportJobs.tsx:208](../../../job-tracker-ui/src/components/ImportExportJobs.tsx#L208) | POST | "/companies" |
| [src/components/ImportExportJobs.tsx:210](../../../job-tracker-ui/src/components/ImportExportJobs.tsx#L210) | POST | "/jobapplications" |
| [src/components/JobTable.tsx:313](../../../job-tracker-ui/src/components/JobTable.tsx#L313) | GET | "/jobapplications" |
| [src/components/JobTable.tsx:380](../../../job-tracker-ui/src/components/JobTable.tsx#L380) | DELETE | `/jobapplications/${job.id}` |
| [src/components/JobTable.tsx:390](../../../job-tracker-ui/src/components/JobTable.tsx#L390) | POST | `/jobapplications/${id}/restore` |
| [src/components/JobTable.tsx:400](../../../job-tracker-ui/src/components/JobTable.tsx#L400) | PATCH | `/jobapplications/${id}/status` |
| [src/components/JobTable.tsx:414](../../../job-tracker-ui/src/components/JobTable.tsx#L414) | DELETE | `/jobapplications/${id}` |
| [src/components/JobTable.tsx:415](../../../job-tracker-ui/src/components/JobTable.tsx#L415) | POST | `/jobapplications/${id}/restore` |
| [src/components/JobTable.tsx:416](../../../job-tracker-ui/src/components/JobTable.tsx#L416) | PATCH | `/jobapplications/${id}/status` |
| [src/components/KanbanBoard.tsx:100](../../../job-tracker-ui/src/components/KanbanBoard.tsx#L100) | GET | "/jobapplications/board" |
| [src/components/KanbanBoard.tsx:144](../../../job-tracker-ui/src/components/KanbanBoard.tsx#L144) | PATCH | `/jobapplications/${movingJobId}/status` |
| [src/components/KanbanBoard.tsx:156](../../../job-tracker-ui/src/components/KanbanBoard.tsx#L156) | PATCH | `/jobapplications/${id}/status` |
| [src/components/MicrosoftAuthCard.tsx:54](../../../job-tracker-ui/src/components/MicrosoftAuthCard.tsx#L54) | GET | "/auth/me" |
| [src/components/MicrosoftAuthCard.tsx:84](../../../job-tracker-ui/src/components/MicrosoftAuthCard.tsx#L84) | POST | "/auth/microsoft/link" |
| [src/components/MicrosoftAuthCard.tsx:91](../../../job-tracker-ui/src/components/MicrosoftAuthCard.tsx#L91) | POST | "/auth/microsoft/exchange" |
| [src/components/MicrosoftAuthCard.tsx:202](../../../job-tracker-ui/src/components/MicrosoftAuthCard.tsx#L202) | POST | "/auth/logout" |
| [src/components/MicrosoftAuthCard.tsx:220](../../../job-tracker-ui/src/components/MicrosoftAuthCard.tsx#L220) | DELETE | "/auth/microsoft/link" |
| [src/components/NotificationsPopover.tsx:41](../../../job-tracker-ui/src/components/NotificationsPopover.tsx#L41) | GET | "/notifications?limit=10" |
| [src/components/NotificationsPopover.tsx:59](../../../job-tracker-ui/src/components/NotificationsPopover.tsx#L59) | POST | `/notifications/${notification.id}/read` |
| [src/components/NotificationsPopover.tsx:76](../../../job-tracker-ui/src/components/NotificationsPopover.tsx#L76) | DELETE | `/notifications/${notification.id}` |
| [src/components/OnboardingChecklist.tsx:47](../../../job-tracker-ui/src/components/OnboardingChecklist.tsx#L47) | GET | "/auth/me" |
| [src/components/OnboardingChecklist.tsx:48](../../../job-tracker-ui/src/components/OnboardingChecklist.tsx#L48) | GET | "/career/profile" |
| [src/components/OnboardingChecklist.tsx:50](../../../job-tracker-ui/src/components/OnboardingChecklist.tsx#L50) | GET | url |
| [src/components/QuickCommandDialog.tsx:69](../../../job-tracker-ui/src/components/QuickCommandDialog.tsx#L69) | GET | "/jobapplications" |
| [src/components/QuickCommandDialog.tsx:73](../../../job-tracker-ui/src/components/QuickCommandDialog.tsx#L73) | GET | "/companies" |
| [src/components/RemindersView.tsx:78](../../../job-tracker-ui/src/components/RemindersView.tsx#L78) | GET | "/jobapplications/reminders" |
| [src/components/RemindersView.tsx:98](../../../job-tracker-ui/src/components/RemindersView.tsx#L98) | PATCH | `/jobapplications/${id}/followup` |
| [src/components/RulesSettingsCard.tsx:27](../../../job-tracker-ui/src/components/RulesSettingsCard.tsx#L27) | GET | "/rules" |
| [src/components/RulesSettingsCard.tsx:42](../../../job-tracker-ui/src/components/RulesSettingsCard.tsx#L42) | PUT | "/rules" |
| [src/components/SessionsSettingsCard.tsx:49](../../../job-tracker-ui/src/components/SessionsSettingsCard.tsx#L49) | GET | "/auth/sessions" |
| [src/components/SessionsSettingsCard.tsx:60](../../../job-tracker-ui/src/components/SessionsSettingsCard.tsx#L60) | DELETE | `/auth/sessions/${id}` |
| [src/components/SessionsSettingsCard.tsx:77](../../../job-tracker-ui/src/components/SessionsSettingsCard.tsx#L77) | POST | "/auth/sessions/revoke-others" |
| [src/components/SettingsView.tsx:80](../../../job-tracker-ui/src/components/SettingsView.tsx#L80) | GET | "/notification-settings" |
| [src/components/SettingsView.tsx:91](../../../job-tracker-ui/src/components/SettingsView.tsx#L91) | PUT | "/notification-settings" |
| [src/components/TwoFactorChallenge.tsx:29](../../../job-tracker-ui/src/components/TwoFactorChallenge.tsx#L29) | POST | "/auth/2fa/challenge" |
| [src/components/TwoFactorSettingsCard.tsx:73](../../../job-tracker-ui/src/components/TwoFactorSettingsCard.tsx#L73) | GET | "/auth/2fa/status" |
| [src/components/TwoFactorSettingsCard.tsx:79](../../../job-tracker-ui/src/components/TwoFactorSettingsCard.tsx#L79) | GET | "/auth/2fa/trusted-devices" |
| [src/components/TwoFactorSettingsCard.tsx:90](../../../job-tracker-ui/src/components/TwoFactorSettingsCard.tsx#L90) | DELETE | `/auth/2fa/trusted-devices/${id}` |
| [src/components/TwoFactorSettingsCard.tsx:99](../../../job-tracker-ui/src/components/TwoFactorSettingsCard.tsx#L99) | POST | "/auth/2fa/trusted-devices/revoke-all" |
| [src/components/TwoFactorSettingsCard.tsx:123](../../../job-tracker-ui/src/components/TwoFactorSettingsCard.tsx#L123) | POST | "/auth/2fa/setup" |
| [src/components/TwoFactorSettingsCard.tsx:128](../../../job-tracker-ui/src/components/TwoFactorSettingsCard.tsx#L128) | POST | "/auth/2fa/disable" |
| [src/components/TwoFactorSettingsCard.tsx:133](../../../job-tracker-ui/src/components/TwoFactorSettingsCard.tsx#L133) | POST | "/auth/2fa/recovery-codes/regenerate" |
| [src/components/TwoFactorSettingsCard.tsx:149](../../../job-tracker-ui/src/components/TwoFactorSettingsCard.tsx#L149) | POST | "/auth/2fa/verify-setup" |
| [src/components/UserManagementCard.tsx:34](../../../job-tracker-ui/src/components/UserManagementCard.tsx#L34) | GET | "/users" |
| [src/components/UserManagementCard.tsx:98](../../../job-tracker-ui/src/components/UserManagementCard.tsx#L98) | POST | "/users" |
| [src/components/UserManagementCard.tsx:152](../../../job-tracker-ui/src/components/UserManagementCard.tsx#L152) | DELETE | `/users/${u.id}` |
| [src/components/UserManagementCard.tsx:167](../../../job-tracker-ui/src/components/UserManagementCard.tsx#L167) | POST | `/users/${u.id}/send-password-reset` |
| [src/components/job-workspace/useJobWorkspaceBaseData.ts:51](../../../job-tracker-ui/src/components/job-workspace/useJobWorkspaceBaseData.ts#L51) | GET | `/jobapplications/${jobId}` |
| [src/components/job-workspace/useJobWorkspaceBaseData.ts:64](../../../job-tracker-ui/src/components/job-workspace/useJobWorkspaceBaseData.ts#L64) | GET | `/attachments/${jobId}` |
| [src/components/job-workspace/useJobWorkspaceBaseData.ts:74](../../../job-tracker-ui/src/components/job-workspace/useJobWorkspaceBaseData.ts#L74) | GET | `/auth/me` |
| [src/components/job-workspace/useJobWorkspaceBaseData.ts:82](../../../job-tracker-ui/src/components/job-workspace/useJobWorkspaceBaseData.ts#L82) | GET | `/jobapplications/${jobId}/history` |
| [src/cvBuilder.ts:265](../../../job-tracker-ui/src/cvBuilder.ts#L265) | GET | "/cv/themes" |
| [src/cvBuilder.ts:266](../../../job-tracker-ui/src/cvBuilder.ts#L266) | GET | `/cv/themes/${encodeURIComponent(themeId)}/preview` |
| [src/cvBuilder.ts:267](../../../job-tracker-ui/src/cvBuilder.ts#L267) | GET | "/cv/outline" |
| [src/cvBuilder.ts:268](../../../job-tracker-ui/src/cvBuilder.ts#L268) | GET | "/cv/variants" |
| [src/cvBuilder.ts:270](../../../job-tracker-ui/src/cvBuilder.ts#L270) | POST | "/cv/variants" |
| [src/cvBuilder.ts:271](../../../job-tracker-ui/src/cvBuilder.ts#L271) | GET | `/cv/variants/${id}` |
| [src/cvBuilder.ts:273](../../../job-tracker-ui/src/cvBuilder.ts#L273) | PUT | `/cv/variants/${id}` |
| [src/cvBuilder.ts:274](../../../job-tracker-ui/src/cvBuilder.ts#L274) | DELETE | `/cv/variants/${id}` |
| [src/cvBuilder.ts:275](../../../job-tracker-ui/src/cvBuilder.ts#L275) | POST | `/cv/variants/${id}/duplicate` |
| [src/cvBuilder.ts:276](../../../job-tracker-ui/src/cvBuilder.ts#L276) | PUT | `/cv/variants/${id}/public` |
| [src/cvBuilder.ts:277](../../../job-tracker-ui/src/cvBuilder.ts#L277) | GET | `/cv/variants/${id}/versions` |
| [src/cvBuilder.ts:278](../../../job-tracker-ui/src/cvBuilder.ts#L278) | POST | `/cv/variants/${id}/versions/${version}/restore` |
| [src/cvBuilder.ts:279](../../../job-tracker-ui/src/cvBuilder.ts#L279) | POST | "/cv/preview" |
| [src/cvBuilder.ts:281](../../../job-tracker-ui/src/cvBuilder.ts#L281) | POST | "/cv/ai/assist" |
| [src/hooks/useCompanies.ts:31](../../../job-tracker-ui/src/hooks/useCompanies.ts#L31) | GET | '/companies' |
| [src/i18n/I18nProvider.tsx:35](../../../job-tracker-ui/src/i18n/I18nProvider.tsx#L35) | PUT | "/auth/preferences/language" |
| [src/views/AdminAuditPage.tsx:49](../../../job-tracker-ui/src/views/AdminAuditPage.tsx#L49) | GET | "/admin/audit?take=200" |
| [src/views/AdminAuditPage.tsx:59](../../../job-tracker-ui/src/views/AdminAuditPage.tsx#L59) | POST | `/admin/audit/${e.id}/undo` |
| [src/views/AdminAuditPage.tsx:73](../../../job-tracker-ui/src/views/AdminAuditPage.tsx#L73) | POST | `/jobapplications/${e.jobApplicationId}/restore` |
| [src/views/AdminSystemPage.tsx:241](../../../job-tracker-ui/src/views/AdminSystemPage.tsx#L241) | GET | "/admin/system" |
| [src/views/AdminSystemPage.tsx:242](../../../job-tracker-ui/src/views/AdminSystemPage.tsx#L242) | GET | "/admin/system/email-settings" |
| [src/views/AdminSystemPage.tsx:243](../../../job-tracker-ui/src/views/AdminSystemPage.tsx#L243) | GET | "/admin/system/cv-benchmark" |
| [src/views/AdminSystemPage.tsx:244](../../../job-tracker-ui/src/views/AdminSystemPage.tsx#L244) | GET | "/admin/system/maintenance-jobs" |
| [src/views/AdminSystemPage.tsx:313](../../../job-tracker-ui/src/views/AdminSystemPage.tsx#L313) | POST | "/users/send-test-email" |
| [src/views/AdminSystemPage.tsx:330](../../../job-tracker-ui/src/views/AdminSystemPage.tsx#L330) | PUT | "/admin/system/email-settings" |
| [src/views/AdminSystemPage.tsx:358](../../../job-tracker-ui/src/views/AdminSystemPage.tsx#L358) | POST | `/admin/system/maintenance-jobs/${encodeURIComponent(jobId)}/runs` |
| [src/views/AdminSystemPage.tsx:381](../../../job-tracker-ui/src/views/AdminSystemPage.tsx#L381) | POST | "/admin/system/ai/probe" |
| [src/views/AdminUsersPage.tsx:49](../../../job-tracker-ui/src/views/AdminUsersPage.tsx#L49) | GET | "/users" |
| [src/views/AdminUsersPage.tsx:93](../../../job-tracker-ui/src/views/AdminUsersPage.tsx#L93) | PUT | `/users/${u.id}/roles` |
| [src/views/AdminUsersPage.tsx:103](../../../job-tracker-ui/src/views/AdminUsersPage.tsx#L103) | POST | `/users/${u.id}/send-password-reset` |
| [src/views/AdminUsersPage.tsx:117](../../../job-tracker-ui/src/views/AdminUsersPage.tsx#L117) | DELETE | `/users/${u.id}` |
| [src/views/AdminUsersPage.tsx:215](../../../job-tracker-ui/src/views/AdminUsersPage.tsx#L215) | POST | "/users" |
| [src/views/CareerProfilePage.tsx:185](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L185) | GET | "/career/profile/versions" |
| [src/views/CareerProfilePage.tsx:195](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L195) | POST | `/career/profile/versions/${version}/restore` |
| [src/views/CareerProfilePage.tsx:220](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L220) | GET | "/profile-cv/runs" |
| [src/views/CareerProfilePage.tsx:232](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L232) | POST | "/profile-cv/upload" |
| [src/views/CareerProfilePage.tsx:248](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L248) | GET | "/career/profile" |
| [src/views/CareerProfilePage.tsx:249](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L249) | GET | "/auth/me" |
| [src/views/CareerProfilePage.tsx:289](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L289) | GET | `/profile-cv/runs/${run.id}/diff` |
| [src/views/CareerProfilePage.tsx:408](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L408) | POST | "/auth/avatar" |
| [src/views/CareerProfilePage.tsx:495](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L495) | DELETE | "/auth/avatar" |
| [src/views/CareerProfilePage.tsx:556](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L556) | POST | "/profile-cv/rebuild" |
| [src/views/CareerProfilePage.tsx:574](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L574) | POST | "/profile-cv/improve" |
| [src/views/CareerProfilePage.tsx:592](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L592) | POST | "/profile-cv/reprocess" |
| [src/views/CareerProfilePage.tsx:669](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L669) | POST | `/operations/${run.operation!.id}/cancel` |
| [src/views/CareerProfilePage.tsx:680](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L680) | POST | `/operations/${run.operation!.id}/retry` |
| [src/views/CareerProfilePage.tsx:726](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L726) | POST | `/profile-cv/runs/${run.id}/accept` |
| [src/views/CareerProfilePage.tsx:737](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L737) | POST | `/profile-cv/runs/${run.id}/discard` |
| [src/views/CareerProfilePage.tsx:772](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L772) | POST | "/profile-cv/parse" |
| [src/views/CareerProfilePage.tsx:855](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L855) | PUT | "/career/profile" |
| [src/views/CorrespondenceInboxPage.tsx:158](../../../job-tracker-ui/src/views/CorrespondenceInboxPage.tsx#L158) | GET | "/correspondence/page" |
| [src/views/CorrespondenceInboxPage.tsx:185](../../../job-tracker-ui/src/views/CorrespondenceInboxPage.tsx#L185) | GET | "/email/providers" |
| [src/views/CorrespondenceInboxPage.tsx:200](../../../job-tracker-ui/src/views/CorrespondenceInboxPage.tsx#L200) | GET | "/jobapplications/choices" |
| [src/views/CorrespondenceInboxPage.tsx:213](../../../job-tracker-ui/src/views/CorrespondenceInboxPage.tsx#L213) | GET | "/email/drafts" |
| [src/views/CorrespondenceInboxPage.tsx:248](../../../job-tracker-ui/src/views/CorrespondenceInboxPage.tsx#L248) | GET | "/email/message" |
| [src/views/CorrespondenceInboxPage.tsx:260](../../../job-tracker-ui/src/views/CorrespondenceInboxPage.tsx#L260) | GET | `/correspondence/message/${item.id}` |
| [src/views/CorrespondenceInboxPage.tsx:375](../../../job-tracker-ui/src/views/CorrespondenceInboxPage.tsx#L375) | DELETE | `/email/drafts/${draft.id}` |
| [src/views/CorrespondenceInboxPage.tsx:394](../../../job-tracker-ui/src/views/CorrespondenceInboxPage.tsx#L394) | PUT | `/email/drafts/${draft.id}` |
| [src/views/CorrespondenceInboxPage.tsx:400](../../../job-tracker-ui/src/views/CorrespondenceInboxPage.tsx#L400) | POST | "/email/drafts" |
| [src/views/CorrespondenceInboxPage.tsx:432](../../../job-tracker-ui/src/views/CorrespondenceInboxPage.tsx#L432) | POST | "/email/send" |
| [src/views/CorrespondenceInboxPage.tsx:447](../../../job-tracker-ui/src/views/CorrespondenceInboxPage.tsx#L447) | DELETE | `/email/drafts/${draft.id}` |
| [src/views/CorrespondenceInboxPage.tsx:476](../../../job-tracker-ui/src/views/CorrespondenceInboxPage.tsx#L476) | POST | `/email/drafts/${draft.id}/new-attempt` |
| [src/views/CorrespondenceInboxPage.tsx:503](../../../job-tracker-ui/src/views/CorrespondenceInboxPage.tsx#L503) | POST | "/gmail/unlink-thread" |
| [src/views/CvBuilderEditor.tsx:312](../../../job-tracker-ui/src/views/CvBuilderEditor.tsx#L312) | POST | cvBuilderApi.exportPdfUrl(variantId) |
| [src/views/CvBuilderPage.tsx:112](../../../job-tracker-ui/src/views/CvBuilderPage.tsx#L112) | POST | cvBuilderApi.exportPdfUrl(id) |
| [src/views/ForgotPasswordPage.tsx:62](../../../job-tracker-ui/src/views/ForgotPasswordPage.tsx#L62) | POST | "/auth/request-password-reset" |
| [src/views/GmailReviewPage.tsx:35](../../../job-tracker-ui/src/views/GmailReviewPage.tsx#L35) | GET | "/gmail/review-candidates" |
| [src/views/GmailReviewPage.tsx:36](../../../job-tracker-ui/src/views/GmailReviewPage.tsx#L36) | GET | "/gmail/suggested-jobs" |
| [src/views/GmailReviewPage.tsx:61](../../../job-tracker-ui/src/views/GmailReviewPage.tsx#L61) | POST | "/gmail/review-decision" |
| [src/views/GmailReviewPage.tsx:88](../../../job-tracker-ui/src/views/GmailReviewPage.tsx#L88) | POST | "/gmail/manual-sync" |
| [src/views/GmailReviewPage.tsx:112](../../../job-tracker-ui/src/views/GmailReviewPage.tsx#L112) | POST | "/gmail/create-suggested-job" |
| [src/views/JobDiscoveryPage.tsx:54](../../../job-tracker-ui/src/views/JobDiscoveryPage.tsx#L54) | GET | "/job-discovery/saved-searches" |
| [src/views/JobDiscoveryPage.tsx:63](../../../job-tracker-ui/src/views/JobDiscoveryPage.tsx#L63) | GET | "/job-discovery/search" |
| [src/views/JobDiscoveryPage.tsx:78](../../../job-tracker-ui/src/views/JobDiscoveryPage.tsx#L78) | POST | "/job-discovery/saved-searches" |
| [src/views/JobDiscoveryPage.tsx:89](../../../job-tracker-ui/src/views/JobDiscoveryPage.tsx#L89) | POST | `/job-discovery/saved-searches/${saved.id}/run` |
| [src/views/JobDiscoveryPage.tsx:100](../../../job-tracker-ui/src/views/JobDiscoveryPage.tsx#L100) | DELETE | `/job-discovery/saved-searches/${saved.id}` |
| [src/views/JobDiscoveryPage.tsx:109](../../../job-tracker-ui/src/views/JobDiscoveryPage.tsx#L109) | PATCH | `/job-discovery/saved-searches/${saved.id}` |
| [src/views/JobDiscoveryPage.tsx:118](../../../job-tracker-ui/src/views/JobDiscoveryPage.tsx#L118) | PATCH | `/job-discovery/saved-searches/${activeSavedSearchId}/results/${encodeURIComponent(jobId)}/dismiss` |
| [src/views/LandingPage.tsx:51](../../../job-tracker-ui/src/views/LandingPage.tsx#L51) | GET | "/auth/me" |
| [src/views/LoginPage.tsx:59](../../../job-tracker-ui/src/views/LoginPage.tsx#L59) | GET | "/auth/config" |
| [src/views/LoginPage.tsx:67](../../../job-tracker-ui/src/views/LoginPage.tsx#L67) | GET | "/auth/me" |
| [src/views/LoginPage.tsx:96](../../../job-tracker-ui/src/views/LoginPage.tsx#L96) | POST | url |
| [src/views/LoginPage.tsx:121](../../../job-tracker-ui/src/views/LoginPage.tsx#L121) | POST | "/auth/resend-verification-email" |
| [src/views/MicrosoftLegacyRelinkPage.tsx:32](../../../job-tracker-ui/src/views/MicrosoftLegacyRelinkPage.tsx#L32) | POST | "/auth/microsoft/legacy-relink/confirm" |
| [src/views/OfferComparisonPage.tsx:14](../../../job-tracker-ui/src/views/OfferComparisonPage.tsx#L14) | GET | "/jobapplications" |
| [src/views/OperationsPage.tsx:47](../../../job-tracker-ui/src/views/OperationsPage.tsx#L47) | GET | "/operations?limit=50" |
| [src/views/OperationsPage.tsx:48](../../../job-tracker-ui/src/views/OperationsPage.tsx#L48) | GET | "/notifications?limit=50" |
| [src/views/OperationsPage.tsx:101](../../../job-tracker-ui/src/views/OperationsPage.tsx#L101) | POST | `/notifications/${notification.id}/read` |
| [src/views/OperationsPage.tsx:105](../../../job-tracker-ui/src/views/OperationsPage.tsx#L105) | DELETE | `/notifications/${notification.id}` |
| [src/views/OperationsPage.tsx:131](../../../job-tracker-ui/src/views/OperationsPage.tsx#L131) | POST | `/operations/${operation.id}/cancel` |
| [src/views/OperationsPage.tsx:136](../../../job-tracker-ui/src/views/OperationsPage.tsx#L136) | POST | `/operations/${operation.id}/retry` |
| [src/views/ProfilePage.tsx:91](../../../job-tracker-ui/src/views/ProfilePage.tsx#L91) | GET | "/auth/me" |
| [src/views/ProfilePage.tsx:103](../../../job-tracker-ui/src/views/ProfilePage.tsx#L103) | GET | "/auth/email-change" |
| [src/views/ProfilePage.tsx:149](../../../job-tracker-ui/src/views/ProfilePage.tsx#L149) | POST | "/auth/avatar" |
| [src/views/ProfilePage.tsx:202](../../../job-tracker-ui/src/views/ProfilePage.tsx#L202) | DELETE | "/auth/avatar" |
| [src/views/ProfilePage.tsx:272](../../../job-tracker-ui/src/views/ProfilePage.tsx#L272) | POST | "/auth/email-change/request" |
| [src/views/ProfilePage.tsx:290](../../../job-tracker-ui/src/views/ProfilePage.tsx#L290) | POST | "/auth/email-change/cancel" |
| [src/views/ProfilePage.tsx:316](../../../job-tracker-ui/src/views/ProfilePage.tsx#L316) | PUT | "/auth/profile" |
| [src/views/ProfilePage.tsx:350](../../../job-tracker-ui/src/views/ProfilePage.tsx#L350) | POST | "/auth/change-password" |
| [src/views/PublicCvPage.tsx:26](../../../job-tracker-ui/src/views/PublicCvPage.tsx#L26) | GET | `/public-cv/${slug}` |
| [src/views/ResetPasswordPage.tsx:66](../../../job-tracker-ui/src/views/ResetPasswordPage.tsx#L66) | POST | "/auth/reset-password" |
| [src/views/VerifyEmailPage.tsx:31](../../../job-tracker-ui/src/views/VerifyEmailPage.tsx#L31) | POST | emailChange ? "/auth/email-change/confirm" : "/auth/verify-email" |
| [src/views/career/CareerEvidenceBank.tsx:15](../../../job-tracker-ui/src/views/career/CareerEvidenceBank.tsx#L15) | GET | "/career/evidence" |
| [src/views/career/CareerEvidenceBank.tsx:17](../../../job-tracker-ui/src/views/career/CareerEvidenceBank.tsx#L17) | POST | "/career/evidence" |
| [src/views/career/CareerEvidenceBank.tsx:18](../../../job-tracker-ui/src/views/career/CareerEvidenceBank.tsx#L18) | DELETE | `/career/evidence/${item.id}` |
@@ -0,0 +1,97 @@
# Component and source inventory
Every production TSX module under `src` and `app` is listed. Lines are size indicators, not complexity scores. Reachability is relative-import reachability from ClientApp; app entry files are expected to be outside that graph. MUI primitives are dependencies, not missing local components. No unreachable file is approved for deletion.
| Module | Lines | Client graph | Local direct consumers | Rendered component names |
|---|---|---|---|---|
| [app/[[...slug]]/ClientShell.tsx:1](../../../job-tracker-ui/app/[[...slug]]/ClientShell.tsx#L1) | 14 | outside graph | page.tsx | ClientApp |
| [app/layout.tsx:1](../../../job-tracker-ui/app/layout.tsx#L1) | 42 | outside graph | — | Script |
| [app/page.tsx:1](../../../job-tracker-ui/app/page.tsx#L1) | 6 | outside graph | — | ClientShell |
| [src/App.tsx:1](../../../job-tracker-ui/src/App.tsx#L1) | 500 | reachable | ClientApp.tsx | AccountCircleIcon, AccountPlanProvider, AddJobModal, AdminAuditPage, AdminSystemPage, AdminUsersPage, AlarmIcon, AppShell, Application, ApplicationWorkspacePage, Box, BusinessIcon, Button, CareerWorkspacePage, CompaniesTable, CompareArrowsIcon, ConfirmProvider, ConnectedAccountsPage, CorrespondenceInboxPage, CvBuilderEditor, CvBuilderPage, DashboardIcon, DashboardView, DeleteOutlineIcon, DescriptionOutlinedIcon, ForgotPasswordPage, I18nProvider, IconButton, JobDiscoveryPage, JobTable, JobTrackerThemeProvider, KanbanBoard, LandingPage, LegacyApplicationRedirect, LoginPage, MailOutlineIcon, MemoryIcon, MicrosoftLegacyRelinkPage, Navigate, NotFoundPage, NotificationsPopover, OfferComparisonPage, OperationsPage, PageLoader, ProfilePage, PromptProvider, PublicCvPage, QuickCommandDialog, RemindersView, ResetPasswordPage, Route, RouteErrorPage, RouterProvider, Routes, SearchIcon, SettingsIcon, SettingsView, Shell, ShieldIcon, Suspense, ThemeAwareShell, ThemeControlsContext.Provider, ToastProvider, Typography, VerifyEmailPage, ViewKanbanIcon, WorkOutlineIcon |
| [src/ClientApp.tsx:1](../../../job-tracker-ui/src/ClientApp.tsx#L1) | 21 | reachable | ClientShell.tsx | App, ErrorBoundary, I18nProvider, LocalizationProvider |
| [src/ThemeProvider.tsx:1](../../../job-tracker-ui/src/ThemeProvider.tsx#L1) | 26 | reachable | App.tsx | CssBaseline, CssVarsProvider, ThemeModeSynchronizer |
| [src/accountPlan.tsx:1](../../../job-tracker-ui/src/accountPlan.tsx#L1) | 21 | reachable | App.tsx, AddJobModal.tsx, ApplicationAssets.tsx, ApplicationWorkflowAssist.tsx, InterviewPrep.tsx, AiSectionAssistant.tsx, CareerProfilePage.tsx, CvBuilderEditor.tsx | AccountPlanContext.Provider |
| [src/assets/JobbjaktMark.tsx:1](../../../job-tracker-ui/src/assets/JobbjaktMark.tsx#L1) | 19 | reachable | AppShell.tsx | |
| [src/components/AddJobModal.tsx:1](../../../job-tracker-ui/src/components/AddJobModal.tsx#L1) | 652 | reachable | App.tsx | Alert, Autocomplete, Box, Button, Checkbox, Chip, CloseIcon, DatePicker, Dialog, DialogActions, DialogContent, DialogTitle, Divider, FormControlLabel, IconButton, List, ListItem, ListItemText, MenuItem, Step, StepLabel, Stepper, TagsInput, TextField, Typography, UploadFileOutlinedIcon |
| [src/components/AiPrivacySettingsCard.tsx:1](../../../job-tracker-ui/src/components/AiPrivacySettingsCard.tsx#L1) | 76 | reachable | SettingsView.tsx | Alert, Box, Button, FormControlLabel, Paper, Skeleton, Switch, Typography |
| [src/components/AiUsageCard.tsx:1](../../../job-tracker-ui/src/components/AiUsageCard.tsx#L1) | 91 | reachable | SettingsView.tsx | Alert, Box, Button, LinearProgress, Paper, Skeleton, Stack, Typography |
| [src/components/ApplicationAssets.tsx:1](../../../job-tracker-ui/src/components/ApplicationAssets.tsx#L1) | 769 | reachable | ApplicationWorkspacePage.tsx | Alert, ApplicationTailoringSection, ArchiveOutlinedIcon, AutoFixHighIcon, Box, Button, Chip, CoverLetterAiAssistant, Dialog, DialogActions, DialogContent, DialogTitle, Divider, DownloadOutlinedIcon, FormControl, IconButton, InputLabel, MenuItem, OpenInNewIcon, Paper, RestoreIcon, RichTextField, Select, Shell, Skeleton, Stack, SubmittedPackagesSection, TextField, Tooltip, Typography |
| [src/components/ApplicationCalendarActions.tsx:1](../../../job-tracker-ui/src/components/ApplicationCalendarActions.tsx#L1) | 81 | reachable | ApplicationWorkspacePage.tsx | Alert, Box, Button, CalendarMonthOutlinedIcon, CircularProgress, DownloadOutlinedIcon, OpenInNewIcon, Stack, Typography |
| [src/components/ApplicationChecklist.tsx:1](../../../job-tracker-ui/src/components/ApplicationChecklist.tsx#L1) | 224 | reachable | ApplicationWorkspacePage.tsx | Alert, ArrowDownwardIcon, ArrowUpwardIcon, Box, Button, Checkbox, Chip, DeleteOutlineIcon, IconButton, LinearProgress, Paper, Skeleton, Stack, TextField, Tooltip, Typography |
| [src/components/ApplicationIntelligence.tsx:1](../../../job-tracker-ui/src/components/ApplicationIntelligence.tsx#L1) | 380 | reachable | ApplicationWorkspacePage.tsx | Alert, Box, Bullets, Chip, Chips, Divider, LinearProgress, Paper, React.Fragment, SectionShell, Skeleton, Stack, ToggleButton, ToggleButtonGroup, Typography |
| [src/components/ApplicationWorkflowAssist.tsx:1](../../../job-tracker-ui/src/components/ApplicationWorkflowAssist.tsx#L1) | 166 | reachable | ApplicationWorkspacePage.tsx | Alert, Box, Button, CircularProgress, DraftCard, ListCard, Paper, Stack, TwoColumnSection, Typography |
| [src/components/Attachment.tsx:1](../../../job-tracker-ui/src/components/Attachment.tsx#L1) | 26 | outside graph | — | |
| [src/components/Attachments.tsx:1](../../../job-tracker-ui/src/components/Attachments.tsx#L1) | 373 | reachable | ApplicationWorkspacePage.tsx | Alert, Box, Button, Chip, CloudUploadOutlinedIcon, DeleteOutlineIcon, Dialog, DialogActions, DialogContent, DialogTitle, DownloadIcon, DriveFileRenameOutlineIcon, FormControl, IconButton, InputLabel, LinearProgress, MenuItem, Select, Switch, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography, VisibilityOutlinedIcon |
| [src/components/AuthStatusCard.tsx:1](../../../job-tracker-ui/src/components/AuthStatusCard.tsx#L1) | 88 | reachable | ProfilePage.tsx | Box, Button, Paper, Typography |
| [src/components/BackupCard.tsx:1](../../../job-tracker-ui/src/components/BackupCard.tsx#L1) | 138 | reachable | SettingsView.tsx | Alert, Box, Button, Divider, Paper, Typography |
| [src/components/CompaniesTable.tsx:1](../../../job-tracker-ui/src/components/CompaniesTable.tsx#L1) | 346 | reachable | App.tsx | Alert, Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, EditOutlinedIcon, IconButton, Paper, PeopleAltOutlinedIcon, Stack, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TextField, Typography, ViewStateNotice |
| [src/components/Correspondence.tsx:1](../../../job-tracker-ui/src/components/Correspondence.tsx#L1) | 747 | reachable | ApplicationWorkspacePage.tsx | AutoAwesomeIcon, Autocomplete, Box, Button, Chip, CircularProgress, DeleteOutlineIcon, Dialog, DialogActions, DialogContent, DialogTitle, Divider, IconButton, List, ListItemButton, ListItemText, MailOutlineIcon, Paper, React.Fragment, SearchIcon, Tab, Tabs, TextField, ToggleButton, ToggleButtonGroup, Typography |
| [src/components/CropImageDialog.tsx:1](../../../job-tracker-ui/src/components/CropImageDialog.tsx#L1) | 225 | reachable | CareerProfilePage.tsx, ProfilePage.tsx | Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Slider, Typography |
| [src/components/CvTemplateGallery.tsx:1](../../../job-tracker-ui/src/components/CvTemplateGallery.tsx#L1) | 57 | reachable | CvCustomizeTab.tsx, CvBuilderPage.tsx | Box, Button, CheckCircleIcon, Chip, CvTemplateThumbnail, Paper, Stack, Typography |
| [src/components/CvTemplateThumbnail.tsx:1](../../../job-tracker-ui/src/components/CvTemplateThumbnail.tsx#L1) | 35 | reachable | CvTemplateGallery.tsx, CvBuilderPage.tsx | Box |
| [src/components/DashboardView.tsx:1](../../../job-tracker-ui/src/components/DashboardView.tsx#L1) | 682 | reachable | App.tsx | ArrowDownwardIcon, ArrowUpwardIcon, Box, Button, Card, Checkbox, Chip, LinearProgress, Menu, MenuItem, OnboardingChecklist, SectionCard, Stack, TuneIcon, Typography, ViewStateNotice |
| [src/components/EditJobDialog.tsx:1](../../../job-tracker-ui/src/components/EditJobDialog.tsx#L1) | 261 | reachable | JobTable.tsx, ApplicationWorkspacePage.tsx | Autocomplete, Box, Button, Checkbox, Chip, DatePicker, Dialog, DialogActions, DialogContent, DialogTitle, FormControlLabel, MenuItem, Paper, TagsInput, TextField, Typography |
| [src/components/EmailProviderConnections.tsx:1](../../../job-tracker-ui/src/components/EmailProviderConnections.tsx#L1) | 247 | reachable | ConnectedAccountsPage.tsx | Box, Button, CheckCircleIcon, Checkbox, Chip, Divider, FormControlLabel, Paper, ProviderRow, Stack, TextField, Typography |
| [src/components/ErrorBoundary.tsx:1](../../../job-tracker-ui/src/components/ErrorBoundary.tsx#L1) | 63 | reachable | ClientApp.tsx | ErrorBoundaryInner |
| [src/components/GoogleAuthCard.tsx:1](../../../job-tracker-ui/src/components/GoogleAuthCard.tsx#L1) | 301 | reachable | LoginPage.tsx, ProfilePage.tsx | Box, Button, Chip, Paper, TwoFactorChallenge, Typography |
| [src/components/GradientButton.tsx:1](../../../job-tracker-ui/src/components/GradientButton.tsx#L1) | 42 | reachable | LandingPage.tsx | Button |
| [src/components/ImportExportJobs.tsx:1](../../../job-tracker-ui/src/components/ImportExportJobs.tsx#L1) | 282 | reachable | SettingsView.tsx | Box, Button, Paper, Typography |
| [src/components/InterviewPrep.tsx:1](../../../job-tracker-ui/src/components/InterviewPrep.tsx#L1) | 512 | reachable | ApplicationWorkspacePage.tsx | Alert, ApplicationFollowUp, AutoFixHighIcon, Box, Button, Checkbox, Chip, DeleteOutlineIcon, Divider, IconButton, InterviewAiAssistant, LinearProgress, MenuItem, Paper, PrepRow, Shell, Skeleton, Stack, TextField, Tooltip, Typography |
| [src/components/JobDetailsPanels.tsx:1](../../../job-tracker-ui/src/components/JobDetailsPanels.tsx#L1) | 59 | reachable | ApplicationWorkflowAssist.tsx | Box, Button, ListCard, TextField, Typography |
| [src/components/JobFlowBar.tsx:1](../../../job-tracker-ui/src/components/JobFlowBar.tsx#L1) | 186 | outside graph | — | Box, Chip, CloseIcon, EmojiEventsIcon, ForumIcon, MarkEmailReadIcon, React.Fragment, Typography, WorkOutlineIcon |
| [src/components/JobTable.tsx:1](../../../job-tracker-ui/src/components/JobTable.tsx#L1) | 866 | reachable | App.tsx, SettingsView.tsx | Box, Button, Checkbox, Chip, DeleteOutlineIcon, EditJobDialog, EditOutlinedIcon, EmptyJobsState, FormControl, FormControlLabel, IconButton, InputAdornment, InputLabel, Menu, MenuItem, MoreHorizIcon, Paper, RestoreFromTrashOutlinedIcon, SavedViewsMenu, SearchIcon, Select, Stack, Table, TableBody, TableCell, TableHead, TablePagination, TableRow, TableSortLabel, TextField, Tooltip, Typography, ViewColumnIcon, ViewStateNotice, WorkOutlineIcon |
| [src/components/KanbanBoard.tsx:1](../../../job-tracker-ui/src/components/KanbanBoard.tsx#L1) | 428 | reachable | App.tsx | Alert, Box, Card, CardContent, Chip, IconButton, ListSubheader, Menu, MenuItem, MoreHorizIcon, Paper, Typography, ViewStateNotice |
| [src/components/Markdown.tsx:1](../../../job-tracker-ui/src/components/Markdown.tsx#L1) | 68 | outside graph | — | Box, Link, Typography |
| [src/components/MicrosoftAuthCard.tsx:1](../../../job-tracker-ui/src/components/MicrosoftAuthCard.tsx#L1) | 247 | reachable | LoginPage.tsx, MicrosoftLegacyRelinkPage.tsx, ProfilePage.tsx | Box, Button, Chip, Paper, TextField, TwoFactorChallenge, Typography |
| [src/components/NotificationsPopover.tsx:1](../../../job-tracker-ui/src/components/NotificationsPopover.tsx#L1) | 168 | reachable | App.tsx | Alert, Box, Button, CircularProgress, CloseIcon, DeleteOutlineIcon, Divider, DoneIcon, IconButton, Popover, Stack, Tooltip, Typography |
| [src/components/OnboardingChecklist.tsx:1](../../../job-tracker-ui/src/components/OnboardingChecklist.tsx#L1) | 127 | reachable | DashboardView.tsx | Box, Button, CheckCircleIcon, CloseIcon, IconButton, LinearProgress, Paper, RadioButtonUncheckedIcon, Stack, Typography |
| [src/components/ProFeatureNotice.tsx:1](../../../job-tracker-ui/src/components/ProFeatureNotice.tsx#L1) | 55 | reachable | AiSectionAssistant.tsx, CareerProfilePage.tsx, CvBuilderEditor.tsx | Alert, Button, CloseIcon, IconButton, Stack, Typography |
| [src/components/QuickCaptureCard.tsx:1](../../../job-tracker-ui/src/components/QuickCaptureCard.tsx#L1) | 70 | reachable | SettingsView.tsx | Box, Paper, TextField, Typography |
| [src/components/QuickCommandDialog.tsx:1](../../../job-tracker-ui/src/components/QuickCommandDialog.tsx#L1) | 159 | reachable | App.tsx | Box, Dialog, DialogContent, List, ListItemButton, ListItemText, SearchIcon, TextField, Typography |
| [src/components/RemindersView.tsx:1](../../../job-tracker-ui/src/components/RemindersView.tsx#L1) | 139 | reachable | App.tsx | Box, Button, Chip, Divider, Paper, ReminderSection, Typography, ViewStateNotice |
| [src/components/RichTextField.tsx:1](../../../job-tracker-ui/src/components/RichTextField.tsx#L1) | 79 | reachable | ApplicationAssets.tsx, CvBuilderEditor.tsx, CareerProfileSections.tsx | Box, FormatBoldIcon, FormatItalicIcon, FormatUnderlinedIcon, IconButton, LinkIcon, TextField, Tooltip |
| [src/components/RulesSettingsCard.tsx:1](../../../job-tracker-ui/src/components/RulesSettingsCard.tsx#L1) | 99 | reachable | SettingsView.tsx | Alert, Box, Button, Paper, TextField, Typography |
| [src/components/SavedViewsMenu.tsx:1](../../../job-tracker-ui/src/components/SavedViewsMenu.tsx#L1) | 183 | reachable | JobTable.tsx | BookmarkBorderIcon, Button, DeleteOutlineIcon, Divider, IconButton, ListItemText, Menu, MenuItem, TextField, Tooltip |
| [src/components/SessionsSettingsCard.tsx:1](../../../job-tracker-ui/src/components/SessionsSettingsCard.tsx#L1) | 148 | reachable | ProfilePage.tsx | Alert, Button, DeleteIcon, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, List, ListItem, ListItemSecondaryAction, ListItemText, Paper, Typography |
| [src/components/SettingsView.tsx:1](../../../job-tracker-ui/src/components/SettingsView.tsx#L1) | 244 | reachable | App.tsx | AiPrivacySettingsCard, AiUsageCard, Alert, BackupCard, Box, Button, Checkbox, FormControl, FormControlLabel, ImportExportJobs, InputLabel, MenuItem, Paper, QuickCaptureCard, RulesSettingsCard, SectionCard, Select, Skeleton, Tab, TabPanel, Tabs, Typography |
| [src/components/TagsInput.tsx:1](../../../job-tracker-ui/src/components/TagsInput.tsx#L1) | 37 | reachable | AddJobModal.tsx, EditJobDialog.tsx | Autocomplete, Chip, TextField |
| [src/components/TurnstileWidget.tsx:1](../../../job-tracker-ui/src/components/TurnstileWidget.tsx#L1) | 37 | reachable | LoginPage.tsx | Box, Typography |
| [src/components/TwoFactorChallenge.tsx:1](../../../job-tracker-ui/src/components/TwoFactorChallenge.tsx#L1) | 84 | reachable | GoogleAuthCard.tsx, MicrosoftAuthCard.tsx, LoginPage.tsx | Alert, Box, Button, Checkbox, FormControlLabel, TextField, Typography |
| [src/components/TwoFactorSettingsCard.tsx:1](../../../job-tracker-ui/src/components/TwoFactorSettingsCard.tsx#L1) | 391 | reachable | ProfilePage.tsx | Alert, Box, Button, Checkbox, DeleteIcon, Dialog, DialogActions, DialogContent, DialogTitle, Divider, FormControlLabel, IconButton, List, ListItem, ListItemSecondaryAction, ListItemText, Paper, TextField, Typography |
| [src/components/UserManagementCard.tsx:1](../../../job-tracker-ui/src/components/UserManagementCard.tsx#L1) | 184 | outside graph | — | Box, Button, Paper, TextField, Typography |
| [src/components/ViewStateNotice.tsx:1](../../../job-tracker-ui/src/components/ViewStateNotice.tsx#L1) | 51 | reachable | CompaniesTable.tsx, DashboardView.tsx, JobTable.tsx, KanbanBoard.tsx, RemindersView.tsx, AdminAuditPage.tsx | Alert, Box, Button, CircularProgress, Typography |
| [src/components/cv/AiSectionAssistant.tsx:1](../../../job-tracker-ui/src/components/cv/AiSectionAssistant.tsx#L1) | 113 | reachable | CvBuilderEditor.tsx | Alert, AutoFixHighIcon, Box, Button, MenuItem, Paper, ProFeatureNotice, Stack, TextField, Typography |
| [src/components/cv/CvCustomizeTab.tsx:1](../../../job-tracker-ui/src/components/cv/CvCustomizeTab.tsx#L1) | 103 | reachable | CvBuilderEditor.tsx | Box, Button, ControlSlider, CvTemplateGallery, Divider, FormControl, FormControlLabel, IconButton, InputLabel, MenuItem, Paper, Select, Slider, Stack, Switch, TextField, Typography |
| [src/confirm.tsx:1](../../../job-tracker-ui/src/confirm.tsx#L1) | 88 | reachable | App.tsx, InterviewPrep.tsx, dialogs.ts, ApplicationWorkspacePage.tsx, CorrespondenceInboxPage.tsx, CareerEvidenceBank.tsx | Alert, Button, ConfirmContext.Provider, Dialog, DialogActions, DialogContent, DialogTitle, Typography |
| [src/i18n/I18nProvider.tsx:1](../../../job-tracker-ui/src/i18n/I18nProvider.tsx#L1) | 67 | reachable | App.tsx, ClientApp.tsx, AddJobModal.tsx, AiPrivacySettingsCard.tsx, AiUsageCard.tsx, ApplicationAssets.tsx, ApplicationCalendarActions.tsx, ApplicationChecklist.tsx, ApplicationIntelligence.tsx, ApplicationWorkflowAssist.tsx, Attachments.tsx, AuthStatusCard.tsx, BackupCard.tsx, CompaniesTable.tsx, Correspondence.tsx, CropImageDialog.tsx, CvTemplateGallery.tsx, DashboardView.tsx, EditJobDialog.tsx, EmailProviderConnections.tsx, ErrorBoundary.tsx, GoogleAuthCard.tsx, ImportExportJobs.tsx, InterviewPrep.tsx, JobDetailsPanels.tsx, JobTable.tsx, KanbanBoard.tsx, MicrosoftAuthCard.tsx, NotificationsPopover.tsx, OnboardingChecklist.tsx, ProFeatureNotice.tsx, QuickCaptureCard.tsx, QuickCommandDialog.tsx, RemindersView.tsx, RichTextField.tsx, RulesSettingsCard.tsx, SavedViewsMenu.tsx, SessionsSettingsCard.tsx, SettingsView.tsx, TagsInput.tsx, TurnstileWidget.tsx, TwoFactorChallenge.tsx, TwoFactorSettingsCard.tsx, UserManagementCard.tsx, ViewStateNotice.tsx, AiSectionAssistant.tsx, CvCustomizeTab.tsx, confirm.tsx, AppShell.tsx, prompt.tsx, AdminAuditPage.tsx, AdminSystemPage.tsx, AdminUsersPage.tsx, ApplicationWorkspacePage.tsx, CareerProfilePage.tsx, ConnectedAccountsPage.tsx, CorrespondenceInboxPage.tsx, CvBuilderEditor.tsx, CvBuilderPage.tsx, ForgotPasswordPage.tsx, GmailReviewPage.tsx, JobDiscoveryPage.tsx, LandingPage.tsx, LoginPage.tsx, MicrosoftLegacyRelinkPage.tsx, NotFoundPage.tsx, OfferComparisonPage.tsx, OperationsPage.tsx, ProfilePage.tsx, ResetPasswordPage.tsx, RouteErrorPage.tsx, VerifyEmailPage.tsx, CareerEvidenceBank.tsx, CareerProfileSections.tsx, CareerWorkspaceOverview.tsx, ProfileCompleteness.tsx | I18nContext.Provider |
| [src/layout/AppShell.tsx:1](../../../job-tracker-ui/src/layout/AppShell.tsx#L1) | 578 | reachable | App.tsx, LandingPage.tsx | AppBar, Avatar, Badge, Box, Breadcrumbs, Button, ButtonGroup, Chip, Divider, Drawer, IconButton, JobbjaktMark, List, ListItem, ListItemButton, ListItemIcon, ListItemText, Menu, MenuIcon, MenuItem, MenuOpenIcon, NotificationsNoneIcon, SettingsOutlinedIcon, StackLanguageToggle, Toolbar, Tooltip, Typography |
| [src/prompt.tsx:1](../../../job-tracker-ui/src/prompt.tsx#L1) | 84 | reachable | App.tsx, BackupCard.tsx, dialogs.ts | Button, Dialog, DialogActions, DialogContent, DialogTitle, PromptContext.Provider, TextField, Typography |
| [src/toast.tsx:1](../../../job-tracker-ui/src/toast.tsx#L1) | 84 | reachable | App.tsx, AddJobModal.tsx, AiPrivacySettingsCard.tsx, ApplicationWorkflowAssist.tsx, Attachments.tsx, AuthStatusCard.tsx, BackupCard.tsx, CompaniesTable.tsx, Correspondence.tsx, EditJobDialog.tsx, EmailProviderConnections.tsx, GoogleAuthCard.tsx, ImportExportJobs.tsx, JobTable.tsx, MicrosoftAuthCard.tsx, QuickCaptureCard.tsx, RemindersView.tsx, RulesSettingsCard.tsx, SessionsSettingsCard.tsx, SettingsView.tsx, TwoFactorSettingsCard.tsx, UserManagementCard.tsx, AiSectionAssistant.tsx, AdminAuditPage.tsx, AdminUsersPage.tsx, CareerProfilePage.tsx, CorrespondenceInboxPage.tsx, CvBuilderEditor.tsx, CvBuilderPage.tsx, ForgotPasswordPage.tsx, GmailReviewPage.tsx, LoginPage.tsx, ProfilePage.tsx, ResetPasswordPage.tsx | Alert, Button, Snackbar, ToastContext.Provider |
| [src/views/AdminAuditPage.tsx:1](../../../job-tracker-ui/src/views/AdminAuditPage.tsx#L1) | 184 | reachable | App.tsx | Box, Button, Chip, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Typography, ViewStateNotice |
| [src/views/AdminSystemPage.tsx:1](../../../job-tracker-ui/src/views/AdminSystemPage.tsx#L1) | 676 | reachable | App.tsx | Alert, Box, Button, Checkbox, Chip, DetailRow, FormControlLabel, Paper, Stack, SummaryCard, Tab, Tabs, TextField, Typography |
| [src/views/AdminUsersPage.tsx:1](../../../job-tracker-ui/src/views/AdminUsersPage.tsx#L1) | 308 | reachable | App.tsx | Alert, Box, Button, Checkbox, Chip, DataGrid, FormControlLabel, Paper, Stack, TextField, Tooltip, Typography |
| [src/views/ApplicationWorkspacePage.tsx:1](../../../job-tracker-ui/src/views/ApplicationWorkspacePage.tsx#L1) | 491 | reachable | App.tsx | Accordion, AccordionDetails, AccordionSummary, Alert, ApplicationAnalysis, ApplicationCalendarActions, ApplicationChecklist, ApplicationCoverLetterSection, ApplicationCvSection, ApplicationInterviewPrep, ApplicationMatch, ApplicationPackageDraftsSection, ApplicationProgress, ApplicationStatusSuggestion, ApplicationStrategySnapshot, ApplicationTimeline, ApplicationWorkspace, ArrowBackIcon, ArrowForwardIcon, Attachments, AutoFixHighIcon, Box, Button, ChecklistIcon, Chip, Correspondence, DescriptionOutlinedIcon, Divider, EditJobDialog, EditOutlinedIcon, ExpandMoreIcon, FolderOutlinedIcon, IconButton, JobDetailsSection, MailOutlineIcon, OpenInNewIcon, OverviewDetails, OverviewSection, Paper, Skeleton, Stack, Tab, Tabs, Tooltip, Typography, WorkspaceHeader |
| [src/views/CareerProfilePage.tsx:1](../../../job-tracker-ui/src/views/CareerProfilePage.tsx#L1) | 879 | reachable | CareerWorkspacePage.tsx | Accordion, AccordionDetails, AccordionSummary, Alert, Avatar, Box, Button, CareerEvidenceBank, CareerWorkspaceOverview, Checkbox, Chip, CropImageDialog, DeleteOutlineIcon, EducationSection, ExpandMoreIcon, FormControl, FormControlLabel, InputLabel, InterestsSection, LanguagesSection, LinearProgress, LongTailSections, MenuItem, OtherSectionsSection, Paper, PersonalInformationSection, PhotoCameraOutlinedIcon, ProFeatureNotice, ProfessionalSummarySection, ProfileCompleteness, Select, SkillsSection, Tab, Tabs, TextField, Typography, UploadFileOutlinedIcon, WorkExperienceSection |
| [src/views/CareerWorkspacePage.tsx:1](../../../job-tracker-ui/src/views/CareerWorkspacePage.tsx#L1) | 8 | reachable | App.tsx | CareerProfilePage |
| [src/views/ConnectedAccountsPage.tsx:1](../../../job-tracker-ui/src/views/ConnectedAccountsPage.tsx#L1) | 26 | reachable | App.tsx | Box, Button, EmailProviderConnections, Paper, Typography |
| [src/views/CorrespondenceInboxPage.tsx:1](../../../job-tracker-ui/src/views/CorrespondenceInboxPage.tsx#L1) | 750 | reachable | App.tsx | Alert, Autocomplete, Box, Button, Chip, CircularProgress, FormControl, GmailReviewPage, InputLabel, MailOutlineIcon, MenuItem, Pagination, Paper, Select, Stack, TextField, Typography |
| [src/views/CvBuilderEditor.tsx:1](../../../job-tracker-ui/src/views/CvBuilderEditor.tsx#L1) | 1131 | reachable | App.tsx | AddContentCard, AddIcon, AiSectionAssistant, Alert, ArrowBackIcon, ArrowDownwardIcon, ArrowUpwardIcon, AutoFixHighIcon, Box, Button, Chip, Collapse, ContentCopyIcon, ContentTab, CvCustomizeTab, DeleteOutlineIcon, Dialog, DialogActions, DialogContent, DialogTitle, Divider, DocumentAiTab, DragIndicatorIcon, EditorSkeleton, EntryEditor, ExpandMoreIcon, HistoryTab, IconButton, MenuItem, Paper, PictureAsPdfIcon, ProFeatureNotice, PublicIcon, RedoIcon, RichTextField, SaveBadge, SectionRow, Skeleton, SpellcheckIcon, Stack, Tab, Tabs, TextField, Tooltip, TranslateIcon, Typography, UndoIcon, VisibilityIcon, VisibilityOffIcon |
| [src/views/CvBuilderPage.tsx:1](../../../job-tracker-ui/src/views/CvBuilderPage.tsx#L1) | 203 | reachable | App.tsx | AddIcon, Alert, Box, Button, Chip, CvTemplateGallery, CvTemplateThumbnail, DescriptionOutlinedIcon, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Menu, MenuItem, MoreVertIcon, Paper, PublicIcon, Stack, TextField, Typography |
| [src/views/ForgotPasswordPage.tsx:1](../../../job-tracker-ui/src/views/ForgotPasswordPage.tsx#L1) | 101 | reachable | App.tsx | Alert, Box, Button, Paper, TextField, Typography |
| [src/views/GmailReviewPage.tsx:1](../../../job-tracker-ui/src/views/GmailReviewPage.tsx#L1) | 290 | reachable | CorrespondenceInboxPage.tsx | Box, Button, Chip, CircularProgress, Paper, Stack, TextField, Typography |
| [src/views/JobDiscoveryPage.tsx:1](../../../job-tracker-ui/src/views/JobDiscoveryPage.tsx#L1) | 220 | reachable | App.tsx | AddIcon, Alert, BookmarkAddOutlinedIcon, Box, Button, Card, CardActions, CardContent, Chip, CircularProgress, DeleteOutlineIcon, FormControlLabel, MenuItem, RefreshIcon, SearchIcon, Stack, Switch, TextField, Typography |
| [src/views/LandingPage.tsx:1](../../../job-tracker-ui/src/views/LandingPage.tsx#L1) | 282 | reachable | App.tsx | AlarmIcon, AttachIcon, Box, Button, Container, DashboardIcon, GradientButton, InsightsIcon, MailIcon, MatchIcon, Stack, StackLanguageToggle, Typography |
| [src/views/LoginPage.tsx:1](../../../job-tracker-ui/src/views/LoginPage.tsx#L1) | 279 | reachable | App.tsx | Alert, Box, Button, Checkbox, Divider, FormControlLabel, GoogleAuthCard, MicrosoftAuthCard, Paper, TextField, TurnstileWidget, TwoFactorChallenge, Typography |
| [src/views/MicrosoftLegacyRelinkPage.tsx:1](../../../job-tracker-ui/src/views/MicrosoftLegacyRelinkPage.tsx#L1) | 67 | reachable | App.tsx | Alert, Box, Button, CircularProgress, Paper, Typography |
| [src/views/NotFoundPage.tsx:1](../../../job-tracker-ui/src/views/NotFoundPage.tsx#L1) | 41 | reachable | App.tsx | Box, Button, Paper, Typography |
| [src/views/OfferComparisonPage.tsx:1](../../../job-tracker-ui/src/views/OfferComparisonPage.tsx#L1) | 67 | reachable | App.tsx | Alert, Box, Button, Chip, Fact, Paper, Skeleton, Stack, Typography |
| [src/views/OperationsPage.tsx:1](../../../job-tracker-ui/src/views/OperationsPage.tsx#L1) | 148 | reachable | App.tsx | Alert, Box, Button, Chip, LinearProgress, Paper, Stack, Typography |
| [src/views/ProfilePage.tsx:1](../../../job-tracker-ui/src/views/ProfilePage.tsx#L1) | 373 | reachable | App.tsx | Alert, AuthStatusCard, Avatar, Box, Button, Chip, CropImageDialog, DeleteOutlineIcon, Divider, GoogleAuthCard, MicrosoftAuthCard, Paper, PhotoCameraOutlinedIcon, SessionsSettingsCard, TextField, TwoFactorSettingsCard, Typography |
| [src/views/PublicCvPage.tsx:1](../../../job-tracker-ui/src/views/PublicCvPage.tsx#L1) | 87 | reachable | App.tsx | |
| [src/views/ResetPasswordPage.tsx:1](../../../job-tracker-ui/src/views/ResetPasswordPage.tsx#L1) | 115 | reachable | App.tsx | Alert, Box, Button, Paper, TextField, Typography |
| [src/views/RouteErrorPage.tsx:1](../../../job-tracker-ui/src/views/RouteErrorPage.tsx#L1) | 53 | reachable | App.tsx | Box, Button, Paper, Typography |
| [src/views/VerifyEmailPage.tsx:1](../../../job-tracker-ui/src/views/VerifyEmailPage.tsx#L1) | 77 | reachable | App.tsx | Alert, Box, Button, CircularProgress, Paper, Typography |
| [src/views/career/CareerEvidenceBank.tsx:1](../../../job-tracker-ui/src/views/career/CareerEvidenceBank.tsx#L1) | 39 | reachable | CareerProfilePage.tsx | Alert, Box, Button, Chip, DeleteOutlineIcon, MenuItem, Paper, Stack, TextField, Typography |
| [src/views/career/CareerProfileSections.tsx:1](../../../job-tracker-ui/src/views/career/CareerProfileSections.tsx#L1) | 252 | reachable | CareerProfilePage.tsx | AddIcon, Box, Button, Chip, DeleteOutlineIcon, FieldReviewNote, IconButton, LinesField, RichTextField, Stack, TextField, Typography |
| [src/views/career/CareerWorkspaceOverview.tsx:1](../../../job-tracker-ui/src/views/career/CareerWorkspaceOverview.tsx#L1) | 178 | reachable | CareerProfilePage.tsx | ActionCard, Alert, Box, Button, Chip, DescriptionOutlinedIcon, LinearProgress, Paper, PersonOutlineIcon, Skeleton, Stack, Typography, UploadFileOutlinedIcon, WorkOutlineIcon |
| [src/views/career/ProfileCompleteness.tsx:1](../../../job-tracker-ui/src/views/career/ProfileCompleteness.tsx#L1) | 91 | reachable | CareerProfilePage.tsx | Accordion, AccordionDetails, AccordionSummary, Box, Button, Chip, ExpandMoreIcon, LinearProgress, Typography |
@@ -0,0 +1,98 @@
# Protected functionality ledger
This is the current source-backed preservation baseline. **All rows are Preserve** until a later approved migration explicitly records relocation, merger or deprecation. Target-only ideas are separated at the end. A component's existence proves implemented behavior, not live provider availability or usability quality. The [API census](API_CALL_SITES.md) and [component census](COMPONENT_INVENTORY.md) supply the individual call sites/consumers behind these groups.
## Entry, navigation and account
| ID | Current user-facing function | Source / important contract |
|---|---|---|
| E01 | Public product explanation, Free/Pro feature comparison, honest unavailable-billing states and sign-in/register links | `LandingPage`, `planCatalog`; do not invent prices or purchasable capabilities |
| E02 | Local sign-in/registration, remember-me, configured Turnstile, resend verification, reset password, verify email | `LoginPage`, reset/verification views, `TurnstileWidget`; server configuration controls availability |
| E03 | Google/Microsoft sign-in/link flows, Microsoft legacy relink, provider popup success/error handling | `GoogleAuthCard`, `MicrosoftAuthCard`, `MicrosoftLegacyRelinkPage`; OAuth/state/origin rules remain |
| E04 | 2FA challenge, recovery codes, setup/verify/disable/regenerate, trusted devices and revocation | `TwoFactorChallenge`, `TwoFactorSettingsCard`; preserve sensitive confirmation and recovery presentation |
| E05 | Active session list, current-device distinction, single/other-session revocation, logout | `SessionsSettingsCard`, `AppShell`, `auth`, `sessionBoundary`; invalidation must clear private UI |
| E06 | Avatar upload/remove, name/display name/headline, account email-change request/cancel/confirm, local password change | `ProfilePage`; account identity is distinct from canonical career data |
| E07 | Collapsible desktop sidebar, mobile drawer, active subsection matching, keyboard command launcher | `AppShell`, `QuickCommandDialog`; job/company search and fixed navigation/add commands |
| E08 | Theme light/dark/system, EN/Bokmål preference with server hydration, toast/confirm/prompt and error routes | `themePrefs`, `I18nProvider`, `toast`, `confirm`, `prompt`, route error/not-found views |
| E09 | Cross-tab account switch, stale mutation/read rejection, BFCache/focus revalidation and reauthentication | `api`, `sessionBoundary`, `App`; B02 server precondition and client unmount/abort must survive extraction |
## Discover and manage jobs
| ID | Current user-facing function | Source / important contract |
|---|---|---|
| J01 | Search NAV listings by role/company/municipality, sorting, source/freshness/deadline/work-arrangement details, external listing links | `JobDiscoveryPage`; provider failures and empty results distinguishable |
| J02 | Named saved searches, run/delete, automatic alert preference, new/updated results and dismissal | `JobDiscoveryPage`, saved-search APIs; retain owner scope and alert metadata |
| J03 | Add job manually or from URL/pasted listing, reviewed preview, company lookup/create, tags and dates, duplicate warning | `AddJobModal`; preview is not a write; keep B01 outbound boundary and existing review step |
| J04 | Capture via browser extension, bookmarklet and share/capture query; optional job attachment and tailored CV draft after create | `QuickCaptureCard`, `captureUrl`, `App`, `browser-extension`; preserve payload/URL contracts |
| J05 | Job table search/filter/sort/pagination, visible columns/page size, saved named views, row/card actions | `JobTable`, `SavedViewsMenu`; mobile cards and accessible full-workspace entry already exist |
| J06 | Selection/bulk status/delete/restore, soft-delete/trash and restore, edit job/company association | `JobTable`, `EditJobDialog`; preserve partial-error handling and confirmation semantics |
| J07 | Kanban grouped status views, drag move, keyboard pickup/drop/cancel, direct status selection, job opening | `KanbanBoard`, `pipeline`; same records as table, not a second job model |
| J08 | Company directory, recruiter/contact/source/location and pipeline/contact-date editing; company relationship job history | `CompaniesTable`; company creation is integrated with job/import flows, not assumed standalone CRUD |
| J09 | Offer comparison including recorded compensation, decision deadline and notes, source-job links | `OfferComparisonPage`; no new compensation calculator implied |
| J10 | JSON/CSV job export; JSON import; CSV-to-import-JSON conversion and import counts | `ImportExportJobs`; preserve B05 blob bytes/BOM, spreadsheet safety and typed formats; do not claim full account restore from job import |
## Job workspace and application artifacts
| ID | Current user-facing function | Source / important contract |
|---|---|---|
| W01 | Dedicated job workspace and reusable quick overlay; overview/analysis/CV/cover-letter/interview sections; old deep-link mapping | `ApplicationWorkspacePage`, `ApplicationWorkspace`, `jobWorkspaceRoute`; retain full-page/overlay parity |
| W02 | Job detail/status/progression, next actions, dates, description, recruiter/contact and timeline | `JobDetailsSection`, `ApplicationProgress`, `ApplicationTimeline`; do not redefine pipeline enums or history |
| W03 | Analysis, profile match/gaps, strategy snapshot, workflow assistance and status suggestions | `ApplicationAnalysis`, `ApplicationMatch`, `ApplicationStatusSuggestion`, `ApplicationStrategySnapshot`; show provenance/loading/failure and confirmation |
| W04 | Checklist create/edit/complete/delete/order, progress and recommended next action | `ApplicationChecklist`; keep keyboard reorder and persisted item identity |
| W05 | Select/attach a CV, create/tailor document variants, review tailoring guidance and selected-source context | `ApplicationCvSection`, `ApplicationTailoringSection`, `applicationWorkspace`; owner+job association enforced by API |
| W06 | Cover-letter editing, AI suggestion review/reject/apply, saved versions and restore, unsaved navigation protection | `ApplicationAssets`, `CoverLetterAiAssistant`; document override must not mutate master profile |
| W07 | Application draft fields, submission/package preparation, frozen submitted-package versions and archived attachment download | `ApplicationAssets`, `SubmittedPackagesSection`, `applicationWorkspace`; historical package is distinct from current draft |
| W08 | Attachments upload/drag-drop, category/purpose, rename, AI-use flag, preview/download/delete | `Attachments`; owner-scoped binary retrieval, consent selection and size/error handling |
| W09 | Interview questions/categories, manual items, answers, ready status, remove, contextual AI review/add-to-prep | `InterviewPrep`, `applicationWorkspace`; generated facts/answers require review |
| W10 | Interview debrief template and follow-up content/date, readiness and next-action state | `InterviewPrep`; neutral prompts must not seed invented company/achievement facts |
| W11 | Follow-up/reminder workflow, rule-driven dates/stages, notifications, deadline/follow-up ICS and Google/Outlook calendar event actions | `RemindersView`, `RulesSettingsCard`, `ApplicationCalendarActions`; calendar integration already exists, date-only/timestamp semantics must survive |
| W12 | Async operation progress, pending/failed/retry/cancel states and associated notifications | `OperationsPage`, profile processing components; preserve operation IDs and server state, avoid duplicate starts on rerender |
## Career Profile and CVs
| ID | Current user-facing function | Source / important contract |
|---|---|---|
| C01 | Canonical structured career profile: personal details, summary, skills, work, education, languages, interests and long-tail/custom sections | `CareerProfilePage`, `views/career/*`; profile save is an account singleton, CV is an identified derived resource |
| C02 | Profile overview, completeness/import guidance, manual edit, copy raw CV text, avatar and version history/restore | `CareerWorkspacePage`, `CareerProfilePage`; preserve projection/history behavior without redesigning schema |
| C03 | CV/file upload and extraction, rebuild/improve/reprocess, progress/history, diff, explicit low-confidence selection, accept/discard, retry/cancel | `CareerProfilePage`, `/profile-cv/*`; uploaded proposal is not silently canonical truth |
| C04 | Evidence bank: sourced statement/title/category/tags, add/list/delete and truthfulness guidance | `CareerEvidenceBank`; evidence belongs to profile owner and is not AI-invented experience |
| C05 | CV library create/name/copy/delete, template gallery and real sample thumbnails, publish/unpublish/share and PDF download | `CvBuilderPage`, `cvBuilder`; separate public slug from numeric private ID |
| C06 | Studio Template/Content/Customize/AI Tools/History navigation; debounced preview and save state | `CvBuilderEditor`; existing mobile edit/preview and desktop split must retain parity |
| C07 | Built-in item visibility/order, custom sections, preset/free-text section catalog, item/content overrides, hide/remove, keyboard reorder | `CvBuilderEditor`, `components/cv/*`; selected profile source and overrides remain distinguishable |
| C08 | Template-capability-aware typography/colors/header/headings, skills presentation/groups, one/two-column and sidebar settings, photo/icons | `CvCustomizeTab`, theme registry; retain unsupported-setting handling and server render equivalence |
| C09 | A4/Letter, density, margins/spacing, date format, document language, per-section rows/grid/compact/bubbles and columns | `cvBuilder`, `CvCustomizeTab`, content controls; do not drop advanced controls merely to simplify layout |
| C10 | Undo/redo of editor settings, save queue, unsaved guard, history/version restore and preview lifecycle | `CvBuilderEditor`; current queue serializes one mounted editor only, not concurrent browsers |
| C11 | Per-section AI improve/translate/custom instruction and whole-document translate/improve/spelling review | `AiSectionAssistant`, builder AI tab; source/target language, current/suggestion comparison, apply/reject |
| C12 | Authenticated PDF export and anonymous published-CV preview/PDF; long searchable multipage documents | `PublicCvPage`, `cvBuilder`, server renderer; B03 shared resource admission and public ownership/publication checks |
## Correspondence and external accounts
| ID | Current user-facing function | Source / important contract |
|---|---|---|
| M01 | Job-scoped manual note/email log, search, delete, paste/import message; current job/company context | `Correspondence`; manual record is different from sending a real email |
| M02 | Gmail candidate search/import, linked-thread refresh/sync history, import thread, unlink/relink/move with job selection | `Correspondence`; cross-job relationship changes remain owner-bound |
| M03 | Global correspondence inbox with pagination/search/filter/direction/provider/link state, full message and attachment information, source-job links | `CorrespondenceInboxPage`; provider read failure distinct from no messages |
| M04 | Compose/reply, choose connected provider and job/recipient, save/resume/delete drafts, review/confirm send, delivery states and explicit new attempt | `CorrespondenceInboxPage`; persisted draft revision and send idempotency/uncertain delivery controls must survive navigation changes |
| M05 | Gmail review candidates, proposed jobs, link/reject/keep decisions, notes, manual sync and create suggested job | `GmailReviewPage` embedded in inbox; retain legacy review redirect |
| M06 | Gmail/Google and Microsoft Graph connection/status/disconnect, IMAP connection/status/disconnect | `EmailProviderConnections`, `ConnectedAccountsPage`; login identity and mail-provider identity are separate capabilities |
## Dashboard, settings and administration
| ID | Current user-facing function | Source / important contract |
|---|---|---|
| S01 | Personal dashboard counts, activity/funnel/company/skill trends, stage/salary insights and actionable next steps | `DashboardView`, analytics APIs; chart transformations and empty/error states preserved |
| S02 | Five per-owner local visibility preferences; onboarding progress and dismiss; notification bell/unread/read/dismiss | `DashboardView`, `OnboardingChecklist`, `NotificationsPopover`; no server widget-order/resize contract exists yet |
| S03 | Follow-up/ghosting rule settings, email reminder preference, table preferences, theme/language and connected-account links | `SettingsView`, `RulesSettingsCard`; preferences have different scopes, do not replace with one unsafely shared object |
| S04 | AI privacy settings, usage/limits, honest Free/Pro lock states, billing status, conditional checkout and portal | `AiPrivacySettingsCard`, `AiUsageCard`, `AccountPlanProvider`; server entitlement authoritative, not client context defaults |
| S05 | Account export, encrypted backup download, lifecycle status and deliberate deletion confirmation | `BackupCard`; recent-auth/password/provider restrictions remain; a downloadable backup is not proven restore readiness |
| A01 | Admin user list/create, role promotion/demotion guards, reset link and delete with last-admin/self warnings | `AdminUsersPage`, `/users`; API roles enforce privilege regardless of navigation |
| A02 | Admin audit event list/detail, supported undo and job restore | `AdminAuditPage`; preserve event/ownership semantics rather than generic mutation buttons |
| A03 | Separate system health/build/database/AI/email status, SMTP settings/test, AI probe, CV corpus benchmark and maintenance run controls | `AdminSystemPage`; sensitive config values/logs must not move into personal dashboard |
## Target brief items that are not current features
The target grouped navigation would reorganize an existing collapsible sidebar. Jobs/Table and Kanban can become view choices over the existing APIs. Dedicated Analytics/Documents/Notifications destinations would relocate embedded capabilities. They are not permission to delete offers, reminders, correspondence review, operations or legacy URLs.
Dashboard drag/order/resize/reset and cross-device persistence are new work beyond the five local booleans. A general assistant/chat, goals system, new brand/name and additional email/calendar providers are not implied by existing contextual AI or integrations. Retain implemented Google/Outlook calendar actions even though the product brief describes broader calendar ambitions as future work.
During migration, extend this table with destination, regression test and review evidence per ID. Do not treat a screen screenshot or a count of passing tests as proof that all rows survived.
+92
View File
@@ -0,0 +1,92 @@
# Phase 1 — Frontend audit
Date: 2026-09-09. Source checkpoint: `97fce89c002fe86e737ca7387170321d464b80d7` (application changes through `0954876`; subsequent commits contain the brief and CI prerequisite corrections). Audit branch: `codex/ui-redesign-audit`. Test-only packaging correction `23cc250` leaves the frontend census unchanged; its fresh 22 PDF and 915 broader backend passes are recorded in the test assessment.
**Phase 1 source audit complete; redesign implementation has not started.** The repository already implements much of the proposed workflow. Retain its MUI/React foundation and domain contracts, improve shared semantics, then migrate representative screens in small steps. A replacement frontend framework or component library is not justified by the observed problems.
This is a source and regression-evidence audit, not a new visual usability study, production certification, or execution of security ticket B07. The existing security queue still governs unresolved integrity/recovery work. F04 remains open. A pushed revision is not proof of a successful deployment; see [release evidence](../../audits/2026-09-07/validation/b06-completion.md#authorized-release-attempt-and-ci-prerequisite-correction).
## Deliverables and method
| Handoff requirement | Evidence |
|---|---|
| Architecture, styling, state | This document |
| Every declared route/page | [Route map](ROUTE_MAP.md): 31 concrete route patterns, including two redirect aliases; 29 page patterns |
| Existing user functionality | [Preservation ledger](FUNCTIONALITY_INVENTORY.md), including nested screens and non-navigation entry points |
| Components | [All production TSX modules](COMPONENT_INVENTORY.md), shared responsibility map below |
| Tests and gaps | [Test assessment](TEST_INVENTORY.md), [test-file census](TEST_FILES.md) |
| API integration | [Contract map](API_AND_IDENTITY.md), [266 call expressions](API_CALL_SITES.md) |
| Auth, authorization, storage | [Identity and storage boundaries](API_AND_IDENTITY.md) |
| Localisation, mobile, accessibility | Assessment below and [regression risks](RISKS_AND_MIGRATION.md) |
| Migration and decisions | [Proposed sequence and gates](RISKS_AND_MIGRATION.md) |
Read the ten documents required by [ASTRA_HANDOFF](../ASTRA_HANDOFF.md), then traced route elements, their local import graph, event handlers, API wrappers, server controllers/services, security middleware, test configuration and existing validation evidence. The [machine-readable census](source-inventory.json) records 120 production TS/TSX files under `src`/`app`, 76 frontend test files, 266 direct shared-client call expressions, and 34 route declarations. Declarations include a duplicated root and two wildcard routing boundaries; they are not 34 pages. File and expression counts are inventory aids, not coverage percentages.
Regenerate source tables from the repository root after installing the locked frontend dependencies:
```sh
node docs/redesign/audit/generate-inventory.cjs
```
The generator reads tracked source through the installed TypeScript AST. It does not execute application code. API paths supplied through variables are retained as expressions; resolve them with the contract map. CSS, static assets, OAuth SDK traffic and browser-extension entry points require the accompanying manual inspection. Runtime behavior is marked as prior evidence or unverified where this pass did not execute it.
## Architecture and technology
The application is a client-rendered React SPA packaged by Next, not a server-rendered Next route application. [Next configuration](../../../job-tracker-ui/next.config.js) exports static production assets and rewrites development deep links to the root. `app/page.tsx` and `app/[[...slug]]/ClientShell.tsx` load `ClientApp` with SSR disabled; `App.tsx` owns React Router. Nginx supplies the production SPA fallback and `/api` proxy. Preserve direct URL entry, refresh, history navigation and static deployment together.
| Concern | Current implementation | Redesign implication |
|---|---|---|
| Framework | Next 16, React 19, TypeScript strict; exact installed versions in lockfile | Keep build/output model unless a measured requirement needs a change |
| Navigation | React Router 7, outer public routes plus authenticated shell's inner `Routes`, lazy feature imports | Consolidate navigation metadata deliberately; do not accidentally introduce a second active route authority |
| UI | MUI 7, MUI X Data Grid/Date Pickers, Emotion, MUI icons; TanStack **Table**, not Query | Shared tokens and component composition can implement the brief without a library migration |
| Styling | [theme.ts](../../../job-tracker-ui/src/theme.ts), global CSS, MUI overrides, extensive inline `sx`, page-local styling | Theme exists, but duplicated shell/page color and surface choices weaken consistency |
| Typography | Archivo, loaded by app layout; theme typography variants | Preserve fallbacks and loading behavior; font self-hosting is a separate deployment/privacy choice |
| Data transport | One Axios instance in [api.ts](../../../job-tracker-ui/src/api.ts), thin typed domain wrappers and direct page calls | Keep the B02 interceptors and blob download behavior when extracting components |
| State | Local React state/effects; auth, account plan, theme, i18n, toast, prompt and confirm contexts | No Redux, Zustand or React Query store to replace; introduce a cache only for a demonstrated need |
| Async UI | `useViewResource`, resource-specific effects, operation polling, custom refresh events, component-local workspace tab cache | Preserve request sequencing, loading/error/refresh distinction and identity invalidation |
| Forms | Controlled MUI fields; many page-local draft states | Retain dirty guards and validation while extracting forms; do not add persistent private drafts implicitly |
| Documents | Canonical Career Profile, persisted CV settings/overrides, server HTML/PDF renderer, iframe preview | The editor is a domain application, not merely a form to restyle |
| Charts | Dashboard custom SVG/chart presentation | Preserve data meaning and add accessible alternatives where needed; no automatic chart-library replacement |
Dependencies and scripts: [package.json](../../../job-tracker-ui/package.json). Rendering entry and route wiring: [App.tsx](../../../job-tracker-ui/src/App.tsx). No frontend Next API route/server-action backend was found in the audited entry graph; application APIs live in .NET.
## Shared component responsibilities
| Existing foundation | Responsibility to retain / improve |
|---|---|
| `layout/AppShell` navigation model, `QuickCommandDialog` | Collapse/drawer navigation, active-route matching, capture actions, notifications, command search, logout and identity display |
| `theme`, `themePrefs`, `themeBootstrap`, global CSS | Light/dark/system preference, initial paint, semantic colors, spacing and responsive surfaces |
| `ViewStateNotice`, `useViewResource`, toast/confirm/prompt | Loaded, empty, failure, retry and confirmation behavior; give them consistent focus and announcement contracts |
| `RichTextField`, `TagsInput`, date controls | Plain text/markdown storage and form naming; avoid introducing HTML editing semantics during visual work |
| `ApplicationWorkspace`, `ApplicationAssets`, `jobWorkspaceRoute` | Full-page and overlay entry, section/deep-link aliases, derived artifacts and unsaved navigation |
| `components/cv/*`, `CvTemplateGallery`, `CvTemplateThumbnail`, `cvBuilder` | Capability-aware design settings, content editing, sample rendering, ordering and public/export contracts |
| `AiSectionAssistant`, cover-letter AI, interview AI, `aiWorkspace` | Context selection, entitlement states, current/suggested review, explicit acceptance and provenance |
| Account security/settings cards | OAuth links, mail connections, 2FA, sessions, exports, deletion and billing capabilities |
The complete component table includes four production modules outside the current ClientApp import graph: `Attachment`, `JobFlowBar`, `Markdown`, `UserManagementCard`. These are cleanup candidates only after checking non-app consumers and preservation coverage. App entry modules are naturally outside that graph. **Nothing is approved for deletion in Phase 1.**
## Localisation
[I18nProvider](../../../job-tracker-ui/src/i18n/I18nProvider.tsx) uses a typed EN/Bokmål dictionary, string interpolation, English fallback and `uiLanguage` local preference. Default is English unless a stored Norwegian code is present; authenticated `/auth/me` hydration restores the server preference. Changes PUT `/auth/preferences/language`; the document language becomes `en` or `nb-NO`. UI language and CV/AI document language are distinct controls and must remain so.
Most screen text is translated. There are real consistency gaps, for example the mobile job-card accessible name is hardcoded English at [JobTable:661](../../../job-tracker-ui/src/components/JobTable.tsx#L661). API errors and user-generated content are not automatically translated. Reusing translated labels, date/status formatters and long-string layouts should precede per-page copy changes. Browser accessibility tests currently force English; they do not prove Bokmål fit, pronunciation, errors or document formatting. Existing data and language preferences do not require Connor to decide a new default during this audit.
## Responsive behavior and accessibility
The code already adapts several workflows. `AppShell` changes to a drawer below 768 px; desktop sidebar has expanded/collapsed states. `JobTable` uses mobile cards and a separate filter arrangement. Kanban permits narrow-screen horizontal scrolling, keyboard pick-up/drop and a live region. Settings switch from tabs to a labelled select on small screens. The CV editor uses edit/preview panes below 900 px rather than shrinking the desktop split. These are preservation requirements, not missing features.
Responsiveness remains locally defined through mixed media queries and MUI breakpoints. Drawer/dialog nesting, long job titles, tables, email threads and document preview require a common layout contract plus real mobile testing. No new screenshot study or screen-reader session was performed in this Phase 1 pass.
The prior [validated accessibility evidence](../../audits/2026-09-07/validation/README.md#accessibility-conclusions) is **F14**, not draft-recovery F09. It measured shared contrast failures and a preview scroll-region focus failure after a viewport transition. Those are not evidence that every custom control is inaccessible. Current builder rich-text call sites supply labels and Kanban has keyboard support. `RichTextField` still permits unnamed usages in its optional props, and some Customize select patterns need an explicit accessible-name check. These are targeted verification points, not newly reproduced violations.
The automated axe suite samples eight routes and largely waits for `body`/`main`. It can miss loaded content, expanded editors, dialogs and errors. Before migration approval, use populated states, EN/NB, both themes, desktop/mobile; manually test keyboard and NVDA/Narrator, focus restoration, reauthentication, 200%/400% zoom, 320 CSS-pixel reflow, text spacing, forced colors, reduced motion and touch alternatives. Fix shared contrast semantics and the actual preview focus boundary before duplicating new page layouts.
## Principal conclusions
1. Preserve the working domain model and security boundaries; new page organization must not redefine ownership, CV persistence, AI acceptance or export formats.
2. The full job workspace, canonical Career Profile, contextual AI review, CV history and adaptive mobile surfaces already exist. The redesign should improve coherence and discoverability.
3. Shared visual semantics and loaded-state accessibility coverage are weaker than the broad test count suggests. Fix foundations before whole-page migration.
4. Five local dashboard visibility switches are not the proposed configurable dashboard. Ordering, resizing and cross-device persistence are future scope requiring a bounded contract.
5. The known standalone TypeScript failure reproduces. The source baseline is documented, but release/production and unresolved integrity gates must not be called green by implication.
Next work is **Phase 2 — Functional baseline**, subject to the gates in [RISKS_AND_MIGRATION](RISKS_AND_MIGRATION.md). No Phase 2 code, B07, or redesign component changes were made here.
@@ -0,0 +1,73 @@
# Risks and proposed migration approach
This report proposes the next steps; it does not authorize or implement Phase 2, B07 or a backend overhaul. Original security findings keep their IDs and queue ownership. [Validated implementation queue](../../audits/2026-09-07/validation/implementation-queue.md) remains the source for those fixes.
## Prioritized regression risks
| Risk | Source evidence | Smallest appropriate response / gate |
|---|---|---|
| Lost identity boundary during a new shell/cache/client | `App`, `api`, `sessionBoundary`; B02 server session preconditions | Keep private provider unmount, immutable provenance, abort/late-response checks and real A→B tests. Session headers never become rate-limit owner identity |
| Editor redesign hides existing lost-update behavior | CV save payload lacks expected revision; page-local save queue is not cross-editor concurrency | Coordinate existing D01/D02 integrity tickets before changing save/conflict UX. Do not call history/undo optimistic concurrency or add a generic concurrency framework |
| Creation replay becomes easier through capture/dialog rerenders | Preview/duplicate warning and subsequent create are separate requests | Preserve current review flow; existing D04 creation-intent ticket is distinct from identity and record revision. No idempotency work in this audit |
| Route consolidation loses entry contracts | Two router layers, legacy `/applications/:id`, old section mappings, `?add`, notification/company deep links | Route manifest + redirect tests before moving navigation; keep capture and OAuth callbacks functional |
| New styling repeats existing contrast/focus defects | Validated F14 theme pair contrast; builder preview scroll-region transition | A01 semantic foreground/background/state colors, A02 preview structure, A03 loaded/manual verification before broad page work |
| Thin initial-state tests create false confidence | Eight-route axe sample; component API mocks; standalone TS2571 | Phase 2 loaded-interaction and type baseline; require feature-ledger evidence per migrated workflow |
| CV/profile semantics blur in a unified editor | Canonical profile save versus CV override/settings and published slug | Clearly display source versus document override; test master unchanged, source selection, history, publish/unpublish and long PDF |
| AI presentation implies facts or silently applies changes | Contextual suggestions and extraction accept/discard already exist | Preserve preview/reject/apply and source/context metadata; prompt instructions alone do not prove factual accuracy |
| Draft/history/mail/package behavior lost in visual simplification | `ApplicationAssets` 769 lines, inbox 750, correspondence 747; separate persistence/attempt APIs | Extract by cohesive responsibility, not one generic form; keep conflict/send uncertainty, frozen package and unsaved guards |
| Broad navigation has competing labels/destinations | Eleven main nav entries plus account/admin; profile vs career; table/board separate; embedded operations/review | Design grouped IA with an explicit preservation/redirect map; improve discoverability without deleting capabilities |
| Styling consistency remains expensive | Central theme plus hardcoded shell navy/indigo, page-local shadows and large `sx` compositions | Retain MUI; establish tokens and a few layout/field/state primitives, then validate representative surfaces |
| Large editor/page modules couple visual and persistence work | Editor 1,131 lines; career 879; job table 866 | One cohesive extraction at a time, bracketed by real workflow tests; file length alone is not a rewrite justification |
| Dashboard customization mistaken for an existing server contract | Only five visibility booleans in owner-local storage | Keep current prefs until Phase 8; separately decide device-only vs cross-device contract before persistence/schema work |
| International/mobile regressions | Mixed 768/900/MUI breakpoints; hardcoded English mobile accessible name; EN-only axe | Preserve current mobile adaptations; long Bokmål labels and locale/date semantics in the representative matrix |
| App route identity churn | Router memo depends on job display preferences in `App` | Potential state-reset risk, not reproduced here; test changing preferences during meaningful workflow before refactoring router ownership |
| Unstable release proof or assumed production ingress | New CI prerequisite/build failures; Docker unavailable; F04 open; HTTP redirect observed to unreachable port 444 | No stable/live claim from push alone. Keep required gates and complete operator evidence; no trust-all fallback or invented proxy CIDR |
Line counts come from the [source census](source-inventory.json); they are prioritization context, not measured performance. No new authorization bypass is alleged by this redesign audit.
## Recommended order
1. **Finish the authorized release attempt and retain the checkpoint.** Required CI and deploy preflight must pass before calling the changes live. Production F04 runtime/firewall/DNS/peer checks remain a separate closure gate. Audit/planning can continue without claiming Phase 0 stability.
2. **Phase 2 — Functional baseline.** Narrow TS2571 and add full type checking; trace preservation IDs to existing tests; add missing loaded workflow/route/AI-review tests. Preserve B01–B06 regression suites. Coordinate outstanding record-integrity and recovery tickets through their existing queue, without silently starting them here.
3. **Phase 3 — UX architecture.** Define grouped navigation, Jobs view switch, destination for embedded Documents/Analytics/Notifications, full-page/preview contract, contextual AI pattern and mobile workflow rules. Map every current route/feature to its destination and backward-compatible entry. Keep API contracts.
4. **Phase 4 — Shared foundations.** Use existing MUI/Emotion/theme system. Resolve proven semantic contrast and focus defects, then unify tokens, page/layout/state primitives, labelled fields, buttons, dialogs/drawers and tables. Avoid a speculative new design-system framework.
5. **Phase 5 — Representative migration.** Shell → Jobs table/board entry → full job workspace → CV editor; dashboard presentation can join after shell tokens stabilize. Preserve a data-rich populated example, empty/error/locked case, mobile and keyboard path for each. Do not modify editor save semantics concurrently with integrity work.
6. **Phase 6 — Review checkpoint.** Inspect EN/NB × light/dark × desktop/mobile, loaded accessibility, long data, CSV/PDF downloads, identity switching and history. Correct shared defects before repeating the design.
7. **Phase 7 — Remaining routes and nested functions.** Auth/account, career/import/evidence, CV library/public CV, correspondence, reminders/operations, settings and admin; update every preservation row with evidence.
8. **Phase 8 — Dashboard customization.** Add ordering/reset/resizing only with defined layout and persistence semantics. Coordinate any needed migration with restore/rollback readiness. Keep aggregate admin reporting separate.
9. **Phase 9 — Cross-product QA and release evidence.** Full regression, manual access/mobile, document pagination and provider/production checks. Feature parity, not only appearance, determines readiness.
10. **Phase 10 — Cleanup.** Delete legacy modules only after route/import checks and preservation-ledger completion. Do not use static unreachability alone as approval.
No router/state/styling dependency replacement is currently recommended. If a later prototype demonstrates a concrete limitation, compare the smallest alternative against MUI reuse and measure migration/keyboard/theme cost before choosing it.
## Session-sized next scopes and coordination
| Suggested future scope | Boundaries / expected proof | Parallel constraints |
|---|---|---|
| Type and baseline bookkeeping | One test payload narrowing, explicit type script/CI gate, known-failure classification | Independent of visual work; coordinate CI edits with deployment repair |
| Route/preservation regression | Existing route helpers, full/overlay/capture navigation tests | Do not change router structure at the same time |
| Theme semantic contract | Central theme/MUI states + representative loaded contrast fixtures | Separate from backend; integrate before page styling |
| Builder focus contract | Actual preview container, viewport transition and keyboard scroll tests | Must not run concurrently with D01/editor save refactor |
| Shell/navigation proposal | Documentation/interactive prototype and route map only until Phase 3 approved | Can be prepared while tests run; no new production routing yet |
| First screen migration | One agreed shell or Jobs surface with existing handlers/contracts retained | Use settled tokens; no simultaneous edits of its route/state owner |
These are future implementation boundaries, not work started by Phase 1. Mail delivery, billing, schema, restore and infrastructure changes remain outside redesign sessions unless explicitly authorized and independently gated.
## Decisions required from Connor
No answer is required to complete this audit. Ask only when the dependent phase starts:
- **Brand/name/accent:** the brief intentionally leaves them unsettled. Keep current naming and theme until Phase 3/4 chooses them; do not block baseline tests on branding.
- **Dashboard persistence:** whether layout should follow the account across devices materially changes Phase 8's persistence scope. Existing implementation is device-local and owner-keyed.
- **Private local draft recovery:** preserve in-memory drafts and existing server drafts now. New persistent device-local career/CV content needs the privacy/retention choice already recorded under W05.
- **Product additions/deprecations:** new goals/general assistant/providers or removing an existing preservation row need explicit product scope. Navigation relocation alone need not become a series of permission questions.
The repository already answers the current framework, default language, existing calendar support, account/profile distinction and owned-resource semantics. Do not ask Connor to supply those facts.
## Stop conditions
- No large visual migration until loaded regression baseline and shared UI contracts are defined. No stable release label while required CI is red or deployment state unknown.
- No editor persistence redesign before resolving its record conflict contract; B02 must remain green throughout. No schema change before recovery/rollback prerequisites.
- No implicit feature deletion, master-profile mutation from CV overrides, silent AI application, unknown email resend, or private cache reuse across identities.
- No public accessibility claim without manual primary-flow evidence. No F04 closure without actual deployed/runtime evidence; direct-port failure from one workstation is insufficient.
- Stop at Phase 1's audit deliverables in this session. Phase 2 and B07 have not begun.
+63
View File
@@ -0,0 +1,63 @@
# Current route and page map
Source: [App.tsx shell routes](../../../job-tracker-ui/src/App.tsx#L379) and [outer router](../../../job-tracker-ui/src/App.tsx#L472). All paths below are current behavior, not target architecture. Preserve or redirect every path intentionally. `:id` and `:slug` represent route patterns, not single records.
## Public entry routes
| Route | Component | Contract |
|---|---|---|
| `/` | LandingPage | Public product/plans and sign-in entry; authenticated redirection behavior has its own test |
| `/login` | LoginPage | Local/Google/Microsoft sign-in, verification/2FA branches |
| `/register` | LoginPage (`initialMode=register`) | Configuration-gated account creation |
| `/forgot-password` | ForgotPasswordPage | Request reset without disclosing account existence |
| `/reset-password` | ResetPasswordPage | Token-bearing reset flow |
| `/verify-email` | VerifyEmailPage | Verification-token flow |
| `/confirm-email-change` | VerifyEmailPage (`emailChange`) | Pending email-change confirmation |
| `/microsoft-legacy-relink` | MicrosoftLegacyRelinkPage | Existing-account recovery/relink flow |
| `/cv/:slug` | PublicCvPage | Explicitly published CV preview/PDF; no general private CV access |
## Application routes
The shell resolves auth/config and `/auth/me`; deployed server authentication remains authoritative. Admin navigation is hidden for ordinary accounts, while API role checks enforce access even for crafted deep links. A routed component is not itself an authorization boundary.
| Route | Component | Entry / preservation requirement |
|---|---|---|
| `/dashboard` | DashboardView | Personal metrics, next actions, onboarding and local widget visibility |
| `/discover` | JobDiscoveryPage | NAV search, saved searches/alerts, review before tracker import |
| `/jobs` | JobTable (`jobs`) | Filters, search, sort, pagination, saved views, columns, selection/bulk actions, full/preview workspace |
| `/jobs/:id` | ApplicationWorkspacePage | Full job workspace; section/follow-mode query semantics |
| `/reminders` | RemindersView | Follow-ups, deadlines and progression actions |
| `/operations` | OperationsPage | Background progress/retry/cancel and notifications; reachable outside main nav |
| `/kanban` | KanbanBoard | Alternate view of the same jobs; grouped statuses, keyboard and pointer moves |
| `/companies` | CompaniesTable | Company/contact editing and relationship detail; `?edit=id` command entry |
| `/offers` | OfferComparisonPage | Comparison of recorded offers and links to source workspaces |
| `/correspondence` | CorrespondenceInboxPage | Inbox, provider messages, drafts, reply/send and review mode |
| `/correspondence/review` | Redirect | Existing alias to `/correspondence?view=review` |
| `/profile` | ProfilePage | Account identity/avatar/password/email; security cards and account links |
| `/applications/:id` | LegacyApplicationRedirect | Existing alias to `/jobs/:id`; preserves search and router state |
| `/career` | CareerWorkspacePage → CareerProfilePage | Canonical profile, import/review, history and evidence bank |
| `/career/builder` | CvBuilderPage | CV library, templates, creation/copy/manage/share/export |
| `/career/builder/:id` | CvBuilderEditor | Persisted CV variant studio, preview, history and AI review |
| `/admin/audit` | AdminAuditPage | Admin event history and permitted undo/restore |
| `/admin/users` | AdminUsersPage | Admin account/role/reset/deletion controls |
| `/admin/system` | AdminSystemPage | Admin service/configuration/maintenance/benchmark diagnostics |
| `/trash` | JobTable (`trash`) | Deleted-job listing and restoration; retain distinct mode semantics |
| `/settings` | SettingsView | General, follow-up rules, notifications and backup/account lifecycle tabs |
| `/settings/connected-accounts` | ConnectedAccountsPage | Gmail, Microsoft Graph and IMAP provider connections |
There are **31 concrete patterns: 29 page patterns and two redirect aliases**. The remaining three declarations in the AST census are the outer `/*` shell, inner `*` NotFoundPage and inner root redirect. The explicit outer `/` landing route takes precedence over the shell's root redirect. RouteErrorPage is an error boundary, not a separate URL. Do not manufacture an `/analytics`, `/documents` or `/notifications` page from the target brief: their current functions are embedded in dashboard/job/operations/settings surfaces.
## Non-route entries and state contracts
| Entry | Current effect |
|---|---|
| Shell add button; command action; capture URL `?add=` / `?addtext=` | Opens AddJobModal and consumes the query. Browser extension/bookmarklet/share entry depends on this |
| Job row/card; preview action | Full job page or reused ApplicationWorkspace overlay; preserve close/focus, dirty protection and full-page handoff |
| `/jobs/:id?section=...` | Overview, analysis, CV, cover-letter or interview; older `match`, job-details/checklist/documents/timeline/communication values map through existing route helpers |
| `/applications/:id` and older tab contracts | Legacy redirects and numeric tab-to-section mapping; covered by route-contract tests |
| Command search `Ctrl/Cmd+K` | Jobs and companies plus six static commands; company result uses `/companies?edit=id` |
| Notifications/reminders/operations | Deep links can enter a job subsection or processing result without first visiting Jobs |
| Builder public/share/PDF | Public slug lifecycle is separate from authenticated numeric CV identity |
| OAuth popups/callbacks | Provider/backend callback and postMessage flow; not additional React pages. Preserve exact origin/state contracts |
Sources: [jobWorkspaceRoute](../../../job-tracker-ui/src/jobWorkspaceRoute.ts), [AppShell](../../../job-tracker-ui/src/layout/AppShell.tsx), [QuickCommandDialog](../../../job-tracker-ui/src/components/QuickCommandDialog.tsx), [workspace component](../../../job-tracker-ui/src/views/ApplicationWorkspacePage.tsx). Phase 3 may propose navigation merges; this inventory does not authorize deleting aliases or current functionality.
+194
View File
@@ -0,0 +1,194 @@
# Test file inventory
Tracked test files at the audit baseline. Presence is not proof that a feature or every interaction is covered. See TEST_INVENTORY.md for scope and execution evidence.
| Layer | File |
|---|---|
| Backend | [JobTrackerApi.Tests/AccountDataExportTests.cs:1](../../../JobTrackerApi.Tests/AccountDataExportTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AccountDeletionTests.cs:1](../../../JobTrackerApi.Tests/AccountDeletionTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AccountPlansTests.cs:1](../../../JobTrackerApi.Tests/AccountPlansTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AiEvaluationFixtureTests.cs:1](../../../JobTrackerApi.Tests/AiEvaluationFixtureTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AiOperationQueueTests.cs:1](../../../JobTrackerApi.Tests/AiOperationQueueTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AiPrivacyPolicyTests.cs:1](../../../JobTrackerApi.Tests/AiPrivacyPolicyTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AiUsageMeterTests.cs:1](../../../JobTrackerApi.Tests/AiUsageMeterTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AiWorkspaceNotePersistenceTests.cs:1](../../../JobTrackerApi.Tests/AiWorkspaceNotePersistenceTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AiWorkspaceTests.cs:1](../../../JobTrackerApi.Tests/AiWorkspaceTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AnalyticsSalaryTests.cs:1](../../../JobTrackerApi.Tests/AnalyticsSalaryTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ApiAuthorizationPostureTests.cs:1](../../../JobTrackerApi.Tests/ApiAuthorizationPostureTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ApplicationAssetsTests.cs:1](../../../JobTrackerApi.Tests/ApplicationAssetsTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ApplicationCalendarControllerTests.cs:1](../../../JobTrackerApi.Tests/ApplicationCalendarControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ApplicationChecklistTests.cs:1](../../../JobTrackerApi.Tests/ApplicationChecklistTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ApplicationIntelligenceTests.cs:1](../../../JobTrackerApi.Tests/ApplicationIntelligenceTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ApplicationWorkspaceTests.cs:1](../../../JobTrackerApi.Tests/ApplicationWorkspaceTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AttachmentConsistencyTests.cs:1](../../../JobTrackerApi.Tests/AttachmentConsistencyTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AttachmentFlagsRecomputeTests.cs:1](../../../JobTrackerApi.Tests/AttachmentFlagsRecomputeTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AttachmentsControllerTests.cs:1](../../../JobTrackerApi.Tests/AttachmentsControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AuthAndSystemControllerTests.cs:1](../../../JobTrackerApi.Tests/AuthAndSystemControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AuthSessionRevocationTests.cs:1](../../../JobTrackerApi.Tests/AuthSessionRevocationTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/AvatarStorageTests.cs:1](../../../JobTrackerApi.Tests/AvatarStorageTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/BackgroundWorkerTenantTests.cs:1](../../../JobTrackerApi.Tests/BackgroundWorkerTenantTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/BackupControllerTests.cs:1](../../../JobTrackerApi.Tests/BackupControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/BillingControllerTests.cs:1](../../../JobTrackerApi.Tests/BillingControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/BuildMetadataTests.cs:1](../../../JobTrackerApi.Tests/BuildMetadataTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/CareerEvidenceControllerTests.cs:1](../../../JobTrackerApi.Tests/CareerEvidenceControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/CareerProfileControllerTests.cs:1](../../../JobTrackerApi.Tests/CareerProfileControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/CareerProfileServiceTests.cs:1](../../../JobTrackerApi.Tests/CareerProfileServiceTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ClientErrorsControllerTests.cs:1](../../../JobTrackerApi.Tests/ClientErrorsControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/CompanyRelationshipTests.cs:1](../../../JobTrackerApi.Tests/CompanyRelationshipTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/CorrespondenceControllerTests.cs:1](../../../JobTrackerApi.Tests/CorrespondenceControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/CsvExportTests.cs:1](../../../JobTrackerApi.Tests/CsvExportTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/CurrentUserIdLiveEvaluationTests.cs:1](../../../JobTrackerApi.Tests/CurrentUserIdLiveEvaluationTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/CvBuilderTests.cs:1](../../../JobTrackerApi.Tests/CvBuilderTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/CvCorpusHarnessTests.cs:1](../../../JobTrackerApi.Tests/CvCorpusHarnessTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/CvExportRetentionTests.cs:1](../../../JobTrackerApi.Tests/CvExportRetentionTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/CvExtractionCoverageTests.cs:1](../../../JobTrackerApi.Tests/CvExtractionCoverageTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/CvProcessingOperationTests.cs:1](../../../JobTrackerApi.Tests/CvProcessingOperationTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/CvProfileDiffServiceTests.cs:1](../../../JobTrackerApi.Tests/CvProfileDiffServiceTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/DatabaseBackupRunnerTests.cs:1](../../../JobTrackerApi.Tests/DatabaseBackupRunnerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/EmailControllerTests.cs:1](../../../JobTrackerApi.Tests/EmailControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/EmailDraftPersistenceTests.cs:1](../../../JobTrackerApi.Tests/EmailDraftPersistenceTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/EmailDraftsControllerTests.cs:1](../../../JobTrackerApi.Tests/EmailDraftsControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/EmailOwnershipIntegrationTests.cs:1](../../../JobTrackerApi.Tests/EmailOwnershipIntegrationTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/EmailProviderDeliveryTests.cs:1](../../../JobTrackerApi.Tests/EmailProviderDeliveryTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/EmailSendAttemptStoreTests.cs:1](../../../JobTrackerApi.Tests/EmailSendAttemptStoreTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/EmailSendControllerTests.cs:1](../../../JobTrackerApi.Tests/EmailSendControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/EmailStatusClassifierTests.cs:1](../../../JobTrackerApi.Tests/EmailStatusClassifierTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ExternalOriginTests.cs:1](../../../JobTrackerApi.Tests/ExternalOriginTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ForwardedIngressTests.cs:1](../../../JobTrackerApi.Tests/ForwardedIngressTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/GmailControllerTests.cs:1](../../../JobTrackerApi.Tests/GmailControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/GoogleTokenValidatorTests.cs:1](../../../JobTrackerApi.Tests/GoogleTokenValidatorTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/HumanLanguageCatalogTests.cs:1](../../../JobTrackerApi.Tests/HumanLanguageCatalogTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ImapControllerTests.cs:1](../../../JobTrackerApi.Tests/ImapControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ImapProviderTests.cs:1](../../../JobTrackerApi.Tests/ImapProviderTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ImapServiceSsrfGuardTests.cs:1](../../../JobTrackerApi.Tests/ImapServiceSsrfGuardTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/InterviewAiContextTests.cs:1](../../../JobTrackerApi.Tests/InterviewAiContextTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/InterviewPrepPersistenceTests.cs:1](../../../JobTrackerApi.Tests/InterviewPrepPersistenceTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/InterviewPrepTests.cs:1](../../../JobTrackerApi.Tests/InterviewPrepTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobApplicationsApplicationPackageTests.cs:1](../../../JobTrackerApi.Tests/JobApplicationsApplicationPackageTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobApplicationsAppliedDateHistoryTests.cs:1](../../../JobTrackerApi.Tests/JobApplicationsAppliedDateHistoryTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobApplicationsAuthorizationTests.cs:1](../../../JobTrackerApi.Tests/JobApplicationsAuthorizationTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobApplicationsControllerTests.cs:1](../../../JobTrackerApi.Tests/JobApplicationsControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobApplicationsEndpointBehaviorTests.cs:1](../../../JobTrackerApi.Tests/JobApplicationsEndpointBehaviorTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobApplicationsFollowUpDraftTests.cs:1](../../../JobTrackerApi.Tests/JobApplicationsFollowUpDraftTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobApplicationsMariaDraftTests.cs:1](../../../JobTrackerApi.Tests/JobApplicationsMariaDraftTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobApplicationsWorkflowSignalsTests.cs:1](../../../JobTrackerApi.Tests/JobApplicationsWorkflowSignalsTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobCvMatchServiceTests.cs:1](../../../JobTrackerApi.Tests/JobCvMatchServiceTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobDiscoveryControllerTests.cs:1](../../../JobTrackerApi.Tests/JobDiscoveryControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobImportHttpTransportTests.cs:1](../../../JobTrackerApi.Tests/JobImportHttpTransportTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobImportServiceTests.cs:1](../../../JobTrackerApi.Tests/JobImportServiceTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobLifecycleEventTests.cs:1](../../../JobTrackerApi.Tests/JobLifecycleEventTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobOpportunitySyncTests.cs:1](../../../JobTrackerApi.Tests/JobOpportunitySyncTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/JobPipelineTests.cs:1](../../../JobTrackerApi.Tests/JobPipelineTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/LocalAuthIdentityTests.cs:1](../../../JobTrackerApi.Tests/LocalAuthIdentityTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/MaintenanceJobDispatcherTests.cs:1](../../../JobTrackerApi.Tests/MaintenanceJobDispatcherTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/MeteredSummarizerServiceTests.cs:1](../../../JobTrackerApi.Tests/MeteredSummarizerServiceTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/MicrosoftGraphControllerTests.cs:1](../../../JobTrackerApi.Tests/MicrosoftGraphControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/MicrosoftGraphProviderTests.cs:1](../../../JobTrackerApi.Tests/MicrosoftGraphProviderTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/MicrosoftTokenValidatorTests.cs:1](../../../JobTrackerApi.Tests/MicrosoftTokenValidatorTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/MigrationChainTests.cs:1](../../../JobTrackerApi.Tests/MigrationChainTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/NotificationSettingsControllerTests.cs:1](../../../JobTrackerApi.Tests/NotificationSettingsControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/OperationsControllerTests.cs:1](../../../JobTrackerApi.Tests/OperationsControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/OwnershipGuardTests.cs:1](../../../JobTrackerApi.Tests/OwnershipGuardTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/PdfRenderAdmissionTests.cs:1](../../../JobTrackerApi.Tests/PdfRenderAdmissionTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ProEntitlementAuthorizationTests.cs:1](../../../JobTrackerApi.Tests/ProEntitlementAuthorizationTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ProductionConfigTests.cs:1](../../../JobTrackerApi.Tests/ProductionConfigTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/ProfileCvControllerTests.cs:1](../../../JobTrackerApi.Tests/ProfileCvControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/PublicCvControllerTests.cs:1](../../../JobTrackerApi.Tests/PublicCvControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/RateLimitPartitionKeysTests.cs:1](../../../JobTrackerApi.Tests/RateLimitPartitionKeysTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/RouteUniquenessTests.cs:1](../../../JobTrackerApi.Tests/RouteUniquenessTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/RulesEngineProspectTests.cs:1](../../../JobTrackerApi.Tests/RulesEngineProspectTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/SavedJobSearchAlertTests.cs:1](../../../JobTrackerApi.Tests/SavedJobSearchAlertTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/SessionContextMiddlewareTests.cs:1](../../../JobTrackerApi.Tests/SessionContextMiddlewareTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/SessionsControllerTests.cs:1](../../../JobTrackerApi.Tests/SessionsControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/SqliteDateTimeOffsetCompatibilityTests.cs:1](../../../JobTrackerApi.Tests/SqliteDateTimeOffsetCompatibilityTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/SqliteMigrationHelperTests.cs:1](../../../JobTrackerApi.Tests/SqliteMigrationHelperTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/StageAnalyticsTests.cs:1](../../../JobTrackerApi.Tests/StageAnalyticsTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/StartupSchemaOwnershipTests.cs:1](../../../JobTrackerApi.Tests/StartupSchemaOwnershipTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/StrategySnapshotOperationTests.cs:1](../../../JobTrackerApi.Tests/StrategySnapshotOperationTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/SubmittedApplicationPackageTests.cs:1](../../../JobTrackerApi.Tests/SubmittedApplicationPackageTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/SummarizerServiceTests.cs:1](../../../JobTrackerApi.Tests/SummarizerServiceTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/TwoFactorControllerTests.cs:1](../../../JobTrackerApi.Tests/TwoFactorControllerTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/UserOperationStoreTests.cs:1](../../../JobTrackerApi.Tests/UserOperationStoreTests.cs#L1) |
| Backend | [JobTrackerApi.Tests/UsersControllerTests.cs:1](../../../JobTrackerApi.Tests/UsersControllerTests.cs#L1) |
| Browser extension | [browser-extension/tests/capture-url.test.mjs:1](../../../browser-extension/tests/capture-url.test.mjs#L1) |
| Browser / HTTP | [e2e/accessibility.spec.ts:1](../../../job-tracker-ui/e2e/accessibility.spec.ts#L1) |
| Browser / HTTP | [e2e/account-isolation.spec.ts:1](../../../job-tracker-ui/e2e/account-isolation.spec.ts#L1) |
| Browser / HTTP | [e2e/csv-export.spec.ts:1](../../../job-tracker-ui/e2e/csv-export.spec.ts#L1) |
| Browser / HTTP | [e2e/job-discovery.spec.ts:1](../../../job-tracker-ui/e2e/job-discovery.spec.ts#L1) |
| Browser / HTTP | [e2e/kanban-theme.spec.ts:1](../../../job-tracker-ui/e2e/kanban-theme.spec.ts#L1) |
| Browser / HTTP | [e2e/smoke.spec.ts:1](../../../job-tracker-ui/e2e/smoke.spec.ts#L1) |
| Browser / HTTP | [ingress-tests/production.spec.ts:1](../../../job-tracker-ui/ingress-tests/production.spec.ts#L1) |
| Browser / HTTP | [pdf-tests/admission.spec.ts:1](../../../job-tracker-ui/pdf-tests/admission.spec.ts#L1) |
| Browser / HTTP | [rate-limit-tests/isolation.spec.ts:1](../../../job-tracker-ui/rate-limit-tests/isolation.spec.ts#L1) |
| Frontend unit/component | [src/App.test.tsx:1](../../../job-tracker-ui/src/App.test.tsx#L1) |
| Frontend unit/component | [src/LandingPage.authRedirect.test.tsx:1](../../../job-tracker-ui/src/LandingPage.authRedirect.test.tsx#L1) |
| Frontend unit/component | [src/account-data-export.test.tsx:1](../../../job-tracker-ui/src/account-data-export.test.tsx#L1) |
| Frontend unit/component | [src/account-scoped-state.test.tsx:1](../../../job-tracker-ui/src/account-scoped-state.test.tsx#L1) |
| Frontend unit/component | [src/admin-audit-page.test.tsx:1](../../../job-tracker-ui/src/admin-audit-page.test.tsx#L1) |
| Frontend unit/component | [src/admin-system-page.test.tsx:1](../../../job-tracker-ui/src/admin-system-page.test.tsx#L1) |
| Frontend unit/component | [src/admin-users-page.test.tsx:1](../../../job-tracker-ui/src/admin-users-page.test.tsx#L1) |
| Frontend unit/component | [src/ai-section-assistant.test.tsx:1](../../../job-tracker-ui/src/ai-section-assistant.test.tsx#L1) |
| Frontend unit/component | [src/ai-usage-card.test.tsx:1](../../../job-tracker-ui/src/ai-usage-card.test.tsx#L1) |
| Frontend unit/component | [src/app-shell-notifications.test.tsx:1](../../../job-tracker-ui/src/app-shell-notifications.test.tsx#L1) |
| Frontend unit/component | [src/application-assets.test.tsx:1](../../../job-tracker-ui/src/application-assets.test.tsx#L1) |
| Frontend unit/component | [src/application-calendar.test.tsx:1](../../../job-tracker-ui/src/application-calendar.test.tsx#L1) |
| Frontend unit/component | [src/application-checklist.test.tsx:1](../../../job-tracker-ui/src/application-checklist.test.tsx#L1) |
| Frontend unit/component | [src/application-drafts.test.ts:1](../../../job-tracker-ui/src/application-drafts.test.ts#L1) |
| Frontend unit/component | [src/application-intelligence.test.tsx:1](../../../job-tracker-ui/src/application-intelligence.test.tsx#L1) |
| Frontend unit/component | [src/application-route-contracts.test.ts:1](../../../job-tracker-ui/src/application-route-contracts.test.ts#L1) |
| Frontend unit/component | [src/application-workflow-assist.test.tsx:1](../../../job-tracker-ui/src/application-workflow-assist.test.tsx#L1) |
| Frontend unit/component | [src/application-workspace-overlay.test.tsx:1](../../../job-tracker-ui/src/application-workspace-overlay.test.tsx#L1) |
| Frontend unit/component | [src/applicationWorkspace.test.ts:1](../../../job-tracker-ui/src/applicationWorkspace.test.ts#L1) |
| Frontend unit/component | [src/attachments.test.tsx:1](../../../job-tracker-ui/src/attachments.test.tsx#L1) |
| Frontend unit/component | [src/captureUrl.test.ts:1](../../../job-tracker-ui/src/captureUrl.test.ts#L1) |
| Frontend unit/component | [src/career-evidence.test.tsx:1](../../../job-tracker-ui/src/career-evidence.test.tsx#L1) |
| Frontend unit/component | [src/career-workspace-page.test.tsx:1](../../../job-tracker-ui/src/career-workspace-page.test.tsx#L1) |
| Frontend unit/component | [src/companies-relationship.test.tsx:1](../../../job-tracker-ui/src/companies-relationship.test.tsx#L1) |
| Frontend unit/component | [src/confirm-flow.test.tsx:1](../../../job-tracker-ui/src/confirm-flow.test.tsx#L1) |
| Frontend unit/component | [src/confirm.test.tsx:1](../../../job-tracker-ui/src/confirm.test.tsx#L1) |
| Frontend unit/component | [src/correspondence-gmail-import.test.tsx:1](../../../job-tracker-ui/src/correspondence-gmail-import.test.tsx#L1) |
| Frontend unit/component | [src/correspondence-inbox-page.test.tsx:1](../../../job-tracker-ui/src/correspondence-inbox-page.test.tsx#L1) |
| Frontend unit/component | [src/correspondence-search-context.test.ts:1](../../../job-tracker-ui/src/correspondence-search-context.test.ts#L1) |
| Frontend unit/component | [src/csv-export.test.tsx:1](../../../job-tracker-ui/src/csv-export.test.tsx#L1) |
| Frontend unit/component | [src/cv-builder-deep-link.test.tsx:1](../../../job-tracker-ui/src/cv-builder-deep-link.test.tsx#L1) |
| Frontend unit/component | [src/cv-builder-page.test.tsx:1](../../../job-tracker-ui/src/cv-builder-page.test.tsx#L1) |
| Frontend unit/component | [src/cv-template-thumbnail.test.tsx:1](../../../job-tracker-ui/src/cv-template-thumbnail.test.tsx#L1) |
| Frontend unit/component | [src/cvBuilder.test.ts:1](../../../job-tracker-ui/src/cvBuilder.test.ts#L1) |
| Frontend unit/component | [src/daily-control-loop.test.tsx:1](../../../job-tracker-ui/src/daily-control-loop.test.tsx#L1) |
| Frontend unit/component | [src/dialog-flow.test.tsx:1](../../../job-tracker-ui/src/dialog-flow.test.tsx#L1) |
| Frontend unit/component | [src/email-provider-connections.test.tsx:1](../../../job-tracker-ui/src/email-provider-connections.test.tsx#L1) |
| Frontend unit/component | [src/end-to-end-trust-loop.test.tsx:1](../../../job-tracker-ui/src/end-to-end-trust-loop.test.tsx#L1) |
| Frontend unit/component | [src/gmail-review-page.test.tsx:1](../../../job-tracker-ui/src/gmail-review-page.test.tsx#L1) |
| Frontend unit/component | [src/i18n-provider.test.tsx:1](../../../job-tracker-ui/src/i18n-provider.test.tsx#L1) |
| Frontend unit/component | [src/interview-prep.test.tsx:1](../../../job-tracker-ui/src/interview-prep.test.tsx#L1) |
| Frontend unit/component | [src/job-discovery.test.tsx:1](../../../job-tracker-ui/src/job-discovery.test.tsx#L1) |
| Frontend unit/component | [src/kanban-grouped-board.test.tsx:1](../../../job-tracker-ui/src/kanban-grouped-board.test.tsx#L1) |
| Frontend unit/component | [src/landing-page.test.tsx:1](../../../job-tracker-ui/src/landing-page.test.tsx#L1) |
| Frontend unit/component | [src/login-page.test.tsx:1](../../../job-tracker-ui/src/login-page.test.tsx#L1) |
| Frontend unit/component | [src/microsoft-legacy-relink-page.test.tsx:1](../../../job-tracker-ui/src/microsoft-legacy-relink-page.test.tsx#L1) |
| Frontend unit/component | [src/nginx-config.test.ts:1](../../../job-tracker-ui/src/nginx-config.test.ts#L1) |
| Frontend unit/component | [src/notifications-popover.test.tsx:1](../../../job-tracker-ui/src/notifications-popover.test.tsx#L1) |
| Frontend unit/component | [src/offer-comparison.test.tsx:1](../../../job-tracker-ui/src/offer-comparison.test.tsx#L1) |
| Frontend unit/component | [src/onboarding-checklist.test.tsx:1](../../../job-tracker-ui/src/onboarding-checklist.test.tsx#L1) |
| Frontend unit/component | [src/operations-page.test.tsx:1](../../../job-tracker-ui/src/operations-page.test.tsx#L1) |
| Frontend unit/component | [src/pipeline.test.ts:1](../../../job-tracker-ui/src/pipeline.test.ts#L1) |
| Frontend unit/component | [src/planCatalog.test.ts:1](../../../job-tracker-ui/src/planCatalog.test.ts#L1) |
| Frontend unit/component | [src/pro-feature-notice.test.tsx:1](../../../job-tracker-ui/src/pro-feature-notice.test.tsx#L1) |
| Frontend unit/component | [src/profile-page.test.tsx:1](../../../job-tracker-ui/src/profile-page.test.tsx#L1) |
| Frontend unit/component | [src/prompt.test.tsx:1](../../../job-tracker-ui/src/prompt.test.tsx#L1) |
| Frontend unit/component | [src/public-cv-page.test.tsx:1](../../../job-tracker-ui/src/public-cv-page.test.tsx#L1) |
| Frontend unit/component | [src/quick-capture.test.tsx:1](../../../job-tracker-ui/src/quick-capture.test.tsx#L1) |
| Frontend unit/component | [src/session-boundary.test.ts:1](../../../job-tracker-ui/src/session-boundary.test.ts#L1) |
| Frontend unit/component | [src/settings-view.test.tsx:1](../../../job-tracker-ui/src/settings-view.test.tsx#L1) |
| Frontend unit/component | [src/sidebar-active-nav.test.ts:1](../../../job-tracker-ui/src/sidebar-active-nav.test.ts#L1) |
| Frontend unit/component | [src/theme-state.test.tsx:1](../../../job-tracker-ui/src/theme-state.test.tsx#L1) |
| Frontend unit/component | [src/turnstile-widget.test.tsx:1](../../../job-tracker-ui/src/turnstile-widget.test.tsx#L1) |
| Frontend unit/component | [src/two-factor-settings.test.tsx:1](../../../job-tracker-ui/src/two-factor-settings.test.tsx#L1) |
| Frontend unit/component | [src/use-view-resource.test.tsx:1](../../../job-tracker-ui/src/use-view-resource.test.tsx#L1) |
| Frontend unit/component | [src/verify-email-page.test.tsx:1](../../../job-tracker-ui/src/verify-email-page.test.tsx#L1) |
| Frontend unit/component | [src/workflow-trust-signals.test.tsx:1](../../../job-tracker-ui/src/workflow-trust-signals.test.tsx#L1) |
| Repository safety | [scripts/test-ingress-topology.py:1](../../../scripts/test-ingress-topology.py#L1) |
| Repository safety | [scripts/test-ingress.py:1](../../../scripts/test-ingress.py#L1) |
| Repository safety | [scripts/test-ollama-evaluation.py:1](../../../scripts/test-ollama-evaluation.py#L1) |
| Repository safety | [scripts/test-supply-chain.py:1](../../../scripts/test-supply-chain.py#L1) |
| Parser / AI service | [tools/summarizer/tests/test_app.py:1](../../../tools/summarizer/tests/test_app.py#L1) |
+58
View File
@@ -0,0 +1,58 @@
# Test baseline and gaps
The [test-file census](TEST_FILES.md) lists every discovered tracked frontend test file (76: 67 unit/component and nine browser/HTTP specification files), 106 backend test-source files, plus extension/parser/repository safety files. Counts describe files, not executed cases or coverage percentages. The source snapshot is `97fce89`; subsequent bounded CI packaging corrections are tracked in the B06 release log, not redesign work.
## Test layers
| Layer | Setup and demonstrated scope | Limit |
|---|---|---|
| Frontend unit/component | Jest, jsdom, Testing Library; [config](../../../job-tracker-ui/jest.config.cjs). Account switching, routes, workspace/drafts, CV, mail, admin, theme, translations, dialogs and imports/exports | Babel strips TypeScript; mocks do not prove server ownership or real provider behavior |
| General browser | [Playwright config](../../../job-tracker-ui/playwright.config.ts): one Chromium project, isolated .NET API/SQLite data and local frontend; production static build supported | Chromium only; no actual Traefik/nginx; no cross-browser or screen-reader certification |
| Browser smoke | Nine cases in `e2e/smoke.spec.ts`: health/readiness, public plans, login, Free restrictions, reviewed job create, deep-linked job workspace/dirty guard, career, public CV/PDF, long searchable Code PDF | Selected journeys, not exhaustive editor states or all providers |
| Account isolation | Four `e2e/account-isolation.spec.ts` cases: original A→B replay, missing/forged context, crafted CV ownership/association, two-tab private-state disposal/Back | Retain API and database assertions when UI changes |
| Accessibility | Two axe cases over eight sampled routes | See missing state matrix below |
| Other general browser | One each discovery responsive review, dark Kanban, CSV security/UTF-8 byte preservation | Does not establish whole-app mobile/theme parity |
| PDF HTTP probe | `pdf-tests/admission.spec.ts` and dedicated config | Synthetic bounded concurrent requests; admission differs from time-window limiting |
| Rate-limit HTTP probe | `rate-limit-tests/isolation.spec.ts` and dedicated config | Nine account/session/IP/auth/forwarding scenarios; native API topology |
| Production ingress HTTP | `ingress-tests/production.spec.ts` and dedicated config | Six native production-mode origin/proxy checks; not running nginx or Traefik |
| Backend | xUnit/Moq, SQLite/InMemory and HTTP test seams; API/service ownership, auth, parser, CV/history/PDF, queue, billing, export, migration and rate/proxy tests | Provider-host tests and fault/probe tests have separate runtime requirements; SQLite is not full MariaDB proof |
| Repository/dependencies | Compose rendering + 17 hostile mutations, secret scan/SBOM, evaluation and supply-chain scripts | Config validation cannot prove host firewall or actual socket peers |
| Adjacent clients/services | Browser-extension node tests and Python parser/service tests | Preserve capture/document boundary; avoid pretending these are covered by React Jest |
The default browser suite currently contains **18 tests**. The nine special browser/HTTP files count includes six general e2e files and three separately configured suites. Special configurations must be invoked explicitly; a plain general Playwright run does not run all of them.
## Existing evidence versus fresh execution
| Evidence | Result and classification |
|---|---|
| Previous B06 unchanged application regression | 166 focused backend, 3 Compose, 6 production HTTP, 9 rate-limit HTTP passed; [exact prior commands/results](../../audits/2026-09-07/validation/b06-completion.md) |
| Previous B06 broader baseline | 915 selected backend tests, 298 frontend tests/67 suites, 18 browser tests, Release builds and targeted lint passed; external-DNS-dependent IMAP test excluded locally and explicitly documented |
| Fresh Phase 1 type reproduction | From `job-tracker-ui`: `node node_modules/typescript/bin/tsc --noEmit --incremental false` → exit 1, `src/interview-prep.test.tsx(120,10): error TS2571: Object is of type 'unknown'.` |
| Fresh release-prerequisite checks | `python scripts/test-ingress.py` → 3/3 pass; real standalone Compose path also tested; official downloaded Linux binary digest verified; tracked-secret scan and diff check pass |
| Fresh packaging regression at `23cc250` | Explicit installed .NET 9.0.317 SDK: Release build + **22/22 PDF admission tests** pass, then **915/915 selected backend tests** pass (same documented external-DNS IMAP exclusion). Results: `.artifacts/redesign-audit/backend.trx` |
| Actual CI push verification | Runs 736/737 exposed missing Compose/token prerequisites; corrected. Run 738 passed Compose/safety/extension/parser/API build, then exposed Linux PDF test-fixture packaging collision. Follow-up result belongs in [release log](../../audits/2026-09-07/validation/b06-completion.md#authorized-release-attempt-and-ci-prerequisite-correction) |
| Live/container boundary | Local Docker engine unavailable; F04 production evidence remains incomplete. No audit claim of real proxy-chain success |
The selected broader backend suite was repeated for the PDF fixture packaging change; the frontend suite was not repeated merely for documentation edits. Preserve the distinction between prior unchanged-source evidence, newly executed checks and actual CI failures. Run 739 subsequently failed earlier in the unchanged API compiler with `csc.dll` exit 139 on both existing attempts; it did not reach the corrected test-project build. No test gate was bypassed.
## Exact TypeScript root cause
[Interview test:120](../../../job-tracker-ui/src/interview-prep.test.tsx#L120) reads `.content` from `mockedApi.post.mock.calls[0][1]`. Axios's mocked generic request-data argument is typed `unknown`; the test dereferences it without narrowing. The runtime assertion can pass because Babel removes types. The production component's emitted behavior is not shown broken by this test diagnostic.
[tsconfig](../../../job-tracker-ui/tsconfig.json) includes `src`, including tests. CI runs Jest/lint/Next build but has no explicit full standalone `tsc --noEmit` gate. Next's successful build is not evidence that this exact standalone test-inclusive program passed. Phase 2 should narrow the test payload appropriately and introduce a deliberate full type gate. Do not weaken strictness, blanket-exclude tests or call this a P1 production outage. No type fix was made in Phase 1.
## Missing regression proof before redesign
| Priority | Add or preserve evidence |
|---|---|
| First | Stable type-check gate; B02 stale/queued mutation + cross-tab unmount as shared-client acceptance; legacy URL/overlay/full-page parity |
| First | Populated CV editor/profile/job detail plus open menus/dialogs/error/conflict states in EN/NB, light/dark, mobile/desktop; preserve underlying draft/history assertions |
| First | AI suggestions rejected/accepted distinctly; actual profile values unchanged when editing a CV/cover letter; unsupported/locked capabilities behave honestly |
| First | Typed date values, JSON import/export and B05 CSV bytes; attachments/private/public download distinctions; package history remains frozen |
| Before mail migration | Draft revisions, uncertain send/new attempt, provider reconnect/read failure, ownership and explicit send confirmation; use synthetic/sandbox providers |
| Before admin migration | Non-admin denied APIs, role revocation and last-admin guards, sensitive diagnostics excluded from personal pages |
| Before public release | Keyboard + NVDA/Narrator, preview scroll/focus, zoom/reflow, forced colors, real mobile keyboard and touch; provider/production gates separately |
Axe currently scans `/`, `/login`, `/dashboard`, `/jobs`, `/kanban`, `/career`, `/settings`, `/admin/system`, mostly after `body`/`main` appears, in English. Missing builder library/editor, job detail, discovery, offers, mail/review, public CV, account security, registration/reset/verification, operations, admin users/audit and interactive loaded states must be selected intentionally. Do not convert a green shell sample into a WCAG compliance claim.
Recommended later commands: locked dependency restore; Release backend build/test; full Jest; standalone tsc; lint; production frontend build; general Playwright static-export suite; explicit PDF/rate/ingress configurations; Compose validator and `git diff --check`. Use the environment/setup commands from the completion reports rather than guessing SDK paths or running probes against production.
@@ -0,0 +1,76 @@
// Read-only source census for the Phase 1 audit. Uses the repository's installed TypeScript parser.
const fs = require('fs');
const path = require('path');
const cp = require('child_process');
const root = process.cwd();
const ts = require(path.join(root, 'job-tracker-ui/node_modules/typescript'));
const out = path.join(root, 'docs/redesign/audit');
fs.mkdirSync(out, {recursive:true});
const paths = cp.execFileSync('git', ['ls-files'], {encoding:'utf8'}).trim().split('\n');
const files = paths.filter(p => /^job-tracker-ui\/(src|app)\/.+\.[jt]sx?$/.test(p) && !/\.test\./.test(p) && !p.endsWith('setupTests.ts'));
const tests = paths.filter(p => /(?:\.test\.[jt]sx?$|\.spec\.tsx?$)/.test(p) && p.startsWith('job-tracker-ui/'));
const sources = {};
const routes = [];
function loc(sf,n) { return sf.getLineAndCharacterOfPosition(n.getStart(sf)).line + 1; }
function resolve(from, dep) {
if (!dep.startsWith('.')) return null;
const base = path.posix.normalize(path.posix.join(path.posix.dirname(from),dep));
return [base, ...['.ts','.tsx','.js','.jsx','/index.ts','/index.tsx'].map(s=>base+s)].find(p=>files.includes(p)) || null;
}
for (const file of files) {
const content = fs.readFileSync(path.join(root,file),'utf8');
const sf = ts.createSourceFile(file,content,ts.ScriptTarget.Latest,true,file.endsWith('tsx')?ts.ScriptKind.TSX:ts.ScriptKind.TS);
const info = {lines:content.split(/\r?\n/).length, imports:[], api:[], labels:[], components:[], storage:[], functions:[]};
function visit(n) {
if(ts.isImportDeclaration(n) && ts.isStringLiteral(n.moduleSpecifier)) info.imports.push(n.moduleSpecifier.text);
if(ts.isCallExpression(n)) {
if(n.expression.kind===ts.SyntaxKind.ImportKeyword && n.arguments[0] && ts.isStringLiteral(n.arguments[0])) info.imports.push(n.arguments[0].text);
if(ts.isPropertyAccessExpression(n.expression) && /^(api|axios)$/.test(n.expression.expression.getText(sf)) && /^(get|post|put|patch|delete|request)$/.test(n.expression.name.text)) info.api.push({line:loc(sf,n),method:n.expression.name.text.toUpperCase(),url:n.arguments[0]?.getText(sf)||''});
if(n.expression.getText(sf)==='t' && n.arguments[0] && ts.isStringLiteral(n.arguments[0])) info.labels.push(n.arguments[0].text);
if(/(?:localStorage|sessionStorage)\.(?:getItem|setItem|removeItem)$/.test(n.expression.getText(sf))) info.storage.push({line:loc(sf,n),call:n.getText(sf).replace(/\s+/g,' ').slice(0,220)});
}
if((ts.isFunctionDeclaration(n)||ts.isVariableDeclaration(n)) && n.name && /^[A-Z]/.test(n.name.getText(sf))) info.functions.push({name:n.name.getText(sf),line:loc(sf,n)});
if(ts.isJsxOpeningElement(n)||ts.isJsxSelfClosingElement(n)) {
const tag=n.tagName.getText(sf);
if(/^[A-Z]/.test(tag)) info.components.push(tag);
if(tag==='Route') {
const attrs=Object.fromEntries(n.attributes.properties.filter(ts.isJsxAttribute).map(a=>[a.name.getText(sf),a.initializer?.getText(sf)||'']));
routes.push({file,line:loc(sf,n),...attrs});
}
}
if(file.endsWith('/App.tsx') && ts.isPropertyAssignment(n) && n.name.getText(sf)==='path' && ts.isStringLiteral(n.initializer)) routes.push({file,line:loc(sf,n),path:n.initializer.text,element:n.parent.getText(sf).replace(/\s+/g,' ')});
ts.forEachChild(n,visit);
}
visit(sf);
for(const key of ['imports','labels','components']) info[key]=[...new Set(info[key])].sort();
info.dependencies=info.imports.map(i=>resolve(file,i)).filter(Boolean);
sources[file]=info;
}
const reachable = new Set();
function walk(file) { if(reachable.has(file)||!sources[file])return; reachable.add(file); sources[file].dependencies.forEach(walk); }
walk('job-tracker-ui/src/ClientApp.tsx');
for (const [file,info] of Object.entries(sources)) {
info.reachableFromClientApp=reachable.has(file);
info.importedBy=Object.keys(sources).filter(f=>sources[f].dependencies.includes(file));
}
const summary = {baseline:cp.execFileSync('git',['rev-parse','HEAD'],{encoding:'utf8'}).trim(),sourceFiles:files.length,frontendTestFiles:tests.length,apiCallSites:Object.values(sources).reduce((n,s)=>n+s.api.length,0),routeDeclarations:routes.length};
fs.writeFileSync(path.join(out,'source-inventory.json'),JSON.stringify({summary,routes,tests,sources},null,2)+'\n');
const cell=s=>String(s).replaceAll('|','\\|').replaceAll('\n',' ');
const link=(file,line)=>`[${file.replace('job-tracker-ui/','')}:${line}](../../../${file}#L${line})`;
// docs/redesign/audit is three directories below the repository root.
const sourceLink=link;
let api='# API call-site inventory\n\nGenerated with the installed TypeScript AST from the committed baseline. Each row is an actual `api`/`axios` call expression, not a claim of runtime test coverage. Paths are relative to the shared `/api` base; interpolations are preserved. Domain wrappers are included. Companion technical audit maps contracts and authorization.\n\n| Source | Method | URL expression |\n|---|---|---|\n';
for(const [file,info] of Object.entries(sources)) for(const call of info.api) api+=`| ${sourceLink(file,call.line)} | ${call.method} | ${cell(call.url)} |\n`;
fs.writeFileSync(path.join(out,'API_CALL_SITES.md'),api);
let components='# Component and source inventory\n\nEvery production TSX module under `src` and `app` is listed. Lines are size indicators, not complexity scores. Reachability is relative-import reachability from ClientApp; app entry files are expected to be outside that graph. MUI primitives are dependencies, not missing local components. No unreachable file is approved for deletion.\n\n| Module | Lines | Client graph | Local direct consumers | Rendered component names |\n|---|---|---|---|---|\n';
for(const [file,info] of Object.entries(sources)) if(file.endsWith('.tsx')) components+=`| ${sourceLink(file,1)} | ${info.lines} | ${info.reachableFromClientApp?'reachable':'outside graph'} | ${cell(info.importedBy.map(f=>path.basename(f)).join(', ')||'—')} | ${cell(info.components.join(', '))} |\n`;
fs.writeFileSync(path.join(out,'COMPONENT_INVENTORY.md'),components);
let testList='# Test file inventory\n\nTracked test files at the audit baseline. Presence is not proof that a feature or every interaction is covered. See TEST_INVENTORY.md for scope and execution evidence.\n\n| Layer | File |\n|---|---|\n';
for(const file of paths.filter(p => tests.includes(p) || /^JobTrackerApi.Tests\/.+\.cs$/.test(p) && /Tests?\.cs$/.test(p) || /^browser-extension\/tests\/.+\.test\.mjs$/.test(p) || /^tools\/summarizer\/tests\/.+\.py$/.test(p) || /^scripts\/test-.+\.py$/.test(p))) {
const layer=file.startsWith('job-tracker-ui/src/')?'Frontend unit/component':file.startsWith('job-tracker-ui/')?'Browser / HTTP':file.startsWith('JobTrackerApi.Tests/')?'Backend':file.startsWith('tools/')?'Parser / AI service':file.startsWith('browser-extension/')?'Browser extension':'Repository safety';
testList+=`| ${layer} | ${sourceLink(file,1)} |\n`;
}
fs.writeFileSync(path.join(out,'TEST_FILES.md'),testList);
console.log(JSON.stringify(summary));
console.log('Largest:',Object.entries(sources).sort((a,b)=>b[1].lines-a[1].lines).slice(0,12).map(([f,s])=>[f,s.lines]));
console.log('Outside graph:',Object.entries(sources).filter(([f,s])=>f.endsWith('.tsx')&&!s.reachableFromClientApp).map(([f])=>f));
File diff suppressed because it is too large Load Diff