The soft reset to 77073ba inadvertently staged deletions of all phase 2
and 3 artifacts. This commit restores them from their source commits so
subsequent task commits build on the complete prior-phase foundation:
- components/mobile/{BottomNav,HeaderBar,KpiCardMobile,MoreDrawer,NeedsAttentionStrip,WorkerStatusRow}
- app/mobile/layout.tsx, dashboard/page.tsx, analyzer/page.tsx
- app/api/mobile/dashboard/route.ts
- All .planning/** files from phases 01-04
- CLAUDE.md, app/layout.tsx, app/styles/brand.css, public/manifest.json
7.2 KiB
phase: 02-mobile-shell-more-drawer plan: 02 subsystem: mobile-shell tags: [mobile, navigation, shell, drawer, layout, react-state]
dependency_graph: requires: - phase: 02-01 provides: HeaderBar, BottomNav, MoreDrawer components in components/mobile/ provides: - app/mobile/layout.tsx (new shell wiring all three components with shared drawer state) - DRAWER-06 fulfilled — app/mobile/nav/page.tsx deleted, /mobile/nav returns 404 affects: - All /mobile/* pages — they automatically land inside the new shell (header + bottom nav visible) - Phases 3-7 — page authors must NOT add their own header or bottom nav
tech-stack: added: [] patterns: - Single useState(drawerOpen) in layout.tsx shared between two triggers (avatar + More button) - pb-[calc(theme(spacing.16)+env(safe-area-inset-bottom))] for bottom-nav-aware main padding - 'use client' layout with controlled Sheet drawer via child component props
key-files: created: [] modified: - app/mobile/layout.tsx deleted: - app/mobile/nav/page.tsx
key-decisions:
- "Single useState in layout.tsx — no Zustand, no Context — per CLAUDE.md no new state libraries"
- "pb-[calc(theme(spacing.16)+env(safe-area-inset-bottom))] Tailwind 4 arbitrary value worked without fallback to inline style"
- "No redirect for /mobile/nav deletion — per DRAWER-06 spec, 404 is the desired behavior"
- "Cleared .next cache before type-check to resolve stale validator.ts reference to deleted page"
patterns-established:
- "Mobile layout owns all chrome (header, bottom nav, drawer) — mobile pages render content only"
- "Drawer state lifted to layout — single Sheet instance shared between multiple triggers"
requirements-completed: [SHELL-01, SHELL-05, DRAWER-06]
duration: 8min completed: "2026-05-03"
Phase 02 Plan 02: Mobile Shell Wiring Summary
app/mobile/layout.tsx rewritten to wire HeaderBar + BottomNav + MoreDrawer with single shared useState, completing the Phase 2 mobile shell redesign
Performance
- Duration: ~8 min
- Started: 2026-05-03T20:03:00Z
- Completed: 2026-05-03T20:11:18Z
- Tasks: 3 auto + 1 visual checkpoint (auto-approved)
- Files modified: 2 (1 rewrite, 1 deletion)
Accomplishments
app/mobile/layout.tsxfully rewritten — sticky HeaderBar, scrollable main with bottom-nav-aware padding, fixed BottomNav, MoreDrawer with shared open state- Single
useState(drawerOpen)wires both the header avatar and the bottom-nav More button to the same drawer instance — no Zustand, no Context, no prop-drilling app/mobile/nav/page.tsxdeleted; visiting/mobile/navnow returns Next.js 404 per DRAWER-06 spec- TypeScript clean (
npx tsc --noEmitexits 0) and full build clean (272 routes,/mobile/navabsent from route table) - Combined with Plan 01, all 15 phase requirements (SHELL-01..06, NAV-01..03, DRAWER-01..06) are now satisfied
Requirements Addressed
| Requirement | Description | Status |
|---|---|---|
| SHELL-01 | /mobile/layout.tsx replaced in-place with new shell |
Closed |
| SHELL-05 | Scrollable main with bottom-nav-aware padding (pb-[calc(theme(spacing.16)+env(safe-area-inset-bottom))]) |
Closed |
| DRAWER-06 | /mobile/nav/page.tsx deleted; no redirect; 404 on visit |
Closed |
Combined with Plan 01, all 15 phase requirements are now closed:
| Plan | Requirements closed |
|---|---|
| 02-01 | SHELL-02, SHELL-03, SHELL-04, SHELL-06, NAV-01, NAV-02, NAV-03, DRAWER-01, DRAWER-02, DRAWER-03, DRAWER-04, DRAWER-05 |
| 02-02 | SHELL-01, SHELL-05, DRAWER-06 |
Task Commits
- Task 1: Rewrite app/mobile/layout.tsx -
7a095fb(feat) - Task 2: Delete app/mobile/nav/page.tsx -
2af7395(feat) - Task 3: Type-check + build gate - no commit (gate-only task; Tasks 1-2 already committed)
- Task 4: Visual checkpoint - auto-approved (auto mode active)
Files Created/Modified
app/mobile/layout.tsx— Rewritten; now imports HeaderBar/BottomNav/MoreDrawer, owns single useState for drawer, pads main content to clear bottom nav + safe-area insetapp/mobile/nav/page.tsx— Deleted; 91 lines removed; standalone nav page replaced by MoreDrawer Sheet
Decisions Made
- Single useState in layout.tsx — No new state libs per CLAUDE.md constraint. Both
onAvatarClickandonMoreClickcall() => setDrawerOpen(true); the Radix Sheet'sonOpenChangepropagates close events back throughsetDrawerOpen. - Tailwind 4 arbitrary value worked —
pb-[calc(theme(spacing.16)+env(safe-area-inset-bottom))]was accepted by the Tailwind 4 build without needing the inline-style fallback documented in the plan. - No redirect on /mobile/nav deletion — Per CONTEXT.md DRAWER-06: "URL was never bookmarked-worthy." Standard 404 is correct behavior.
Deviations from Plan
Auto-fixed Issues
1. [Rule 3 - Blocking] Cleared .next cache before type-check
- Found during: Task 3 (type-check gate)
- Issue:
.next/types/validator.tscontained a stale generated reference to../../app/mobile/nav/page.jsfrom a previous build. Runningnpx tsc --noEmitimmediately after deleting the file produced TS2307 on this generated file. - Fix:
rm -rf .nextbefore re-runningnpx tsc --noEmit. The generated validator regenerates on build and does not include the deleted route. - Files modified: None (cache directory, not source)
- Verification: Type-check exits 0 after cache clear; subsequent
npm run buildalso exits 0 - Committed in: Not committed (cache directory is gitignored)
Total deviations: 1 auto-fixed (1 blocking — stale build cache) Impact on plan: Necessary to unblock the type-check gate. No source file changes required.
Issues Encountered
None beyond the stale .next cache (documented above as a deviation).
User Setup Required
None — no external service configuration required.
Notes for Phases 3–7
Every /mobile/* page now automatically renders inside the new shell. Page authors must NOT add their own header or bottom nav. The layout provides:
- Sticky
<HeaderBar>at the top (brand + Bell placeholder + avatar → drawer) - Scrollable
<main>with bottom padding pre-applied (clears the 64px bottom nav + safe-area inset) - Fixed
<BottomNav>at the bottom (4 tabs + More → drawer) <MoreDrawer>(Sheet side="right") with three sections (Mobile sections / Full site / Account + Sign out)
Pages should render their own <h1> and content — the chrome is fully handled by the layout.
Known Stubs
None introduced by this plan. (Existing stubs from Plan 01 carry forward: analyzer placeholder card and Bell empty onClick — both intentional and documented in 02-01-SUMMARY.md.)
Threat Flags
None — no new network endpoints, no new auth paths, no new DB access. Layout is purely client-side React state + UI composition.
Self-Check: PASSED
Files verified:
app/mobile/layout.tsx— exists, imports all three components, contains useState + drawerOpen + safe-area-inset-bottomapp/mobile/nav/page.tsx— does not exist (deleted)/mobile/navabsent fromnpm run buildroute table
Commits verified:
7a095fb— feat(02-02): rewrite mobile layout2af7395— feat(02-02): delete app/mobile/nav/page.tsx