Browse documents

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 (Widget contract; 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)

#WidgetCategorySource
1KPI CardkpiComputed / Query
2KPI Trend (number + sparkline)kpiTelemetry / Query
3GaugekpiTelemetry
4Line / Area ChartchartTelemetry
5Bar ChartchartQuery
6Pie / Donut ChartchartQuery
7HeatmapchartQuery
8HistogramchartQuery
9Data TabletableQuery
10Pivot TabletableQuery
11Asset Map (geographic)mapAsset / Location
12Floor / Ceiling Plan (with markers)mapLocation + Asset
13Alert FeedalertLive SSE
14Work Order ListworkflowQuery
15Work Order KanbanworkflowQuery
16Workflow Status (instance)workflowWorkflow Phase 7
17AI ChataiPhase 6
18AI Insight CardaiPhase 6
19Image / SVGmediaStatic / URL
20Iframe EmbedembedURL
21Markdown / NotemediaStatic
22Telemetry Live TilekpiSSE
23Calendar MiniworkflowQuery
24Incident CounterkpiQuery

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) via react-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 Widget types + 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.create can 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

RiskLIMitigation
Drag-drop performance with 20+ widgets23Virtualise off-screen widgets; defer chart paint until visible.
TV-mode memory leak over long soak33Soak test; per-widget unmount on rotation; cap browser cache.
Theme escape (hard-coded colours leak through)32Lint rule banning hex / rgb in component code outside tokens.
Inspector forms incomprehensible to non-tech users33Curated form copy, sensible defaults, examples per field.