# Application Workspace (Phase 5) > Phase 5, Milestones 1–2 (2026-07-19). The per-application workspace: what it is, what it deliberately > is not, and how it composes existing systems. Companion to `cv-builder.md`, > `ai-career-assistant.md`, `career-profile-model.md`. ## What it is A dedicated surface for one `JobApplication` at `/applications/{id}`, so an application is a place you work rather than a row you edit in a modal. Job tracking stays the product; the workspace is the application's home. **Core principle:** the user should never ask *"what do I do next?"* — the overview always answers it. ## What it is NOT The workspace **owns no data and duplicates none**. It is an aggregate read plus a navigation shell: | Section | Backed by (existing system) | |---|---| | Checklist | `ApplicationChecklistItem` — completion state only, seeded from the readiness signals | | CV | Phase 4 `CvVariant` — a lens over the master `CareerProfile` | | Analysis / Match / Interview | Phase 5 `AiWorkspacePanel` + `AiInteraction` history | | Documents | `Attachment` | | Communication | `Correspondence` | | Activity / Timeline | `JobEvent` | | Stage semantics | `JobPipeline` | No career data is copied into the application. Nothing in this feature writes to the master profile, a CV variant, or a cover letter. ## Backend `GET /api/jobapplications/{id}/workspace` → `WorkspaceOverviewDto` (`ApplicationWorkspaceController` + `ApplicationWorkspaceService`). One aggregate read instead of the page fanning out: role/company/location/salary, status + pipeline group, applied/deadline/follow-up dates, the attached CV variant (id, name, theme), cover-letter presence, document count, AI interaction count + last run, recent `JobEvent` activity, and the computed **next recommended action**. Read-only and tenant-scoped (`OwnerUserId`), returning 404 for another user's application. ### Next recommended action Milestone 2 moved this onto the checklist: **the first pending checklist item**, ordered by category priority (`preparation` → `submission` → `follow-up` → `interview` → `custom`) then the user's own ordering. `null` means nothing is outstanding. That means the overview cannot recommend something the user has already ticked off, a dismissed item never comes back as a recommendation, and a task the user added themselves can legitimately be the next action. There is no second ruleset to keep in sync. ## The checklist `ApplicationChecklistItem` — a **workflow guidance layer**, not a store of truth. It records only "is this step done, and does the user still want it". The CV still lives in `CvVariant`, documents in `Attachment`, history in `JobEvent`, follow-up in `JobApplication.FollowUpAt`. ### System items and auto-completion Each default item carries a stable `SystemKey` and usually an `AutoSignal` — the *same* signal `/readiness` already computed. On every read the service re-syncs: - signal satisfied + item pending → **done**, `IsAutoCompleted = true` - signal no longer satisfied + item was auto-completed → back to **pending** - a **manual** tick clears `IsAutoCompleted` and therefore sticks, even against the signal So "readiness says the CV is missing" and "the checklist says Prepare a CV is pending" cannot drift apart — they read the same state. The user always wins over the signal. | System key | Category | Signal | |---|---|---| | `review-job-details` | preparation | advert text present | | `complete-career-profile` | preparation | career profile with at least one experience | | `prepare-cv` | preparation | CV variant attached, or tailored CV text | | `review-cv-match` | preparation | *manual* | | `create-cover-letter` | preparation | cover letter present | | `attach-portfolio` | preparation | `HasPortfolio` | | `attach-supporting-documents` | preparation | at least one `Attachment` | | `save-application-answers` | preparation | saved answer draft in `Notes` | | `capture-recruiter-contact` | preparation | `Company.RecruiterEmail` | | `confirm-submitted` | submission | applied date set and out of the prospect stage | | `add-follow-up-reminder` | follow-up | `FollowUpAt` set | | `set-next-action` | follow-up | `NextAction` written | | `prepare-interview-notes` | interview | prep notes present, **or** not at an interview stage | | `research-company` | interview | *manual* | Seeding is idempotent per `(JobApplicationId, SystemKey)` — enforced by a unique index, so a re-read never duplicates. Custom items have a `NULL` `SystemKey`; both SQLite and MariaDB treat NULLs as distinct in a unique index, so a user can add as many as they like. Deleting a **system** item dismisses it (a hard delete would be undone by the next seed); deleting a **custom** item removes the row. Dismissed items leave the progress denominator entirely. ### API `/api/jobapplications/{id}/checklist` — `GET` (seeds + syncs + returns items and progress), `POST` (custom item), `PATCH /{itemId}`, `DELETE /{itemId}`, `PUT /order` (array of ids). Tenant-scoped on `OwnerUserId`; another user's application is a 404. ### Relationship to the other systems - **Not `JobEvent`** — the checklist is forward-looking intent; `JobEvent` is the append-only history. - **Not follow-ups** — `FollowUpAt`, `RulesEngine` and the reminder hosted service still own scheduling. The checklist only asks whether a follow-up exists. - **Not `Attachment` / `CvVariant`** — it reads their presence as a signal and stores nothing of them. ### Future AI suggestions An AI-suggested task is just a checklist row with `IsSystemGenerated = false` and no `AutoSignal`, created after the user approves it. Nothing in the AI path may create, complete or delete an item without approval — same rule as everywhere else (`ai-career-assistant.md`). ### Schema provisioning `ApplicationChecklistItems` follows the established MariaDB-safe path: the scaffolded migration (`20260719085904_AddApplicationChecklistItems`) is a **no-op**, and the table is created by the idempotent reconciler in `StartupInitializationExtensions`, which has correct DDL per provider. A SQLite-scaffolded migration would emit `TEXT` datetimes and a PK without `AUTO_INCREMENT` on MariaDB — the failure that crashed prod startup for the Phase 4 tables. Verified on MariaDB 11: `int AUTO_INCREMENT` PK, `varchar`/`datetime(6)`/`tinyint(1)` columns, both indexes inside the 3072-byte key limit, cascade delete from `JobApplications`, the unique index rejecting a duplicate system key, and NULL system keys not colliding. ## Frontend `ApplicationWorkspacePage` (`/applications/:id`) — a left nav plus a content pane, section selected by `?section=`, so a section is linkable and survives refresh. Reached from the job dialog's "Open application workspace" button. The dialog passes an optional `onOpenWorkspace` callback rather than calling `useNavigate` itself: `JobDetailsDialog` must stay renderable without a `` (several suites mount it standalone), so router context belongs to the caller. The Checklist section (`ApplicationChecklist`) groups items by category, shows a completion bar, and supports tick/untick, add, remove and reorder. System items are labelled "Detected" when a signal completed them, custom items "Yours". Every mutation re-reads, because only the backend's sync knows the real post-mutation state. Implemented now: Overview, Checklist, Job Details, and the sections that reuse an existing component (Analysis/Match/Interview → `AiWorkspacePanel`, Documents → `Attachments`, Communication → `Correspondence`). Sections owned by later milestones state their milestone instead of faking functionality. ## Relationship to `/readiness` `GET /{id}/readiness` keeps its DTO shape (`score`, `level`, `completed`, `missing`, `reminders`, `workflowSignal`) and still backs the dialog's Readiness tab — but as of Milestone 2 it no longer runs its own parallel checklist. It **projects** the persisted checklist: - `completed` / `missing` — the live (non-dismissed) items by status - `score` — the checklist completion percentage - `level` — Ready ≥ 80, Needs polish ≥ 60, otherwise Needs work - `reminders` / `workflowSignal` — unchanged; `BuildWorkflowSignal` remains the health/attention view So the division is: **the checklist is the workflow the user drives, readiness is the calculation and health indicator derived from it.** One system, two projections. ## Extension points - **New section**: add to `WORKSPACE_SECTIONS` and render it; nav is data-driven. - **New next-action rule**: add one clause to `ApplicationWorkspaceService.NextStep` — ordered, so position is the priority. - **More overview data**: extend `WorkspaceOverviewDto`; the page reads one payload. ## Milestones 1. ✅ Workspace foundation — route, nav shell, aggregate overview, next recommended action. 2. ✅ Checklist and progress tracking — persisted items, auto-completion from the readiness signals, custom items, reordering, dismissal; readiness refactored into a projection of it. 3. Timeline and activity history. 4. Job analysis. 5. Career matching. 6. CV integration. 7. Cover letter workflow. 8. Documents. 9. Interview preparation. 10. Dashboard improvements.