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>
61 lines
2.2 KiB
Markdown
61 lines
2.2 KiB
Markdown
---
|
|
name: mutation-command
|
|
description: Add a write/submit operation — infrastructure adapter method plus an application command factory returning Result, keeping the reducer pure. Use for any POST/PUT/DELETE a form or action triggers.
|
|
---
|
|
|
|
# Mutation command
|
|
|
|
Reducer = "what the new state is"; command = "go do it, then say what happened".
|
|
The UI holds an application command, never the network client (lint-enforced).
|
|
|
|
## Skeleton
|
|
|
|
**Adapter method** (`<context>/infrastructure/<name>.adapter.ts`) — takes the
|
|
machine's `Valid` type, returns the server's answer, no parse (server is authority):
|
|
|
|
```ts
|
|
@Injectable({ providedIn: 'root' })
|
|
export class ChangeRequestAdapter {
|
|
private client = inject(ApiClient);
|
|
async changeRequest(data: Valid): Promise<string> {
|
|
/* → server reference */
|
|
}
|
|
}
|
|
```
|
|
|
|
**Command factory** (`<context>/application/submit-<name>.ts`) — binds the adapter in
|
|
an injection context; `runSubmit` is the one try/catch + ProblemDetails mapping:
|
|
|
|
```ts
|
|
export function createSubmitChangeRequest() {
|
|
const adapter = inject(ChangeRequestAdapter);
|
|
return (data: Valid): Promise<Result<string, string>> =>
|
|
runSubmit(() => adapter.changeRequest(data), SUBMIT_FAILED);
|
|
}
|
|
```
|
|
|
|
**Caller** (organism, field initializer — same shape as `createStore`): on the
|
|
machine's `Submitting` state, run the command, then dispatch
|
|
`SubmitConfirmed` / `SubmitFailed { error }`. Never throw into the template.
|
|
|
|
## Optimistic updates on shared state
|
|
|
|
When a root store's view must reflect the write before the server confirms:
|
|
`begin*` (flip pending) → `confirm*` (clear + `resource.reload()`) / `rollback*`
|
|
(undo). See `src/app/registratie/application/big-profile.store.ts`.
|
|
|
|
## Worked examples
|
|
|
|
- `src/app/registratie/infrastructure/change-request.adapter.ts`
|
|
- `src/app/registratie/application/submit-change-request.ts`
|
|
- `src/app/registratie/application/draft-sync.ts` — `createDraftSync(...)` bundles
|
|
draft persistence + submit for wizard flows; prefer it when the form has a draft.
|
|
- `src/app/shared/application/submit.ts` — `runSubmit`, `SUBMIT_FAILED`.
|
|
|
|
## Verify
|
|
|
|
```bash
|
|
npm test && npm run lint && npm run build
|
|
# exercise the failure path in the browser: ?scenario=error on the submitting page
|
|
```
|