Session 34: Design system Phase C — app shell, nav, routing, auth gate, footer, 404 (1818 tests)

VYNDR 2.0 conversion, Phase C (the frame every page sits inside). Frontend-only;
zero backend changes.

- Nav rewritten: new .wm Wordmark, mono uppercase links, More dropdown, search/
  bell/read-meter/avatar, Ticker under the bar. layout main paddingTop 64 -> 96.
- Routing: web/src/lib/routes.js (GATED/OPEN/HASH_ALIASES, isGatedRoute,
  resolveHashAlias). Client AuthGate bounces signed-out users off personal
  routes to /login?next=. HashRedirect maps #scan/#terminal to real routes.
- Footer rewritten to system voice + Detroit signature; mounted globally in
  layout (removed per-page dup).
- 404 converted to the north star (scanlines, crt-sweep, glitch wordmark, amber).
- Stub pages for terminal/compare/invite/help/about/notifications via RouteStub.

Honest reconciliations: auth gate is client-side (no auth-helpers pkg; session is
client-side Supabase); GATED narrowed to protect the free-scan funnel; did not
stub over existing real pages; redirect param is ?next= (what /login reads).

26 new tests. Backend 1792 -> 1818, 142 suites, zero regressions. Web build clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kev
2026-06-15 23:27:58 -04:00
parent a74b5dd1ed
commit 907c7b17c1
19 changed files with 1020 additions and 430 deletions
+90 -2
View File
@@ -4,8 +4,96 @@
2026-06-15
## Current Phase
SHIP BUILD v33.0 — VYNDR 2.0 design system, Phase A+B: tokens + global CSS +
fonts + glitch keyframes + shared components (Session 33)
SHIP BUILD v34.0 — VYNDR 2.0 design system, Phase C: app shell — nav, routing,
auth gate, footer, 404 (Session 34)
## Session 34 (2026-06-15) — SHIPPED
Phase C of the VYNDR 2.0 conversion: the app shell every page sits inside.
Frontend-only; ZERO backend changes. Converted the nav/footer/404 to the design
and added the routing + auth-gate frame. Backend 1792 → **1818 tests** (+26),
142 suites, zero regressions. Web build clean (exit 0, 36 routes).
### Honest reconciliations (spec ↔ our reality — same discipline as the S32 NFL-key fix)
- **Auth gate is CLIENT-side, not server middleware.** The prompt's example used
`createMiddlewareClient` from `@supabase/auth-helpers-nextjs` — that package
isn't installed, our auth is client-side Supabase (session in localStorage via
`@supabase/supabase-js`), and the existing `middleware.ts` is locale-only. A
server middleware physically can't read that session. So the gate runs in
`<AuthGate>` (client) on top of the existing Supabase auth (rule 5 honored).
Locale middleware left untouched.
- **Narrowed the GATED set.** The prototype gated dashboard + scan; those are OUR
free-scan acquisition funnel (anon/free get 5 reads), so gating them is a
monetization regression. GATED = ledger/tracker/account/profile/settings/
notifications/invite (genuinely personal surfaces). dashboard/scan stay OPEN.
- **Did NOT stub over existing real pages.** The prompt's stub list assumed
ledger/tracker/blog/game/responsible/offline didn't exist — they do, with real
content. Stubs created ONLY for genuinely-missing routes.
- **Redirect param is `?next=`,** not the prompt's `?redirect=` — that's the
param our `/login` page already reads (`router.replace(next)`).
### C.1 — Traced the shell
Nav used legacy `@/components/Wordmark` (`.wordmark`). Auth = `AuthContext`/
`useAuth` (user/tier/scansRemaining/loading/signOut). `middleware.ts` = locale
only. Footer existed but was mounted only on the landing page. 28 route pages.
### C.2 — Nav (`components/Nav.tsx` rewritten)
- New `@/components/vyndr` Wordmark (size md, cursor, beta — `.wm` markup).
- Primary links SLATE/TERMINAL/SCAN/LEDGER + a **More** dropdown (Compare,
Tracker, The Report, Invite, Pricing, Settings). All nav chrome JetBrains Mono,
uppercase, 11px, 0.08em; active = `--g-a`, hover `--text-0`, default `--text-1`.
- Right cluster: `` Query search trigger, NotificationBell (signed-in), read
meter (`n/5 · MO`, free + scan/dashboard only) / `∞ TIER` plan badge, avatar
menu (Account/Settings/Upgrade/Log out). Mobile toggle kept (full mobile shell
is Session 37).
- **Ticker** mounted under the bar (sample items; real feed = Session 38). Header
is now a fixed wrapper = 60px nav + 32px ticker → `layout` main `paddingTop`
64 → 96.
### C.3 — Routing + auth gate
- `web/src/lib/routes.js` (CommonJS, unit-testable): `GATED_ROUTES`,
`OPEN_ROUTES`, `HASH_ALIASES`, `isGatedRoute(path)`, `resolveHashAlias(hash)`.
- `components/AuthGate.tsx` — waits for `loading`, then bounces signed-out users
off gated routes to `/login?next=<path>`. Mounted around `<main>` in layout.
- `components/vyndr/HashRedirect.tsx` — maps `#scan`/`#terminal`/… to real routes
once on mount (keeps Next file-based routing; honors old share links). Mounted
in layout.
- Stub pages (design-system `RouteStub`, system language "ROUTE UNDER
CONSTRUCTION · SESSION xx"): `/terminal`, `/compare`, `/invite`, `/help`,
`/about`, `/notifications`.
### C.4 — Footer (`components/Footer.tsx` rewritten)
System voice: Wordmark sm+beta, mono columns PRODUCT/COMPANY/LEGAL, legal/21+
line with `--amber` 1-800-522-4700, and **BUILT BY KEVON BUTLER · DETROIT ·
© 2026 VYNDR**. Now mounted GLOBALLY in the layout (removed the per-page import
from the landing page to avoid a double footer).
### C.5 — 404 north star (`app/not-found.tsx` rewritten)
Full-page `.scanlines`, `.crt-sweep` on load, glitch Wordmark (lg), amber-glow
"TRANSMISSION INTERRUPTED", giant `--amber` 404 (`.wm` data-text), "This page
doesn't exist. / The signal was lost.", VBtn CTAs (client `NotFoundActions`
so the page stays a server component for metadata).
### Files created
- `web/src/lib/routes.js`
- `web/src/components/AuthGate.tsx`
- `web/src/components/vyndr/{HashRedirect,NotFoundActions,RouteStub}.tsx`
- `web/src/app/{terminal,compare,invite,help,about,notifications}/page.tsx`
- `tests/unit/vyndrAppShell.test.js` (26 tests: routing logic, gate, nav/footer/
404 contracts, layout wiring, stubs-don't-clobber-real-pages)
### Files modified
- `web/src/components/Nav.tsx`, `web/src/components/Footer.tsx`
- `web/src/app/layout.tsx` (mount HashRedirect + AuthGate + global Footer,
paddingTop 96), `web/src/app/not-found.tsx`, `web/src/app/page.tsx` (drop dup
footer)
### Deferred (Sessions 35+)
- Real screens for the stubbed routes (D/E), mobile shell (F), living-layer
ticker/heartbeat data + nav-string i18n (G). The Nav search `` currently links
to `/scan`; the ⌘K command palette is Phase G.
---
## Session 33 (2026-06-15) — SHIPPED