Files
jobtrackingapp/docs/architecture/application-workspace.md
T
cesnimda 3a906b881e
CI and Deploy / test (push) Failing after 1m8s
CI and Deploy / deploy (push) Has been skipped
feat(workspace): unified application checklist (Phase 5 milestone 2)
Evolve the existing readiness workflow into one persisted, user-controlled
checklist rather than adding a second tracker.

ApplicationChecklistItem records only completion state and user intent. Each
default system item carries a stable SystemKey and an AutoSignal — the same
signal /readiness already computed — and re-syncs on every read: a satisfied
signal auto-completes the item, a reverted signal reopens it, and a manual tick
always wins. Users can add, reorder, dismiss and delete.

Readiness is refactored into a projection of the checklist (score = completion
percentage, completed/missing = live items by status). Its DTO shape and the
workflowSignal/reminders health view are unchanged, so no API contract breaks.

The workspace's next recommended action now comes from the first pending
checklist item in category priority order (preparation, submission, follow-up,
interview, custom), replacing the parallel ruleset — so the overview can never
recommend something already ticked off, and a user's own task can be next.

The table follows the established MariaDB-safe path: the scaffolded migration is
a no-op and the idempotent reconciler owns the DDL for both providers. Verified
on MariaDB 11 — auto_increment PK, varchar/datetime(6)/tinyint(1) columns, both
indexes inside the key limit, cascade delete, unique system key per application,
and NULL system keys not colliding for custom items.

329 backend tests, 94 frontend tests, type check, production build and both
Docker builds pass locally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 11:15:46 +02:00

9.0 KiB
Raw Blame History

Application Workspace (Phase 5)

Phase 5, Milestones 12 (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}/workspaceWorkspaceOverviewDto (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.

Milestone 2 moved this onto the checklist: the first pending checklist item, ordered by category priority (preparationsubmissionfollow-upinterviewcustom) 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}/checklistGET (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-upsFollowUpAt, 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 <Router> (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.
  4. Cover letter workflow. 8. Documents. 9. Interview preparation. 10. Dashboard improvements.