Files
jobtrackingapp/docs/redesign/phase-3/DASHBOARD_ARCHITECTURE.md
T
2026-09-10 18:15:05 +02:00

15 KiB
Raw Blame History

Dashboard architecture

ARC-04 / ARC-05; PRES-S01, PRES-S02, PRES-W02–PRES-W12, PRES-C05, PRES-A01–PRES-A03. New work: NEW-01, NEW-05, NEW-08, NEW-11 in Open decisions.

Existing implementation and honest metric meanings

DashboardView calls stats, analytics, analytics-overview, tags, tag-trends and reminders under /jobapplications. It persists five owner-local visibility flags: cards, activity, funnel, companies, skills. No order, resize, goal or server layout contract exists.

AnalyticsService, analytics controller and DTOs establish these constraints:

  • stats.active and overview.totalActive count non-deleted tracked jobs, including closed and pre-application statuses. They do not measure in-flight applications. total includes deleted rows.
  • The funnel counts jobs currently in each canonical stage. It is not a historical cohort conversion funnel. Unknown custom values may be absent from that canonical-stage series; byStatus retains raw values.
  • Monthly analytics selects jobs applied within a month-aligned window, then counts their dated responses in the displayed months. It is not all responses received in that period, and not an eventual response probability.
  • Source breakdown uses current Company.Source and includes prospects. Top-source/top-company lists are truncated; do not treat their sum as the whole population.
  • Time in stage is median current occupancy age, with fallback to DateApplied or SavedAt when a transition is unavailable. It is not completed-stage duration.
  • Median first response uses rows with both dates; averageDaysSinceApplied is application age, not response speed. Current calculations clamp negative durations; data-quality labeling must not pretend dates were verified.
  • Upcoming interview captions derived from “interview-prep” signals identify preparation work, not scheduled interviews.

These are source-backed semantic limitations (P3-O01 in Open decisions). Preserve access to current reports, but label them accurately during their scoped migration. No analytics implementation or retrospective data repair occurs here.

Default personal layout

Useful immediately: tracked-job summary; recorded response summary with denominator; current interview/offer counts; attention/follow-ups/deadlines; application activity; current pipeline distribution; companies and tags; onboarding when incomplete. Keep existing salary/stage/source details reachable from Analytics. New data-dependent widgets are absent until supported, never placeholder zeroes.

Suggested visual order: “Next actions” and key counts first, activity/pipeline next, companies/tags and details below. A new user sees real empty states with Add/import job and Review Career Profile. No sample jobs or fake success metrics. Users may hide any widget; if all are hidden show an intentional layout-empty state with Customize/Restore defaults.

Layout contract for later Phase 8

A small catalogue defines widget ID, localized title, supported sizes and data owner. Use CSS grid with discrete small/medium/wide spans; do not start with a dashboard framework or free-positioned canvas. Plain ordered IDs plus visibility and size metadata suffice; no stored HTML or career content.

Customize mode supports show/hide, drag/reorder plus Move earlier/later, size choices on suitable charts/lists, and Restore defaults with a clear confirmation. Changes give immediate preview; storage failure leaves usable content and a retry/message, never silently claims persistence. Unknown IDs are ignored safely without losing known entries; invalid sizes fall back to defaults. Preserve existing five hidden/visible choices when migrating; do not silently re-enable hidden widgets.

Use one logical order across breakpoints. Mobile has a single-column feed and move/hide controls; desktop width preferences remain saved but inactive on mobile. Charts have supported size ranges, metrics fixed height with wrapped labels. Reset affects only dashboard layout, not jobs, account preferences, goals or canonical profile.

Persistence decision OD-04: recommend owner-keyed device-local metadata first, matching current scope, clearly labelled “Saved for this account on this device.” Cross-device layout requires a separately tested server preference contract before Phase 8; do not claim localStorage syncs devices. Either option must validate owner from the active identity, dispose A's state on switch, handle corrupt/stale data and avoid storing content. Theme/density settings are separate; no generic preference blob that merges unrelated security controls.

Widget catalogue and data requirements

Availability: Existing = current endpoint/behavior with stated meaning; Derivable = fields exist, but a bounded owner-scoped aggregate or read composition is still needed; New data = required facts/contracts do not currently exist. No client N+1 fetch across every job to build global metrics.

ID / widget Availability and data source Definition / boundary / empty behavior
DW-01 Tracked jobs Existing: stats.active Non-deleted records; rename display accordingly, not in-flight applications
DW-02 Active applications Derivable: Status, DateApplied, IsDeleted Explicit applied active-stage mapping; exclude prospects/closed, unknown separate. Do not reuse DW-01
DW-03 Total recorded jobs / trash Existing: total/deleted Label deleted inclusion; trash link retains restore semantics
DW-04 Applications this week Derivable: DateApplied Distinct submissions in agreed local week; no SavedAt substitution; period/timezone gate
DW-05 Applications this month Existing monthly applied point Calendar month label; not rolling appliedLast30Days
DW-06 Applications last 30 days Existing: appliedLast30Days Rolling server-time period, labelled as such until timezone contract is settled
DW-07 Interviews Existing: current Interview stage “Jobs currently at interview”; not number of meetings or all-time interviews
DW-08 Upcoming interviews New data: scheduled interview start/end/timezone Do not infer appointment from Interview status, deadline or follow-up
DW-09 Offers Existing: current Offer stage Current recorded offers, link /offers; historical offer count needs events
DW-10 Rejections Existing: normalized current Rejected stage Current recorded outcome; neutral language, no failure badge
DW-11 Response rate Existing period series or source rates, different denominators Display exact cohort/window and responses/applied sample; no mixing overview and period denominators. No sample = “Not enough recorded data”
DW-12 Interview conversion Derivable with data-quality qualification: status events + application cohort Distinct applied jobs that reached Interview / submitted cohort; current Interview count is not this numerator
DW-13 Offer conversion Derivable with same historical cohort Distinct jobs reaching Offer / submitted cohort (explicit label); missing history shown, not fabricated
DW-14 Application funnel Existing canonical distribution Label “Current pipeline”; include Unknown/custom bucket when migrating. Historical conversion is separate NEW work
DW-15 Applications over time Existing analytics monthly points Applied counts, period/source subtitle and accessible values table
DW-16 Applications by status Existing byStatus Preserve custom/raw values, aliases and unknown labels
DW-17 Applications by sector New normalized sector coverage No reliable tracked-job sector dimension found; NAV listing data alone does not cover tracked history
DW-18 Applications by location Derivable JobApplication.Location Unknown explicit; raw text first, normalized municipality grouping needs a mapping contract
DW-19 Applications by source Existing source response summary; complete count needs aggregate Company.Source is mutable company-level provenance, not original job capture source; top six is not full breakdown
DW-20 Applications by role Derivable JobTitle Raw role/title distribution; normalized role families require taxonomy, not automatic AI classification
DW-21 Average response time Derivable DateApplied/ResponseDate Arithmetic mean over valid paired responses, show n; existing median offered separately, do not relabel it average
DW-22 Median first recorded response Existing overview median Available dated sample; no implication missing dates mean no response
DW-23 Time in pipeline stages Existing current occupancy medians Label current-stage age and fallback; completed durations/history trends need new aggregation
DW-24 AI match statistics Derivable per-job deterministic match output, aggregate missing Require score definition, profile/job version and scored sample; do not trigger generation on dashboard view
DW-25 Recent activity Job-scoped recentActivity/timeline exists; global read missing Bounded owner event feed, source links and safe summaries; monthly applications chart is not event history
DW-26 Deadlines Existing job deadlines/reminders Upcoming/overdue date-only semantics; full period read coverage must be declared
DW-27 Tasks Existing per-job checklist; cross-job aggregate missing Pending/done/dismissed, stable IDs; “Tasks due” awaits per-task due dates
DW-28 Follow-ups / attention Existing reminders/workflowSignal Keep existing reason/action links; feed includes more than overdue follow-ups
DW-29 CV usage Derivable CvVariant job link + package metadata, aggregate missing Current linkage separate from recorded submitted version. A download alone is not “used to apply”
DW-30 CV performance Future qualified historical join Submission cohort + frozen CV/version + outcomes, n and missing-data rate; correlation only; P2-D01 gate
DW-31 Recently edited CVs Existing library UpdatedAtUtc Bound list and safe editor links; not performance
DW-32 Weekly goals New optional goal preference Disabled until chosen, editable/disable/pause; no default quota. Completion uses valid DateApplied, never encouraging unsuitable applications
DW-33 AI recommendations Existing deterministic next steps; new AI aggregation/panel optional Label rule-based guidance honestly; user-invoked AI only, grounded reasons, hide/ignore, no implicit edits
DW-34 Companies Existing topCompanies Recorded activity and responses; top eight and unknowns disclosed
DW-35 Skills/tags and trends Existing tags/tag-trends Job tags, not the user's verified skills. tags does not consume a months parameter; label its actual period
DW-36 Salary insights Existing currency/period groups Preserve separate currencies/periods; no inferred FX conversion
DW-37 Work arrangement New consistent tracked dimension Imported description text alone is not a reliable remote/hybrid aggregate
DW-38 Interview/offer trends Derivable historical events with completeness limits Not current-stage counts plotted as historical outcomes; no synthetic transition dates
DW-39 Response/match trends Partial existing monthly responses; match history missing Define cohort vs events, scoring version and missing history before trend claims

Period controls must explain which widgets are all-time, current snapshot or selected-period. Do not put a global “this month” above unfiltered all-time data. Zero, unknown, loading, unauthorized/provider-unavailable and failed are distinct. No automatic polling/generation per widget beyond current service needs. Keyboard/data-table alternatives accompany every chart.

Separate aggregate admin dashboard

Propose /admin overview; retain /admin/users, /admin/audit and /admin/system. Current system page is operational diagnostics, not product analytics. Never compute product metrics by downloading individual profiles or the existing admin user table into a dashboard.

Candidate Current evidence Required implementation / honest limit
Registered users Identity users exist New authorized server count; define inclusion of pending/deleting accounts
New users by period ApplicationUser has no registration timestamp Reliable creation event/timestamp contract and historical coverage; do not infer from OAuth-linked dates
Active users Sessions exist, no agreed activity metric Define meaningful activity/time window/retention; active sessions are not active people
Total jobs tracked Admin system exposes operational counts Verify scope and deletion inclusion; new explicit aggregate endpoint for product meaning, not reuse diagnostic counts blindly
Interviews/offers recorded Job statuses/events exist Server aggregate with distinct job/event meaning and missing-history qualification
CVs created CvVariant timestamps exist Authorized count/time buckets; owner-scoped personal library is not admin aggregate
Documents generated Several artifact types/render paths exist Define successful persisted artifact vs PDF render/download/retry; no unified document counter today
AI usage Usage metering exists Aggregate actions/tokens/period/failures as supported; no prompts, responses or career facts
Common sectors No reliable shared sector dimension Future normalized dimension and privacy-safe grouping
Common locations/roles/technologies Job location/title/tags exist New bounded aggregate; use job metadata, not individual profile skill extraction
Subscription/trial metrics Stripe status fields/entitlements exist; no generic trial contract proven Define paid/active/cancelled periods from billing authority; never infer trials from Free accounts
Onboarding/adoption/churn/conversion Current checklist/UI alone does not supply product event funnel Future event/consent/retention definitions; no fabricated denominator

Privacy: aggregate-only responses, no owner IDs/names/emails/job descriptions/CV content. For sensitive breakdowns propose fixed coarse cohorts, minimum cell size 10 with complementary suppression, no arbitrary filters/drill-down that reconstruct smaller groups. This is a review proposal, not an anonymity guarantee. Totals/period differences and rare roles can still identify; evaluate release scope/retention before implementation. Support access remains separately authorized/audited and cannot be reached by clicking an analytics bar. Denial must be server-enforced even when admin navigation is hidden.

Admin dashboard work waits for OD-09's metric/privacy definition. Personal layout settings never affect aggregate scopes or admin operational controls.