One-time prettier --write so the new format:check CI gate starts green. .prettierignore excludes generated (api-client.ts, documentation.json), vendored (public/cibg-huisstijl), and backend (dotnet format owns it). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2.3 KiB
2.3 KiB
name, description
| name | description |
|---|---|
| new-feature | Add a feature (screen, flow, capability) to this Angular SSP following the house pipeline — domain first, then infrastructure, application, UI last. Use whenever building anything user-facing that has business rules or data. |
New feature (the pipeline)
Every feature is built inward-out. Never start with the component.
Steps
-
Domain (
<context>/domain/, pure TS, no Angular imports — lint-enforced)- Data types + pure rules. Forms/wizards get a
*.machine.ts→ use the form-machine skill. - Raw input that must be valid → branded value object → use the value-object skill.
- Co-locate a
.spec.ts; test the pure functions directly, no TestBed. - Server-owned rules stay here only as reference impl + test, marked server-owned; the FE renders the server's decision (ADR-0001).
- Data types + pure rules. Forms/wizards get a
-
Infrastructure (
<context>/infrastructure/, the only layer that touches HTTP)- Read → screen-shaped endpoint + adapter → use the bff-endpoint skill.
- Write → command adapter returning
Result→ use the mutation-command skill.
-
Application (
<context>/application/)- Shared cross-page state →
providedIn: 'root'store exposingRemoteDatasignals. - Page-local flow state →
createStore(initial, reduce)from@shared/application/store, held in the component. - Side effects live in commands (
submit-*.ts), never in the reducer.
- Shared cross-page state →
-
UI last (
<context>/ui/)- A page is composition of existing blocks —
<app-page-shell>,<app-async>, atoms/molecules fromshared/ui. Adding a new building block is the exception → ui-component skill. - Templates dispatch messages, never mutate. Async data always renders through
<app-async>. - All copy via
$localizewith stable@@context.keyids. - Route: lazy
loadComponentunder theShellComponentparent inapp.routes.ts,canActivate: [authGuard]when protected.
- A page is composition of existing blocks —
Worked example
The intake wizard slice, end to end:
src/app/herregistratie/domain/intake.machine.ts(+ spec)src/app/herregistratie/infrastructure/src/app/herregistratie/ui/(wizard component + page)
Verify (GREEN gate)
npm run lint && npm run check:tokens && npm test && npm run build
cd backend && dotnet test # if the backend changed