Phase 5 — Dashboard System
Status: Shipped ✅ · Owner: Frontend Lead · Duration: 4 weeks · Gate: G5
1. Overview
Phase 5 builds the customisable dashboard system — the headline differentiator. Drag-and-drop layouts, a rich widget library drawn from every module, themable per tenant and per user, clickable navigation, and three first-class view modes: Standard (browser), TV (kiosk / wall display), and War Room (multi-panel ops view). Inspired by ThingsBoard's dashboard model but built specifically for SFMS data.
2. Objectives
- O5.1 — Drag-and-drop dashboard editor with grid snapping, resizing, and per-widget configuration.
- O5.2 — Widget framework that any module (existing or future) can register into.
- O5.3 — ≥20 production widgets at launch covering KPIs, charts, asset map, work-order pivot, telemetry live, alert feed, RAG chat, workflow status, image, embed, table, gauge, sparkline.
- O5.4 — Per-user dashboards (personal) + per-tenant dashboards (shared) with permission controls.
- O5.5 — Theme system (light / dark / brand) plus per-user accent + density.
- O5.6 — Three view modes: Standard, TV (auto-rotate panels, hidden chrome), War Room (multi-panel, multi-tenant if permitted).
- O5.7 — Click-through navigation from any widget to the relevant detail screen.
- O5.8 — Dashboard sharing (link with permission grants; embeddable iframe option).
- O5.9 — Templates library (start with a blank, FM ops, energy, executive summary, KTC-style).
3. Scope
3.1 In-scope
- Dashboard CRUD + versioning + revert.
- Widget framework (
Widgetcontract; manifest; props schema; data-source binding). - Drag-drop grid (react-grid-layout) with snap, resize, lock, copy/paste.
- Widget library (≥20 widgets — list below).
- Theme engine: light / dark / brand-tenant; user-level accent and density override.
- View modes: Standard, TV, War Room.
- Click-through routing.
- Share + embed.
- Templates library.
- Per-widget refresh cadence + data caching.
- SSE-bound live widgets (telemetry, alerts).
- Mobile read view (responsive collapse; full edit on desktop).
3.2 Out-of-scope
- Custom widget development by tenants (post-launch; needs sandboxing).
- Cross-tenant dashboards beyond War Room with explicit cross-tenant permission.
- Native mobile shell (PWA only in Phase 8).
4. Dependencies
- Phase 2 (auth, themes, shell) and Phase 4 (SFMS data and entities to populate widgets).
- Phase 3 (telemetry stream for live widgets).
5. Architecture & Design
5.1 Widget contract
export interface WidgetManifest {
id: string; // 'kpi.card', 'chart.timeseries', etc.
name: string;
category: 'kpi' | 'chart' | 'table' | 'map' | 'alert' | 'workflow' | 'ai' | 'media' | 'embed';
description: string;
propsSchema: ZodSchema;
dataSources: DataSourceDef[]; // describes the queries it needs
defaultLayout: { w: number; h: number };
modes: Array<'standard' | 'tv' | 'war-room'>;
}
export interface WidgetComponentProps<TProps> {
props: TProps;
data: any; // resolved by the runtime
ctx: WidgetCtx; // tenant, user, theme, refresh, isLive
}
A registry collects all widgets at boot. New widgets only require: manifest + React component + (optional) editor panel.
5.2 Dashboard model (Mongo)
type Dashboard = {
_id: ObjectId;
tenantId: string;
ownerId?: string; // null = tenant-shared
name: string;
description?: string;
theme: 'light' | 'dark' | 'brand' | string;
mode: 'standard' | 'tv' | 'war-room';
layout: { w: number; h: number; cols: number; rowHeight: number };
widgets: WidgetInstance[];
permissions: { roles: string[]; users: string[]; public?: boolean };
version: number;
history: DashboardVersion[]; // snapshots for revert
createdAt: Date; updatedAt: Date; createdBy: string; updatedBy: string;
};
type WidgetInstance = {
id: string; // local id
manifestId: string; // points to a manifest
layout: { x: number; y: number; w: number; h: number };
props: Record<string, unknown>; // passes propsSchema validation
refresh?: number; // seconds; null = manual / live SSE
};
5.3 Data binding
Each widget declares one or more DataSourceDefs. The runtime resolves them through:
- Query bindings — saved query over the API (telemetry, work-orders, assets, KPIs).
- Live bindings — SSE subscriptions filtered by the widget's params.
- Computed bindings — small expressions (jsonata or similar) computed client-side from upstream sources.
5.4 Theme model
- Light and Dark are baseline.
- Brand theme is per-tenant:
tenants.branding = { primary, accent, logo, fontFamily, radius, density }. - User overrides: each user can set accent + density (cosy / comfortable / compact).
- Persistence: dashboard records preferred theme; user record records personal overrides.
- All theming uses CSS variables; no hard-coded colors in widget code.
5.5 View modes
- Standard: full chrome (sidebar, top bar), editable.
- TV: chrome hidden, automatic refresh, auto-rotate between dashboards if a "playlist" is configured, full-screen, keyboard-shortcut to exit.
- War Room: multi-pane grid (configurable 2×2, 3×2, 4×3 etc.), each pane a dashboard, designed for ops centre / NOC wall. Optional cross-tenant view for managed-service operators with explicit consent.
5.6 Sharing & embedding
- Share link: stable URL with permission token; can require login (recommended) or be public read.
- Embed: iframe-friendly URL with optional theme override (
?theme=dark&hide=chrome); CSP allow-list maintained. - Public dashboards: tenants opt-in; only widgets in a "public-safe" allow-list render (no PII).
5.7 Widget library (launch set, ≥20)
| # | Widget | Category | Source |
|---|---|---|---|
| 1 | KPI Card | kpi | Computed / Query |
| 2 | KPI Trend (number + sparkline) | kpi | Telemetry / Query |
| 3 | Gauge | kpi | Telemetry |
| 4 | Line / Area Chart | chart | Telemetry |
| 5 | Bar Chart | chart | Query |
| 6 | Pie / Donut Chart | chart | Query |
| 7 | Heatmap | chart | Query |
| 8 | Histogram | chart | Query |
| 9 | Data Table | table | Query |
| 10 | Pivot Table | table | Query |
| 11 | Asset Map (geographic) | map | Asset / Location |
| 12 | Floor / Ceiling Plan (with markers) | map | Location + Asset |
| 13 | Alert Feed | alert | Live SSE |
| 14 | Work Order List | workflow | Query |
| 15 | Work Order Kanban | workflow | Query |
| 16 | Workflow Status (instance) | workflow | Workflow Phase 7 |
| 17 | AI Chat | ai | Phase 6 |
| 18 | AI Insight Card | ai | Phase 6 |
| 19 | Image / SVG | media | Static / URL |
| 20 | Iframe Embed | embed | URL |
| 21 | Markdown / Note | media | Static |
| 22 | Telemetry Live Tile | kpi | SSE |
| 23 | Calendar Mini | workflow | Query |
| 24 | Incident Counter | kpi | Query |
6. Detailed Specifications
6.1 API surface (Phase 5 additions)
GET /api/v1/dashboards
POST /api/v1/dashboards
GET /api/v1/dashboards/:id
PATCH /api/v1/dashboards/:id
DELETE /api/v1/dashboards/:id
POST /api/v1/dashboards/:id/versions (snapshot)
POST /api/v1/dashboards/:id/restore (from version)
POST /api/v1/dashboards/:id/share (create share token)
POST /api/v1/dashboards/:id/play (TV-mode playlist control)
GET /api/v1/widgets (manifest catalogue)
GET /api/v1/widgets/:id (single manifest)
GET /api/v1/dashboard-templates
POST /api/v1/dashboards/from-template/:id
6.2 Permissions added
dashboard.read dashboard.create dashboard.update dashboard.delete
dashboard.share dashboard.publish-public
dashboard.template.read dashboard.template.create
widget.register (system; for adding new widget kinds in deployments)
6.3 Performance budgets
- Dashboard render (cold) p95 < 3 s with 12 widgets.
- Live widget update lag p95 < 2 s after telemetry event.
- TV-mode rotation transitions < 250 ms.
- War-room with 4 dashboards × 12 widgets stays within 1.5 GB browser memory after 24h soak.
6.4 UX details
- Editor: left palette (widget categories), right inspector (selected widget's props + data sources), main canvas (grid). Undo / redo. Multi-select.
- Inspector forms generated from
propsSchema(Zod) viareact-hook-form+ zod resolver. - Click on a widget value → drill into the canonical record (asset/work-order/etc.).
- Templates picker on dashboard create.
- Keyboard shortcuts (documented in
?overlay). - Co-edit lock (one editor at a time per dashboard).
7. Implementation Tasks
Epic 5.A — Widget framework
- 5.A.1
Widgettypes + registry; manifest validator. - 5.A.2 Data-source resolver (query, live, computed).
- 5.A.3 Inspector generator from Zod schemas.
Epic 5.B — Editor
- 5.B.1 Grid with react-grid-layout (snap, resize, lock).
- 5.B.2 Palette + drag from palette to grid.
- 5.B.3 Inspector panel with live preview.
- 5.B.4 Undo / redo (history stack).
- 5.B.5 Versioning + revert UI.
Epic 5.C — View modes
- 5.C.1 Standard mode (default).
- 5.C.2 TV mode (chrome hidden, auto-refresh, playlist).
- 5.C.3 War Room mode (multi-pane shell + cross-tenant safeguard).
- 5.C.4 Fullscreen toggle + remote control endpoint for TV mode.
Epic 5.D — Theme system
- 5.D.1 Token tier (base) + tenant tier (brand) + user tier (overrides).
- 5.D.2 Theme switch with persistence.
- 5.D.3 Tenant settings UI (brand kit upload).
Epic 5.E — Widget library
- 5.E.1 Implement widgets #1–#24 (parallelisable across two devs).
- 5.E.2 Storybook coverage for every widget.
- 5.E.3 Per-widget defaults + sample data for Storybook.
Epic 5.F — Sharing / embed
- 5.F.1 Share token model + UI.
- 5.F.2 Embed route with optional theme params.
- 5.F.3 Public dashboards (opt-in, allow-list widgets).
Epic 5.G — Templates
- 5.G.1 Template service + admin CRUD.
- 5.G.2 Launch templates: Blank, FM Ops, Energy, Executive Summary, KTC Reference.
8. Acceptance Criteria
- AC5.1 — A user with
dashboard.createcan create a dashboard, drag in widgets, configure, save, and reload the same state. - AC5.2 — Per-user dashboard is private to that user; per-tenant dashboard is visible to all members with role grants.
- AC5.3 — Theme switch between light, dark, and brand applies instantly; user override persists.
- AC5.4 — TV mode runs on a monitor for 24 hours with auto-refresh and zero memory growth issue (soak test passes).
- AC5.5 — War Room shows 4 panels at once; one of them can be a different dashboard.
- AC5.6 — Clicking a value in a Work Order widget jumps to that work order detail.
- AC5.7 — Sharing a dashboard with a colleague (in or out of tenant per permission) works as designed.
- AC5.8 — Templates produce a working dashboard immediately, ready to demo on the KTC fixture.
9. Test Requirements
- Unit: ≥80% on widget framework + theme + view-mode logic.
- Integration: data-source resolution, share tokens, templates.
- e2e: build a dashboard end-to-end; switch view modes; share + open as recipient; theme switch.
- Visual regression: per widget, per theme (Chromatic or Playwright snapshots).
- Performance: cold-load + interaction budgets.
- Soak: TV-mode 24h on a real display (or scripted browser).
- Accessibility: every widget keyboard-navigable; colour contrast meets WCAG 2.2 AA.
10. Documentation Requirements
docs/dashboards/getting_started.md.docs/dashboards/widget_catalogue.md(one section per widget).docs/dashboards/themes.md.docs/dashboards/view_modes.md.docs/dashboards/sharing_and_embedding.md.- ADR-018: Drag-drop library choice.
- ADR-019: Chart library choices.
- Updated OpenAPI spec.
11. Sign-off Criteria (Gate G5)
- All Acceptance Criteria met.
- Product Owner accepts a live demo running the KTC Reference template populated with fixture data, in all three view modes.
- Frontend Lead, Product Owner, Design Lead sign
_gates/Gate_G5_signoff.md. - Tagged
phase-5-v1.0.
12. Risks & Mitigations
| Risk | L | I | Mitigation |
|---|---|---|---|
| Drag-drop performance with 20+ widgets | 2 | 3 | Virtualise off-screen widgets; defer chart paint until visible. |
| TV-mode memory leak over long soak | 3 | 3 | Soak test; per-widget unmount on rotation; cap browser cache. |
| Theme escape (hard-coded colours leak through) | 3 | 2 | Lint rule banning hex / rgb in component code outside tokens. |
| Inspector forms incomprehensible to non-tech users | 3 | 3 | Curated form copy, sensible defaults, examples per field. |