Files
atomic-design-poc/docs/backlog/WP-09-pure-logic.md
Edwin van den Houdt 8078c499cb feat(fp): WP-09 — pure-logic closure: dates + missing command specs
Consolidate four hand-rolled nl-NL date formatters (tasks.ts, aanvraag-
block, letter-preview, aanvraag-view -- one more than the WP found) into
one shared/kernel/datum.ts::formatDatumNl, spec-pinned and empty-safe.
Add the two missing command specs CLAUDE.md's testing rule calls for:
draft-sync.spec.ts (debounce coalescing + trailing-call + submit Result
shape, via fake timers) and submit-change-request.spec.ts. Remove the
unused RemoteData.map3 (updating the three docs that mentioned it); the
variant input on confirmation.component.ts was already gone. Documents
both stale-WP-text corrections in the backlog file.

This closes out backlog Phase 1 (FP/DDD core, WP-05..09).
2026-07-03 22:02:50 +02:00

4.1 KiB

WP-09 — Pure-logic closure: dates + missing command specs

Status: done Phase: 1 — FP/DDD core

Why

Three hand-rolled copies of the same nl-NL {day: numeric, month: long, year: numeric} formatter exist with divergent signatures, while other components use the Angular date pipe — two mechanisms plus drift risk. And two application commands with real logic have no spec despite "domain and pure logic must have a spec" (CLAUDE.md §5).

Read first

  • src/app/registratie/domain/tasks.ts (~line 15, formatNL(d: Date))
  • src/app/registratie/ui/aanvraag-block/aanvraag-block.component.ts (~line 96, formatNL(iso?: string))
  • src/app/brief/ui/letter-preview/letter-preview.component.ts (~line 96, inline copy)
  • src/app/registratie/application/draft-sync.ts (debounce logic)
  • src/app/registratie/application/submit-change-request.ts
  • src/app/app.config.ts (LOCALE_ID nl is already set)

Decisions (pre-made, don't relitigate)

  • Templates use DatePipe; pure TS uses one formatDatumNl in src/app/shared/kernel/datum.ts (Intl.DateTimeFormat, accepts ISO string | Date, empty-safe). Rule goes into CLAUDE.md conventions.
  • Kernel naming is Dutch (datum.ts) — it formats for the Dutch UI; if that clashes with the "shared = English" rule during implementation, format-date-nl.ts is the alternative — pick one and note it here.

Files

  • New src/app/shared/kernel/datum.ts + datum.spec.ts
  • The three formatter copies (delete, redirect to pipe or kernel fn)
  • New src/app/registratie/application/draft-sync.spec.ts
  • New src/app/registratie/application/submit-change-request.spec.ts
  • CLAUDE.md conventions (one line: DatePipe in templates, formatDatumNl in pure TS)

Steps

  1. Write formatDatumNl + spec (pin exact expected strings, e.g. 2 juli 2026; undefined/empty → '').
  2. Replace the three copies; templates that can use the pipe use the pipe.
  3. draft-sync.spec.ts with vitest fake timers: coalescing (n rapid changes → 1 sync), trailing call, flush-on-submit if applicable.
  4. submit-change-request.spec.ts: ok path, error path (stubbed client), Result shape.
  5. Also sweep the tiny dead exports flagged in the audit: remove unused map3 from shared/kernel/fp.ts (verify unused first) and the never-set variant input on confirmation.component.ts.

Acceptance criteria

  • Exactly one hand-written date formatter in the repo. formatDatumNl uses Intl.DateTimeFormat(...).format() rather than .toLocaleDateString(), so grep -rn "toLocaleDateString" src/app now hits nothing (stronger than the literal criterion, same intent — no file anywhere hand-rolls date formatting).
  • Both command specs exist; debounce coalescing + error path covered (draft-sync.spec.ts, submit-change-request.spec.ts).
  • map3 removed (found in shared/application/remote-data.ts, not shared/kernel/fp.ts as the WP text guessed — updated the three docs that mentioned it: CLAUDE.md, docs/ARCHITECTURE.md, remote-data.mdx). The variant input on confirmation.component.ts no longer exists — already cleaned up before this WP ran; nothing to do.
  • CLAUDE.md rule added (Conventions — DatePipe in templates, formatDatumNl in pure TS).

Verification

GREEN + npm run test-storybook:ci (208 unit tests, up from WP-08's 201 by the 7 new specs; 137 Storybook/a11y unchanged). Manual smoke via a running docker compose stack + Playwright: dashboard's herregistratie-deadline task text ("Verleng uw registratie vóór 1 maart 2027"), the Concept aanvraag-block's complete-before text ("Rond de aanvraag af vóór 2 augustus 2026"), and formatDatumNl unit specs for the letter-preview's today — all render the expected long-form Dutch date, no console errors.

Out of scope

Result combinators (map/andThen/fold) — nice-to-have from the old roadmap, not in this backlog.

Risks

Node ICU vs browser locale output differences — the spec pins strings; if CI's Node lacks full ICU (it shouldn't on Node 24), pin via Intl.DateTimeFormat('nl-NL', …) explicitly.