Scrum4Me/docs/old/plans/PBI-11-mobile-shell.md
Janpeter Visser b39c3ec2e1
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>
2026-05-11 19:46:00 +02:00

198 lines
9.4 KiB
Markdown
Raw Permalink 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.

# PBI-11 — Mobile-shell met landscape-lock (settings + backlog + solo)
> **Status:** READY · priority 3 · sort_order 8
> **Stories:** ST-1133 (TaskDialog full-screen) · ST-1134 (foundation) · ST-1135 (UA-redirect) · ST-1136 (settings) · ST-1137 (backlog) · ST-1138 (solo) · ST-1139 (docs + E2E)
## Doel
Scrum4Me bruikbaar maken op een mobiele telefoon, beperkt tot drie schermen — Settings (account + product-selector + QR-pairing-instructie + logout), Product Backlog (PBI/Story/Task aanmaken), Solo Paneel (voortgang vastleggen). Landscape-orientatie afgedwongen via PWA-manifest + CSS-overlay. App-naam en -icoon onderdrukken op `/m/*`. Desktop-app blijft ongewijzigd.
## Drie architectuur-beslissingen
### Beslissing A — gedeelde dialog-classes (raakt ST-1133 + ST-1138)
Alle entity-dialogen (PbiDialog, StoryDialog, TaskDialog, TaskDetailDialog) delen dezelfde class-string in [components/shared/entity-dialog-layout.ts](../../components/shared/entity-dialog-layout.ts):
```ts
export const entityDialogContentClasses = cn(
'flex flex-col p-0 gap-0',
'max-h-[90vh] w-full max-w-[calc(100%-2rem)]',
'sm:max-w-[90vw] sm:max-h-[85vh]',
'lg:max-w-[50vw] lg:min-w-[480px]',
)
```
→ Mobile-fullscreen wordt via één edit op deze constant geregeld:
```ts
'max-sm:w-screen max-sm:h-screen max-sm:max-w-none max-sm:rounded-none'
```
**Gevolg voor stories:**
- ST-1133 T-317 muteert `entity-dialog-layout.ts`, niet `task-dialog.tsx` rechtstreeks
- ST-1138 T-332 vervalt als file-edit — wordt verify-only (controleer dat TaskDetailDialog mee-erft)
- PBI/Story-dialogen krijgen mobile-fullscreen "voor niets" (handig voor ST-1137)
### Beslissing B — eigen route group `app/(mobile)/`
Parent layout `app/(app)/layout.tsx` rendert NavBar, MinWidthBanner, StatusBar, SoloRealtimeBridge, NotificationsBridge. Een nested layout in `(app)/m/` kan deze parent-output **niet** verwijderen (Next.js layouts erven naar binnen, niet vervangen).
**Keuze:** verplaats `/m/*` naar een eigen route group `app/(mobile)/m/{settings,pair,products}/...` met eigen `app/(mobile)/layout.tsx`.
**Auth-guard duplicatie voorkomen** door `getSession()`-check te extraheren naar `lib/auth-guard.ts`:
```ts
// lib/auth-guard.ts
export async function requireSession() {
const session = await getSession()
if (!session.userId) redirect('/login')
return session
}
```
Beide layouts (`(app)/layout.tsx` en `(mobile)/layout.tsx`) roepen deze helper aan. Bestaande `/m/pair/page.tsx` (M10 QR-pairing) verhuist mee naar `app/(mobile)/m/pair/page.tsx` — geen URL-wijziging, alleen filesystem-move.
**Gevolg voor stories:**
- ST-1134 T-321 schrijft `app/(mobile)/layout.tsx`, niet `app/(app)/m/layout.tsx`
- ST-1136 page wordt `app/(mobile)/m/settings/page.tsx`
- ST-1137 page wordt `app/(mobile)/m/products/[id]/page.tsx`
- ST-1138 page wordt `app/(mobile)/m/products/[id]/solo/page.tsx`
- M10's `/m/pair` verhuist naar `app/(mobile)/m/pair/` — URL ongewijzigd, geen redirect-migratie nodig
### Beslissing C — gescheiden SplitPane cookie-key
ST-1137 hergebruikt `BacklogSplitPane` (drie panelen). Op mobile rendert die in tab-mode (auto-switch + back-button uit ST-1116). De SplitPane bewaart split-percentages in een cookie.
**Keuze:** gescheiden cookie-key voor mobile — `split-pane:backlog-3-mobile:<id>` — zodat mobile-gebruikers (die in tab-mode geen split-percentages bewerken maar wel terug kunnen schakelen) de desktop-split niet beïnvloeden.
**Gevolg voor stories:**
- ST-1137 T-328 geeft expliciete `cookieKey`-prop aan `BacklogSplitPane` op de mobile-route
## Hergebruik (al aanwezig)
| Wat | Bron |
|---|---|
| Mobile tab-mode in `SplitPane` (incl. `tabLabels`, `mobileBreakpoint`, `activeTab`) | ST-1116 — [components/split-pane/split-pane.tsx](../../components/split-pane/split-pane.tsx) |
| Click-cascade auto-switch in `BacklogSplitPane` | ST-1116 commit `3e86a8d` |
| QR-pairing route `/m/pair` | M10 commit `625221f` |
| `/m/pair` confirmation page | bestaand |
| Functional-spec mobile-tabs sectie | `docs/specs/functional.md:234-235` |
## Stories
### ST-1133 — TaskDialog full-screen op mobile (verifieer en fix)
**Doel:** entity-dialogen renderen 100vw × 100vh op viewport `<640px`.
**Acceptance:**
- `entityDialogContentClasses` in `components/shared/entity-dialog-layout.ts` bevat `max-sm:w-screen max-sm:h-screen max-sm:max-w-none max-sm:rounded-none`
- Sticky header en footer blijven bereikbaar; body scrollt
- Werkt voor TaskDialog, TaskDetailDialog, PbiDialog, StoryDialog (alle gebruiken de constant)
- Tests dekken mobile-render via `window.innerWidth`-mock voor minstens TaskDialog en TaskDetailDialog
- Geen regressie op desktop (`sm:max-w-[90vw]` blijft op `>=640px`)
**Tasks:**
- T-316 inventariseer huidige render
- T-317 fix de gedeelde constant
- T-318 tests
### ST-1134 — Mobile shell foundation (route group + landscape-guard + tab-bar + manifest)
**Doel:** route group `(mobile)`, landscape-overlay, bottom tab-bar, PWA-manifest.
**Acceptance:**
- `app/(mobile)/layout.tsx` rendert zonder NavBar / AppIcon / MinWidthBanner / StatusBar
- Auth-guard via gedeelde `lib/auth-guard.ts` helper; `(app)/layout.tsx` gebruikt dezelfde helper
- `<LandscapeGuard>` toont rotate-overlay in portrait (window.matchMedia)
- `<MobileTabBar>` bottom-fixed met 3 lucide-iconen (ListTree, Activity, Settings); tap-targets ≥44×44 px
- `public/manifest.json` bevat `"orientation": "landscape"`
- M10 `/m/pair` verhuist filesystem-only naar `app/(mobile)/m/pair/` — URL onveranderd
- Tests: LandscapeGuard render-states, TabBar route-active, auth-guard helper
**Tasks:**
- T-319 LandscapeGuard
- T-320 MobileTabBar
- T-321 `(mobile)/layout.tsx` + manifest + auth-guard extractie + filesystem-move van `/m/pair`
### ST-1135 — Mobile UA-redirect bij login
**Acceptance:**
- `lib/user-agent.ts` exporteert `isPhoneUA(ua: string | null): boolean` op basis van `Mobi`-substring
- `actions/auth.ts` `loginAction` redirect bij phone-UA naar `/m/products/[active]/solo`; zonder actief product naar `/m/settings`
- Tablet-UA en desktop-UA blijven op `/dashboard`
- Demo-user volgt zelfde routing
- Tests dekken alle paden (phone met/zonder product, tablet, desktop, null UA, demo)
**Tasks:** T-322 helper · T-323 loginAction integratie · T-324 tests
### ST-1136 — Mobile Settings-pagina
**Acceptance:**
- `app/(mobile)/m/settings/page.tsx`
- Toont username, isDemo-badge, actief-product-naam
- Product-selector — klik → `setActiveProductAction` + redirect `/m/products/[id]/solo`
- QR-pairing-instructie — link "Open scrum4me.app/login op je desktop om in te loggen via QR"
- Logout-knop met AlertDialog "Uitloggen?" → `logoutAction`
- Geen avatar-upload, geen bio-edit
- Tests render-states + logout-flow
**Tasks:** T-325 layout · T-326 logout-flow · T-327 tests
### ST-1137 — Mobile Product Backlog-pagina
**Acceptance:**
- `app/(mobile)/m/products/[id]/page.tsx` hergebruikt PbiList/StoryPanel/TaskPanel + backlog-store
- `BacklogSplitPane` rendert in tab-mode op `<1024px`; auto-switch op selectie blijft werken
- TaskDialog-searchParams wiring (`?newTask=`, `?editTask=`, `?storyId=`) werkt
- Cookie-key gescheiden: `split-pane:backlog-3-mobile:<id>`
- + knoppen voor PBI/Story/Task werken; demo blijft read-only
- Tests: page-rendering met initial state, tab-mode, click-cascade-flow
**Tasks:** T-328 page wrapper + cookie-key · T-329 TaskDialog wiring · T-330 tests
### ST-1138 — Mobile Solo Paneel
**Acceptance:**
- `app/(mobile)/m/products/[id]/solo/page.tsx` hergebruikt SoloBoard
- 3 kanban-kolommen blijven; horizontal scroll
- TaskDetailDialog rendert 100vw × 100vh op `<640px`**gedekt door beslissing A** (entityDialogContentClasses)
- "Voer uit"-knop bereikbaar
- SSE-stream blijft werken
- Tests: solo-page rendert, TaskDetailDialog erft mobile-classes (zonder eigen file-edit)
**Tasks:**
- T-331 page wrapper
- T-332 verify-only (geen file-edit; controleer dat shared constant uit ST-1133 doorwerkt)
- T-333 tests
### ST-1139 — Docs sync + end-to-end verificatie
**Acceptance:**
- `docs/specs/functional.md` heeft "Mobile shell"-sectie; desktop-first-clausule herzien
- `docs/architecture.md` beschrijft route group `(mobile)`, manifest landscape, UA-redirect, gedeelde auth-guard
- `npm run lint && npm test && npm run build` slagen
- E2E checklist (11 punten — zie hieronder)
- Bekende limiet: iOS Safari PWA-orientation-lock werkt niet 100% — CSS-overlay als fallback
**Tasks:** T-334 functional-spec · T-335 architecture-doc · T-336 E2E-verificatie
## Verificatie (E2E checklist uit T-336)
1. `npm run lint && npm test && npm run build` slagen
2. DevTools mobile-emulatie iPhone 12 landscape: `/m/products/[id]` rendert tab-mode, geen NavBar, tab-bar onderaan
3. Portrait → rotate-overlay zichtbaar; landscape → overlay verdwijnt
4. Tab-bar 3 iconen werken (Backlog/Solo/Settings)
5. Login phone-UA → redirect `/m/products/[id]/solo`; desktop-UA → `/dashboard`
6. Backlog-flow: + PBI, + Story, + Task in TaskDialog
7. Solo-flow: tap task → TaskDetailDialog full-screen, "Voer uit"-knop bereikbaar
8. TaskDialog full-screen op `<640px` (via shared constant)
9. PWA-installatie test op echte mobile (Android of iOS)
10. `/m/pair` QR-flow intact na route-group-verhuizing
11. Demo op mobile read-only; logout via `/m/settings` werkt; geen Scrum4Me-tekst of AppIcon op `/m/*`
## Out of scope
- Tablets (geen Mobi-UA) blijven desktop-flow gebruiken
- iOS PWA full-orientation-lock (CSS-overlay is fallback)
- Avatar/bio editor op mobile-settings
- 1-koloms-kanban (3-koloms blijft, swipe horizontaal)