# WP-08 — One store idiom + machine naming + TEA MDX Status: done Phase: 1 — FP/DDD core ## Why Docs (`docs/fp-tea-atomic-design.md`, ARCHITECTURE §2c) teach `createStore` as THE wiring, but the wizard pages hand-wire `signal(model)` + local `dispatch()` — juniors see two idioms and copy the wrong one. Machine naming also drifts: `change-request.machine.ts` exports bare `State`/`Msg`; `upload.machine.ts` exports `reduceUpload`/`initialUpload`. ## Read first - `src/app/shared/application/store.ts` (`createStore`) + its spec - `docs/fp-tea-atomic-design.md` Part on TEA-in-Angular - All `*.machine.ts` files (6) and their UI wiring sites (wizard components/pages) ## Decisions (pre-made, don't relitigate) - **`createStore` is THE idiom** — migrate the hand-wired pages to it. One shape everywhere is the teachability win; the migration is ~5 lines per page. - Naming convention (goes into CLAUDE.md §3): - State/Msg types are context-prefixed: `ChangeRequestState`, `ChangeRequestMsg` (rename the bare ones; other machines already comply). - A top-level machine exports `initial` + `reduce`. - A **composable sub-machine** (embedded in a parent model) keeps prefixed value exports: `initialUpload`/`reduceUpload` **stay** — prefixing avoids alias noise at the composition site. ## Files - `src/app/registratie/domain/change-request.machine.ts` (+ spec + consumers) — rename - Wizard UI wiring: `registratie-wizard.component.ts`, `intake-wizard.component.ts`, `herregistratie-wizard.component.ts` (whichever hand-wire `signal`+dispatch) → `createStore` - `CLAUDE.md` §3 — the naming + wiring convention - New `src/docs/machines.mdx` — title `Foundations/State Machines (TEA)` ## Steps 1. Rename `State`/`Msg` in change-request (mechanical; lint/build finds consumers). 2. Swap hand-wired model signals for `createStore(initial, reduce)` in the wizard components; templates keep dispatching messages — no template changes expected. 3. Write the convention into CLAUDE.md §3 (including the sub-machine rule). 4. MDX page: Model/Msg/reduce, commands-outside-reducers, `createStore` wiring, the naming rules — linking `herregistratie.machine.ts` as the worked example. ## Acceptance criteria - [x] `grep -rn "export type State\b\|export type Msg\b" src/app` → empty. - [x] Every machine consumer wires via `createStore`; no local `signal(model)` + hand-rolled dispatch remains. - [x] Convention documented in CLAUDE.md; MDX renders. - [x] All machine specs pass unchanged (reducers untouched). ## Verification GREEN + `npm run test-storybook:ci` (197 unit / 137 Storybook, unchanged from WP-07 — this WP touched no reducer logic). Manual smoke via a running `docker compose` stack + Playwright: the change-request form (the renamed machine) submitted end-to-end with a referentie shown; the intake wizard stepped forward and back; the herregistratie wizard loaded its first step — no console errors across all three. ## Deviation from the original plan **Step 2 (migrate wizard pages off hand-wired `signal(model)`+`dispatch()` onto `createStore`) turned out to already be done.** `registratie-wizard.component.ts`, `intake-wizard.component.ts`, `herregistratie-wizard.component.ts`, and `change-request-form.component.ts` all already wire `createStore(initial, reduce)` — confirmed both by reading each file and by `git log -p` on `registratie-wizard.component.ts`, which shows `createStore` present since the file's introduction. `grep -rn "= signal<.*State>\|= signal(init" src/app` (excluding specs) turns up nothing outside `store.ts` itself and `brief.store.ts`'s two unrelated transient-state signals (WP-07). The WP's "Why" section was accurate for an earlier snapshot of the codebase but stale by the time this WP ran — only the `change-request.machine.ts` naming fix (Step 1) and the CLAUDE.md/MDX documentation (Steps 3–4) had real work left. ## Out of scope Changing reducer logic or messages; store specs for root stores (they're covered where logic exists). ## Risks Rename ripple — purely mechanical; reducer specs are the net.