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
6.2 KiB
| phase | plan | subsystem | tags | dependency_graph | tech_stack | key_files | decisions | metrics | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 02-mobile-shell-more-drawer | 01 | mobile-shell |
|
|
|
|
|
|
Phase 02 Plan 01: Mobile Shell Components Summary
Three new reusable shell components and an analyzer route placeholder — the building blocks Plan 02 will wire into app/mobile/layout.tsx to complete the mobile shell redesign.
What Was Built
MoreDrawer (components/mobile/MoreDrawer.tsx) — shadcn Sheet (side="right") with controlled open/onOpenChange props so both the header avatar and the bottom-nav More button share one drawer instance. Three sections:
- Mobile sections: Engagement (in-shell, no ExternalLink)
- Full site: Quotes, Configuration Items, Backup Status, Ticket Digest, Admin/Sync (each with ExternalLink icon)
- Account: user initials + name/email (read-only) + Sign out (calls
signOut()then navigates to/auth/sign-in)
HeaderBar (components/mobile/HeaderBar.tsx) — sticky header with bg-background/95 backdrop-blur border-b pt-safe. Left: WulfMark + "Pulse" wordmark linked to /mobile/dashboard. Right: Bell placeholder (aria-label="Notifications", empty onClick) + compact avatar circle (h-7 w-7) calling onAvatarClick prop. No page title in the header.
BottomNav (components/mobile/BottomNav.tsx) — fixed bottom bar (border-t bg-background pb-safe, max-w-lg mx-auto, h-16). Four tabs: Dashboard (LayoutDashboard), Tickets (Ticket), Finance (DollarSign), Analyzer (Sparkles) — all with pathname.startsWith(href) active detection (text-primary when active, text-muted-foreground otherwise). Fifth cell: More button calling onMoreClick prop.
Analyzer placeholder (app/mobile/analyzer/page.tsx) — minimal server component with "coming soon" card. Resolves the /mobile/analyzer route so the new Analyzer tab doesn't 404 before Phase 6 (ANL-01..06) ships the real feed.
Requirements Addressed
| Requirement | Status |
|---|---|
| SHELL-02 | Sticky header, brand mark+wordmark, /mobile/dashboard link, backdrop blur, border-b |
| SHELL-03 | Bell placeholder with aria-label, empty onClick |
| SHELL-04 | Avatar circle h-7 w-7, triggers drawer via onAvatarClick |
| SHELL-06 | Fixed bottom nav, max-w-lg mx-auto, border-t, pb-safe |
| NAV-01 | 4 tab icons: LayoutDashboard, Ticket, DollarSign, Sparkles + Menu for More |
| NAV-02 | 4 routes: /mobile/dashboard, /mobile/tickets, /mobile/finance, /mobile/analyzer |
| NAV-03 | pathname.startsWith(href) active detection, text-primary/text-muted-foreground |
| DRAWER-01 | More button in BottomNav triggers shared drawer via onMoreClick prop |
| DRAWER-02 | Sheet side="right" (locked decision) |
| DRAWER-03 | Mobile sections: Engagement /mobile/engagement (no ExternalLink) |
| DRAWER-04 | Full site: Quotes, Config Items, Backup Status, Ticket Digest, Admin/Sync with ExternalLink |
| DRAWER-05 | Account: user display (read-only) + Sign out via signOut() + router.push('/auth/sign-in') |
Locked Decisions Honored
side="right"— locked in CONTEXT.md DRAWER-02- No shadcn
avatarprimitive — uses existing initials-circle pattern from UserMenu - Bell
onClickis empty — SHELL-03 explicitly says "placeholder only this iteration" - No
<h1>in HeaderBar — SHELL-02 explicit: "pages render their own H1" - MoreDrawer uses controlled state (props, not internal) — both triggers share one drawer
Notes for Plan 02
Plan 02 rewrites app/mobile/layout.tsx and deletes app/mobile/nav/page.tsx. When wiring the new components:
// In layout.tsx (Plan 02):
const [drawerOpen, setDrawerOpen] = useState(false);
<HeaderBar onAvatarClick={() => setDrawerOpen(true)} />
<MoreDrawer open={drawerOpen} onOpenChange={setDrawerOpen} />
<BottomNav onMoreClick={() => setDrawerOpen(true)} />
Deviations from Plan
None — plan executed exactly as written.
Known Stubs
| File | Stub | Reason |
|---|---|---|
app/mobile/analyzer/page.tsx |
"coming soon" card, no data | Intentional — Phase 6 (ANL-01..06) owns the real mobile analyzer feed. This file exists only to prevent a 404 on the new BottomNav Analyzer tab. |
components/mobile/HeaderBar.tsx |
Bell onClick is empty | Intentional — SHELL-03 explicitly defers real notifications to Phase 7+. |
Threat Flags
None — no new network endpoints, no new auth paths, no new DB access. All trust boundaries match the plan's threat model exactly.
Self-Check: PASSED
Files verified:
components/mobile/HeaderBar.tsx— existscomponents/mobile/BottomNav.tsx— existscomponents/mobile/MoreDrawer.tsx— existsapp/mobile/analyzer/page.tsx— exists
Commits verified:
6630589— feat(02-01): create MoreDrawer component14375f1— feat(02-01): create HeaderBar componenta42c0a8— feat(02-01): create BottomNav component3fc0ee3— feat(02-01): add /mobile/analyzer placeholder
Build: npx tsc --noEmit --pretty exits 0, npm run build exits 0 (273 routes generated, /mobile/analyzer in route table).