Prioritised backlog from a three-part analysis of the atomic-design + FP showcase: concrete P1-P3 items per track with file paths, teaching value, and effort. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8.2 KiB
Showcase roadmap
Prioritised backlog for making this POC a stronger teaching showcase for atomic design + FP in the UI — optimising for maintainability, speed, and low cognitive load for junior and senior developers.
How to read this
Each track below is a table of concrete items: Item · Where · Why · Effort · Priority. Nothing here is built yet — pick items off the top. Priorities: P1 = highest teaching-value-per-effort, do first; P2 = strengthens the showcase; P3 = backlog. Effort is a rough solo estimate.
This roadmap is deliberately scoped to three tracks (Storybook-as-curriculum, FP primitives, Enforcement depth). A fourth track — onboarding docs (GETTING-STARTED, GLOSSARY, layer-dependency diagram, ADR index) — was identified but de-scoped for now.
Current strengths (what NOT to touch)
The foundations are already exemplary and should be preserved as-is:
- Pure reducers / state machines —
*.machine.tsmodel illegal states away with tagged unions; effects live in commands, never inreduce. RemoteData<E,T>(src/app/shared/application/remote-data.ts) —map/map2/map3/andThen/fromResource/foldRemote, rendered via the<app-async>molecule.- Parse-don't-validate value objects (
src/app/registratie/domain/value-objects/) — branded types built only through aResult-returning parser. - Anti-corruption parsers at every DTO seam (
infrastructure/*.adapter.ts). - ESLint-enforced layer boundaries (
eslint.config.mjs): noany,domain/imports no Angular, cross-context direction locked. - Storybook — 96% story coverage, a11y addon + docs addon on, titled
Layer/Name. - Token linting (
npm run check:tokens) blocks hardcoded colours.
The gaps below are about teaching reach, not correctness.
Track A — Storybook as a curriculum
Storybook is the showcase vehicle, but today it renders isolated components with no
narrative. .storybook/main.ts already globs ../src/**/*.mdx and loads
@storybook/addon-docs, so MDX pages drop in with zero config.
| Item | Where | Why (teaching value / cognitive load) | Effort | Prio |
|---|---|---|---|---|
| Atomic-design primer (MDX) | src/docs/atomic-design.mdx |
The pyramid + the "each layer imports only below" rule, with a live composition chain of real components: button (atom) → form-field (molecule) → document-upload (organism) → page-shell (template). Links to the ESLint rules that enforce it. Gives newcomers the mental model before they read code. |
2–3h | P1 |
| Design-token gallery (MDX) | src/docs/design-tokens.mdx |
RHC colours, the --rhc-space-max-* spacing scale (with resolved px), typography; plus when to use a raw --rhc-* token vs. an --app-* wrapper from src/styles.scss. Answers the senior's "what's the actual value of --rhc-space-max-md?" and ties to check:tokens. |
2h | P1 |
| FP-in-the-UI primer (MDX) | src/docs/fp-in-ui.mdx |
A Storybook front door to the concepts already in src/app/showcase/concepts.page.ts and docs/fp-tea-atomic-design.md (RemoteData, machine, parse-don't-validate) so the component library and the FP guide cross-link instead of living apart. |
1.5h | P1 |
argTypes / controls |
high-traffic atom stories: button, text-input, radio-group, status-badge, alert (src/app/shared/ui/*/*.stories.ts) |
Lets devs explore every variant from the Controls panel instead of editing story code. Fastest "play with it" path for juniors. | 1.5h | P2 |
Anatomy story for async |
src/app/shared/ui/async/async.stories.ts |
Show all four states (Loading / Empty / Failure / Success) in one view — it teaches the exhaustive fold but doesn't currently display it exhaustively. | 45m | P2 |
play / interaction tests |
2–3 stories (button disabled-during-submit; form-field error announced via role="alert"; async retry calls reload()) |
Demonstrates behaviour, not just appearance, and doubles as regression cover. Feeds Track C's CI gate. | 2h | P2 |
| Shell story | src/app/shared/layout/shell/shell.stories.ts |
The only component with no story; a canvas showing the persistent header/footer completes the library. | 30m | P3 |
Track B — FP primitives
The pure core is excellent but under-demonstrates a few composition tools; learners currently hand-branch and reinvent them.
| Item | Where | Why (teaching value / cognitive load) | Effort | Prio |
|---|---|---|---|---|
Result combinators |
src/app/shared/kernel/fp.ts (+ new fp.spec.ts) |
Add map, mapErr, andThen, fold, getOrElse. Today only direct r.ok ? … : … branching exists — fine for one step, painful across a pipeline. Biggest single FP gap. Then refactor one real call site to show parse ▸ mapErr(localize) ▸ map(toDomain). |
1.5h | P1 |
| Value-object specs | postcode.spec.ts, uren.spec.ts, big-nummer.spec.ts next to src/app/registratie/domain/value-objects/*.ts |
The repo's own rule is "domain must have a spec," yet only email does. Cover normalisation ("1234AB"→"1234 AB"), boundaries, and invalid inputs. Closing this makes the rule credible and teaches value-object testing. |
1h | P1 |
| Property-based test example | one spec (e.g. Postcode normalisation idempotence, or the RemoteData.map functor-composition law); adds fast-check dev-dep |
Every current test is example-based. One law-based test shows how to catch edge cases you didn't enumerate. Flag: introduces a new dev dependency — justified because property testing is an explicit teaching goal. | 1h | P2 |
NonEmptyArray<T> helper |
src/app/shared/kernel/fp.ts; use for vraagIds / required upload categories |
Makes "at least one" a type rather than a runtime check — a crisp "make illegal states unrepresentable" lesson applied to collections. | 1h | P3 |
| Effect/command testability (note) | src/app/registratie/application/{draft-sync,submit-*}.ts |
Direction only, not built here: inject the HTTP effect so commands are unit-testable without a full component. Documents how to close the one untested layer. | — | P3 |
Track C — Enforcement depth
ESLint checks imports; several documented rules are otherwise only hoped-for. Turning them into machine-checked guarantees is itself a teachable "fitness function" pattern.
| Item | Where | Why (teaching value / cognitive load) | Effort | Prio |
|---|---|---|---|---|
| Architecture-fitness test | src/architecture.spec.ts + npm run check:architecture, wired into .github/workflows/ci.yml |
A vitest that scans domain/ for Angular/HTTP/RxJS imports and asserts cross-context direction. Belt-and-suspenders over ESLint, and a worked example of an executable architecture rule. |
2h | P1 |
| a11y as a CI gate | Storybook test-runner + axe (or vitest + axe on rendered atoms), added to ci.yml |
The a11y addon's checks are visible in the panel but not enforced. Gating them turns "we care about a11y" into a guarantee — high value for a design-system showcase. | 2–3h | P1 |
| Interaction tests in CI | run Track-A play tests via the Storybook test-runner in ci.yml |
Makes behavioural stories part of the pipeline, not just docs. | 1h | P2 |
| Domain coverage gate | vitest coverage threshold on domain/** |
Guarantees the "domain must have a spec" rule holds as the code grows. | 45m | P3 |
| Dependency-graph visual | madge script producing an SVG/JSON of the layer graph |
A generated picture makes the architecture graspable at a glance and catches accidental edges. | 45m | P3 |
Suggested sequencing
Do P1 across tracks, interleaved so each shows value early:
- [B]
Resultcombinators + value-object specs — small, self-contained, immediate. - [A] the three MDX pages — the visible "showcase" upgrade.
- [C] architecture-fitness test + a11y-in-CI — locks the guarantees in.
Then P2 (controls, anatomy/interaction stories, property test, interaction tests in CI). P3 items are backlog. None of this changes runtime behaviour or the public component API; it is additive teaching + enforcement.