docs(cleanup): archief verouderde plannen, backlog en root-duplicaten (#191)
* docs(cleanup): archief verouderde plannen, backlog en root-duplicaten
- 6 plans naar docs/old/plans/ (PBI-11/75/78, user-settings-store, Local github setup, lees-de-readme — laatste was verkeerde repo)
- docs/backlog/ naar docs/old/backlog/ (pre-MCP statische registry; live werk loopt via Scrum4Me-MCP)
- 6 root-level duplicaten naar docs/old/ (functional, {pbi,story,task}-dialog, product-backlog, backlog)
- 2 landing plans (niet uitgevoerd) krijgen archived: true frontmatter — blijven op plek maar uit INDEX
- scripts/generate-docs-index.mjs: skip docs/old/** + skip archived: true
- CLAUDE.md: rijen docs/backlog/, docs/plans/<key>-*.md, docs/manual/ weg; Track B-sectie verwijderd
- README.md / CHANGELOG.md / docs/plans/v1-readiness.md: link-fixes naar nieuwe locaties
Verify groen (lint + typecheck + 718 tests). docs/INDEX.md geregenereerd.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(cleanup): registreer handmatige verplaatsingen en fix referenties
- 4 plans verplaatst naar docs/old/plans/ (M10-qr-pairing-login, auto-pr-deploy-sync, docs-restructure-ai-lookup, v1-readiness)
- 3 archive-plans verplaatst naar docs/old/plans/ (archive-map nu leeg)
- ST-1114-copilot-reviews + 3 research-docs naar nieuwe docs/Ideas/ map
- Duplicaat docs/old/2026-04-27-m8-realtime-solo.md verwijderd (origineel zit in docs/old/plans/)
- Link-fixes naar nieuwe locaties:
- CHANGELOG.md → docs/old/plans/v1-readiness.md
- docs/runbooks/deploy-control.md → docs/old/plans/auto-pr-deploy-sync.md (2x)
- docs/runbooks/worker-idempotency.md → docs/old/plans/auto-pr-deploy-sync.md
- docs/plans/docs-restructure-pbi-spec.md → docs/old/plans/docs-restructure-ai-lookup.md (4x text + 2x href)
- docs/INDEX.md geregenereerd (96 docs, was 100)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d587be2fb3
commit
b39c3ec2e1
36 changed files with 1068 additions and 49 deletions
128
docs/old/plans/PBI-75-sprint-task-edit-store.md
Normal file
128
docs/old/plans/PBI-75-sprint-task-edit-store.md
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
# PBI-75 — Sprint task-edit client-side via workspace-store
|
||||
|
||||
## Context
|
||||
|
||||
In het Sprint-scherm (`/products/<id>/sprint/<sprintId>`) duurt het bewerken van een taak onevenredig lang. Klik op een taakregel of het potlood-icoon roept `router.push(?editTask=<id>)` aan vanuit [`components/sprint/task-list.tsx:226`](../../components/sprint/task-list.tsx). Dat triggert:
|
||||
|
||||
- **Volledige server re-render** van [`app/(app)/products/[id]/sprint/[sprintId]/page.tsx`](../../app/(app)/products/[id]/sprint/[sprintId]/page.tsx) met zware queries (sprint, alle sprintStories+tasks, productMembers, alle PBIs+stories voor het backlog-paneel)
|
||||
- **Tweede Prisma-query** in [`EditTaskLoader`](../../app/_components/tasks/edit-task-loader.tsx) voor task-detail (incl. `implementation_plan`)
|
||||
- **Na save**: `router.push(closePath)` + `revalidatePath` → opnieuw alle queries
|
||||
|
||||
De [`sprint-workspace-store`](../../stores/sprint-workspace/store.ts) (sinds PBI-74 Story 9) bevat al alles voor een client-side edit-flow:
|
||||
|
||||
- [`setActiveTask(taskId)`](../../stores/sprint-workspace/store.ts) (regel 337) — zet `context.activeTaskId` + roept `ensureTaskLoaded()` aan
|
||||
- [`ensureTaskLoaded(taskId)`](../../stores/sprint-workspace/store.ts) (regel 414) — `GET /api/tasks/{id}` → upsert met `_detail: true`
|
||||
- [`selectActiveTask`](../../stores/sprint-workspace/selectors.ts) (regel 91) — bestaat, nog geen consumer
|
||||
- [`applyTaskEvent`](../../stores/sprint-workspace/store.ts) (regel 748) — SSE-events propageren idempotent na server-save
|
||||
- Optimistic-mutation primitives (`applyOptimisticMutation` / `settleMutation` / `rollbackMutation`)
|
||||
|
||||
Het patroon "URL-param → store" bestaat al voor product-workspace in [`components/backlog/url-task-sync.tsx`](../../components/backlog/url-task-sync.tsx) — we volgen dat als precedent.
|
||||
|
||||
**Doel**: klik op een taak opent de edit-dialoog client-side via store-state binnen ~100ms. Geen URL-navigatie, geen server re-render, alleen `GET /api/tasks/{id}` voor het detail.
|
||||
|
||||
## Aanpak
|
||||
|
||||
**Architectuur**: store-mounted dialog + URL-sync component voor deeplinks.
|
||||
|
||||
1. **Klik-flow**: `TaskList.openEditDialog` roept `setActiveTask(taskId)` aan op de store. Geen `router.push`.
|
||||
2. **Render-flow**: nieuwe client-component `SprintTaskDialogMount` zit binnen `SprintHydrationWrapper`, subscribet `selectActiveTask`, en rendert `<TaskDialog>` zodra de active task `_detail === true` is.
|
||||
3. **Save-flow**: `TaskDialog` krijgt optionele `onClose`/`onSaved` callbacks (backwards compatible met bestaande `closePath`). Mount geeft `onClose = () => setActiveTask(null)`. Server action `saveTask` blijft `revalidatePath` doen voor server-cache; SSE-event update store via `applyTaskEvent`.
|
||||
4. **Deeplink-flow**: nieuwe `SprintUrlTaskSync` leest `?editTask=<id>` en roept `setActiveTask(id)` aan (analoog aan `url-task-sync.tsx`).
|
||||
|
||||
## Bestanden + wijzigingen
|
||||
|
||||
### Nieuw — `components/sprint/sprint-task-dialog-mount.tsx`
|
||||
Client component. Subscribet `selectActiveTask` (single-value, geen `useShallow`). Wanneer task aanwezig is en `isDetail(task)` true, mappt naar `TaskDialogTask`-shape:
|
||||
- `status`: via `taskStatusFromApi` uit [`lib/task-status.ts`](../../lib/task-status.ts) (lowercase API → Prisma UPPER_SNAKE)
|
||||
- `implementation_plan: task.implementation_plan ?? null`
|
||||
- `created_at: new Date(task.created_at)`
|
||||
|
||||
Rendert `<TaskDialog task={mapped} productId={productId} onClose={() => setActiveTask(null)} isDemo={isDemo} />`. Geen render tussen `setActiveTask` en `_detail: true` (detail-fetch <100ms).
|
||||
|
||||
### Nieuw — `components/sprint/sprint-url-task-sync.tsx`
|
||||
Kopie van [`components/backlog/url-task-sync.tsx`](../../components/backlog/url-task-sync.tsx) maar tegen `useSprintWorkspaceStore` en `writeTaskHint` uit [`stores/sprint-workspace/restore`](../../stores/sprint-workspace/restore.ts).
|
||||
|
||||
### Wijziging — `components/sprint/task-list.tsx` (regels 225-227)
|
||||
Vervang:
|
||||
```ts
|
||||
function openEditDialog(taskId: string) {
|
||||
router.push(`${pathname}?editTask=${taskId}`)
|
||||
}
|
||||
```
|
||||
door:
|
||||
```ts
|
||||
function openEditDialog(taskId: string) {
|
||||
useSprintWorkspaceStore.getState().setActiveTask(taskId)
|
||||
}
|
||||
```
|
||||
`openCreateDialog` (regel 222) blijft URL-gebaseerd — out-of-scope.
|
||||
|
||||
### Wijziging — `app/(app)/products/[id]/sprint/[sprintId]/page.tsx`
|
||||
- Verwijder `editTask` uit searchParams-destructuring (regel 36)
|
||||
- Verwijder `editTask &&`-block met `<Suspense><EditTaskLoader>` (regels 250-260)
|
||||
- Verwijder ongebruikte imports (`EditTaskLoader`, `TaskDialogSkeleton`, evt. `Suspense`)
|
||||
- Mount binnen `SprintHydrationWrapper`:
|
||||
```tsx
|
||||
<SprintHydrationWrapper ...>
|
||||
<SprintBoardClient ... />
|
||||
<SprintTaskDialogMount productId={id} isDemo={isDemo} />
|
||||
<SprintUrlTaskSync />
|
||||
</SprintHydrationWrapper>
|
||||
```
|
||||
- `newTask`-block (regels 241-248) blijft ongemoeid — out-of-scope.
|
||||
|
||||
### Wijziging — `app/_components/tasks/task-dialog.tsx`
|
||||
Maak `closePath` optioneel + voeg `onClose`/`onSaved` toe (backwards compatible):
|
||||
```ts
|
||||
interface TaskDialogProps {
|
||||
task?: TaskDialogTask
|
||||
storyId?: string
|
||||
productId: string
|
||||
closePath?: string
|
||||
onClose?: () => void
|
||||
onSaved?: (taskId: string) => void
|
||||
isDemo?: boolean
|
||||
}
|
||||
```
|
||||
Refactor de drie `router.push(closePath)`-calls (regels 104, 120, 155) naar één helper:
|
||||
```ts
|
||||
function close() {
|
||||
if (onClose) { onClose(); return }
|
||||
if (closePath) router.push(closePath)
|
||||
}
|
||||
```
|
||||
Bestaande callers (`EditTaskLoader`, mobile, product-page, sprint `newTask`-block) blijven werken via `closePath`. Nieuwe `SprintTaskDialogMount` gebruikt `onClose`.
|
||||
|
||||
### Geen wijziging
|
||||
- `stores/sprint-workspace/selectors.ts` — `selectActiveTask` bestaat al
|
||||
- `app/_components/tasks/edit-task-loader.tsx` — nog gebruikt door product-page en mobile
|
||||
|
||||
## Edge cases
|
||||
|
||||
- **Status-enum mapping**: store API-lowercase → Prisma UPPER_SNAKE via `taskStatusFromApi`, fallback `'TO_DO'`
|
||||
- **`_detail: true` race**: mount rendert pas wanneer `isDetail(task)` true is — geen flash met undefined velden
|
||||
- **Demo-mode**: prop blijft via server doorlopen, dialog respecteert al `isDemo`
|
||||
- **Dirty-close-guard**: ingebouwd in dialog (regels 107, 172) — werkt via `onClose`
|
||||
- **SSE na save**: `applyTaskEvent` updatet store automatisch
|
||||
- **Deeplink + task niet bestaat**: `GET /api/tasks/{id}` 404 → store doet niets, dialog opent niet (huidige `redirect()` verdwijnt — acceptabel)
|
||||
|
||||
## Verificatie
|
||||
|
||||
1. **Browser** (`npm run dev`): klik op task in takenlijst → dialog opent <100ms, geen URL-verandering, alleen `GET /api/tasks/<id>` in Network
|
||||
2. **Save**: wijzig titel → Opslaan → dialog sluit → store toont nieuwe titel via SSE
|
||||
3. **Deeplink**: `?editTask=<id>` → dialog opent via `SprintUrlTaskSync`
|
||||
4. **Bestaande flows ongebroken**: product-page edit, mobile edit, sprint `?newTask=1`
|
||||
5. **`npm run verify && npm run build`**
|
||||
6. **Vitest**: `__tests__/components/sprint/sprint-task-dialog-mount.test.tsx` — hydreer store, mock fetch, `setActiveTask(id)`, assert UPPER_SNAKE status + `onClose` clear
|
||||
|
||||
## Risico's
|
||||
|
||||
- Andere mounts (mobile, product-backlog, sprint `newTask`) blijven URL-gebaseerd — `closePath?` optional houdt ze werkend
|
||||
- Geen `redirect()` bij not-found-deeplink (klein UX-verschil)
|
||||
- SSE-latency 100-500ms na save — eventueel later mitigeren via `applyOptimisticMutation` in `onSaved`-callback
|
||||
|
||||
## Out-of-scope (follow-up PBIs)
|
||||
|
||||
- `?newTask=1`-flow naar store
|
||||
- Mobile + product-backlog mounts
|
||||
- `EditTaskLoader` verwijderen wanneer alle callers over zijn
|
||||
Loading…
Add table
Add a link
Reference in a new issue