diff --git a/.planning/STATE.md b/.planning/STATE.md index 5881c07..e5a1350 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -4,7 +4,7 @@ milestone: v1.0 milestone_name: milestone status: executing stopped_at: Completed 02-mobile-shell-more-drawer/02-02-PLAN.md -last_updated: "2026-05-03T20:12:16.875Z" +last_updated: "2026-05-03T20:16:53.152Z" last_activity: 2026-05-03 progress: total_phases: 8 @@ -25,7 +25,7 @@ See: .planning/PROJECT.md (updated 2026-05-03) ## Current Position -Phase: 2 +Phase: 3 Plan: Not started Status: Ready to execute Last activity: 2026-05-03 @@ -36,7 +36,7 @@ Progress: [░░░░░░░░░░] 0% **Velocity:** -- Total plans completed: 2 +- Total plans completed: 4 - Average duration: — - Total execution time: 0.0 hours @@ -45,6 +45,7 @@ Progress: [░░░░░░░░░░] 0% | Phase | Plans | Total | Avg/Plan | |-------|-------|-------|----------| | 01 | 2 | - | - | +| 02 | 2 | - | - | **Recent Trend:** diff --git a/.planning/phases/02-mobile-shell-more-drawer/02-VERIFICATION.md b/.planning/phases/02-mobile-shell-more-drawer/02-VERIFICATION.md new file mode 100644 index 0000000..f7a8ff3 --- /dev/null +++ b/.planning/phases/02-mobile-shell-more-drawer/02-VERIFICATION.md @@ -0,0 +1,184 @@ +--- +phase: 02-mobile-shell-more-drawer +verified: 2026-05-03T20:30:00Z +status: human_needed +score: 15/15 must-haves verified +human_verification: + - test: "Open /mobile/dashboard in DevTools mobile view (390px wide). Confirm sticky header renders: Wulf mark logo (image, not placeholder) + 'Pulse' wordmark on the left, Bell icon + avatar circle on the right. No page title text in the header bar itself." + expected: "Sticky bar at top with bg-background/95 backdrop-blur + bottom border. WulfMark image visible. 'Pulse' text beside it. Bell and initials circle on the right. No h1/title text inside the header." + why_human: "Visual rendering of the WulfMark brand image (variant='mark') cannot be verified by grep — the component may render correctly or fall back silently depending on image availability." + - test: "Tap the avatar circle in the header. Verify the More drawer opens from the right side. Then close it. Tap the More button in the bottom nav. Verify the same drawer opens again from the right." + expected: "A single Sheet drawer slides in from the right (side=right). Both triggers open the same drawer instance (not two separate drawers). Pressing Esc or tapping outside closes it." + why_human: "Shared-state drawer wiring and slide-in animation cannot be confirmed by static code inspection alone — requires runtime observation." + - test: "Open the More drawer. Verify three sections in order: (1) 'Mobile sections' with a single Engagement row and NO ExternalLink icon on it; (2) 'Full site' with Quotes, Configuration Items, Backup Status, Ticket Digest, Admin / Sync — each with an ExternalLink icon on the right; (3) 'Account' showing the signed-in user's name/email and a red Sign out button." + expected: "Sections render in correct order. Engagement row has no ExternalLink hint. All five Full site rows have ExternalLink icons. Account section shows real user identity from session." + why_human: "Runtime session data (user.name, user.email) and conditional rendering of the user identity block require a live session to verify. The ExternalLink icon placement is visually confirmed in code but the section ordering and visual grouping require runtime inspection." + - test: "Tap Sign out in the More drawer. Verify it navigates to /auth/sign-in and the user is fully signed out (refreshing the page returns to sign-in, not an authenticated mobile page)." + expected: "signOut() is called, then router.push('/auth/sign-in') executes. The Better Auth session is terminated. No redirect loop, no 500 error." + why_human: "Auth session termination and redirect behavior requires a live auth session and network interaction with the Better Auth backend." + - test: "On /mobile/tickets, open a ticket detail (e.g. /mobile/tickets/123). With the detail page open, verify the Tickets tab in the bottom nav is still highlighted (active state, text-primary color)." + expected: "pathname.startsWith('/mobile/tickets') returns true for /mobile/tickets/123, so the Tickets tab shows text-primary. Other tabs show text-muted-foreground." + why_human: "Active tab highlighting for nested routes (/mobile/tickets/[id]) requires runtime navigation to confirm the startsWith logic produces the correct visual state." + - test: "Scroll to the bottom of content on /mobile/dashboard (or any mobile page with enough content to scroll). Verify the last content row is visible ABOVE the bottom nav — not hidden underneath it." + expected: "The pb-[calc(theme(spacing.16)+env(safe-area-inset-bottom))] padding on
ensures content does not hide under the 64px bottom nav. On a phone with a home indicator, there is also adequate space below the More button." + why_human: "CSS safe-area-inset-bottom value is device-specific and cannot be computed statically. Requires visual inspection on a phone-sized viewport, ideally a device with a home indicator." + - test: "Navigate directly to http://localhost:3100/mobile/nav. Verify it returns the Next.js 404 page and does NOT render the old standalone nav UI." + expected: "Standard Next.js 404 page. The old nav page content (links list) does not appear." + why_human: "Requires a running dev server to confirm the 404 response and that Next.js routing correctly falls through to the 404 page." +--- + +# Phase 2: Mobile Shell + More Drawer Verification Report + +**Phase Goal:** Every `/mobile/*` page renders inside a new layout — sticky header (Wulf mark + Bell placeholder + avatar), scrollable content, and a 5-cell bottom nav whose fifth control opens a Sheet drawer that fully replaces `/mobile/nav`. +**Verified:** 2026-05-03T20:30:00Z +**Status:** human_needed +**Re-verification:** No — initial verification + +## Goal Achievement + +### Observable Truths + +| # | Truth | Status | Evidence | +|---|-------|--------|----------| +| 1 | `app/mobile/layout.tsx` mounts HeaderBar + BottomNav + MoreDrawer with shared `useState` drawer state | VERIFIED | layout.tsx imports all three; single `drawerOpen` state; both `onAvatarClick` and `onMoreClick` call `() => setDrawerOpen(true)`; `MoreDrawer open={drawerOpen} onOpenChange={setDrawerOpen}` | +| 2 | HeaderBar has Wulf mark + Pulse wordmark linked to /mobile/dashboard, Bell placeholder (aria-label="Notifications", empty onClick), avatar trigger | VERIFIED | `WulfMark variant="mark"`, `Pulse`, `href="/mobile/dashboard"`, `aria-label="Notifications"` with empty onClick body, avatar button calling `onAvatarClick` | +| 3 | `
` has bottom padding clearing bottom nav height (h-16=64px) + safe-area inset | VERIFIED | `pb-[calc(theme(spacing.16)+env(safe-area-inset-bottom))]` on `
` in layout.tsx line 28 | +| 4 | BottomNav has 4 link tabs (Dashboard, Tickets, Finance, Analyzer) + More button = 5 cells | VERIFIED | TABS const has 4 entries with LayoutDashboard/Ticket/DollarSign/Sparkles icons; fifth `