fix(layout+pages): default user=null + page audit sweep (P0 #7) #15

Merged
varutasu merged 4 commits from convoy/fix-layout-default-user into main 2026-05-24 15:31:37 -04:00
varutasu commented 2026-05-24 11:07:22 -04:00 (Migrated from github.com)

Summary

Resolves P0 #7 from .convoys/ship-readiness.md — the last open P0 ship-blocker. Until now, every page that rendered <Layout> without explicitly passing user impersonated the maintainer (me@randallstillwell.com) in the navbar and three additional page bodies leaked the same email through hardcoded useState seeds.

This PR is the fix-layout-default-user convoy, two briefs in two commits on a single branch:

Brief 1 — components/Layout.js (commit ddf8fd2)

  • Layout's default prop changed from user = { email: 'me@randallstillwell.com', role: 'user' }user = null
  • UserProfileDropdown now branches on user === null and renders a "Sign in" → /login CTA instead of the maintainer's avatar
  • New test/components/Layout.test.js with 5 regression-lock assertions (no maintainer email when prop omitted / null; "Sign in" link present; supplied email renders; no "Guest" placeholder)
  • Adds jsdom@^29 + @testing-library/react@^16 to devDependencies and a 3-line esbuild block to vitest.config.js to parse JSX in .js files

Brief 2 — 7 pages swept (commit 8c7d127)

Per the architect's per-page bucket table (Decision B in .convoys/fix-layout-default-user.md), 7 of 17 Layout-importing pages needed code changes — the other 10 were already correct.

Pass user={user} to Layout (4 pages, 11 call sites):

  • pages/scanner.js (1 call)
  • pages/decks.js (3 calls)
  • pages/deck-builder.js (4 calls)
  • pages/deck/[id].js (3 calls)

All four still import useAuth from lib/auth-context.js — intentional and stays as-is until the queued single-auth-provider convoy collapses the three parallel auth surfaces.

Replace leaky page-level seed with useState(null) + null-guards (R2 mitigation):

  • pages/profile.js — 15 sync user.* reads, all guarded (optional chaining on JSX reads; early if (!user) return '' in getDisplayName / getInitials; {user?.created_at && ...} wrapping the formatDate block to avoid "Invalid Date")
  • pages/settings.js — 1 sync user.email read on a disabled input, guarded via value={user?.email || ''}

Replace hardcoded const with useAuth():

  • pages/card/[id].jsconst user = { email: 'me@...', role: 'user' }const { user } = useAuth() from lib/use-auth.js

Verification

rg 'me@randallstillwell.com' pages/   → 0 hits
rg 'me@randallstillwell.com' .         → 7 hits, all expected:
  - .convoys/* (3 docs)
  - .convoys/ship-readiness.md (audit)
  - AGENTS.md (gotcha #8 — to be marked RESOLVED post-merge)
  - components/Layout.js.backup (no-go append-only)
  - test/components/Layout.test.js (negative assertions, Brief 1)
  • npm run test:run21/21 green (16 pre-existing + 5 new from Brief 1)
  • npm run lint → exit 1, 128 problems (exact baseline match — confirmed via stash before/after)
  • Anonymous curl /cards → HTTP 200, zero maintainer-email matches

Flagged but deferred (out of scope)

  • 4 pages still import useAuth from lib/auth-context.jssingle-auth-provider convoy (P1 #9)
  • components/MobileNavigation.js still receives a dead user prop → cleanup-mobile-nav-dead-props (or fold into god-component-split)
  • pages/card/[id].js also imports useIsAdmin from lib/admin-auth (third parallel auth surface) → same single-auth-provider convoy
  • Pre-existing lint warnings (next/image, react-hooks/exhaustive-deps, etc.) in profile.js and card/[id].js — verified pre-existing via stash before/after

Test plan

  • Vitest: 21/21 pass
  • Lint: baseline match (128 problems)
  • rg 'me@randallstillwell.com' pages/ → 0 hits
  • Anonymous curl /cards → no maintainer email leak
  • Logged-OUT manual smoke: /cards, /card/<id>, /collection/<slug> show "Sign in" CTA, no maintainer email
  • Logged-IN manual smoke (non-admin user): /dashboard, /profile, /settings, /decks, /scanner, /deck-builder render without null-deref console errors during the auth loading window
  • Vercel preview: same checks against deployed preview

Closes P0 #7. After merge, doc-writer will mark .convoys/ship-readiness.md + AGENTS.md gotcha #8 RESOLVED.

Made with Cursor

## Summary Resolves **P0 #7** from [`.convoys/ship-readiness.md`](.convoys/ship-readiness.md) — the last open P0 ship-blocker. Until now, every page that rendered `<Layout>` without explicitly passing `user` impersonated the maintainer (`me@randallstillwell.com`) in the navbar and three additional page bodies leaked the same email through hardcoded `useState` seeds. This PR is the **`fix-layout-default-user` convoy**, two briefs in two commits on a single branch: ### Brief 1 — `components/Layout.js` (commit `ddf8fd2`) - Layout's default prop changed from `user = { email: 'me@randallstillwell.com', role: 'user' }` → `user = null` - `UserProfileDropdown` now branches on `user === null` and renders a "Sign in" → `/login` CTA instead of the maintainer's avatar - New `test/components/Layout.test.js` with 5 regression-lock assertions (no maintainer email when prop omitted / null; "Sign in" link present; supplied email renders; no "Guest" placeholder) - Adds `jsdom@^29` + `@testing-library/react@^16` to `devDependencies` and a 3-line `esbuild` block to `vitest.config.js` to parse JSX in `.js` files ### Brief 2 — 7 pages swept (commit `8c7d127`) Per the architect's per-page bucket table (Decision B in `.convoys/fix-layout-default-user.md`), 7 of 17 Layout-importing pages needed code changes — the other 10 were already correct. **Pass `user={user}` to Layout** (4 pages, 11 call sites): - `pages/scanner.js` (1 call) - `pages/decks.js` (3 calls) - `pages/deck-builder.js` (4 calls) - `pages/deck/[id].js` (3 calls) All four still import `useAuth` from `lib/auth-context.js` — intentional and stays as-is until the queued `single-auth-provider` convoy collapses the three parallel auth surfaces. **Replace leaky page-level seed with `useState(null)` + null-guards** (R2 mitigation): - `pages/profile.js` — 15 sync `user.*` reads, all guarded (optional chaining on JSX reads; early `if (!user) return ''` in `getDisplayName` / `getInitials`; `{user?.created_at && ...}` wrapping the `formatDate` block to avoid "Invalid Date") - `pages/settings.js` — 1 sync `user.email` read on a disabled input, guarded via `value={user?.email || ''}` **Replace hardcoded const with `useAuth()`**: - `pages/card/[id].js` — `const user = { email: 'me@...', role: 'user' }` → `const { user } = useAuth()` from `lib/use-auth.js` ## Verification ``` rg 'me@randallstillwell.com' pages/ → 0 hits rg 'me@randallstillwell.com' . → 7 hits, all expected: - .convoys/* (3 docs) - .convoys/ship-readiness.md (audit) - AGENTS.md (gotcha #8 — to be marked RESOLVED post-merge) - components/Layout.js.backup (no-go append-only) - test/components/Layout.test.js (negative assertions, Brief 1) ``` - `npm run test:run` → **21/21 green** (16 pre-existing + 5 new from Brief 1) - `npm run lint` → exit 1, **128 problems** (exact baseline match — confirmed via stash before/after) - Anonymous `curl /cards` → HTTP 200, zero maintainer-email matches ## Flagged but deferred (out of scope) - 4 pages still import `useAuth` from `lib/auth-context.js` → `single-auth-provider` convoy (P1 #9) - `components/MobileNavigation.js` still receives a dead `user` prop → `cleanup-mobile-nav-dead-props` (or fold into `god-component-split`) - `pages/card/[id].js` also imports `useIsAdmin` from `lib/admin-auth` (third parallel auth surface) → same `single-auth-provider` convoy - Pre-existing lint warnings (`next/image`, `react-hooks/exhaustive-deps`, etc.) in `profile.js` and `card/[id].js` — verified pre-existing via stash before/after ## Test plan - [x] Vitest: 21/21 pass - [x] Lint: baseline match (128 problems) - [x] `rg 'me@randallstillwell.com' pages/` → 0 hits - [x] Anonymous `curl /cards` → no maintainer email leak - [ ] Logged-OUT manual smoke: `/cards`, `/card/<id>`, `/collection/<slug>` show "Sign in" CTA, no maintainer email - [ ] Logged-IN manual smoke (non-admin user): `/dashboard`, `/profile`, `/settings`, `/decks`, `/scanner`, `/deck-builder` render without `null`-deref console errors during the auth loading window - [ ] Vercel preview: same checks against deployed preview Closes P0 #7. After merge, doc-writer will mark `.convoys/ship-readiness.md` + AGENTS.md gotcha #8 RESOLVED. Made with [Cursor](https://cursor.com)
vercel[bot] commented 2026-05-24 11:07:28 -04:00 (Migrated from github.com)

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tcg-vault Ready Ready Preview, Comment May 24, 2026 7:22pm

Request Review

[vc]: #d4AAihT7yxQ8KrTbHqKQ+0IGrF6ZQMhkJLcKSyd7KT4=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJ0Y2ctdmF1bHQiLCJwcm9qZWN0SWQiOiJwcmpfRjZXOEVvRkd3Y0g3aWVGcnRvRlNlOXdVVkFhNSIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiJ0Y2ctdmF1bHQtZ2l0LWNvbnZveS1maXgtbGF5LWVlMDcyNS1yYW5kYWxsLXN0aWxsd2VsbHMtcHJvamVjdHMudmVyY2VsLmFwcCJ9LCJpbnNwZWN0b3JVcmwiOiJodHRwczovL3ZlcmNlbC5jb20vcmFuZGFsbC1zdGlsbHdlbGxzLXByb2plY3RzL3RjZy12YXVsdC9vNlQ3VDc5bnFhS2N4OGFCSnN2czYya1ZDNmpYIiwicHJldmlld1VybCI6InRjZy12YXVsdC1naXQtY29udm95LWZpeC1sYXktZWUwNzI1LXJhbmRhbGwtc3RpbGx3ZWxscy1wcm9qZWN0cy52ZXJjZWwuYXBwIiwibmV4dENvbW1pdFN0YXR1cyI6IkRFUExPWUVEIiwicm9vdERpcmVjdG9yeSI6bnVsbH1dLCJyZXF1ZXN0UmV2aWV3VXJsIjoiaHR0cHM6Ly92ZXJjZWwuY29tL3ZlcmNlbC1hZ2VudC9yZXF1ZXN0LXJldmlldz9vd25lcj12YXJ1dGFzdSZyZXBvPXRjZy12YXVsdCZwcj0xNSJ9 The latest updates on your projects. Learn more about [Vercel for GitHub](https://vercel.link/github-learn-more). | Project | Deployment | Actions | Updated (UTC) | | :--- | :----- | :------ | :------ | | [tcg-vault](https://vercel.com/randall-stillwells-projects/tcg-vault) | ![Ready](https://vercel.com/static/status/ready.svg) [Ready](https://vercel.com/randall-stillwells-projects/tcg-vault/o6T7T79nqaKcx8aBJsvs62kVC6jX) | [Preview](https://tcg-vault-git-convoy-fix-lay-ee0725-randall-stillwells-projects.vercel.app), [Comment](https://vercel.live/open-feedback/tcg-vault-git-convoy-fix-lay-ee0725-randall-stillwells-projects.vercel.app?via=pr-comment-feedback-link) | May 24, 2026 7:22pm | <a href="https://vercel.com/vercel-agent/request-review?owner=varutasu&repo=tcg-vault&pr=15" rel="noreferrer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://agents-vade-review.vercel.sh/request-review-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://agents-vade-review.vercel.sh/request-review-light.svg"><img src="https://agents-vade-review.vercel.sh/request-review-light.svg" alt="Request Review"></picture></a>
github-actions[bot] commented 2026-05-24 11:07:35 -04:00 (Migrated from github.com)

Pipeline Health

Build + CI gates

Gate Status
Vercel build (Preview) pass
CI: Lint pass
CI: Schema map fresh skipped
Preview smoke in progress
Visual diff in progress

Build runs on Vercel; this CI runs lint and schema-map drift only (no duplicate build).

Role reports

Role Status
Reviewer report pending
A11y audit pending
Design system audit pending

See individual comments above for details. This rollup updates automatically.

<!-- pipeline-rollup --> ## Pipeline Health ### Build + CI gates | Gate | Status | | --- | --- | | Vercel build (Preview) | ✅ pass | | CI: Lint | ✅ pass | | CI: Schema map fresh | ❌ skipped | | Preview smoke | ⏳ in progress | | Visual diff | ⏳ in progress | _Build runs on Vercel; this CI runs lint and schema-map drift only (no duplicate build)._ ### Role reports | Role | Status | | --- | --- | | Reviewer report | ⏳ pending | | A11y audit | ⏳ pending | | Design system audit | ⏳ pending | See individual comments above for details. This rollup updates automatically.
github-actions[bot] commented 2026-05-24 15:32:48 -04:00 (Migrated from github.com)

Visual Diff

Screenshots and diffs uploaded as artifacts: view run

If intentional changes: update snapshots locally with npx playwright test --project=visual --update-snapshots and commit.

## Visual Diff Screenshots and diffs uploaded as artifacts: [view run](https://github.com/varutasu/tcg-vault/actions/runs/26370491608) If intentional changes: update snapshots locally with `npx playwright test --project=visual --update-snapshots` and commit.
Sign in to join this conversation.
No description provided.