# WP-24 — Letter canvas (edit on the letter) Status: todo Phase: 6 — Brief v2 (edit-on-the-letter, org templates, server-rendered preview) ## Why The drafter should compose **on the letter** — letterhead above, footer/signature below, content blocks edited in place — instead of in an abstract form next to a separate preview. PRD Brief v2 §4. This is a **presentation rebuild only**: the domain model, `brief.machine.ts`, and every `BriefMsg` stay byte-identical. ## Read first - PRD Brief v2 §2b (fidelity note), §4, §10; the sample `voorbeeldbrief-inschrijving.pdf` - `src/app/brief/ui/letter-composer/letter-composer.component.ts` (the `canEdit` pivot) - `src/app/brief/ui/letter-preview/letter-preview.component.ts` (rendering that migrates in) - `docs/backlog/WP-23-org-template-backend.md` (the `orgTemplate` on `BriefViewDto`) ## Decisions (pre-made, don't relitigate) - **One stylesheet is the FE⇄BE rendering contract**: `public/letter.css` — class vocabulary `.letter`, `.letter__letterhead`, `.letter__body`, `.letter__signature`, `.letter__footer`, `.letter__page-break`; margins as `--letter-margin-*` custom props; `@page`/print rules. Loaded via `` in `index.html` (app + Storybook). WP-25's backend renderer inlines the same file; its parity test is the fence. - **`LetterCanvasComponent`** (new organism, `Domein/Brief/Letter Canvas`) with `editableRegions: 'content' | 'template' | 'none'` — one component serves drafter composing, approver review (and in WP-26, the admin editor). Letter typography on the canvas is the letter's, not the portal UI's — but still token-bridged. - `'content'` mode hosts the **existing** `letter-section`/`letter-block` components unchanged; letterhead/footer/signature render read-only with a subtle tint and a first-use caption ("komt uit de huisstijl van de organisatie"). - `'none'` mode absorbs `letter-preview`'s rendering (paragraph grouping, placeholder chips, sample-values toggle); **`ui/letter-preview/` is then deleted** — the PRD explicitly supersedes it; no third rendering is maintained. - **Page-break indicator is approximate by design**: a dashed line per A4-content interval with the caption "±pagina-einde — afdrukvoorbeeld is leidend" (PRD §2b honesty requirement). - `brief.machine.ts` and `BriefMsg` are untouched — `git diff` must prove it. ## Files - `public/letter.css` (new), `src/index.html` (link) - `src/app/brief/domain/org-template.ts` (new, pure) — `OrgTemplate` type - `src/app/brief/infrastructure/brief.adapter.ts` (+spec) — parse `orgTemplate` - `src/app/brief/ui/letter-canvas/*` (new: component + stories) - `src/app/brief/ui/letter-composer/letter-composer.component.ts` (pivot swap) + stories - `src/app/brief/ui/brief.page.ts` (pass orgTemplate through) - delete `src/app/brief/ui/letter-preview/*` ## Steps 1. `letter.css` from the sample PDF's geometry (A4 proportions, letterhead, address window + reference block, footer rule, signature). 2. `OrgTemplate` domain type + `parseOrgTemplate` boundary in the adapter (+spec). 3. Canvas organism: three modes, zoom input, page-break indicator. 4. Migrate `letter-preview` rendering into `'none'` mode; delete the component, fold its stories into the canvas stories. 5. Swap the composer's `@if (canEdit())` pivot for ``. 6. Stories: three modes + zoom + page-break, all axe-gated. ## Acceptance criteria - [ ] Drafter edits blocks in place on the letter surface; passage picker and diagnostics click-to-locate still work on the canvas. - [ ] Approver sees the identical surface read-only with the action bar. - [ ] Letterhead/footer/signature come from `orgTemplate` and are visibly non-editable. - [ ] `git diff` shows zero changes in `brief.machine.ts` / `brief.ts` Msg surface. - [ ] `letter-preview` is gone; no story regression (`test-storybook:ci` green). - [ ] Full GREEN + e2e smoke. ## Verification GREEN one-liner; `npm run e2e` (brief flow); manual: `?role=drafter` compose on canvas, `?role=approver` review; `?scenario=slow|error` still degrade gracefully through ``. ## Out of scope Server-rendered preview + `[NOG IN TE VULLEN]` resolution (WP-25); admin `'template'` mode wiring beyond the input existing (WP-26 gives it a consumer); zoom controls polish + standaardbrief + diff badges (WP-27). ## Risks The canvas duplicates the letter markup that WP-25's backend renderer will emit — acceptable *only* because `letter.css` is shared and WP-25 adds the class-parity test; until WP-25 lands, the canvas is the sole consumer, so no drift is possible. Deleting `letter-preview` breaks any deep import of it — repo-wide grep before delete.