docs(adr-0023): charts and dashboards — d3 + observable plot
CI / scan (pull_request) Successful in 3m30s
CI / commits (pull_request) Successful in 3m48s
CI / check (pull_request) Successful in 4m1s
CI / a11y (pull_request) Successful in 3m7s
Docs site / build (pull_request) Successful in 3m24s
CI / perf (pull_request) Successful in 8m13s

Records the decision to use D3 + Observable Plot, wrapped in a new
`libs/shared/charts/` lib, as the chart toolkit shared by
`portal-shell` and `portal-admin`. Implementation lands as a
separate chantier (`pnpm add` + `libs/shared/charts/` foundations +
3 starter components + audit-page integration).

The user's original ask cited D3 directly. The ADR honours that
preference but pairs D3 with Observable Plot — the same team's
higher-level layer (Mike Bostock / Observable Inc.). Plot turns
"standard charts" (bar / donut / line / stacked-bar / scatter) into
~50 LOC per type instead of the ~250 LOC each that raw D3 would
take. The shared lib's component contract stays uniform whether the
underlying technique is Plot or raw D3 — `<lib-bar-chart>`,
`<lib-heatmap>`, all expose the same `[data] / [caption] /
[description] / [ariaLabel] / [colorScheme]` signal-based shape.

Accessibility is enforced at the lib level (not bolted on per
chart): SVG `<title>` + `<desc>`, `<details>`-based tabular
fallback, colour-blind-safe palettes (Viridis / Cividis for
sequential, ColorBrewer Set2 for categorical), AA-contrast text,
`prefers-reduced-motion` gating. Six commitments, each unit-tested
so a sloppy contributor can't drop one silently.

Bundle impact (~65 KB gzip for the v1 vocabulary loaded on a
chart-bearing lazy chunk) stays well under ADR-0017's 100 KB lazy-
chunk cap via per-`d3-*` module imports.

Considered + rejected:
* D3 alone — 250 LOC per chart × 4-5 charts × consistent a11y
  posture across them all = sustained code investment before the
  first dashboard ships.
* Apache ECharts — 600 KB minified + canvas rendering with an
  `aria` plugin afterthought + JSON-config idiom is the furthest
  from the Angular-Signals direction the workspace runs on.
* Chart.js — narrower vocabulary than Plot, canvas-rendered with
  weaker out-of-the-box a11y, dark-mode integration brittle.

CLAUDE.md and `docs/decisions/README.md` updated in the same
change. ADR-0017 (perf budgets) and ADR-0016 (a11y baseline) are
referenced as the binding constraints; this ADR doesn't supersede
either, it operationalises both for the chart surface.
This commit is contained in:
Julien Gautier
2026-05-16 21:22:41 +02:00
parent 6c42d4c232
commit aa87db4362
3 changed files with 174 additions and 1 deletions
+1
View File
@@ -66,3 +66,4 @@ ADRs are listed in numerical order. To slice by topic, filter on the `Tags` colu
| [0020](0020-portal-admin-app.md) | `portal-admin` — dedicated SPA for portal administration, sharing the existing BFF | accepted | `frontend`, `backend`, `security`, `infrastructure`, `process` | 2026-05-11 |
| [0021](0021-phase-2-security-baseline.md) | Phase-2 security baseline — helmet, CORS allowlist, double-submit CSRF, rate limiting, structured error envelope | accepted | `security`, `backend` | 2026-05-13 |
| [0022](0022-docs-site-vitepress.md) | Documentation site — VitePress + Mermaid plugin, separate static deployment | accepted | `process`, `infrastructure` | 2026-05-15 |
| [0023](0023-charts-d3-observable-plot.md) | Charts + dashboards — D3 + Observable Plot wrapped in `libs/shared/charts` | accepted | `frontend`, `accessibility`, `performance` | 2026-05-16 |