Audit "apply high-value": extract four shared helpers into shared/application/ and rewire the editor stores (behaviour unchanged, existing specs are the gate): - action-state.ts: ActionState/SaveState (were duplicated in both brief stores). - history.ts: createHistory<T> (extracted from BriefStore's WP-27 undo/redo; WP-32 reuses). - debounced-save.ts: createDebouncedSave (the 600ms timer/PendingSave dance, was 2×+). - machine-remote-data.ts: machineRemoteData (the loading/failed/loaded→RemoteData switch, 3×). Each helper has a co-located spec. Deferred DDD findings (contracts/ inconsistency, a parse* traverse combinator, the 6× Seed boilerplate) are reported in the WP file, not built. npm run ci green; 323 tests (+13 helper specs); brief/org-template/stamdata specs unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
53 lines
2.6 KiB
Markdown
53 lines
2.6 KiB
Markdown
# WP-31 — Shared store helpers (audit: apply high-value)
|
|
|
|
Status: done
|
|
Phase: 7 — refinements
|
|
|
|
## Why
|
|
|
|
A code audit found real duplication across the editor stores. This WP extracts the four
|
|
highest-value shared helpers and rewires the stores to them (behaviour unchanged), and
|
|
**reports** the lower-value / riskier DDD items as deferred backlog. Extracting `createHistory`
|
|
here also unblocks WP-32 (stamdata undo) so it needn't copy-paste the brief pattern.
|
|
|
|
## Decisions (pre-made, don't relitigate)
|
|
|
|
- Extract into `shared/application/` (importable by every context; must not import back).
|
|
- Apply the four concrete extractions + reuse; **do not** chase the deferred DDD items in this
|
|
phase (bound the diff). Behaviour must be identical — the existing store specs are the gate.
|
|
|
|
## Files
|
|
|
|
- New (each with a co-located spec): `shared/application/action-state.ts` (`ActionState`/
|
|
`SaveState`), `history.ts` (`createHistory<T>`), `debounced-save.ts` (`createDebouncedSave`),
|
|
`machine-remote-data.ts` (`machineRemoteData`).
|
|
- Rewired: `brief/application/brief.store.ts` (all four), `brief/application/org-template.store.ts`
|
|
(types + debounced-save + remote-data), `beheer/application/stamdata.store.ts` (remote-data).
|
|
|
|
## Acceptance criteria
|
|
|
|
- [x] `ActionState`/`SaveState` defined once; both brief stores import them.
|
|
- [x] `createHistory` backs brief undo/redo (identical semantics; specs pass).
|
|
- [x] `createDebouncedSave` backs both brief stores' autosave, integrating `PendingSave`.
|
|
- [x] `machineRemoteData` backs the RemoteData projection in all three stores.
|
|
- [x] `npm run ci` green; all pre-existing store specs still pass (no behaviour change).
|
|
|
|
## Deferred (reported, not built) — audit findings for a later WP
|
|
|
|
- **`contracts/` folder inconsistency:** only `beheer/` + `registratie/` have a `contracts/`
|
|
folder; `brief/`/`herregistratie/`/`auth/` declare wire DTOs inline in adapters. Decide whether
|
|
inline DTOs are a sanctioned exception or should be normalized.
|
|
- **`parse*` traverse combinator:** ~35 `parse*` boundary fns repeat an array-parse-and-collect
|
|
shape; a shared `traverse`/`parseAll` `Result` combinator would collapse the common idiom.
|
|
- **`Seed { state }` msg boilerplate:** the `Seed`/`return m.state` pair repeats in 6 machines —
|
|
cheap and per-machine typed; extract only if it earns its keep.
|
|
|
|
## Out of scope
|
|
|
|
- The deferred items above (this WP only applies the four extractions).
|
|
|
|
## Risks
|
|
|
|
- Behaviour drift in the central stores — mitigated: the extractions are 1:1 with the originals
|
|
and gated by the existing brief/org-template/stamdata specs (all green).
|