Scrum4Me/docs/patterns/dialog.md
Madhura68 3ad85d0167 docs: sync data-model, glossary en specs met huidig schema
Brengt de docs gelijk met de werkelijkheid na PBI-46/47/50/58/59/61/63
en M12. Belangrijkste fixes:

- data-model.md herschreven naar prisma/schema.prisma: nieuwe entiteiten
  (Idea, IdeaLog, IdeaProduct, UserQuestion, ClaudeQuestion, ClaudeJob,
  SprintRun, SprintTaskExecution, ClaudeWorker, LoginPairing,
  PushSubscription, ModelPrice, ProductMember), nieuwe enums
  (FAILED/EXCLUDED, OPEN/CLOSED/ARCHIVED, ADMIN, etc.) en codes
  (PBI/ST/T/SP-N) toegevoegd; verwijderde todos-tabel verwijderd.
- glossary.md: Sprint zonder "max 1 actief" (PBI-63), Story/Task incl.
  FAILED/EXCLUDED, Todo verwijderd, Idea/SprintRun/ClaudeJob/
  verify_result toegevoegd.
- project-structure.md: app/(app)/todos vervangen door
  ideas/insights/jobs/manual/admin/solo; api-tree volledig.
- overview.md: "geen realtime in v1" en Docker-rationale herschreven —
  Postgres LISTEN/NOTIFY + SSE, claude_jobs als queue, opt-in
  Docker-deploy-flow.
- functional.md: F-08 Todo-lijst -> Ideeen-laag, F-09 multi-sprint,
  F-10 Task-status incl. FAILED/EXCLUDED, F-11 endpoint-lijst,
  navigatiestructuur, datamodel-schets en Flow 3 bijgewerkt.
- README.md API-tabel: /api/todos weg, ideas/jobs/users/profile/health
  toegevoegd, kort over realtime/auth-pair/internal/cron.
- patterns + mcp-integration runbook: Todo-/ACTIVE-references vervangen
  door Idea/OPEN; create_todo MCP-tool note over verwijdering.

Linkcheck groen (105 files), INDEX hergegenereerd (98 docs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 07:59:18 +02:00

439 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: "Entity Dialog"
status: active
audience: [ai-agent, contributor]
language: nl
last_updated: 2026-05-08
when_to_read: "Before building any create/edit/detail dialog component."
---
# Pattern — Entity Dialog
Deze pagina is **bindend** voor elke create/edit/detail-dialog in Scrum4Me, ongeacht het achterliggende dataobject (PBI, Story, Task, Idea, Sprint, Product, User, of toekomstige entiteiten). Een nieuwe dialog die hier niet aan voldoet, hoort niet gemerged te worden.
> **Doel:** elke dialog voelt identiek aan voor de gebruiker, hergebruikt dezelfde primitives, en heeft de drielaagse demo-policy + auth-scoping standaard ingebakken.
Voor entity-specifieke afwijkingen of velden: schrijf één begeleidende doc per entiteit (zie sectie [§ Per-entiteit profile](#per-entiteit-profile-verplicht)). Voorbeeld: `docs/specs/dialogs/task.md` is het Task-profiel.
---
## 1 — Verplichte uitgangspunten
| # | Regel | Bron / waarom |
|---|---|---|
| 1.1 | Bouw op `components/ui/dialog.tsx` (de bestaande shadcn/`@base-ui/react`-wrapper). **Geen** directe imports van dialog-primitives uit `@base-ui/react`. | Voorkomt twee parallelle dialog-implementaties met inconsistente animatie/focus-trap/theming |
| 1.2 | Gebruik composition via de **`render`-prop** (zie `CLAUDE.md` "UI Library Conventions"). Nooit Radix' `asChild`. | Project gebruikt `@base-ui/react`, niet Radix |
| 1.3 | Mode (`create` vs `edit` vs `detail` vs `inspector`) wordt afgeleid uit één input — een prop, een `state`-object of een `searchParam`. **Niet** twee aparte componenten. Voor `inspector`: zie § 4a. | Voorkomt code-duplicatie en inconsistente labels/footer-layouts |
| 1.4 | Auth-scoping op elke server action via `productAccessFilter(userId)` (of het scope-helper-equivalent). Cross-tenant writes mogen onmogelijk zijn. | `CLAUDE.md` "Toegangsmodel" + `docs/patterns/server-action.md` |
| 1.5 | **Drielaagse demo-policy** (verplicht — zie § 6) op elke write-actie. | `CLAUDE.md` "Demo-check" + `docs/architecture.md#demo-user-policy` |
| 1.6 | Validatie via één gedeeld zod-schema (`lib/schemas/<entity>.ts`) — gebruikt door zowel form als server action. | `CLAUDE.md` "Validatie" |
| 1.7 | Foutcodes volgen de project-conventie (§ 5). | `CLAUDE.md` "Foutcodes API" |
| 1.8 | Geen willekeurige Tailwind-kleuren (`bg-blue-500` etc.). Alleen MD3-tokens uit `app/styles/theme.css`. | `docs/design/styling.md` |
---
## 2 — Stack & dependencies
Toegestane runtime-deps voor dialog-werk (al aanwezig of standaard pattern):
| Doel | Voorkeur | Acceptabele alternatief |
|---|---|---|
| Form-state | `react-hook-form` + `@hookform/resolvers/zod` | `useActionState` + `useFormStatus` (Server Actions, native React) |
| Auto-grow textarea | `react-textarea-autosize` | — |
| Markdown-rendering (preview) | `react-markdown` + `remark-gfm` (via bestaande `<Markdown>`-wrapper) | — |
| Toasts | `sonner` | — |
| Iconen | `lucide-react` | — |
> **Per-dialog mag je kiezen tussen `react-hook-form` of `useActionState`.** Beide patronen draaien al in deze codebase. Kies één per dialog en blijf consistent binnen dat bestand. Mix ze niet.
Verboden in dialog-context (v1):
- `material-color-utilities` (dynamic color valt buiten v1)
- Nieuwe form-libraries — geen `formik`, `final-form`, etc.
---
## 3 — Component-architectuur
### 3.1 Reusables (`components/entity-dialog/` of `components/shared/`)
Deze primitives kennen géén entity-specifieke types en mogen door élke dialog gebruikt worden:
| Primitive | Locatie | Verantwoordelijkheid |
|---|---|---|
| `<Dialog>` + `<DialogContent>` etc. | `components/ui/dialog.tsx` | Shell, motion, focus-trap, backdrop |
| `<PrioritySelect>` / `<PrioritySegmented>` | `components/shared/priority-select.tsx` | P1-P4 — identiek over alle entiteiten |
| `<DemoTooltip>` | `components/shared/demo-tooltip.tsx` | Wrapper rond write-knoppen voor demo-modus (laag 3 van 3) |
| Auto-grow textarea | (toe te voegen wanneer nodig in `components/shared/`) | Wrapper rond `react-textarea-autosize` met char-counter + markdown-hint |
| Dirty-close-guard | (gedeelde AlertDialog-flow) | "Wijzigingen niet opgeslagen — weggooien?" |
| `<Markdown>` | `components/markdown.tsx` | `react-markdown` + `remark-gfm` voor description/criteria-preview |
> Wanneer je een primitive twee keer kopieert tussen entity-dialogs, **promote 'm meteen** naar `components/shared/` (of `components/entity-dialog/`). Drie keer is te laat.
### 3.2 Entity-specifieke laag (`components/<domain>/<entity>-dialog.tsx`)
Per entiteit één wrapper-bestand dat:
1. De juiste form/body rendert
2. De juiste server actions koppelt (`save<Entity>Action`, `delete<Entity>Action`)
3. Entiteit-specifieke labels levert ("Story bewerken", "PBI aanmaken", etc.)
Een entity-dialog bevat **geen** layout-mechanica, motion-config of dirty-check zelf — die komen uit § 3.1.
---
## 4 — Layout & responsive gedrag
Identiek voor élke dialog (geen entity-specifieke variaties tenzij expliciet beargumenteerd in het entity-profile):
| Breakpoint | Breedte | Hoogte |
|---|---|---|
| Mobiel (< 640px) | full-screen | full-screen |
| Tablet (6401024px) | `90vw` | `max-h-[85vh]` |
| Desktop (≥ 1024px) | `max-w-[50vw]`, `min-w-[480px]` | `max-h-[85vh]` |
Verplicht:
- Padding `p-6` rondom (24px)
- Veld-spacing in body `space-y-6` (24px)
- **Sticky** header (titel + close) en **sticky** footer (knoppen)
- Body scrollt onafhankelijk; geneste scrolls vermijden
- Footer heeft `border-t` in `outline-variant`
---
## 4a — Inspector-mode (hybrid detail + inline-edit)
Een inspector-dialog is een **detail-overlay met inline-bewerkbare velden** voor een lopend record (typisch een taak, run of job). Onderscheidt zich op drie punten van create/edit/detail:
| Aspect | Create/Edit/Detail | Inspector |
|---|---|---|
| Persistence | submit-knop in footer roept één Server Action aan | per-veld blur-save via Route Handler (`PATCH`) of fine-grained Server Actions |
| Footer | statisch (`Annuleren` + `Opslaan`/`Aanmaken`/`Verwijderen`) | dynamisch bevat status-indicatoren en context-knoppen (bv. "Voer uit", "Annuleer agent", "Open PR") afhankelijk van een job/run-status |
| Body | sequentieel form (één entiteit invullen) | gegroepeerde secties: read-only metadata + bewerkbare controls + activity-status |
| Dirty-guard | verplicht 8.1) | n.v.t. wijzigingen worden direct gepersisteerd |
| Submit-shortcut | Cmd/Ctrl+Enter verplicht 8.2) | n.v.t. geen submit |
| Validatie | 422-fieldErrors in form | toast bij PATCH-fout, optimistisch terugdraaien |
**Wanneer kiezen voor inspector i.p.v. detail-mode?**
- Het record is "actief" (bv. agent draait erop) en meta-edits moeten direct effect hebben zonder save-cycle
- Verschillende velden gaan naar verschillende endpoints en willen niet gebundeld worden
- De footer toont liveness-info (job-status) i.p.v. acties op het hele record
**Layout-eisen (verplicht, gelijk aan §4):**
- Bouw op `components/ui/dialog.tsx`
- `<DialogContent className={entityDialogContentClasses}>`
- Sticky header met `entityDialogHeaderClasses` of equivalent (`shrink-0` + `border-b border-outline-variant`)
- Body in `entityDialogBodyClasses` (`flex-1 overflow-y-auto px-6 py-6 space-y-6`)
- Footer in `entityDialogFooterClasses` + extra modifiers voor wrap-gedrag bij dynamische knoppen (`flex flex-wrap items-center gap-2`)
**Wat blijft hetzelfde als bij andere modi:**
- Drielaagse demo-policy 6) proxy-guard, server/route-handler `session.isDemo`-check, `<DemoTooltip>` rond bewerkbare controls
- MD3-tokens 9), motion 8.4), backdrop 8.5), focus return 8.3)
- Auth-scoping op elke write 1.4)
- Eén entity-profile in `docs/specs/dialogs/<entity>.md`
**Wat je expliciet niet doet in inspector-mode:**
- Geen `useDirtyCloseGuard` (geen dirty-state) Esc/backdrop sluit direct
- Geen `useDialogSubmitShortcut` (geen submit)
- Geen verplichte `lib/schemas/<entity>.ts` voor het hele record wél schema's per PATCH-veld of per fine-grained action
- Geen footer met statische save/cancel-knoppen die suggereren bundle-save
**Voorbeeld in deze codebase:** `components/solo/task-detail-dialog.tsx` opent een lopende solo-taak, plan-textarea slaat op blur op via `PATCH /api/tasks/:id`, verify-toggles direct via dezelfde route, footer toont job-status met context-acties (Voer uit / Wacht op agent / Annuleer / Open PR / Mislukt).
Profiel: `docs/specs/dialogs/task-detail.md`.
---
## 5 — Validatie & foutcodes
### 5.1 zod-schema
Eén `lib/schemas/<entity>.ts` per entiteit. Geïmporteerd door zowel form als server action geen aparte definities.
### 5.2 Foutcodes (verplicht)
| Code | Wanneer | UI-respons |
|---|---|---|
| **422** | zod-validatiefout (server-side dubbelcheck) | `fieldErrors` mappen naar `form.setError()`, géén toast |
| **403** | demo-sessie probeert te schrijven, of cross-tenant write geblokkeerd | toast "Niet toegestaan in demo-modus" of "Geen toegang", form blijft open |
| **400** | malformed JSON-body (`request.json()` faalt) alleen bij REST-route-handlers | toast "Ongeldige aanvraag" |
| **500** | onverwachte serverfout | toast met "Opnieuw proberen"-knop, form-state behouden |
> Field-level errors zijn **alleen** geldig bij `code: 422`. Bij andere codes is `fieldErrors` ongedefinieerd.
### 5.3 Field-level rendering
- Errors **onder** het veld, in `text-error`, met `border-error` op het input-element
- Géén toast voor field-level errors
- Submit-knop **blijft enabled** bij errors klik scrollt naar eerste error-veld + focus
- react-hook-form mode: `onTouched` (eerste validatie bij blur, daarna onChange)
---
## 6 — Drielaagse demo-policy (verplicht voor write-dialogs)
Elke dialog die schrijft (create / edit / delete) MOET door alle drie de lagen heen:
1. **Middleware-guard** in `proxy.ts` blokkeert demo-sessies op write-routes vóór de server action loopt. Returnt **403**.
2. **`session.isDemo`-check** binnen elke `save<Entity>Action` / `delete<Entity>Action` zelf defense-in-depth voor het geval een actie buiten een proxy-route loopt. Returnt **403**.
3. **`<DemoTooltip show={isDemo}>`** rond de submit- en delete-knoppen UI-laag: knoppen `disabled` met tooltip "Demo-modus: opslaan uitgeschakeld".
> Eén laag missen = bug. Reviewers moeten alle drie de lagen kunnen aanwijzen in de PR.
---
## 7 — Submission-flow
### 7.1 Server Action (template)
```ts
// actions/<entity>.ts
'use server'
export async function save<Entity>Action(
input: <Entity>Input,
context: { /* ids voor revalidatePath en scope */ },
): Promise<Save<Entity>Result> {
const session = await getSession()
if (!session.userId) return { ok: false, code: 403, error: 'forbidden' }
if (session.isDemo) return { ok: false, code: 403, error: 'demo_readonly' }
const scope = await productAccessFilter(session.userId) // verplicht
const parsed = <entity>Schema.safeParse(input)
if (!parsed.success) {
return { ok: false, code: 422, error: 'validation', fieldErrors: parsed.error.flatten().fieldErrors }
}
// ... Prisma write binnen `scope` ...
// revalidatePath(...) op de context-route
return { ok: true, <entity>: row }
}
type Save<Entity>Result =
| { ok: true; <entity>: <Entity> }
| { ok: false; code: 422; error: 'validation'; fieldErrors: Record<string, string[]> }
| { ok: false; code: 403; error: 'demo_readonly' | 'forbidden' }
| { ok: false; code: 500; error: 'server_error' }
```
### 7.2 Revalidation
`revalidatePath` op de **context-route** waarin de dialog werd geopend, niet op een statisch path. Context wordt door de aanroepende client meegegeven (geen hard-coded paths in de action).
### 7.3 Submit-flow
- Synchroon (geen optimistic update in v1, behalve waar het store-patroon `usePlannerStore` al bestaat)
- Tijdens submit: cancel- en submit-knop disabled, spinner of "…" in submit-knop, velden **blijven enabled**
- Server saniteert en valideert opnieuw met hetzelfde zod-schema
---
## 8 — Dialog-gedrag (UX-regels)
### 8.1 Sluiten met dirty state
- Form niet aangeraakt Esc / backdrop-klik / Cancel sluiten **direct**
- Form `isDirty` Esc / backdrop-klik / Cancel triggeren `AlertDialog`: *"Wijzigingen niet opgeslagen — weggooien?"*
### 8.2 Keyboard shortcuts
| Toets | Actie |
|---|---|
| **Esc** | Sluiten (met dirty-check) |
| **Cmd/Ctrl + Enter** | Submit vanuit elk veld |
| **Enter in `<input type=text>`** | **Geen** submit (alleen Cmd/Ctrl+Enter) |
| **Enter in `<textarea>`** | Newline (default browser, niet overriden) |
| **Tab** | Top-naar-bottom door velden, dan Cancel Submit (en Delete in edit-mode) |
### 8.3 Focus management
- Bij openen: focus op het eerste tekstveld (meestal `title` / `name`)
- Edit-mode: cursor aan het einde van bestaande waarde, **geen auto-select** (anders typt user per ongeluk weg)
- Bij sluiten: focus terug naar het element dat de dialog opende (`@base-ui/react` doet dit by default niet breken)
- Bij submit-error: focus naar eerste error-veld
### 8.4 Motion (MD3-conform)
- Open: 250ms, easing `cubic-bezier(0.2, 0, 0, 1)`, scale 0.951 + opacity 01
- Close: 200ms, easing `cubic-bezier(0.4, 0, 1, 1)`
### 8.5 Backdrop
`rgba(0,0,0,0.4)` (iets sterker dan MD3-default 0.32 voor contrast op zowel licht als donker).
---
## 9 — Theming (MD3-tokens)
| Surface | Token |
|---|---|
| Dialog-background | `surface-container-high` + `shadow-2xl` (getemperde opacity) |
| Form input-background | `surface-container-low`, geen shadow |
| Footer top-border | `outline-variant` |
| Submit-knop (filled) | `primary` background + `on-primary` tekst |
| Cancel-knop (text) | geen background + `primary` tekst |
| Delete-knop (tonal error) | `error-container` background + `on-error-container` tekst |
Density: **comfortable** (geen compact). Single-line input `h-14` (56px MD3-default).
Typography:
- `headline-small` (24px) dialog-titel
- `body-large` (16px) form-input tekst
- `body-medium` (14px) helptext, counter
---
## 10 — Footer
### 10.1 Edit-mode
```
[ Verwijderen ] [ Annuleren ] [ Opslaan ]
tonal (error-container) text filled (primary)
```
### 10.2 Create-mode
```
[ Annuleren ] [ Aanmaken ]
text filled (primary)
```
### 10.3 Detail-mode (read-only)
```
[ Sluiten ]
filled (primary)
```
### 10.4 Delete-flow (verplicht patroon)
1. Klik "Verwijderen" `AlertDialog`: *"Weet je zeker? Dit kan niet ongedaan worden."*
2. Bevestigen `delete<Entity>Action` (zelfde auth-scoping én demo-checks als save) `revalidatePath` op context-route dialog sluit toast "<Entity> verwijderd"
3. Geen undo in v1
---
## 11 — Triggers & URL-state
Elke dialog wordt geopend vanuit een context-pagina (sprint, backlog, dashboard, …). Twee patronen zijn toegestaan:
### 11.1 URL-based (voorkeur voor deep-link-bare dialogen)
```
?new<Entity>=1 → create-dialog open
?edit<Entity>=<id> → edit-dialog open
```
Kies dit patroon wanneer de dialog gedeeld of gebookmarkt moet kunnen worden, of wanneer Suspense + skeleton voor edit-mode gewenst is.
Sluiten = dezelfde route opnieuw pushen zonder de query-params.
### 11.2 State-based (voor pure UI-dialogen binnen één client-component)
```tsx
const [dialogState, setDialogState] = useState<DialogState | null>(null)
<EntityDialog state={dialogState} onClose={() => setDialogState(null)} />
```
Kies dit patroon voor dialogen die altijd binnen één parent-component leven en geen deep-linking nodig hebben (bv. PBI-dialog binnen PbiList, Story-dialog binnen StoryPanel).
> Mix de twee patronen niet binnen één entity-dialog. Documenteer in het entity-profile welk patroon gekozen is en waarom.
### 11.3 Server-side fetch in edit-mode
Bij URL-based pattern: server component fetcht het record vóór render — **inclusief auth-scoping**. Bestaat het record niet of valt het buiten scope → toast + redirect naar context-route zonder query-param.
Voor state-based pattern: het record komt al uit de parent (in-memory store of server-prop), dus geen aparte fetch nodig.
---
## 12 — Per-entiteit profile (verplicht)
Voor elke entiteit met een dialog hoort één profiel-doc te bestaan: `docs/<<entity>-dialog>.md` (of vergelijkbaar). Het profiel **vult de generieke spec aan** en bevat **alleen** de entity-specifieke onderdelen.
### Verplichte secties van het entity-profile
```md
# <Entity>Dialog Profiel
> Volgt `docs/patterns/dialog.md`. Dit document beschrijft alleen de afwijkingen en entity-specifieke keuzes.
## Velden
| Veld | Type | Mode | Validatie |
|---|---|---|---|
| ... | ... | create / edit / both | ... |
## URL- of state-pattern
- Gekozen: <URL-based | state-based>
- Reden: <korte motivatie>
- Routes (indien URL-based): `?new<Entity>=1` op `<route>`, `?edit<Entity>=<id>` op `<route>`
## Status-veld (indien aanwezig)
- Enum: ...
- Dot-kleur-mapping: ...
- Default bij create: ...
## Server actions
- `save<Entity>Action` — locatie, context-arg, revalidate-paden
- `delete<Entity>Action` — locatie, context-arg, revalidate-paden
## Speciale gedragingen (alleen indien de generieke spec niet volstaat)
- ... (bv. story-log-tab, claude-question-historie, file-upload, etc.)
## Bewust NIET in v1
- ...
```
> Geen entity-profile = geen merge. Reviewers checken op het bestaan van het profiel-bestand bij een PR die een nieuwe dialog introduceert.
---
## 13 — Bewust **niet** in deze pattern (out of scope)
Deze items zijn over het algemeen niet welkom in een dialog. Een entity-profile mag ze toevoegen, maar moet dan de afweging documenteren:
- ❌ Bulk-edit (meerdere records tegelijk)
- ❌ Drag-and-drop binnen de dialog (drag hoort op de lijst-view)
- ❌ Tabs voor secties — alleen spacing-gebaseerde groepering
- ❌ Section-headers — implicit via spacing, geen labels
- ❌ Sub-entiteiten (parent-child binnen dezelfde dialog)
- ❌ File uploads (uitzondering: avatar — eigen pattern)
- ❌ Comments / activity log binnen de dialog (mag wel als read-only side-panel; zie `StoryLog`)
- ❌ Optimistic locking — last-write-wins binnen scope
- ❌ Cmd+K / quick-create zonder dialog
- ❌ Templates voor terugkerende records
- ❌ Telemetrie / per-veld analytics
---
## 14 — Verificatie-checklist (per nieuwe dialog)
Reviewer en bouwer lopen deze door vóór merge:
- [ ] Bouwt op `components/ui/dialog.tsx` (geen directe `@base-ui/react`-imports)
- [ ] Composition via `render`-prop waar nodig
- [ ] Layout volgt § 4 (responsive breakpoints, padding, sticky header/footer)
- [ ] zod-schema in `lib/schemas/<entity>.ts`, gedeeld door form en action
- [ ] Server action heeft `productAccessFilter(userId)` + `session.isDemo`-check
- [ ] `proxy.ts` heeft een guard voor de bijbehorende write-route(s) (laag 1)
- [ ] Submit/Delete-knoppen omwikkeld met `<DemoTooltip show={isDemo}>` (laag 3)
- [ ] Foutcodes 422/403/500 correct teruggemapt naar UI (zie § 5)
- [ ] Dirty-close-guard actief
- [ ] Cmd/Ctrl+Enter submit, Esc sluit (met dirty-check)
- [ ] Focus management: opent op eerste veld, geen auto-select in edit-mode
- [ ] Motion + backdrop conform § 8.48.5
- [ ] Alleen MD3-tokens; geen `bg-blue-500`-style classes
- [ ] Footer-layout per mode conform § 10
- [ ] Delete-flow: AlertDialog → action → toast
- [ ] URL- of state-pattern gekozen + gedocumenteerd in entity-profile
- [ ] Entity-profile bestaat in `docs/` en is up-to-date
- [ ] Test gedekt: server action met validatie + demo + scope, en component-test op render + submit-flow
---
## 15 — Referenties
- `CLAUDE.md` — UI Library Conventions, Demo-check, Foutcodes API, Validatie
- `docs/design/styling.md` — MD3-tokens, kleurklassen
- `docs/architecture.md` — Demo user policy, scope-helpers
- `docs/patterns/server-action.md` — Server Action template (auth + Zod)
- `docs/patterns/zustand-optimistic.md` — voor lijst-views die de dialog aanroepen
- `docs/specs/dialogs/task.md` — voorbeeld-profile voor entiteit "Task"