Files
GearBox/.planning/phases/27-top-nav-restructure-and-search-bar-rethink/27-VERIFICATION.md

183 lines
12 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
---
phase: 27-top-nav-restructure-and-search-bar-rethink
verified: 2026-04-10T00:00:00Z
status: passed
score: 5/5 must-haves verified
re_verification: false
human_verification:
- test: "Visual verification of TopNav on desktop"
expected: "Logo, Home/Collection/Setups links, search bar, and user avatar visible in a horizontal bar at the top"
why_human: "CSS layout and visual rendering cannot be verified programmatically"
- test: "AuthPromptModal triggered by anonymous Collection/Setups click"
expected: "Clicking Collection or Setups while not logged in opens AuthPromptModal — no navigation occurs"
why_human: "E2E seed runs as authenticated user; unauthenticated state requires a separate fixture"
- test: "BottomTabBar visible on mobile viewport"
expected: "4-tab bar fixed at screen bottom on 375px viewport; TopNav shows only logo and avatar (no nav links)"
why_human: "Responsive CSS breakpoints require a real browser to validate"
- test: "FAB not visible on mobile"
expected: "Floating action button is hidden below md breakpoint"
why_human: "CSS hidden/block toggle requires visual inspection"
- test: "CatalogSearchOverlay triggered from TopNav search bar and BottomTabBar Search tab"
expected: "Clicking search bar (desktop) or Search tab (mobile) opens the full-screen overlay"
why_human: "Overlay interaction requires a live browser session"
---
# Phase 27: Top Nav Restructure & Search Bar Rethink — Verification Report
**Phase Goal:** Replace the minimal TotalsBar with a persistent top navigation bar (logo, section links, catalog search, user avatar) and move mobile navigation to a bottom tab bar — elevating Setups to top-level and removing the landing page hero
**Verified:** 2026-04-10
**Status:** passed
**Re-verification:** No — initial verification
---
## Goal Achievement
### Observable Truths (from ROADMAP Success Criteria)
| # | Truth | Status | Evidence |
|---|-------|--------|---------|
| 1 | A persistent top nav bar shows logo, Home/Collection/Setups links, catalog search, and user avatar on desktop | ✓ VERIFIED | `TopNav.tsx` renders logo (`LucideIcon name="package"` + "GearBox"), `<nav class="hidden md:flex">` with Home/Collection/Setups `NavLinkOrButton` elements, a `hidden md:flex` search button calling `openCatalogSearch`, and `<UserMenu />` or "Sign in" |
| 2 | Clicking Collection or Setups while anonymous triggers AuthPromptModal instead of navigating | ✓ VERIFIED | `NavLinkOrButton` renders `<button onClick={openAuthPrompt}>` when `isProtected && !isAuthenticated`; same pattern in `BottomTabBar.tsx` |
| 3 | On mobile, navigation appears as a fixed bottom tab bar with Home, Collection, Setups, and Search icons | ✓ VERIFIED | `BottomTabBar.tsx` uses `fixed bottom-0 left-0 right-0 md:hidden` with 4 tabs (Home/house, Collection/package, Setups/layers, Search/search); framer-motion entry animation included |
| 4 | The landing page no longer has a hero section — content starts with Popular Setups | ✓ VERIFIED | `src/client/routes/index.tsx` contains no `HeroSection`, no "Discover Gear", no `lucide-react` import, no `useAuth`, no `useUIStore`; `LandingPage` renders `<PopularSetupsSection />` as first child |
| 5 | Setups has its own top-level route accessible from the nav bar, not nested in Collection tabs | ✓ VERIFIED | `src/client/routes/setups/index.tsx` exists with `createFileRoute("/setups/")` rendering `<SetupsView />`; `collection/index.tsx` has `TAB_ORDER = ["gear", "planning"]` with no "setups" reference |
**Score: 5/5 truths verified**
---
### Required Artifacts
| Artifact | Expected | Status | Details |
|----------|----------|--------|---------|
| `src/client/components/TopNav.tsx` | Persistent top navigation bar replacing TotalsBar | ✓ VERIFIED | 130 lines, exports `TopNav`, uses `useMatchRoute`, `openAuthPrompt`, `openCatalogSearch`, `hidden md:flex`, `<UserMenu />` |
| `src/client/components/BottomTabBar.tsx` | Mobile bottom tab bar with 4 navigation items | ✓ VERIFIED | 95 lines, exports `BottomTabBar`, uses `fixed bottom-0 md:hidden z-20`, framer-motion, `openCatalogSearch`, `openAuthPrompt` |
| `src/client/routes/setups/index.tsx` | Top-level Setups route page | ✓ VERIFIED | Exists, `createFileRoute("/setups/")`, renders `<SetupsView />` in `max-w-7xl` container |
| `src/client/routes/collection/index.tsx` | Collection page with Gear and Planning tabs only | ✓ VERIFIED | `TAB_ORDER = ["gear", "planning"]`, `z.enum(["gear", "planning"]).catch("gear")`, zero "setups" occurrences |
| `src/client/routes/__root.tsx` | Root layout with TopNav, BottomTabBar, and updated FAB visibility | ✓ VERIFIED | Imports and renders `<TopNav />` and `<BottomTabBar />`; no `TotalsBar`; FAB wrapped in `<div class="hidden md:block">`; root div has `pb-16 md:pb-0` |
| `src/client/routes/index.tsx` | Landing page without hero section | ✓ VERIFIED | Starts with `<PopularSetupsSection />`; no hero, no unused imports |
| `e2e/dashboard.spec.ts` | Updated dashboard E2E tests matching new nav layout | ✓ VERIFIED | Tests for TopNav presence, nav links, bottom tab bar on mobile; old hero tests replaced |
| `e2e/collection.spec.ts` | Updated collection E2E tests without Setups tab assertions | ✓ VERIFIED | "setups tab URL falls back to gear tab" replaces old setups-tab test; `/setups` route test added |
---
### Key Link Verification
| From | To | Via | Status | Details |
|------|----|-----|--------|---------|
| `__root.tsx` | `TopNav.tsx` | `import { TopNav }` + `<TopNav />` | ✓ WIRED | Line 22 import, line 138 render |
| `__root.tsx` | `BottomTabBar.tsx` | `import { BottomTabBar }` + `<BottomTabBar />` | ✓ WIRED | Line 19 import, line 177 render |
| `TopNav.tsx` | `uiStore.ts` | `useUIStore``openCatalogSearch`, `openAuthPrompt` | ✓ WIRED | Both actions destructured and called |
| `BottomTabBar.tsx` | `uiStore.ts` | `useUIStore``openCatalogSearch`, `openAuthPrompt` | ✓ WIRED | Both actions destructured and called |
| `setups/index.tsx` | `SetupsView.tsx` | `import { SetupsView }` + `<SetupsView />` | ✓ WIRED | Direct import and render in `SetupsPage` |
---
### Data-Flow Trace (Level 4)
| Artifact | Data Variable | Source | Produces Real Data | Status |
|----------|--------------|--------|-------------------|--------|
| `src/client/routes/index.tsx``PopularSetupsSection` | `data` from `useDiscoverySetups(6)` | `useDiscovery.ts` hook → `/api/discovery/setups` | Yes — real DB query through existing discovery hooks | ✓ FLOWING |
| `src/client/routes/index.tsx``RecentItemsSection` | `data` from `useDiscoveryItems(8)` | `useDiscovery.ts` hook → `/api/discovery/items` | Yes | ✓ FLOWING |
| `src/client/routes/index.tsx``TrendingCategoriesSection` | `data` from `useDiscoveryCategories(12)` | `useDiscovery.ts` hook → `/api/discovery/categories` | Yes | ✓ FLOWING |
| `TopNav.tsx` | `auth?.user` from `useAuth()` | `useAuth` hook → `/api/auth/me` | Yes | ✓ FLOWING |
| `BottomTabBar.tsx` | `auth?.user` from `useAuth()` | `useAuth` hook → `/api/auth/me` | Yes | ✓ FLOWING |
---
### Behavioral Spot-Checks
| Behavior | Check | Result | Status |
|----------|-------|--------|--------|
| `TopNav.tsx` exports `TopNav` function | `grep -c "export function TopNav"` | 1 | ✓ PASS |
| `BottomTabBar.tsx` exports `BottomTabBar` function | `grep -c "export function BottomTabBar"` | 1 | ✓ PASS |
| `__root.tsx` has no TotalsBar reference | `grep -c "TotalsBar"` | 0 | ✓ PASS |
| `collection/index.tsx` has no "setups" string | `grep -c "setups"` | 0 | ✓ PASS |
| `__root.tsx` includes `/setups` in isPublicRoute | `grep '/setups"'` | line 123 present | ✓ PASS |
| `__root.tsx` has mobile bottom padding | `grep 'pb-16 md:pb-0'` | line 137 present | ✓ PASS |
| `layers` icon in iconData curated set | `grep '"layers"'` | line 209 present | ✓ PASS |
| `house` icon resolves in lucide-react | `node -e "... icons['House']"` | true | ✓ PASS |
---
### Requirements Coverage
The plans declare NAV-01 through NAV-05 as requirement IDs. These identifiers do NOT exist in `.planning/REQUIREMENTS.md` — the requirements file covers v2.1 milestones (PUBL-xx, DISC-xx, CATL-xx, SEED-xx, INFR-xx) and does not include a NAV-xx section. Phase 27 was planned after the requirements document was last updated (2026-04-09).
| Requirement | Source Plan(s) | Description (from ROADMAP/context) | Status |
|-------------|---------------|------------------------------------|--------|
| NAV-01 | 27-00, 27-01, 27-03 | Persistent top nav bar with logo, section links, search, avatar | ✓ SATISFIED — TopNav implemented, wired in __root.tsx |
| NAV-02 | 27-01, 27-03 | Auth interception: anonymous clicks on protected nav links open AuthPromptModal | ✓ SATISFIED — NavLinkOrButton and BottomTabBar both implement this |
| NAV-03 | 27-01, 27-03 | Active route highlighted in nav | ✓ SATISFIED — useMatchRoute drives active/inactive class in both components |
| NAV-04 | 27-00, 27-03 | Landing page hero removed; content starts with Popular Setups | ✓ SATISFIED — index.tsx confirmed clean |
| NAV-05 | 27-00, 27-02 | Setups elevated to top-level /setups route; removed from Collection tabs | ✓ SATISFIED — setups/index.tsx exists; collection/index.tsx clean |
**Note:** NAV-01 through NAV-05 are phase-internal requirement identifiers not registered in REQUIREMENTS.md. They are not orphaned — they were defined for this phase only and carry no cross-phase traceability obligation. No formal update to REQUIREMENTS.md is required unless the project owner chooses to retroactively add the NAV section.
---
### Anti-Patterns Found
| File | Pattern | Severity | Impact |
|------|---------|----------|--------|
| `BottomTabBar.tsx` line 52 | Uses icon name `"house"` for Home tab; plan specified `"home"` and neither is in the curated `iconGroups` list | Info | No user impact — `LucideIcon` resolves icon names directly from `lucide-react`'s `icons` object, and `House` exists in the package. Renders correctly. The curated set is only used by the IconPicker UI, not LucideIcon rendering. |
No blocker or warning anti-patterns found.
---
### Human Verification Required
#### 1. TopNav Visual Layout (Desktop)
**Test:** Open http://localhost:5173 in a wide browser window (1280px+)
**Expected:** Top bar shows: package icon + "GearBox" text on left, "Home / Collection / Setups" links in center (hidden on narrow), search button on right, user avatar or "Sign in" link
**Why human:** CSS `hidden md:flex` visibility and flex layout require a real browser
#### 2. AuthPromptModal on Anonymous Clicks
**Test:** Open the app while logged out, click "Collection" or "Setups" in the nav
**Expected:** AuthPromptModal appears — no navigation to /collection or /setups
**Why human:** E2E seed environment is authenticated; unauthenticated test fixture is not in scope
#### 3. Mobile Bottom Tab Bar
**Test:** Use DevTools to set viewport to 375px width, reload
**Expected:** Bottom bar with 4 icon+label items (Home, Collection, Setups, Search) is fixed at the bottom; TopNav shows only logo and avatar
**Why human:** Responsive CSS requires a live browser viewport
#### 4. FAB Hidden on Mobile
**Test:** In 375px viewport, verify no floating action button appears
**Expected:** FAB is not visible on mobile; visible on desktop (1280px+)
**Why human:** `hidden md:block` wrapper CSS requires visual inspection
#### 5. Search Overlay Triggers
**Test:** Click the search bar in TopNav (desktop) and the Search tab in BottomTabBar (mobile)
**Expected:** CatalogSearchOverlay opens in both cases
**Why human:** UI interaction and overlay rendering require a live browser
---
### Gaps Summary
No gaps found. All 5 phase success criteria are met by the implementation:
- `TopNav.tsx` is a complete, fully-wired component with auth interception, active-route detection, search trigger, and user menu
- `BottomTabBar.tsx` is a complete mobile nav with framer-motion animation, auth interception, and search trigger
- `/setups` route exists and renders `SetupsView` in a standard page layout
- `collection/index.tsx` has exactly 2 tabs (Gear, Planning) with no Setups reference
- `__root.tsx` mounts both new components, removes TotalsBar, hides FAB on mobile, adds public route for /setups, and adds mobile bottom padding
- `index.tsx` (landing page) is clean of hero section, unused imports, and starts with Popular Setups
- E2E test files are updated with post-Phase-27 assertions
Five human verification items remain for visual and interaction confirmation but do not represent code gaps.
---
_Verified: 2026-04-10_
_Verifier: Claude (gsd-verifier)_