c9a1e195fe3de905ae2b4056ce3fcf76af97448e
1 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7ee7b2dadf |
docs(adr-0023): charts and dashboards — d3 + observable plot (#170)
## Summary
Records the decision to use **D3 + Observable Plot**, wrapped in a new `libs/shared/charts/`, as the chart toolkit shared by `portal-shell` and `portal-admin`. ADR-only — implementation lands as the next chantier(s).
This is staged as a 3-PR chantier per the agreed plan:
| PR | Périmètre |
| --- | --- |
| **PR 1 (this one)** | ADR-0023 — decision + a11y contract + bundle plan. |
| PR 2 | `libs/shared/charts/` foundations + 3 starter components (`<lib-bar-chart>`, `<lib-donut-chart>`, `<lib-stacked-bar-chart>`). |
| PR 3 | Integration on the `/audit` page — daily-volume bar + outcome-breakdown donut + event-type-over-time stacked bar. |
## What lands
### [`docs/decisions/0023-charts-d3-observable-plot.md`](docs/decisions/0023-charts-d3-observable-plot.md)
Full MADR 4.0.0 record. Highlights:
- **Choice**: D3 + Observable Plot, both from Mike Bostock / Observable Inc., both MIT, both past 1.0. Plot covers ~80 % of standard charts in declarative one-liners; D3 stays the escape hatch for bespoke viz (heatmap, sankey, …) inside the same lib.
- **Why not D3 alone**: ~250 LOC per chart × 4-5 types × a11y discipline = sustained code investment before the first dashboard ships.
- **Why not ECharts / Chart.js**: 600 KB minified + canvas-rendered + an `aria` plugin afterthought (ECharts), or narrower vocabulary + brittle dark-mode (Chart.js). Both furthest from the Angular-Signals-zoneless idiom the rest of the workspace runs on.
- **A11y contract** is baked into `_internal/` (palette, tabular fallback, SVG `<title>` / `<desc>` builders) so every chart inherits WCAG 2.2 AA + AAA-targeted compliance from the lib, not from contributor discipline. Six commitments, each unit-tested per chart component.
- **Bundle plan**: ~65 KB gzip added to a chart-bearing lazy chunk (d3 modules tree-shaken + Plot + thin wrapper) — well under [ADR-0017](docs/decisions/0017-performance-budgets-lighthouse-ci.md)'s 100 KB cap.
- **Component contract**: every `<lib-*-chart>` exposes the same Signal-based input shape (`[data]`, `[caption]`, `[description]`, `[ariaLabel]`, `[colorScheme]`) regardless of whether Plot or raw D3 powers the rendering.
### [`docs/decisions/README.md`](docs/decisions/README.md)
ADR-0023 added to the index table.
### [`CLAUDE.md`](CLAUDE.md)
- "Architecture (recorded in ADRs)" gains a "Charts + dashboards" bullet describing the lib + a11y baseline + bundle posture.
- "Repository status" bumps the ADR range to `0001 → 0023`.
- "Still on the roadmap" gains the charts implementation entry pointing at this ADR.
## Notes for the reviewer
- **Why honour the user's D3 preference rather than recommend pure ECharts?** D3 (and by extension Plot) is the closest match to the project's tech bar ("stable, recognized, battle-tested") for data-viz on the web; it's also the user's stated preference, and Plot's higher-level layer eliminates the "250 LOC per chart" cost that would otherwise push us toward an alternative. The ADR explicitly walks through ECharts + Chart.js as runners-up so future challengers see the trade-offs we chose against.
- **Why a single shared lib rather than per-app charts?** Both SPAs (portal-shell + portal-admin) will host dashboards. The chart vocabulary, a11y contract, palette, and theme integration are identical between the two — duplicating into app-local code would invite drift. The lib stays at `libs/shared/charts/` next to `libs/shared/ui/`.
- **Why the `_internal/` folder for cross-cutting code?** Single source of truth for the colour palette and the a11y plumbing. A lint rule (added in PR 2) will ban consumers from importing `d3-scale-chromatic` directly so the colour-blind-safe palette stays the only path.
- **Why no ADR amendment to ADR-0016 / ADR-0017?** Both are binding constraints, not superseded. The new ADR operationalises both for the chart surface; cross-references in the "Related ADRs" section make that explicit.
## Test plan
- [x] ADR validates as MADR 4.0.0 (frontmatter, section order, tag vocabulary).
- [x] No code touched — lint / test / build matrix unaffected.
- [x] `docs/decisions/README.md` index updated in the same change per the [ADR conventions](docs/decisions/README.md#conventions).
- [ ] Review for trade-off accuracy: are the bundle estimates fair? Is the "Plot covers ~80 % of standard charts" framing defensible against the user's mental model of D3?
- [ ] Implementation chantier (PR 2) lands directly behind this if accepted: `pnpm add -w d3 @observablehq/plot @types/d3`, `libs/shared/charts/` scaffold via `pnpm nx g @nx/angular:library --name=shared-charts --directory=libs/shared/charts --standalone=true --unitTestRunner=vitest-analog --tags="scope:shared,type:shared" --no-interactive`, then the 3 starter components.
## What's next
If accepted as-is, PR 2 (lib foundations + 3 starter components) follows. If a reviewer wants to push back on D3-vs-ECharts or on the a11y contract's strictness, this is the right PR to surface that — no implementation has started.
---------
Co-authored-by: Julien Gautier <julien.gautier@apf.asso.fr>
Reviewed-on: #170
|