---
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)_
