Bij sprint-switch wordt de sprint-content server-side opgevraagd. Wanneer
de sprint precies één PBI (en die PBI exact één story binnen de sprint)
heeft, worden PBI en story automatisch geselecteerd. Alle drie keuzes
(sprint, pbi, story) worden atomair in user-settings opgeslagen zodat ze
cross-device blijven hangen.
- lib/user-settings.ts: layout krijgt nullable activePbis +
activeStories per product.
- lib/active-sprint.ts: setActiveSelectionInSettings schrijft de drie
keys atomair + notify pg_notify.
- actions/active-sprint.ts: switchActiveSprintAction(productId, sprintId)
doet de server-side auto-select-resolutie (single PBI → single story)
en returnt { sprintId, pbiId, storyId }.
- components/shared/sprint-switcher.tsx: handleSwitchSprint roept de
nieuwe action aan en synchroniseert de workspace-store gelijk zodat
de UI geen flash krijgt voor de SSR-refresh.
- components/backlog/active-selection-hydrator.tsx (nieuw): client-side
effect dat user-settings.activePbis/activeStories naar workspace-store
spiegelt; wint van de localStorage hint-restore.
- app/(app)/products/[id]/page.tsx: ActiveSelectionHydrator gemount
binnen BacklogHydrationWrapper.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- lib/user-settings.ts: activeSprints values nullable in Zod-schema.
Key-aanwezigheid heeft nu betekenis (key+null = bewust geen sprint;
key ontbreekt = fallback-cascade).
- lib/active-sprint.ts: nieuwe readStoredActiveSprintState helper +
resolveActiveSprint respecteert expliciet 'cleared' state zonder fallback.
clearActiveSprintInSettings schrijft null i.p.v. de key te verwijderen.
- actions/active-sprint.ts: nieuwe clearActiveSprintAction met auth +
membership-check.
- components/shared/sprint-switcher.tsx: '— Geen actieve sprint —'-optie
in dropdown, disabled wanneer er geen actieve sprint is.
- Tests: nieuwe active-sprint.test.ts (resolver-paden + clear),
active-sprint-action.test.ts (action-laag), uitbreiding user-settings.test.ts.
Plan: docs/plans/PBI-79-backlog-sprint-workflow.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(PBI-76): extend UserSettings schema with layout
Adds layout.splitPanePositions and layout.activeSprints. These will
hold values currently kept in client-side and server-side cookies
(Phase 2). Two new tests cover the shape.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(PBI-76): migrate SplitPane positions to user-settings store
Outside of a drag the store is the source of truth (cross-tab
updates flow in for free). During a drag we keep splits in local
state so mousemove does not round-trip through the store. On
mouseup we persist the final splits via setPref. Removes
document.cookie reads/writes — cookieKey is reused as the
store-key for backwards compat.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(PBI-76): resolveActiveSprint reads from User.settings
lib/active-sprint:
- New helpers: getActiveSprintIdFromSettings, setActiveSprintInSettings,
clearActiveSprintInSettings — all read/write user.settings.layout.activeSprints.
- resolveActiveSprint(productId, userId) — userId now required, falls back
to first OPEN, then most recent CLOSED sprint.
- Cookie helpers (getActiveSprintIdFromCookie/setActiveSprintCookie/
clearActiveSprintCookie) removed.
Callers updated to pass session.userId. The cookie-based fallback path
is gone — `actions/active-sprint.ts` and `actions/sprints.ts` will be
updated in the next commit (T-917).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(PBI-76): rewrite setActiveSprint callers to use settings
setActiveSprintAction, syncActiveSprintCookieAction, and the two
sprint-creation paths in actions/sprints.ts now write through
setActiveSprintInSettings (which also emits pg_notify for cross-tab
sync) instead of dropping a cookie. The action names keep the
'cookie' suffix in the user-visible API for now — clean rename can
come later.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(PBI-76): migration helper v2 — handle legacy cookies
Bumps marker version to 'v2'. buildMigrationPatch now also scans
document.cookie for `sp:*` (split-pane positions) and
`active_sprint_*` (active sprint per product) and lifts them into
layout.splitPanePositions / layout.activeSprints. clearLegacyStorage
replaces clearLegacyLocalStorage and clears both keys and cookies.
clearLegacyLocalStorage stays as a deprecated alias so the bridge
upgrade is a single rename.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(PBI-76): align tests with new SplitPane and active-sprint flow
- split-pane.test.tsx: seed positions via Zustand store instead of
document.cookie; mock @/actions/user-settings so the prisma client
is not transitively initialised in jsdom.
- backlog-split-pane.test.tsx: same action mock.
- sprint-dates.test.ts: add user.findUnique/update + $executeRaw
mocks because createSprintAction now writes to user-settings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>