CareerVector UI shell
The CareerVector UI lives under ui/ as a SvelteKit app that SSRs on
Cloudflare Workers, hydrates in the browser, and persists durable state
through the @cv/workspace-client SDK to D1 and the realtime relay. This
document is the canon entry point for the human-facing surface.
Three top-level routes inside a workspace
| Route | Surface | Primary components |
|---|---|---|
/[wsId]/dashboard |
The matrix — every job in the workspace, scored, filterable, groupable | Dashboard.svelte, table/*, job-detail/* |
/[wsId]/kanban |
Phase-oriented pipeline view of the same jobs | KanbanBoard.svelte, PhaseColumn.svelte |
/[wsId]/cvl/[pane] |
Quarry editor (CV / CL / Notes / Settings) | CVLEditor.svelte, editors/* |
A read-only mirror at /view/[wsId]/... projects the same data with every
write path globally disabled — see no-user-accounts.md and the read-only
view canon doc.
Dashboard table
The dashboard is CareerVector's main product surface, not the CV generator. The matrix renders jobs as rows and a configurable column set:
- Built-in columns — title, company, location, salary, score, status, added-at, score breakdown. Always available.
- Custom columns — user-defined evaluation dimensions (boolean K.O.s, numeric 0–10, hard facts). Created via the Columns modal; populated by the evaluate stage; render through the same DataCell as built-ins.
- Origin tinting — every cell carries actor identity from
workspace_sub_doc_ops; the dashboard projects that into the per-cell origin map and tints by provider (seetinted-cell-by-actor).
Column order, widths, and visibility are stored in the layout and
order-state sub-docs so peers see the same arrangement.
Per-job detail panel
Clicking a row opens JobDetail.svelte as a slide-over panel with five tabs:
| Tab | Tone | Purpose |
|---|---|---|
| Overview | neutral | Identity fields, status, raw job posting metadata |
| Description | primary | Scraped / pasted description, edit access |
| Intel | success | Enrichment-derived facts: industry, signals |
| Scorecard | error | Multi-dimensional score breakdown |
| Commute | warning | Google Maps directions vs home address |
Each tab is its own component so the panel hydrates lazily and the realtime patches scope to the touched tab.
Toolbar and modal stack
Toolbar.svelte and the toolbar modals under components/toolbar/modals/
provide the entry points for every workspace-wide configuration:
- AddJob, JobImport, Import — bring jobs into the workspace.
- CloudKeys, ai/ChainEditor — manage BYOK chains.
- Columns, Kanban, Visuals — configure the dashboard / kanban surfaces.
- Commute, Docs, Icons — workspace settings.
Each modal commits through the op catalog so the change syncs to other peers the same way a job-cell write does. See the toolbar-config-modals feature file for the contract.
Kanban view
KanbanBoard.svelte is the second projection over the same jobs. Phases come
from settings.kanbanPhases; dragging a card across phases dispatches a
job.update op so the dashboard's status column updates in real time.
Offline shell
service-worker.ts caches the app shell so a cold reload over flaky network
still paints the workspace. The service worker does not cache realtime data
— the workspace document arrives through the realtime channel — but it does
keep navigation, modals, and the editor reachable while waiting for the
relay.
Cloudflare Worker bindings
app.d.ts declares the SvelteKit Platform.env shape for +server.ts and
*.server.ts files: CV_DB (D1), CV_BUCKET (R2), RELAY_CF (service
binding), APP_MODE, JOBCACHE_* vars, ADMIN_TOKEN. Provider keys are
typed loosely because the canonical set lives in lib/domain and is mirrored
by wrangler.toml.
What this shell is not
- Not the CV/PDF generator. PDF rendering happens inside the CVL editor via the Typst WASM client. The dashboard table is the product.
- Not the place to add per-user state. Settings live in workspace sub-docs;
browser localStorage is only for cosmetic preferences (see
no-user-accounts.md). - Not the realtime broker. The Durable Object in
relay/cf/is. The UI is a client of that broker via the@cv/workspace-clientSDK.