Commit graph

17 commits

Author SHA1 Message Date
Janpeter Visser
1f8cbacb0a
feat: shared backlog filter popover + sprint header polish (v1.3.3) (#184)
- Move sprint switcher into sprint header, centered between title and actions
- Extract BacklogFilterPopover as shared component used by sprint and product backlog
- Add sort options (code/priority/status) with single-pill asc/desc toggle
- Default sprint backlog status filter to OPEN, remove "alleen niet klaar" button
- Persist collapsed state and filter popover open in localStorage
- Fix hydration flicker: defer localStorage read to useEffect with prefsLoaded gate for writes
- Increase sprint switcher text size for readability

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 11:12:04 +02:00
Janpeter Visser
98ee05d458
feat(PBI-74): sprint-workspace-store (Story 9) (#181)
* feat(PBI-74): sprint-workspace-store skelet (Story 9 / T-879)

- stores/sprint-workspace/{types,store,selectors,restore}.ts conform
  product-workspace blueprint
- ContextSlice: activeProduct, activeSprintId, activeStoryId, activeTaskId
- EntitiesSlice: sprintsById, storiesById, tasksById
- RelationsSlice: sprintIdsByProduct, storyIdsBySprint, taskIdsByStory
- LoadingSlice met activeRequestId voor race-safe ensure*Loaded
- SyncSlice: realtimeStatus, lastResyncAt, resyncReason
- Realtime applyRealtimeEvent voor sprint/story/task entities + unknown-event
  fallback, parent-move handling, child-cleanup bij D op sprint/story
- Optimistic mutations: sprint-story-order, sprint-task-order, entity-patch
- LocalStorage hints (storage key sprint-workspace-hints) per product/sprint
- 45 unit-tests groen — verplicht 13 cases uit workspace-store.md §Tests

* feat(PBI-74): sprint hydratie + realtime SSE (Story 9 / T-880)

- app/api/realtime/sprint/route.ts: SSE-stream LISTEN/NOTIFY op
  scrum4me_changes, filter entity ∈ {sprint, story, task} per product_id;
  ready-event, heartbeat 25s, hard-close 240s
- lib/realtime/use-sprint-realtime.ts: client-hook met backoff-reconnect;
  ready-cycle telt; geen close op hidden; setRealtimeStatus
- lib/realtime/use-sprint-workspace-resync.ts: visibility + online triggers
  resyncActiveScopes('visible' | 'reconnect')
- components/sprint/sprint-hydration-wrapper.tsx: hydrateSnapshot via
  useEffect met fingerprint-check; mount realtime + resync
- app/(app)/products/[id]/sprint/[sprintId]/page.tsx: wrap SprintBoardClient
  in SprintHydrationWrapper; bouw SprintWorkspaceTask-shape voor
  tasksByStoryWorkspace en SprintHydrationData voor de wrapper

Schaduw-fase: useSprintStore blijft parallel werken in board components
totdat T-881 die migreert en T-883 de oude store opruimt.

* feat(PBI-74): migreer sprint-board componenten naar workspace-store (Story 9 / T-881)

- TaskList: leest tasks via selectTasksForStory met useShallow; DnD via
  applyOptimisticMutation('sprint-task-order') + settle/rollback
- SprintBacklogLeft: leest stories via selectStoriesForActiveSprint met
  useShallow; props 'stories' verwijderd
- SprintBoardClient: leest sprintStories uit selector i.p.v. lokale state;
  add/remove via direct setState met manuele snapshot-rollback;
  reorder via applyOptimisticMutation('sprint-story-order'); assignee-
  change via store entity-mutation; tasksByStory en sprintStoryIdList
  props weg
- app/(app)/.../sprint/[sprintId]/page.tsx: bouwt SprintHydrationData voor
  wrapper; geeft alleen non-store props door aan SprintBoardClient

useSprintStore wordt nergens meer geïmporteerd — alleen comment-referentie
in SprintHydrationWrapper. Cleanup van het bestand zelf in T-883.

Verify groen (671 tests, typecheck, lint clean).

* feat(PBI-74): read-routes voor sprint-workspace + cache-headers (Story 9 / T-882)

- GET /api/products/[id]/sprints — lijst sprints per product
  (ensureProductSprintsLoaded). force-dynamic, productAccessFilter,
  start_date/end_date naar ISO-date string.
- GET /api/sprints/[id]/workspace — sprint snapshot met sprint-meta,
  stories (incl. taskCount/doneCount/assignee), tasks gegroepeerd per
  story (ensureSprintLoaded). force-dynamic, productAccessFilter via
  product, status-vertaling via taskStatusToApi/storyStatusToApi.

Race-safe loaders (activeRequestId-guard), restore-flow (cascade-restore
via writeProductHint/writeSprintHint/writeStoryHint/writeTaskHint),
resync-laag (useSprintWorkspaceResync visibility + online), unknown-event
filter (isUnknownEntityEvent → resyncActiveScopes('unknown-event')) zijn
allemaal in T-879/T-880 al ingebouwd; T-882 sluit het loop met de
ontbrekende API-endpoints + cache-headers (cache: 'no-store' op fetches,
force-dynamic op routes).

* feat(PBI-74): cleanup oude sprint-store (Story 9 / T-883)

- rm stores/sprint-store.ts — alle componenten lezen nu via
  useSprintWorkspaceStore (T-881 voltooide imports-migratie)
- update SprintHydrationWrapper-comment: schaduw-fase referenties
  verwijderd

Verify: 671 tests groen, typecheck clean, build groen.
Grep useSprintStore = 0.

* docs(PBI-74): update Story 9 status in implementatieplan (T-884)

- Frontmatter: ready-to-execute → in-progress; revision 1 → 2;
  last_updated 2026-05-09 → 2026-05-10
- Stories-tabel: kolom Status toegevoegd (Stories 1-8 DONE via PR #180,
  Story 9 met T-884 op review)
- §Story 9: per-taak status + acceptatie-checklist voor T-884 manuele
  staging-checks
- Aanbeveling-blokje: noteert dat Story 9 vroeger gestart is dan het
  ontwerpdoc adviseerde
2026-05-10 06:53:04 +02:00
Janpeter Visser
5df04feb11
feat(PBI-74): Zustand product-workspace rearchitecture (Stories 1-8) (#180)
* feat(PBI-74): product-workspace store skelet + test-infra (Story 1)

Skelet voor de nieuwe `product-workspace-store` die op termijn de gefragmenteerde
`backlog-store`/`planner-store`/`selection-store`/`product-store` vervangt. Deze
PR levert alleen het skelet + tests; UI-consumers worden in latere stories
omgezet.

- vitest naar jsdom + tests/setup.ts (MemoryStorage, default fetch-stub) — G6/G8
- stores/product-workspace/{types,store,selectors,restore}.ts — immer-middleware,
  alle slices en acties (hydrate, setActive*, ensure*Loaded met activeRequestId-
  guard, applyRealtimeEvent, resyncActiveScopes/loadedScopes, optimistic
  mutations). Restore-wiring in setters volgt in Story 4 (T-857/T-858).
- selectors gebruiken module-level EMPTY refs (G1) en documenteren useShallow-
  vereiste (G2)
- 34 nieuwe unit-tests dekken §Testing setup-checklist uit het ontwerp:
  hydrateSnapshot, selection-cascade, applyRealtimeEvent (I/U/D + parent-move +
  ander-product + unknown-entity → resync), delete-cleanup, race-safe loaders,
  ensureTaskLoaded _detail-flag, resyncActiveScopes ensure-keten, restore-hints
  read/write/clear, optimistic mutation rollback/settle/SSE-echo idempotent
- docs/api/rest-contract.md: audit-sectie met de vier ontbrekende
  ensure*Loaded-endpoints (worden toegevoegd in Story 7 / T-870)

Refs: PBI-74, ST-1318, T-837..T-843
Bron-ontwerp: docs/plans/zustand-store-rearchitecture.md
Implementatieplan: docs/plans/zustand-workspace-store-implementation.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(PBI-74): dual-dispatch hydratie + realtime naar workspace-store (Story 2)

Story 2 — schaduw-fase: BacklogHydrationWrapper en useBacklogRealtime voeden
nu ook de nieuwe product-workspace-store, terwijl de oude useBacklogStore /
useProductStore leidend blijft voor componenten. Story 3 verschuift consumers
één voor één; Story 8 ruimt de oude stores op.

- T-844: BacklogHydrationWrapper roept naast useBacklogStore.setInitialData
  ook useProductWorkspaceStore.hydrateSnapshot aan. Productname-prop optioneel
  toegevoegd voor activeProduct-context.
- T-845: useBacklogRealtime onmessage dispatcht events naar zowel oude store
  (applyChange) als nieuwe store (applyRealtimeEvent). Geen wijziging aan
  reconnect/visibility — Story 5.
- T-846: dev-only logWorkspaceFingerprint helper vergelijkt counts tussen
  oude en nieuwe store na hydrate en na elk realtime-event. console.warn bij
  mismatch; opt-in debug log via NEXT_PUBLIC_DEBUG_WORKSPACE_FINGERPRINT=1.
  Bestand TODO-marked voor verwijdering in Story 8 (T-878).
- T-847: SetCurrentProduct schrijft naast oude useProductStore ook
  useProductWorkspaceStore.setActiveProduct({id, name}); cleanup cleart beide.
  setActiveProduct triggert ensureProductLoaded — fetch-stub tot Story 7
  (T-870) de LIST-endpoints toevoegt.

Verify: lint+typecheck clean, 636/636 tests groen (geen UI-regressie omdat
oude store leidend blijft).

Refs: PBI-74, ST-1319, T-844..T-847

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(PBI-74): migreer backlog-componenten naar workspace-store (Story 3)

Story 3 verplaatst alle UI-consumers van de oude vier stores
(useBacklogStore/usePlannerStore/useSelectionStore/useProductStore) naar de
nieuwe product-workspace-store. De oude stores blijven nog bestaan voor
hydration-wrapper en realtime-hook (dual-dispatch); Story 8 ruimt ze op.

- T-848 backlog-split-pane.tsx: leest activePbiId/activeStoryId uit
  context-slice (primitives, geen useShallow nodig).
- T-849 pbi-list.tsx: selectVisiblePbis(useShallow); DnD via
  applyOptimisticMutation('pbi-order' + optionele 'entity-patch' bij
  cross-priority drag), met settle/rollback per server-result.
- T-850 story-panel.tsx: selectStoriesForActivePbi(useShallow); DnD via
  applyOptimisticMutation('story-order' + entity-patch bij priority change).
- T-851 task-panel.tsx: selectTasksForActiveStory(useShallow); DnD via
  applyOptimisticMutation('task-order'); detail-view (ensureTaskLoaded +
  isDetail) zit in de task-dialog (apart component, niet in deze lijst).
- T-852 start-sprint-button.tsx: selectActivePbi + selectStoriesForActivePbi
  voor free-story count.
- T-853 set-current-product.tsx: alleen workspace-store.setActiveProduct
  (oude useProductStore-import verwijderd).
- T-854 G1/G2-audit: alle nieuwe selectors gebruiken module-level EMPTY
  refs (G1) en useShallow voor lijsten (G2). Geen 'Maximum update depth'-
  warnings tijdens npm test.
- T-855 tests bijgewerkt: backlog-split-pane.test, task-panel.test,
  integration.test gebruiken nu setState op workspace-store (helpers
  resetWorkspace/setActiveStoryAndTasks/selectPbi/selectStory).

Verify: lint+typecheck clean, 636/636 tests groen. UI-consumers van
oude stores zijn nu nul (uitgezonderd dual-dispatch in hydration-wrapper en
realtime-hook + dev-fingerprint-helper, die in Story 8/T-873/T-878 verdwijnen).

Refs: PBI-74, ST-1320, T-848..T-855

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(PBI-74): race-safe loaders + restore-hints + URL-prioriteit (Story 4)

- T-856: activeRequestId-guard zat al in store.ts uit Story 1; bevestigd door
  de race-safety test (in-flight ensurePbiLoaded mag niet overschrijven).
- T-857: restore-hint flow toegevoegd in setActiveProduct/setActivePbi/
  setActiveStory. Async chain: await ensureXxxLoaded → guard check →
  readHints → valideer hint via entities.byId → setActiveYyy(hint).
  Geen setTimeout-trick — chain is alleen await-based.
- T-858: writeProductHint/writePbiHint/writeStoryHint/writeTaskHint
  aangeroepen direct na set(...) zodat de hint-persistentie altijd
  consistent is met de in-store selectie.
- T-859: nieuwe components/backlog/url-task-sync.tsx — leest
  ?editTask=&lt;id&gt; uit useSearchParams, schrijft de hint en roept
  setActiveTask aan zodat de URL wint boven een eerder gepersisteerde
  task-hint. Gemount in beide product-pages (desktop + mobile) binnen
  BacklogHydrationWrapper.
- T-860: 6 nieuwe vitest-cases — 4 voor hint-persist per setter, 2 voor de
  restore-flow chain (hint die niet in entities zit wordt genegeerd; hint
  die wel in entities zit wordt toegepast). Bestaande race-safety test
  blijft groen.

Verify: lint+typecheck clean, 642/642 tests groen.

Refs: PBI-74, ST-1321, T-856..T-860

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(PBI-74): hidden-tab + reconnect resync (Story 5)

Per ontwerp samen in één commit zodat geen vangnet wegvalt zonder vervanging.

- T-861: useBacklogRealtime sluit niet meer op visibilitychange hidden;
  EventSource blijft open zolang browser/netwerk dit toelaten. Reconnect bij
  netwerkfout blijft via backoff. visibilitychange fungeert nog wel als
  re-connect-trigger als de stream tussentijds is gesloten (b.v. 240s
  hard-close server-side).
- T-862: 'ready'-event-handler telt connect-cycles. De eerste 'ready' is de
  initial connect (geen resync). Bij latere 'ready' (post-reconnect) wordt
  resyncActiveScopes('reconnect') aangeroepen om gemiste events op te halen.
- T-863: nieuwe lib/realtime/use-workspace-resync.ts — luistert op
  document.visibilitychange (hidden→visible) en window.online; dispatcht
  resyncActiveScopes('visible') resp. 'reconnect'. Mounted in
  BacklogHydrationWrapper na useBacklogRealtime.
- T-864: 4 nieuwe vitest-cases voor useWorkspaceResync (jsdom): visible→
  visible event, online event, hidden negeren, cleanup-bij-unmount.

Daarnaast lint-cleanup: ongebruikte 'order'-variabelen in pbi-list en
story-panel weggehaald.

Verify: lint+typecheck clean, 646/646 tests groen.

Refs: PBI-74, ST-1322, T-861..T-864

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(PBI-74): unknown-event fallback tests (Story 6)

T-865 (isUnknownEntityEvent filter) en T-866 (resync-trigger in
applyRealtimeEvent) zijn al in Story 1 geïmplementeerd in store.ts;
deze story breidt de test-coverage uit met expliciete negatieve cases
voor het type-veld noise pattern.

T-867 — 5 nieuwe vitest-cases:
- unknown entity met ANDER product_id → geen resync
- claude_job_status (type) → geen resync
- worker_heartbeat (type) → geen resync
- claude_job_enqueued (type) → geen resync
- payload zonder entity en zonder type → genegeerd
- question-entity (entity-veld, geen type, niet pbi/story/task) → resync trigger

Verify: lint+typecheck clean, 651/651 tests groen.

Refs: PBI-74, ST-1323, T-865..T-867

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(PBI-74): cache-headers + LIST endpoints (Story 7)

- T-868: cache: 'no-store' was al ingebouwd in fetchJson helper (Story 1).
  Bevestigd door bestaande ensureProductLoaded test die de fetch-init
  controleert.
- T-869: force-dynamic toegevoegd op alle vier nieuwe LIST-endpoints.
- T-870: vier nieuwe routes voor ensure*Loaded:
  - GET /api/products/:id/backlog → ProductBacklogSnapshot
  - GET /api/pbis/:id/stories → BacklogStory[]
  - GET /api/stories/:id/tasks → BacklogTask[]
  - GET /api/tasks/:id (nieuwe handler naast bestaande PATCH) → TaskDetail
    met _detail: true marker
  Auth via authenticateApiRequest (Bearer of iron-session); access-control
  via productAccessFilter (gebruiker is owner of member van het product).
  Statussen worden via taskStatusToApi/storyStatusToApi/pbiStatusToApi
  vertaald naar lowercase API-vorm.
- T-871: SSE-route /api/realtime/backlog stuurt al ready-event direct na
  LISTEN (regel 106) — geen wijziging nodig.

Verify: lint+typecheck clean, 651/651 tests groen.

Refs: PBI-74, ST-1324, T-868..T-871

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(PBI-74): oude stores opruimen (Story 8)

Workspace-store is nu de enige bron voor product-backlog client-state. De
vier voorgangers en de dual-dispatch-infrastructuur zijn verwijderd.

- T-872: grep over codebase op useBacklogStore/usePlannerStore/
  useSelectionStore/useProductStore is leeg.
- T-873..T-876: stores/{backlog,planner,selection,product}-store.ts deleted.
- T-877: __tests__/realtime/payload-contract.test.ts en
  __tests__/api/backlog-realtime.test.ts deleted — pbi/story/task I|U|D
  payload-handling wordt al gedekt door
  __tests__/stores/product-workspace/store.test.ts (incl. parent-move,
  idempotent inserts, delete-cleanup).
- T-878: lib/realtime/dev-workspace-fingerprint.ts deleted, dual-dispatch
  uit BacklogHydrationWrapper en lib/realtime/use-backlog-realtime.ts
  weggehaald. stores/products-store.ts (lijst van producten ≠ active
  product) blijft ongewijzigd.

Bijwerkingen:
- BacklogPbi en BacklogStory types in components/backlog/story-panel.tsx en
  components/sprint/sprint-backlog.tsx krijgen sort_order zodat ze met de
  workspace-types overeenkomen.
- Server-pages /products/[id]/page.tsx (desktop+mobile) en
  /products/[id]/sprint/[sprintId]/page.tsx selecteren sort_order op story
  en mappen het door in de hydration-payload.

Verify: lint+typecheck clean, 626/626 tests groen (verlies van 25 redundante
oude-store tests; workspace-store tests dekken hetzelfde gedrag).

Refs: PBI-74, ST-1325, T-872..T-878

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(PBI-74): richtlijn workspace-store + realtime patroon

Documenteert het patroon dat in Stories 1-8 is opgeleverd, zodat een
volgende workspace-store (sprint, of een nieuwe bounded context) hetzelfde
recept volgt.

- docs/patterns/workspace-store.md (nieuw): wanneer een workspace-store, de
  vijf state-slices, selectors-regels (G1/G2), race-safe ensure*Loaded met
  activeRequestId-guard (G4), SSE-hook + applyRealtimeEvent met
  unknown-event filter, hidden-tab + reconnect resync via
  useWorkspaceResync, restore-hint flow met await-chain en URL-prioriteit,
  optimistic mutations (applyOptimisticMutation/rollback/settle), API
  endpoint-vereisten (force-dynamic, cache: no-store), test-setup met
  MemoryStorage + originalActions snapshot + mockImplementation, gotchas
  G1-G8 als comment-template, en het 8-staps migratiepad.
- docs/patterns/zustand-optimistic.md: bijgewerkt voor de nieuwe
  workspace-store API; verwijst voor het bredere patroon naar
  workspace-store.md. Voorbeelden voor pbi-order + entity-patch.
- CLAUDE.md: patterns quickref aangevuld met workspace-store-rij.

Verify: typecheck clean.

Refs: PBI-74

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(PBI-74): solo + notifications hooks volgen ook hidden-tab/resync patroon

Het uitgangspunt van PBI-74 (robuust tegen gemiste SSE-events, hidden tabs
en onbekende notify-vormen) gold universeel — niet alleen voor
product-workspace. use-solo-realtime en use-notifications-realtime hadden
nog dezelfde bug die use-backlog-realtime in Story 5 al opgelost kreeg:
sluit stream op hidden, geen resync.

Reproductie (zoals gemeld): solo-screen open in tab A, product-backlog
open in tab B; bewerk task-title in tab B → tab A's solo-SSE was gesloten
(hidden) en kreeg het NOTIFY-event nooit. Tab terug naar solo →
EventSource reconnect maar geen resync → oude title persisteert. Postgres
NOTIFY heeft geen replay, dus zonder resync zijn die events permanent
verloren.

Fix in beide hooks (zelfde patroon als Story 5 voor backlog):
- Stream blijft open op visibilitychange hidden — geen close() meer.
- Bij hidden→visible én bij window 'online': router.refresh() zodat de
  server-component opnieuw fetcht en de initial-state-prop ververst (wat
  voor solo de tasks-record reset via initTasks; voor notifications de
  questions-bel-state).
- Bij latere 'ready'-events na reconnect (use-solo-realtime): zelfde
  router.refresh() trigger zodat we niet vertrouwen op alleen het
  visibility-pad.

Verify: lint + typecheck clean, 626/626 tests groen.

Refs: PBI-74

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs: fix broken links in research-repo plan

docs/plans/lees-de-readme-md-validated-book.md beschrijft een research-
repo migratiepad. De links waren geschreven vanuit het research-repo-
perspectief (paden als stores/data-store.ts, ../Scrum4Me/CLAUDE.md,
docs/plans/zustand-store-rearchitecture.md zonder relative-prefix), wat
de doc-link-checker hier laat falen.

- Header-note toegevoegd dat het document voor de research-repo is.
- Interne refs (zustand-store-rearchitecture.md, CLAUDE.md) → relatieve
  paden die in deze repo wél resolven (./zustand-..., ../../CLAUDE.md).
- Research-repo-only refs (stores/data-store.ts,
  hooks/use-event-stream.ts, components/*-select.tsx, etc.) → inline
  code-tags met "(research-repo)" suffix; de link-checker slaat ze over
  en de leesbaarheid blijft.

Verify: npm run docs:check-links → ✓ All doc links valid (118 files).

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 02:25:19 +02:00
Janpeter Visser
d292e445d9
Sprint: Verbeteren debug mode (#179)
* feat(PBI-49): add debugProps helper + Vitest test

Adds lib/debug.ts with debugProps(id, component, file) that returns
data-debug-id and data-debug-label attrs in dev mode, empty object in
production. Adds __tests__/lib/debug.test.ts covering both modes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(PBI-49): add debug-id pattern doc + CLAUDE.md reference

Adds docs/patterns/debug-id.md documenting the named-component boundary
rule (6 punten), helper-voorbeeld, skip-criteria en motivatie voor
handmatige pad-argumenten. Voegt verwijzing toe aan CLAUDE.md
patterns-tabel.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(PBI-49): migrate 17 shared/ components to debugProps helper

Replace hardcoded data-debug-id + data-debug-label attribute pairs with
{...debugProps(id, component, file)} spread in all 17 components/shared/
files. Existing debug-ids preserved unchanged.

* feat(PBI-49): add debugProps to backlog/, sprint/, solo/ components

* feat(PBI-49): add debugProps to jobs/ + ideas/ components

* feat(PBI-49): add debugProps to products/ + settings/ + notifications/ components

* feat(PBI-49): add debugProps to admin/ + dashboard/ + dialogs/ + mobile/ + split-pane/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(PBI-49): use attr(data-debug-id) for debug tooltip in globals.css

* refactor(PBI-49): remove data-debug-label from debugProps helper + test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(PBI-49): strip unused component/file args from debugProps in shared/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(PBI-49): add BEM sub-element data-debug-id to StatusBar, NavBar, PanelNavBar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(PBI-49): add BEM sub-element data-debug-id to components/sprint/*

- new-sprint-dialog: __submit on submit button
- sprint-backlog: __list on SprintBacklogLeft + SprintBacklogRight scroll areas
- sprint-board-client: root wrapper div (display:contents) + __drag-overlay
- sprint-header: __title on goal button, __dates on dates button, __actions on action cluster
- sprint-run-controls: root on controls div, __start/__cancel on action buttons; __blockers-dialog on dialog content
- start-sprint-button: root on trigger button, __dialog on dialog content, __submit on submit button
- sync-active-sprint-cookie: no debug-id (returns null, side-effect only), comment added

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(PBI-49): add BEM sub-element data-debug-id to components/backlog/*

* feat(PBI-49): add BEM sub-element data-debug-id to components/ideas/*

* feat(PBI-49): add BEM sub-element data-debug-id to components/dashboard/* + components/markdown.tsx

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(PBI-49): add BEM sub-element data-debug-id to new-product-button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(PBI-49): add BEM sub-element data-debug-id to components/solo/*

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(PBI-49): add BEM sub-elements to nav-status-indicators

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(PBI-49): add BEM sub-element data-debug-id to components/jobs/*

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(PBI-49): add BEM sub-element data-debug-id to components/products/*

* feat(PBI-49): add BEM sub-element data-debug-id to components/notifications/*

- answer-modal: __content (scroll area), __submit (footer)
- notifications-bridge: skip comment (bridge, non-rendering wrapper)
- notifications-realtime-mount: skip comment (returns null)
- notifications-sheet: __header, __items (questions list)
- push-toggle: __switch (button), __label (button text) on subscribed/unsubscribed states

* feat(PBI-49): add BEM sub-element data-debug-id to components/settings/*

- leave-product-button: root only (single-button component)
- min-quota-editor: __input (number input), __save (save button)
- profile-editor: __username (bio/short-description input), __save (submit)
- role-manager: __roles (checkbox list), __add (save button)
- token-manager: __tokens (active tokens list), __generate (create button)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(PBI-49): add BEM sub-element data-debug-id to admin, auth, dialogs, entity-dialog, mobile, split-pane

* docs(PBI-49): add debug-labels BEM pattern doc + CLAUDE.md entry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 22:46:29 +02:00
Janpeter Visser
71319e629d
feat(PBI-71): UX-fix 'lege sprint' + sprint-switch data-refresh (#175)
- StartSprintButton dialog toont 3-state banner: info met accurate vrije-
  stories count + PBI-context, of waarschuwing als geen PBI geselecteerd
  is, of waarschuwing als de geselecteerde PBI 0 vrije stories heeft
- Voeg sprint_id toe aan BacklogStory/Story/SprintStory + select in PB-
  pagina's en sprint-board mappings, zodat de banner accuraat kan tellen
- createSprintAction: revalidatePath met 'layout' flag voor consistency
  met createSprintWithPbisAction (top-nav 'Sprint' link ververst direct)

Sprint-switch data-refresh op alle relevante pagina's:

- BacklogHydrationWrapper: fingerprint-based re-hydratie zodat PB-data
  na router.refresh opnieuw uit nieuwe initialData komt (was: useEffect
  met lege deps draaide alleen 1x)
- SprintBoardClient: key={sprint.id} forceert remount bij sprint-switch
  zodat lokale sprintStories/sprintStoryIds-state vers ge-init wordt
- Solo (desktop + mobile): gebruik resolveActiveSprint(id) ipv eerste
  OPEN-sprint, plus key={sprint.id} op SoloBoard voor remount

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 16:27:24 +02:00
6a76bc0f8c feat(sprint): edit-icoon op PBI (Product Backlog) en story (Sprint Backlog)
- PBI-rij in Product Backlog-kolom: ✎-icoon rechts uitgelijnd, opent PbiDialog
  (rij is nu div role=button i.p.v. nested-button)
- Story-rij in Sprint Backlog-kolom: ✎-icoon vóór de Trash, opent StoryDialog
- SprintStory + PbiWithStories verrijkt met velden die de dialogen lezen
  (description / acceptance_criteria / pbi_id / created_at op story; priority /
  status / description op PBI)
- pbi.status via pbiStatusToApi → PbiStatusApi (DB UPPER_SNAKE → API lowercase)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 09:19:49 +02:00
cc6baeebc1 feat(sprint): filter popover op Product-Backlog-kolom
Spiegelt het filter-patroon van de Product Backlog-pagina (PbiList) naar de
Sprint-Product-Backlog-kolom: prioriteit + status pills, actieve-filter chips,
localStorage-persistentie. Bestaande collapse-/expand-/alleen-niet-klaar-knoppen
blijven naast de popover staan.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 09:10:05 +02:00
1cb5772edd
M12 / ST-1110: Demo gebruiker read-only (#17)
* feat(ST-1110.3): add proxy.ts demo-guard for non-GET API routes

* feat(ST-1110.3+4): demo-guard proxy + block demo in QR-pairing

- proxy.ts: gebruik unsealData ipv getIronSession (middleware-compatibel)
- pair/start: isDemo-check via cookies() guard
- pair/claim: check pairing.user.is_demo na DB-read; 403 + clearPairCookie

* feat(ST-1110.5): unify demo write-button pattern to disabled+tooltip

Convert all !isDemo && <Button> patterns to <DemoTooltip show={isDemo}>
<Button disabled={isDemo}> so demo visitors see app capabilities.
Affects: pbi-list, story-panel, story-dialog, task-list, sprint-backlog,
token-manager, product-list, activate-product-button, leave-product-button,
settings page.

* test(ST-1110.6): proxy demo-guard coverage — 403 for demo+non-GET on /api/*

* docs(ST-1110.7): document three-layer demo-readonly policy and mirror plan
2026-04-29 18:44:14 +02:00
88dca4102c
feat(M9): active product backlog — persistent active PB, NavBar splits, sprint card styling (#10)
* feat(tooling): extend backlog parser to support PBI-x milestone headers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(backlog): mark ST-801–806 as done

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(backlog): sorteer PBI's en stories op prio/code/datum, onthoud keuze in localStorage; vergroot sprint-afronden dialoog

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-901): add user.active_product_id with FK to Product

- Nullable relation User → Product with onDelete: SetNull
- Index on active_product_id for join performance
- Migration: 20260427165329_add_user_active_product_id
- Install @tanstack/react-table (was missing from node_modules)
- Fix PRIORITY_COLORS ref removed in earlier refactor
- Note: User schema change affects vendor/scrum4me-mcp submodule — run prisma generate + tsc --noEmit there after merge

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: restore priority color on PBI filter pill

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-902): add setActiveProduct + clearActiveProduct server actions

- actions/active-product.ts: setActiveProductAction validates access via
  productAccessFilter, rejects archived products and demo users
- archiveProductAction: clears active_product_id for all affected users in transaction
- removeProductMemberAction: clears active_product_id for removed member
- leaveProductAction: clears active_product_id for leaving user

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-903): load active product in layout, replace cookie with DB lookup in solo

- layout.tsx: fetch active_product_id, resolve product, clear stale ref server-side
- NavBar: add activeProduct prop (rendering changes in ST-904)
- solo/page.tsx: redirect via user.active_product_id instead of lastProductId cookie
- proxy.ts: remove lastProductId cookie logic
- lib/cookies.ts: deleted (no longer used)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-904): split NavBar into 5 tabs with disabled-states and product-switcher dropdown

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(ST-905): add Activeer button per product row in dashboard and product header

* feat(ST-906): redirect to dashboard with toast when active product becomes inaccessible

* feat(ST-907): tests for active-product actions and functional spec update for M9

* docs(M9): add implementation plan document and link from backlog

* feat: active PB indicator, Maak actief button and new product link in settings

* feat: apply priority-color card style to sprint story rows

* fix: move add-to-sprint click from entire card to + Toevoegen button

* feat: apply priority-color card style to sprint task rows

* fix(sprint-backlog): prevent text selection on PBI collapse button

* chore: bump version to 0.4.0 (M9 active product backlog)

* fix(landing): align logged-in nav left to match app NavBar

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 20:25:13 +02:00
b71eb53fa8 feat(ST-507): show code badges on cards, lists and dialogs across the app
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 20:36:59 +02:00
802aa58157 feat(ST-354): add bulk-claim button to Sprint Backlog panel header
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 16:26:07 +02:00
358c88a9d9 feat(ST-353): add assignee chip and claim/reassign dropdown to sprint story card
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 16:24:34 +02:00
0a27be4886 feat(ST-313): merge sprint board into single three-panel view
- TriplePane component with two resizable dividers, localStorage persistence, mobile tabs
- SprintBoardClient replaces SprintBacklogClient + PlanningRightClient
- Left panel: Product Backlog (PBIs with stories to add to sprint)
- Middle panel: Sprint Backlog (stories in sprint, click to select, sortable)
- Right panel: TaskList for selected story
- /sprint/planning redirects to /sprint
- Remove PlanningLeft, PlanningRightClient, SprintBacklogClient

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 22:53:39 +02:00
0bf635eca1 feat: ST-612 drag-and-drop tussen Product Backlog en Sprint Backlog
Vervangt de '+ Sprint' knop door cross-panel drag-and-drop:
- Sleep story van rechts (PB) naar links (SB) om toe te voegen
- Sleep story van links (SB) naar rechts (PB) om te verwijderen
- Gedeelde DndContext in SprintBacklogClient voor beide panelen
- Visuele dropzone-highlight bij hoveren
- Optimistische UI-updates met rollback bij fouten

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 17:00:25 +02:00
ecc7a10679 fix: lint errors en warnings opgelost voor CI 2026-04-24 14:09:03 +02:00
d11b114fc1 feat: ST-601-ST-612 M6 polish, beveiliging en launch-ready
- ST-601/602: loading skeletons en error boundary
- ST-603: Sonner toasts op alle CRUD-operaties
- ST-604: DemoTooltip op uitgeschakelde knoppen
- ST-605: KeyboardSensor dnd-kit, Escape sluit modals
- ST-606: min-width banner < 1024px
- ST-607: WCAG AA aria-labels en skip link
- ST-608: rate limiting login (10/min) en registratie (5/uur)
- ST-609: security integratietests cross-user toegang (7 tests)
- ST-610: GitHub Actions CI/CD workflow
- ST-611: README met quickstart, deployment en API-docs
- ST-612: Lars-flow acceptatiechecklist
- fix: settings toont gebruikersnaam i.p.v. interne id
- fix: seed idempotent, testdata altijd gekoppeld aan demo-gebruiker

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 12:36:23 +02:00
d92e548f88 feat: ST-301-ST-312 M3 Sprint Backlog en Sprint Planning
- useSprintStore met sprintStoryOrder/taskOrder (ST-301)
- Sprint aanmaken modal met Sprint Goal validatie (ST-302)
- Sprint Backlog pagina SplitPane layout met Sprint Goal header (ST-303)
- Stories toevoegen aan Sprint via knop in rechterpaneel (ST-304)
- Sprint Backlog volgorde aanpassen via dnd-kit (ST-305)
- Story uit Sprint verwijderen met status terug naar OPEN (ST-306)
- Sprint Planning pagina SplitPane met story selectie (ST-307)
- Taken aanmaken inline in rechterpaneel (ST-308)
- Taak drag-and-drop verticaal met optimistische update (ST-309)
- Taakstatus toggle TO_DO/IN_PROGRESS/DONE met voortgangsindicator (ST-310)
- Taak inline bewerken en verwijderen (ST-311)
- Sprint afronden dialoog met per-story Done/Terug keuze (ST-312)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 11:51:27 +02:00