8 template-generic skills in .claude/skills/ (new-feature, new-context, value-object, form-machine, bff-endpoint, mutation-command, ui-component, new-ssp), condensed from CLAUDE.md/ARCHITECTURE/fp-tea/ADRs and pointing at this repo's worked examples. CLAUDE.md gains a pointer. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2.2 KiB
name, description
| name | description |
|---|---|
| mutation-command | 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):
@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:
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.tssrc/app/registratie/application/submit-change-request.tssrc/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
npm test && npm run lint && npm run build
# exercise the failure path in the browser: ?scenario=error on the submitting page