docs(taxonomy): move spec files into docs/specs/
This commit is contained in:
parent
e56a038b4d
commit
2e47bda28e
14 changed files with 37 additions and 36 deletions
128
docs/specs/dialogs/pbi.md
Normal file
128
docs/specs/dialogs/pbi.md
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
---
|
||||
title: "PbiDialog Profiel"
|
||||
status: active
|
||||
audience: [ai-agent, contributor]
|
||||
language: nl
|
||||
last_updated: 2026-05-03
|
||||
---
|
||||
|
||||
# PbiDialog Profiel
|
||||
|
||||
> Volgt **`docs/patterns/dialog.md`** (de generieke spec voor élke entity-dialog in Scrum4Me).
|
||||
> Dit document beschrijft alleen de PBI-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 (server kent dan zelf een code toe) |
|
||||
| `title` | `string` (required) | beide | trim, 1-200 chars |
|
||||
| `priority` | `int` (1-4, P1 = hoogste) | beide | int 1-4, default 2 (kan via `defaultPriority`-prop bij create) |
|
||||
| `status` | `PbiStatusApi` enum | beide | enum, default `'ready'` |
|
||||
| `description` | `string \| null` | beide | optional, max 2000 chars, plain textarea (geen markdown rendering binnen de dialog) |
|
||||
|
||||
`PbiStatusApi` enum (lowercase, mapped via `lib/task-status.ts`): zie `<PbiStatusSelect>` voor de waarden.
|
||||
|
||||
### Veld-specifiek gedrag
|
||||
|
||||
- **Code + Titel** in één rij (`grid-cols-[6rem_1fr]`)
|
||||
- **Prioriteit + Status** in één rij (`grid-cols-2`)
|
||||
- **Prioriteit** via `<PrioritySelect>` (gedeelde primitive, géén segmented buttons in deze dialog)
|
||||
- **Status** via `<PbiStatusSelect>` (PBI-specifieke wrapper rond gedeelde select)
|
||||
- **Description** is `<Textarea rows={3} resize-none>` — géén auto-grow, géén markdown-hint, géén char-counter (afwijking van generieke spec; rationale: PBI-descriptions zijn doorgaans kort en richtinggevend)
|
||||
|
||||
---
|
||||
|
||||
## URL- of state-pattern
|
||||
|
||||
- **Gekozen:** state-based (`state: PbiDialogState | null` prop, gerendeerd binnen `PbiList`)
|
||||
- **Reden:** PBI-dialog leeft altijd binnen `PbiList` op de product-backlog-pagina; deep-linking is niet vereist en zou een tweede edit-flow toevoegen.
|
||||
- **State-shape:**
|
||||
```ts
|
||||
type PbiDialogState =
|
||||
| { mode: 'create'; productId: string; defaultPriority?: number }
|
||||
| { mode: 'edit'; pbi: PbiDialogPbi; productId: string }
|
||||
```
|
||||
- **Sluiten:** `onClose()` callback uit de parent — `setState(null)` in `PbiList`.
|
||||
|
||||
---
|
||||
|
||||
## Status-veld
|
||||
|
||||
- **Default bij create:** `'ready'` (PBI-default state)
|
||||
- **Geen verberging in create-mode** — anders dan TaskDialog wordt status hier wél getoond bij create, omdat een PBI zonder expliciete status onhandig is voor backlog-grooming
|
||||
|
||||
---
|
||||
|
||||
## Server actions
|
||||
|
||||
| Actie | Locatie | Form-binding | Revalidatie |
|
||||
|---|---|---|---|
|
||||
| `createPbiAction` | `actions/pbis.ts` | via `useActionState` + `<form action>` (FormData) | server-side `revalidatePath` op product-backlog |
|
||||
| `updatePbiAction` | `actions/pbis.ts` | idem | idem |
|
||||
| ~~`deletePbiAction`~~ | **(ontbreekt)** | n.v.t. | n.v.t. |
|
||||
|
||||
Beide acties moeten de drielaagse demo-policy volgen (zie § Bekende gaps).
|
||||
|
||||
---
|
||||
|
||||
## Speciale gedragingen
|
||||
|
||||
### Form-state via `useActionState`
|
||||
|
||||
PbiDialog gebruikt het `useActionState` + `useFormStatus`-patroon (Server Actions / native React), niet `react-hook-form`. Dit is een toegestaan alternatief volgens de generieke spec § 2. Field-errors worden gemapt via een lokale `fieldError(field)`-helper die `result.error` als `Record<string, string[]>` interpreteert wanneer 'm geen string is.
|
||||
|
||||
### `key`-prop op `<form>`
|
||||
|
||||
Het `<form>`-element heeft `key={isEdit ? pbi!.id : 'create'}` — dit reset native form-state (defaultValues) wanneer de dialog tussen create en edit wisselt of wanneer een ander record bewerkt wordt.
|
||||
|
||||
### Hidden inputs voor server-binding
|
||||
|
||||
`priority` en `status` worden via `<input type="hidden">` doorgegeven aan de Server Action (de UI-controls zijn JS-state, niet directe form-fields).
|
||||
|
||||
---
|
||||
|
||||
## Triggers
|
||||
|
||||
- **Create-trigger:** `+ PBI`-knop in `PanelNavBar` van `PbiList` → `setPbiDialogState({ mode: 'create', ... })`
|
||||
- **Edit-trigger:** edit-icoon op een PBI-rij in `PbiList` → `setPbiDialogState({ mode: 'edit', pbi, ... })`
|
||||
|
||||
---
|
||||
|
||||
## Bekende gaps t.o.v. generieke spec
|
||||
|
||||
> Deze items wijken af van `docs/patterns/dialog.md` en horen in een vervolg-PR rechtgezet (niet onderdeel van de huidige docs-introductie).
|
||||
|
||||
- ❌ **Geen `<DemoTooltip>`** rond submit-knop — laag 3 van de drielaagse demo-policy ontbreekt voor PBI-create/update. Dat betekent dat een demo-user de knop kan klikken; de server action blokkeert nog steeds (laag 2), maar de UX is suboptimaal.
|
||||
- ❌ **Geen delete-knop / `deletePbiAction`** — alleen create + update. Of dat bewust is (PBI's worden nooit verwijderd, alleen status veranderd) of een gat, moet expliciet worden besloten en in dit profiel vastgelegd.
|
||||
- ❌ **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 — bewust weggelaten omdat PBI-descriptions kort zijn, maar verdient expliciete bevestiging.
|
||||
- ⚠️ **Layout wijkt af** van de generieke responsive-tabel: `sm:max-w-md` i.p.v. de `max-w-[50vw]` / `90vw` / full-screen-progressie uit § 4.
|
||||
|
||||
---
|
||||
|
||||
## Bewust NIET in v1
|
||||
|
||||
Specifiek voor PbiDialog (boven op de algemene out-of-scope-lijst in `docs/patterns/dialog.md` § 13):
|
||||
|
||||
- ❌ Inline aanmaken van child-stories binnen de PBI-dialog (gebeurt via StoryDialog vanuit `StoryPanel`)
|
||||
- ❌ Bulk-status-update over meerdere PBI's
|
||||
- ❌ PBI-templates / kopiëren
|
||||
|
||||
---
|
||||
|
||||
## Referenties
|
||||
|
||||
- `components/backlog/pbi-dialog.tsx` — implementatie
|
||||
- `actions/pbis.ts` — server actions
|
||||
- `components/shared/priority-select.tsx` — gedeelde priority-control
|
||||
- `components/shared/pbi-status-select.tsx` — PBI-status-select
|
||||
- `lib/task-status.ts` — `PbiStatusApi`-mapper
|
||||
- `docs/patterns/dialog.md` — generieke spec (bron-of-truth)
|
||||
- `docs/architecture.md` — datamodel `Pbi`
|
||||
- `docs/styling.md` — MD3-tokens, status- en priority-kleuren
|
||||
171
docs/specs/dialogs/story.md
Normal file
171
docs/specs/dialogs/story.md
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
---
|
||||
title: "StoryDialog Profiel"
|
||||
status: active
|
||||
audience: [ai-agent, contributor]
|
||||
language: nl
|
||||
last_updated: 2026-05-03
|
||||
---
|
||||
|
||||
# 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 | null` prop, gerendeerd binnen `StoryPanel`)
|
||||
- **Reden:** StoryDialog leeft binnen `StoryPanel` met live-store-data (geselecteerde PBI bepaalt zichtbare stories); deep-linking zou parallelle data-fetch-paden vereisen.
|
||||
- **State-shape:**
|
||||
```ts
|
||||
type StoryDialogState =
|
||||
| { mode: 'create'; pbiId: string; productId: string; defaultPriority?: number }
|
||||
| { mode: 'edit'; story: Story; productId: string }
|
||||
```
|
||||
- **Sluiten:** `onClose()` callback uit de parent — `setState(null)` in `StoryPanel`.
|
||||
|
||||
---
|
||||
|
||||
## 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 of `sprint-id` zetten via story-actions
|
||||
- `IN_SPRINT → DONE` — alle taken op `DONE` zetten triggert auto-promotion (zie story-status-logic in `actions/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:
|
||||
|
||||
1. Story-titel als dialog-title (groot)
|
||||
2. Story-code als monospace-badge rechtsboven (klein)
|
||||
3. Twee badges direct onder de titel: priority-badge (kleur via `PRIORITY_COLORS`) en status-badge (kleur via `STATUS_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:
|
||||
|
||||
- `description` via gedeelde `<Markdown>`-wrapper (`react-markdown` + `remark-gfm`)
|
||||
- `acceptance_criteria` als 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 in `PanelNavBar` van `StoryPanel` → `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 in `EmptyPanel` (zelfde state als create-trigger)
|
||||
|
||||
---
|
||||
|
||||
## Bekende gaps t.o.v. generieke spec
|
||||
|
||||
> Deze items wijken af van `docs/patterns/dialog.md` en 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-lg` met eigen `max-h-[90vh]` + `flex flex-col` i.p.v. de exacte `max-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` — implementatie
|
||||
- `actions/stories.ts` — server actions (incl. `getStoryLogsAction`)
|
||||
- `components/shared/priority-select.tsx` — gedeelde priority-control
|
||||
- `components/shared/story-log.tsx` — activity-log paneel
|
||||
- `components/shared/demo-tooltip.tsx` — demo-policy laag 3
|
||||
- `components/markdown.tsx` — gedeelde markdown-wrapper
|
||||
- `lib/task-status.ts` — status-enum-mapper
|
||||
- `docs/patterns/dialog.md` — generieke spec (bron-of-truth)
|
||||
- `docs/architecture.md` — datamodel `Story`
|
||||
- `docs/styling.md` — MD3-tokens, status- en priority-kleuren
|
||||
135
docs/specs/dialogs/task.md
Normal file
135
docs/specs/dialogs/task.md
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
---
|
||||
title: "TaskDialog Profiel"
|
||||
status: active
|
||||
audience: [ai-agent, contributor]
|
||||
language: nl
|
||||
last_updated: 2026-05-03
|
||||
---
|
||||
|
||||
# TaskDialog Profiel
|
||||
|
||||
> Volgt **`docs/patterns/dialog.md`** (de generieke spec voor élke entity-dialog in Scrum4Me).
|
||||
> Dit document beschrijft alleen de Task-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 |
|
||||
|---|---|---|---|
|
||||
| `title` | `string` (required) | beide | trim, 1-120 chars |
|
||||
| `description` | `string \| null` | beide | optional, max 2.000 chars, markdown |
|
||||
| `implementation_plan` | `string \| null` | beide | optional, max 10.000 chars, markdown |
|
||||
| `priority` | `int` (1-4, P1 = hoogste) | beide | int 1-4, default 3 |
|
||||
| `status` | `TaskStatus` enum | alleen edit (default `TO_DO` op create, niet getoond) | enum |
|
||||
| `created_at` | `Date` | alleen edit | read-only metadata in header |
|
||||
|
||||
`TaskStatus` enum: `TO_DO | IN_PROGRESS | REVIEW | DONE`.
|
||||
|
||||
### Veld-specifiek gedrag
|
||||
|
||||
- **Auto-grow textareas** (`description`, `implementation_plan`) via `react-textarea-autosize`. Max 6 regels (description) / 12 regels (implementation_plan), daarna `overflow-y-auto`.
|
||||
- **Karakter-counter** vanaf 75% van de limiet, klein, rechtsonder, `text-muted-foreground`. Bv. `1547 / 2000`.
|
||||
- **Markdown-hint** onder elk textarea: `Markdown ondersteund (lijstjes, **vet**, \`code\`)`.
|
||||
- **Priority** als segmented buttons via `<PrioritySelect>` / `<PrioritySegmented>`. Default P3 (Medium).
|
||||
- **Status** met gekleurde dot:
|
||||
- `TO_DO` — grijs
|
||||
- `IN_PROGRESS` — `status-in-progress` (blauw)
|
||||
- `REVIEW` — paars
|
||||
- `DONE` — `status-done` (groen)
|
||||
- **`created_at` als header-metadata** in edit-mode, naast de titel: `Aangemaakt: 23 apr 2026`. Klein, `muted-foreground`, géén form-veld.
|
||||
|
||||
---
|
||||
|
||||
## URL- of state-pattern
|
||||
|
||||
- **Gekozen:** URL-based (`searchParams`)
|
||||
- **Reden:** TaskDialog wordt geopend vanuit twee context-pagina's (sprint-detail en product-backlog) en moet deep-linkable zijn voor share/refresh-scenario's. Suspense + skeleton voor edit-mode loading is gewenst.
|
||||
- **Routes:**
|
||||
```
|
||||
/sprint/<sprintId>?newTask=1 → create
|
||||
/sprint/<sprintId>?editTask=<taskId> → edit
|
||||
/products/<productId>/backlog?newTask=1 → create
|
||||
/products/<productId>/backlog?editTask=<taskId> → edit
|
||||
```
|
||||
- **Sluiten:** `router.push(<base-route>)` zonder query-params.
|
||||
- **Server-side fetch in edit-mode:** server component fetcht de taak vóór render mét `productAccessFilter(userId)`. Bestaat de taak niet of valt 'm buiten scope → toast + redirect naar de context-route.
|
||||
- Optioneel: `nuqs` als de query-state-handling te omslachtig wordt — pas introduceren als losse refactor-task, niet inline.
|
||||
|
||||
---
|
||||
|
||||
## Status-veld
|
||||
|
||||
Verberg `status` in **create-mode** (default = `TO_DO` is genoeg). Toon alleen in edit-mode als `<Select>` met gekleurde dot per optie.
|
||||
|
||||
---
|
||||
|
||||
## Server actions
|
||||
|
||||
| Actie | Locatie | Context-arg | Revalidatie |
|
||||
|---|---|---|---|
|
||||
| `saveTask` | `app/actions/tasks.ts` | `{ sprintId?: string; productId?: string }` | `revalidatePath('/sprint/<sprintId>')` óf `revalidatePath('/products/<productId>/backlog')` afhankelijk van context |
|
||||
| `deleteTask` | `app/actions/tasks.ts` | idem | idem |
|
||||
|
||||
Beide acties volgen de drielaagse demo-policy + auth-scoping uit `docs/patterns/dialog.md` § 6–7.
|
||||
|
||||
---
|
||||
|
||||
## Speciale gedragingen
|
||||
|
||||
### Triggers (bestaande UI vervangen)
|
||||
|
||||
Deze TaskDialog is de **enige** create/edit-flow voor taken in beide contexten (sprint én backlog). Bestaande inline-edit-paden in `components/sprint/task-list.tsx` en het backlog-equivalent worden vervangen, niet ernaast geplaatst.
|
||||
|
||||
- **Create-trigger:** filled button `+ Nieuwe taak` in tasklist-header → zet `?newTask=1` op huidige route
|
||||
- **Edit-trigger:** klik op de hele rij in de tasklist (geen apart edit-icoon) → zet `?editTask=<id>` op huidige route
|
||||
- **Loading edit-mode:** Suspense met minimale skeleton (3 grijze balken), `200ms`-delay zodat snelle fetches geen flicker tonen
|
||||
|
||||
### Markdown-rendering elders
|
||||
|
||||
`description` en `implementation_plan` worden buiten de dialog (taakdetail, hover-card) gerenderd via de gedeelde `<Markdown>`-wrapper (`react-markdown` + `remark-gfm`). Niet in de dialog zelf.
|
||||
|
||||
---
|
||||
|
||||
## Implementatie-volgorde (suggestie)
|
||||
|
||||
Hergebruik dit als checklist bij het bouwen of refactoren van TaskDialog:
|
||||
|
||||
1. Dependencies in `package.json` (zie `docs/patterns/dialog.md` § 2)
|
||||
2. zod-schema in `lib/schemas/task.ts` — gedeeld door form en action
|
||||
3. `productAccessFilter`-helper checken in `lib/auth/`
|
||||
4. `saveTask` / `deleteTask` in `app/actions/tasks.ts` met auth-scoping + demo-check (laag 2)
|
||||
5. `proxy.ts`-guard voor demo-write-routes (laag 1) — alleen als nog niet aanwezig
|
||||
6. Eventueel ontbrekende MD3-tokens in `app/styles/theme.css` aanvullen
|
||||
7. `<DemoTooltip>` rond submit/delete-knoppen (laag 3)
|
||||
8. TaskDialog — create-mode eerst (minder edge cases)
|
||||
9. Edit-mode toevoegen (status, delete, `created_at`-metadata)
|
||||
10. URL-state via native `searchParams` op beide context-pagina's
|
||||
11. Bestaande task-row trigger refactoren (klikbaar maken naar dialog)
|
||||
12. Suspense + skeleton voor edit-mode + scope-check op fetch
|
||||
13. Dirty-close-guard
|
||||
14. Keyboard shortcuts (Cmd+Enter)
|
||||
|
||||
---
|
||||
|
||||
## Bewust NIET in v1
|
||||
|
||||
Specifiek voor TaskDialog (boven op de algemene out-of-scope-lijst in `docs/patterns/dialog.md` § 13):
|
||||
|
||||
- ❌ Sub-tasks / parent-child relaties tussen taken
|
||||
- ❌ Tags / labels / categorieën op taken
|
||||
- ❌ Due dates / reminders per taak
|
||||
- ❌ Time tracking (uren-registratie) — wel relevant voor inspannings-monitor, eigen feature
|
||||
- ❌ Sharing / collaboration per taak
|
||||
- ❌ Templates voor terugkerende taken
|
||||
|
||||
---
|
||||
|
||||
## Referenties
|
||||
|
||||
- `docs/patterns/dialog.md` — generieke spec (bron-of-truth voor alles wat hier niet beschreven is)
|
||||
- `docs/architecture.md` — datamodel `Task`
|
||||
- `docs/styling.md` — MD3-tokens, status- en priority-kleuren
|
||||
- `lib/task-status.ts` — enum-mapper DB ↔ API
|
||||
Loading…
Add table
Add a link
Reference in a new issue