* docs: plan load render workspace alignment * fix: normalize workspace status hydration * fix: avoid duplicate backlog hydration load * refactor: use sprint store active story * refactor: migrate solo to workspace store * chore: stabilize verification ignores
7.3 KiB
| title | date | status | scope | source_review | chosen_solo_option | |||||
|---|---|---|---|---|---|---|---|---|---|---|
| Verbeterplan load/render Product Backlog, Sprint en Solo | 2026-05-10 | draft |
|
../recommendations/load-render-implementation-review-2026-05-10.md | 5B - Solo workspace-store migratie |
Verbeterplan load/render Product Backlog, Sprint en Solo
Doel
Maak de load/render-flow van Product Backlog, Sprint en Solo voorspelbaar, gelijkvormig en goedkoper:
- geen dubbele initial loads;
- een expliciet status-contract tussen server, API, stores en UI;
- consistente hydration/resync na reconnect, tab-visible en refresh;
- minder stale render state in Solo;
- duidelijke store-eigenaarschap per scherm.
Uitgangspunten
- De route/API-boundary mag lowercase API-statussen blijven gebruiken.
- De interne Product/Sprint workspace UI verwacht nu story/task statussen als DB
UPPER_SNAKE. - Product Backlog en Sprint zijn de referentie voor het gewenste patroon: server snapshot, client hydration wrapper, workspace-store, SSE, directe store-resync.
- Solo hoeft niet in dezelfde grote store te worden gemigreerd in de eerste stap, maar zijn refresh-hydration moet wel correct worden.
Fase 1 - Status-contract vastleggen en afdwingen
Stap 1.1 - Leg het interne contract vast
Besluit en documenteer:
- PBI-status in Product Backlog blijft API-lowercase zolang
PBI_STATUS_LABELSenPBI_STATUS_COLORSdaarop gebouwd zijn. - Story-status en task-status in Product/Sprint workspace-stores zijn intern
UPPER_SNAKE. - API routes blijven lowercase teruggeven aan externe/REST clients.
Stap 1.2 - Voeg adapters toe aan de workspace-store boundary
Maak kleine adapterfuncties voor API-responses voordat data in stores wordt gehydrateerd:
- Product workspace:
- full backlog snapshot;
- PBI stories;
- story tasks;
- task detail.
- Sprint workspace:
- sprint workspace snapshot;
- story tasks;
- task detail.
Gebruik bestaande mappers uit lib/task-status.ts, bijvoorbeeld storyStatusFromApi en taskStatusFromApi.
Stap 1.3 - Voeg regressietests toe
Test minimaal:
- API lowercase
todowordt in task UI-storeTO_DO; - API lowercase
in_sprintwordt in story UI-storeIN_SPRINT; - bestaande PBI lowercase status blijft lowercase;
- Sprint
STATUS_CYCLEkrijgt nooit lowercase input vanuit de store.
Fase 2 - Dubbele Product Backlog load verwijderen
Stap 2.1 - Maak hydration eigenaar van de initial backlog snapshot
Pas Product Backlog aan naar hetzelfde eigenaarschap als Sprint:
BacklogHydrationWrapperhydrateert snapshot;- wrapper zet ook
context.activeProduct; - wrapper markeert
loadedProductId; SetCurrentProductstart op routes met eigen hydration geen fullensureProductLoaded.
Stap 2.2 - Guard setActiveProduct
Voeg een guard toe zodat setActiveProduct(product) geen ensureProductLoaded start als:
- hetzelfde product al actief is;
loading.loadedProductId === product.id;- er al een volledige snapshot gehydrateerd is.
Stap 2.3 - Meet en verifieer
Controleer in devtools/server logs:
- openen van Product Backlog doet geen extra
/api/products/:id/backlogna de server-render; - navigeren tussen product routes laadt nog steeds correct;
- restore hints voor laatste PBI/story/task blijven werken.
Fase 3 - Sprint selectie gelijkvormig maken
Stap 3.1 - Verplaats geselecteerde story naar de sprint workspace-store
Vervang lokale selectedStoryId in SprintBoardClient door:
useSprintWorkspaceStore((s) => s.context.activeStoryId);useSprintWorkspaceStore.getState().setActiveStory(storyId);- reset via
setActiveStory(null)bij verwijderen uit sprint.
Stap 3.2 - Laat TaskList active-context gebruiken
Maak TaskList gelijkvormig met Product Backlog:
- lees taken via
selectTasksForActiveStory; - behoud
storyIdalleen als fallback of verwijder de prop; - zorg dat
resyncActiveScopesnu de actieve story/task werkelijk kan meenemen.
Stap 3.3 - Restore-hints testen
Verifieer:
- story-selectie blijft behouden na refresh/reconnect;
- task-paneel toont dezelfde story na tab-visible resync;
- verwijderen van de actieve story reset taakpaneel netjes.
Fase 4 - Solo refresh-hydration correct maken
Stap 4.1 - Vervang task-id-only dependency
Vervang taskKey = initialTasks.map(t => t.id).join(',') door een render-relevante fingerprint, bijvoorbeeld:
id;status;sort_order;title;implementation_plan;story_id;story_title;story_code;task_code;- relevante verify/queue velden.
Of hydrateer op iedere nieuwe initialTasks prop als performance acceptabel is.
Stap 4.2 - Sync unassigned stories uit props
Voeg een effect toe die unassignedStories bijwerkt wanneer initialUnassigned inhoudelijk wijzigt.
Stap 4.3 - Sorteer solo kolommen expliciet
Render columnTasks gesorteerd op sort_order en daarna stabiel op code/titel/id. Vertrouw niet op object insertion order.
Stap 4.4 - Test gemiste event scenario's
Test:
- tab hidden, task status wijzigt extern, tab visible: kaart staat in juiste kolom;
- reconnect met dezelfde task ids maar gewijzigde titel/status: UI update;
- nieuwe unassigned story verschijnt na refresh;
- gewijzigde
sort_orderpast de render-volgorde aan.
Fase 5 - Solo naar een gelijkvormig workspace-store patroon
Gekozen route: Optie B. Solo wordt naar een workspace-store patroon gemigreerd dat aansluit op Product Backlog en Sprint.
Optie B - Grote stap
Migreer Solo naar een workspace-store patroon vergelijkbaar met Product/Sprint:
- normalized entities;
- active sprint/product context;
- loaded scopes;
- resync methods;
- realtime event adapters.
Concrete taken:
- Introduceer
stores/solo-workspace/{types,selectors,store}.ts. - Introduceer een
SoloHydrationWrapperdie server snapshot en actieve context hydrateert. - Laat
SoloBoardrenderen vanuit selectors in de solo workspace-store. - Verplaats realtime event handling en job/worker status naar de solo workspace-store.
- Vervang
router.refresh()als primaire resync doorresyncActiveScopes. - Houd route refresh alleen over als expliciete fallback voor onbekende events of navigatiecases.
Fase 6 - Observability en performance check
Voeg tijdelijk of permanent meetpunten toe:
- log of dev-only counter voor hydration calls per scherm;
- log of dev-only counter voor API
ensure*Loadedcalls; - React Profiler rond Product Backlog/Sprint/Solo pane containers;
- netwerkcheck op dubbele fetches.
Acceptatiecriteria:
- Product Backlog doet bij eerste openen maximaal een server snapshot plus SSE connect, geen extra full-backlog client fetch.
- Product en Sprint stores bevatten geen lowercase story/task statussen.
- Solo refresh verwerkt bestaande tasks met gewijzigde velden.
- Product Backlog, Sprint en Solo hebben per scherm precies een duidelijke eigenaar voor initial hydration.
Voorgestelde implementatievolgorde
- Status adapters en tests toevoegen.
- Product Backlog dubbele load verwijderen.
- Sprint active story selectie naar store verplaatsen.
- Solo workspace-store introduceren en hydrateren.
- Solo realtime/resync naar workspace-store verplaatsen.
- Performance/netwerk verifiëren.
Deze volgorde beperkt risico: eerst het data-contract, daarna de extra load, daarna gelijkvormigheid en Solo-resync.