Skip to content

Dashboard Framework Research

This page records why the dashboard is built on the stack it is built on. It is a framework evaluation, not user research: no operator study, interview round or usability test underlies it, and no page should cite it as though one did.

The Stack

Layer Choice Responsible for
Framework React 19 Rendering and component model
Components shadcn/ui, vendored into web/src/components/ui/ Every shared primitive the dashboard composes pages from
Accessibility primitives Base UI Dialog, popover, checkbox and the other headless behaviours the primitives wrap
State Zustand Client stores fed by REST reads and WebSocket events
Command palette cmdk-base (the cmdk port on Base UI Dialog) Global Cmd+K search and page-local scopes
Animation Motion Spring and tween transitions, layout animation, reduced-motion detection
Charts Recharts Sparklines, trends, forecast, and budget charts
Graph canvases @xyflow/react, @dagrejs/dagre, d3-force Workflow editor, org-chart hierarchy layout, communication view
Drag and drop @dnd-kit Agent reassignment, team reordering
Icons lucide-react Every icon in the dashboard
Build Vite, TypeScript Development server, bundling, type checking

Data fetching is deliberately not on that list. The dashboard has no query library: reads go through the typed API client in web/src/api/, and anything that needs to refresh without a WebSocket channel uses the project's own usePolling hook, which carries a skipIfFresh gate so a page already fed by a live channel does not pay for the same state twice.

Alternatives Considered

Criterion React + shadcn/ui Vue + PrimeVue Svelte HTMX
Component ownership Copy-paste model: the components live in this repository and are edited in place npm dependency; the library owns the components and an update can change them Own components, smaller ecosystem to draw them from Server-rendered, minimal client components
Keyboard-first UX cmdk-base, a maintained command-palette primitive No established solution No established solution Not applicable
Animation Motion: spring physics, layout animations, gesture support Vue Transition, with no physics-based library at the same level Built-in transitions, limited physics Not applicable
Accessibility primitives Base UI: headless, composable, WAI-ARIA behaviours ARIA support inside the component library Fewer headless options Server-rendered
TypeScript experience Descriptive errors, which matters for machine-written code Good, with less descriptive JSX errors Good Minimal TypeScript involvement
State management Zustand: framework-agnostic, small API surface Pinia, Vue-specific Runes, built in Server state
Ecosystem Largest, so a niche need usually has a maintained answer Large, smaller than React's Growing Niche
Visualisation Recharts, @xyflow/react ECharts, VueFlow D3-based options Server-rendered charts

Why This One

Component ownership decided it. The copy-paste model means the dashboard owns every component: no upstream release can change the UI, and a primitive is customised in place rather than fought with. That matters more here than in a typical application, because the design system is enforced by a gate (scripts/check_web_design_system.py) that can only enforce rules over components the repository actually holds.

Keyboard-first interaction is not decoration. The dashboard is an operator surface for a system that is supervised, not autonomous, so the operator is in the loop constantly and needs fast access to any page, agent, or setting. A maintained command-palette primitive was a real differentiator between the options.

Accessibility is composed in, not bolted on. Base UI supplies the behaviours (focus trapping, dialog semantics, roving focus) and the vendored primitives supply the styling, so an accessible dialog is the default rather than an achievement. The Storybook accessibility add-on fails a story on a WCAG violation, which only works because the components are local.

Machine-written code is a first-class consumer. Much of this dashboard is written by agents, and TypeScript diagnostics are part of the feedback loop they work against. More descriptive errors mean fewer wasted rounds.

See also the Tech Stack decisions table.

Reference Materials

Resource Location
Brand identity, voice rules, and visual rationale Brand & UX
Implementation specifications UX Guidelines
Page structure and navigation Page Structure & IA
Dependency manifest web/package.json