Files
jobtrackingapp/docs/redesign/phase-8

Phase 8 — Dashboard customisation

Starting baseline: ef94d579cbfec62d1ac38346f556f80276cee95a, verified clean on 21 October 2026. Direct remote codex/ui-redesign-phase4 matches. Work branch: feature/phase8-dashboard-customisation. No main merge, production operation, Phase 9 or Phase 10 is authorised here.

Design and scope

The owner's complete Phase 8 brief authorises autonomous implementation of visibility, ordering, supported sizing, account persistence and reset. Extend the existing DashboardView report owner; retain every metric, source link, period, loading/error boundary and independent Analytics consumer. Administration is unchanged. Use MUI, PageSection, confirmation/toast, existing native drag reorder and explicit move buttons. No dependencies or dashboard framework.

One canonical ordered widget list renders with CSS grid: one column below md, two above it; full-width spans both. Summary supports full-width only. All other widgets support standard and full-width. No fixed content heights, dense grid packing or CSS-only visual reordering. DOM order is reading order. Mobile retains the saved width but renders every widget in one column.

Editing is an explicit draft with immediate preview and a labelled management list. Save awaits server acknowledgement, Cancel discards with confirmation, reset replaces only the draft after confirmation. Loading preferences must not allow overwriting unknown server settings. Failed saves retain the draft; 409 offers explicit reload of the latest layout before reapplying changes. Disable mutation controls while saving. Warn on route navigation and unload with dirty drafts. Restore focus after edit exit and announce ordering changes.

Widget catalogue

All widgets are personal/owner-scoped, default visible, available to any authenticated account. These are existing report sections, not new metrics. Empty account guidance and onboarding remain outside the configurable list. Minimum width is the responsive single-column content area (tested down to 320px viewport); standard desktop columns use minmax(0, 1fr), wrapped text and fluid charts/tables.

Position Stable ID Display / purpose Existing data owner Default size Content states
1 cards Summary cards / tracked jobs, dated applications, current interviews/offers stats full Summary loading/error shared; no fabricated counts
2 attention Needs your attention / existing workflow actions reminders standard Summary boundary; explicit nothing due
3 funnel Current pipeline / canonical stages and raw status links stats + analytics-overview standard Summary boundary; no pipeline data
4 activity Application activity / existing monthly applications and responses analytics full Independent trends boundary; window-empty, exact values table
5 stageAge Current stage age / occupancy medians analytics-overview standard Summary boundary; unavailable sample explained
6 sources Recorded response by source / sample denominators analytics-overview standard Summary boundary; unavailable sample explained
7 salary Salary insights / separate currency and period samples analytics-overview full Summary boundary; unavailable sample explained
8 companies Top companies by activity / exact filtered destinations analytics-overview standard Summary boundary; companies-empty
9 skills Job tags / all-time counts and independent period trends tags + tag-trends standard Trends boundary; tags/trend-empty, exact table

The prior five IDs and hidden choices are preserved. Existing non-configurable sections receive stable IDs. Future unknown IDs are never rendered. Missing widgets in a saved version are appended hidden so a new release does not unexpectedly rearrange a user's visible dashboard. Legacy local flags are used only while the account has no saved layout, and become authoritative on the first explicit Save. Other devices without that old local data receive defaults until Save; no claim is made that prior local data already synced.

Persistence contract

Extend the existing account preference owner (ApplicationUser) with nullable layout JSON and a default-zero revision, using an additive migration. No generic settings table or unrelated account overwrite. GET/PUT /api/auth/preferences/dashboard use local account authentication and derive the owner from the principal, never a supplied account ID. Response/request: {version: 1, revision, widgets: [{id, visible, size}]}. Empty widgets with revision zero denotes an unsaved account. Every successful save increments revision atomically with a conditional SQL update. A stale revision returns 409; simultaneous first saves cannot overwrite each other. JSON is bounded and validated, duplicate IDs and unsupported versions rejected, unsupported sizes normalised/rejected safely. No HTML, data query, job data or administrator statistics is accepted.

SQLite and MariaDB use provider-neutral EF mapping and conditional updates. Explicitly check the existing SQLite startup schema reconciliation/migration infrastructure and the complete migration chain. Legacy accounts gain no layout until first Save. Language, notifications, profile, security stamps and all job/document data remain unchanged.

Adding or changing widgets later

Add a stable ID to both src/dashboardLayout.ts and the backend DashboardLayout allowlist, supply EN/NB titles and the existing report/data owner, then prove allowed widths, empty/error states and ownership. Do not recycle an ID for another meaning. Existing saved layouts append missing known IDs hidden; unsaved accounts receive catalogue defaults. Unknown stored IDs are ignored on read and rejected on write, so preserving metadata across an incompatible client requires a schema-version increment. Future versions are read-only in an older client and cannot be downgraded by its PUT. A genuine rename/removal needs an explicit versioned ID migration and regression proof; there is no speculative alias framework. Feature availability must remain enforced by the data endpoint, independently of layout metadata.

Risk and dependency register

  • Phase 7 is CONDITIONAL GO, not unconditional release acceptance. Read final acceptance and handoff.
  • The historical save failure includes proven DELETE-mode reader/writer contention; P7 enables WAL before reconciliation. Reuse that baseline and add actual layout persistence/concurrency evidence. WAL does not eliminate all writer contention; no retry-count workaround or permanent reliability claim.
  • Human screen reader, physical touch/software keyboard, complete real zoom/reflow, other browser/native output and production font checks remain outstanding.
  • MariaDB runtime is unverified unless a disposable instance is actually exercised; SQL/migration inspection is not runtime proof.
  • Production remains NO-GO: retained filesystem, independently verified off-disk backup/restore, ingress/configuration/schema, rollback, deployed identity and AI model gates are not cleared by this work. P5-13 stays withheld.
  • All 57 preservation groups retain the Phase 7 statuses (56 PARTIAL, C11 DEFERRED) until fresh finite evidence is reconciled. No whole-group closure is inferred.

Checkpoints and TODO

  • P8-00: baseline suites, catalogue, persistence and prerequisite review; commit/push plan.
  • P8-01: editing, visibility, draft/cancel, empty recovery, localisation; focused component tests and shared P8-01/02 checkpoint commit/push.
  • P8-02: existing drag helper, named move buttons, DOM ordering and discrete grid sizing; normalisation/focus tests and shared P8-01/02 checkpoint commit/push.
  • P8-03: additive account storage, validated endpoint, revision conflict, retry/reset/session isolation; backend/frontend integration proof and checkpoint commit/push.
  • P8-04: actual browser desktop/tablet/mobile, EN/NB, themes, keyboard, failures and axe; inspected captures and populated sizing regression; human qualifications retained; checkpoint commit/push.
  • P8-05: full backend1084/frontend917/browser360, separate23 contracts/56sidecar/2sizing/1performance, types/lint/build/security;57-group reconciliation and final decisions/handoff; acceptance checkpoint publication.

Implementation and verification plan

Use test-first changes: reproduce missing draft/cancel behaviour before replacing the immediate local menu; pin order/size normalisation before adding it; prove rejected stale revisions/ownership before enabling server saves. Scope reaches DashboardView, a typed layout catalogue/editor, EN/NB translations, existing Dashboard tests and browser consumers, ApplicationUser/EF migration/startup compatibility, the owner-only preference endpoint and its tests. Analytics and administration consumers receive regression verification only.

Review focus: corrupt/oversized settings; simultaneous first saves; delayed acknowledgements after identity disposal; legacy hidden choices; route cancellation/focus after list movement. Evidence must distinguish real HTTP/storage from mocked UI responses, native browser emulation from physical devices, and source inspection from provider execution.

Baseline commands: dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --configuration Release --no-restore; npm test -- --runInBand. Runtime uses the pinned SDK at C:\Users\Connor\.dotnet\dotnet.exe when needed. Raw run output is under .artifacts/phase8/; portable checkpoint reports record actual totals, commands and limits.