* docs(dialog-pattern): add generic entity-dialog spec Introduceert docs/patterns/dialog.md als bron-of-truth voor elke create/edit/detail-dialog in Scrum4Me, ongeacht het achterliggende dataobject. Bevat 14 secties: uitgangspunten, stack, component- architectuur, layout, validatie, drielaagse demo-policy, submission, dialog-gedrag, theming, footer, triggers/URL-state, per-entiteit profile-template, out-of-scope, en een verificatie-checklist. Registreert het patroon in CLAUDE.md "Implementatiepatronen"-tabel zodat Claude (en mensen) de spec verplicht raadplegen voor elke nieuwe dialog. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(dialog-pattern): convert task spec + add pbi/story entity-profiles Reduceert docs/scrum4me-task-dialog.md van 507 naar ~140 regels: alle gedeelde regels verhuisd naar docs/patterns/dialog.md, dit document bevat nu alleen Task-specifieke velden, URL-pattern, status-veld, server actions, triggers en bewuste out-of-scope-keuzes. Voegt twee nieuwe entity-profielen toe voor bestaande dialogen: - docs/scrum4me-pbi-dialog.md (PbiDialog: state-based, code+title-rij, PbiStatusSelect, geen delete in v1) - docs/scrum4me-story-dialog.md (StoryDialog: state-based, header met status/priority badges, inline activity-log, demo-readonly-fallback, inline-delete-confirm i.p.v. AlertDialog) Beide profielen documenteren expliciet de "Bekende gaps t.o.v. generieke spec" zodat opvolgende PR's de afwijkingen kunnen rechtzetten of bewust kunnen accorderen. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Added pdevelopment docs --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.7 KiB
StoryDialog Profiel
Volgt
docs/patterns/dialog.md(de generieke spec voor élke entity-dialog in Scrum4Me). Dit document beschrijft alleen de Story-specifieke afwijkingen en keuzes — alle gedeelde regels (layout, motion, demo-policy, foutcodes, validatie, theming, dialog-gedrag) staan in de generieke spec en worden hier niet herhaald.
Belangrijk: als een regel in dit profiel botst met de generieke spec, wint de generieke spec. Documenteer hier de afwijking + reden, of pas de generieke spec aan.
Velden
| Veld | Type | Mode | Validatie |
|---|---|---|---|
code |
string | null |
beide | optional, max 30 chars, mono-font, placeholder auto op create |
title |
string (required) |
beide | trim, 1-200 chars |
priority |
int (1-4, P1 = hoogste) |
beide | int 1-4, default 2 (overschrijfbaar via defaultPriority-prop bij create) |
description |
string | null |
beide | optional, plain textarea, placeholder Als… wil ik… zodat… (user-story-template) |
acceptance_criteria |
string | null |
beide | optional, plain textarea, placeholder - Gegeven… Als… Dan… (Gherkin-template) |
status |
StoryStatus enum |
alleen edit | read-only badge in header, niet bewerkbaar in deze dialog |
StoryStatus enum: OPEN | IN_SPRINT | DONE (uppercase in DB).
Veld-specifiek gedrag
- Code + Titel in één rij (
grid-cols-[6rem_1fr]) - Prioriteit via
<PrioritySelect>(gedeelde primitive) - Description als
<Textarea rows={3} resize-none>— géén auto-grow, géén markdown-hint binnen de dialog (afwijking van generieke spec; rationale: stories zijn meestal één zin) - Acceptatiecriteria idem — géén auto-grow, géén char-counter
- Status wordt niet bewerkt vanuit deze dialog. Status verandert via lijst-acties (sleep naar sprint = IN_SPRINT, taak-completion = DONE). Read-only badge in dialog-header.
URL- of state-pattern
- Gekozen: state-based (
state: StoryDialogState | nullprop, gerendeerd binnenStoryPanel) - Reden: StoryDialog leeft binnen
StoryPanelmet live-store-data (geselecteerde PBI bepaalt zichtbare stories); deep-linking zou parallelle data-fetch-paden vereisen. - State-shape:
type StoryDialogState = | { mode: 'create'; pbiId: string; productId: string; defaultPriority?: number } | { mode: 'edit'; story: Story; productId: string } - Sluiten:
onClose()callback uit de parent —setState(null)inStoryPanel.
Status-veld
- Niet bewerkbaar in deze dialog — alleen weergegeven als badge in de header (edit-mode)
- Default bij create:
OPEN(server-default, niet expliciet gezet vanuit form) - Status-overgangen lopen via:
OPEN → IN_SPRINT— drag-and-drop naar een sprint ofsprint-idzetten via story-actionsIN_SPRINT → DONE— alle taken opDONEzetten triggert auto-promotion (zie story-status-logic inactions/stories.ts)
Server actions
| Actie | Locatie | Form-binding | Revalidatie |
|---|---|---|---|
createStoryAction |
actions/stories.ts |
via useActionState + <form action> (FormData) |
server-side revalidatePath op product-backlog |
updateStoryAction |
actions/stories.ts |
idem | idem |
deleteStoryAction |
actions/stories.ts |
aangeroepen vanuit useTransition (geen form) |
server-side revalidatePath |
getStoryLogsAction |
actions/stories.ts |
aangeroepen on-mount in edit-mode | n.v.t. (read-only) |
Alle write-acties zijn drielaags afgedekt (proxy-guard + server-action-check + DemoTooltip op submit-knop).
Speciale gedragingen
Header-presentatie (afwijking van generieke spec)
In edit-mode toont de dialog-header drie elementen boven op de standaard titel:
- Story-titel als dialog-title (groot)
- Story-code als monospace-badge rechtsboven (klein)
- Twee badges direct onder de titel: priority-badge (kleur via
PRIORITY_COLORS) en status-badge (kleur viaSTATUS_COLORS)
Generieke spec gaat uit van een sobere header met alleen headline-small titel + optioneel een created_at-meta-string. StoryDialog wijkt hier bewust van af omdat status + priority belangrijke context zijn voor de gebruiker bij het openen van een story (vaak wisselt iemand vlot tussen meerdere stories).
Demo-modus = read-only weergave
Wanneer isDemo === true én isEdit === true, wordt het form vervangen door een read-only weergave:
descriptionvia gedeelde<Markdown>-wrapper (react-markdown+remark-gfm)acceptance_criteriaals plain whitespace-pre-line tekst
In create-mode is er voor demo-users niets te tonen — de dialog wordt alsnog geopend maar de submit-knop is disabled met <DemoTooltip>.
Dit "read-only-fallback"-patroon is uniek voor StoryDialog tot nu toe. Het zou geadopteerd kunnen worden door andere edit-dialogs zodra demo-flow-vereisten dat rechtvaardigen.
Activity-log (StoryLog) inline
In edit-mode wordt onder het form een <StoryLog>-paneel getoond met de chronologische logs van deze story (commit-hashes, status-transitions, etc.). Logs worden lazy-fetched via getStoryLogsAction(story.id) zodra de dialog opent.
Dit is een read-only side-panel en valt binnen de uitzondering die de generieke spec § 13 maakt voor <StoryLog>-style activity-rendering.
Delete-flow (afwijking van generieke spec)
Generieke spec § 10.4 vereist een AlertDialog voor delete-confirmatie. StoryDialog gebruikt in plaats daarvan een inline-confirm in dezelfde footer-rij:
[ Weet je het zeker? Taken worden ook verwijderd. [Verwijderen] [Annuleren] ]
Een AlertDialog zou een tweede modale laag toevoegen die in deze context onhandig voelt (de dialog zelf is al een interruptive overlay). De inline-confirm is een bewuste afwijking van de generieke spec.
Form-state via useActionState
Net als PbiDialog gebruikt StoryDialog useActionState + useFormStatus, niet react-hook-form. Dit is een toegestaan alternatief volgens de generieke spec § 2.
key-prop op <form>
Het <form> heeft key={isEdit ? story!.id : 'create'} — reset native form-state bij record-wissel of mode-switch.
Triggers
- Create-trigger:
+ Story-knop inPanelNavBarvanStoryPanel→setStoryDialogState({ mode: 'create', pbiId, productId, defaultPriority: 2 }) - Edit-trigger: edit-icoon op een story-card in
StoryPanel→setStoryDialogState({ mode: 'edit', story, productId }) - Empty-state-trigger:
Maak je eerste story aan-knop inEmptyPanel(zelfde state als create-trigger)
Bekende gaps t.o.v. generieke spec
Deze items wijken af van
docs/patterns/dialog.mden horen in een vervolg-PR rechtgezet (niet onderdeel van de huidige docs-introductie).
- ❌ Geen dirty-close-guard — Esc / backdrop / Cancel sluiten direct, ook met onopgeslagen wijzigingen. Generieke spec § 8.1 vereist een AlertDialog bij
isDirty. - ❌ Geen Cmd/Ctrl+Enter shortcut — alleen klik op submit-knop.
- ❌ Geen char-counter / markdown-hint op description / acceptance_criteria — bewust weggelaten, maar verdient expliciete bevestiging als design-keuze.
- ⚠️ Inline-delete-confirm in plaats van AlertDialog (zie § Speciale gedragingen). Bewuste afwijking; de generieke spec mag deze variant expliciet toestaan, of dit profile moet als precedent gelden voor toekomstige dialogen.
- ⚠️ Header-layout met meerdere badges wijkt af van de sobere header in § 4. Bewuste afwijking — context-zwaar bij story-wisselen.
- ⚠️ Layout wijkt af van de generieke responsive-tabel:
sm:max-w-lgmet eigenmax-h-[90vh]+flex flex-coli.p.v. de exactemax-w-[50vw]/90vw/ full-screen-progressie uit § 4.
Bewust NIET in v1
Specifiek voor StoryDialog (boven op de algemene out-of-scope-lijst in docs/patterns/dialog.md § 13):
- ❌ Status bewerken vanuit de dialog (gebeurt via lijst-acties / drag-and-drop / auto-promotion)
- ❌ Inline aanmaken van child-tasks (gebeurt via TaskDialog vanuit
TaskPanel) - ❌ Bulk-edit over meerdere stories
- ❌ Story-templates
- ❌ Linking aan externe issues (GitHub / Linear) — staat op v1.1+ roadmap
Referenties
components/backlog/story-dialog.tsx— implementatieactions/stories.ts— server actions (incl.getStoryLogsAction)components/shared/priority-select.tsx— gedeelde priority-controlcomponents/shared/story-log.tsx— activity-log paneelcomponents/shared/demo-tooltip.tsx— demo-policy laag 3components/markdown.tsx— gedeelde markdown-wrapperlib/task-status.ts— status-enum-mapperdocs/patterns/dialog.md— generieke spec (bron-of-truth)docs/scrum4me-architecture.md— datamodelStorydocs/scrum4me-styling.md— MD3-tokens, status- en priority-kleuren