refactor(auth): collapse lib/auth-context.js + lib/admin-auth.js onto lib/use-auth.js #31

Merged
varutasu merged 1 commit from convoy/single-auth-provider into main 2026-05-26 23:58:08 -04:00
varutasu commented 2026-05-26 23:55:43 -04:00 (Migrated from github.com)

Summary

P1 quality (launch sequence step 9 — .convoys/ship-readiness.md § P1 entry 9). Collapses the
three parallel client-side auth implementations onto lib/use-auth.js as the canonical
single surface. Pre-convoy, a worst-case page mount issued 3 identical GET /api/auth/verify
roundtrips (one per provider/hook). Post-convoy: 1 verify per page mount.

The other two surfaces (lib/auth-context.js and lib/admin-auth.js) are deleted; every
importer is migrated; the <AuthProvider> wrapper is removed from pages/_app.js. No tests
change. Convoy file: .convoys/single-auth-provider.md.

Decisions (full text in convoy file)

  • D1 — Shape parity. No extension to lib/use-auth.js. Zero call sites read login() /
    register() from useAuth(); those flows live in pages/login.js / pages/signup.js which
    hit /api/auth/{login,register} directly and write the token to localStorage. Preserving
    the legacy methods would have been cargo-culting.
  • D2 — useIsAdmin() migration. pages/card/[id].js is the only consumer. Replaced with
    const isAdmin = user?.role === 'admin' derived from the existing useAuth() call. Render
    condition byte-identical.
  • D3 — _app.js provider tree. <ThemeProvider><AuthProvider>{children}</AuthProvider></ThemeProvider>
    <ThemeProvider>{children}</ThemeProvider>. useAuth is hook-only; no replacement
    Provider needed.
  • D4 — Verify-roundtrip dedup. 3 → 1 on card/[id].js; 2 → 1 on every other page-load.
  • D5 — Test impact. Zero test files modified. The 21-test vitest suite is either
    server-side (auth-secret / permission-middleware / auth-utils — 16 tests) or prop-driven
    (Layout.test.js — 5 tests; passes user as a prop, never imports a hook).

Importer inventory

lib/auth-context.jslib/use-auth.js (6 source files)

File Symbol Migration
pages/_app.js AuthProvider Wrapper deleted (D3)
pages/index.js useAuth Path swap
pages/scanner.js useAuth Path swap
pages/decks.js useAuth Path swap
pages/deck/[id].js useAuth Path swap
pages/deck-builder.js useAuth Path swap

lib/admin-auth.js → consolidated onto useAuth (1 source file)

File Symbol Migration
pages/card/[id].js useIsAdmin Inlined as user?.role === 'admin' from existing useAuth() (D2)

AdminProvider and useAdmin() had zero importers — confirmed dead exports.

Adjacent doc / config sweeps

  • .github/CODEOWNERS — dropped 2 lines for deleted files.
  • AGENTS.md § 2 + § 3 — architecture row + "Auth (client)" convention rewritten.
  • .cursor/rules/auth-and-permissions.mdc — § Legacy reframed as "deleted by this convoy"; §
    "Authentication state on the client" updated to post-convoy shape + direct-fetch login flow.
  • .cursor/rules/no-go-zones.mdc — auth-refactors bullet drops deleted files.
  • .cursor/skills/add-page/SKILL.md — checklist + anti-pattern row updated.

Provider tree (before / after)

// before
<ThemeProvider>
  <AuthProvider>
    <Component {...pageProps} />
  </AuthProvider>
</ThemeProvider>

// after
<ThemeProvider>
  <Component {...pageProps} />
</ThemeProvider>

<AdminProvider> was never wired in _app.js to begin with (verified pre-convoy), so no
removal needed there.

Verification

  • rg "lib/auth-context|lib/admin-auth" --type js0 hits in pages/, lib/,
    components/.
  • npm run lint128 → 125 problems (3 fewer errors, from deleted unused-import
    lines; no regression).
  • npm run test:run21/21 pass, including the 5 Layout regression locks from
    fix-layout-default-user (prop-driven, unaffected).
  • npm run build → succeeds end-to-end; all 26 pages compile (10 dynamic API routes + 16
    pages/** views including every file modified). No SSR / static-generation breakage
    that would have surfaced if a page tried to use the legacy context hook unwrapped.
  • Manual smoke — deferred to operator post-merge (npm run dev, log in, click around
    dashboard / profile / settings / collections / cards / card/[id] / admin/card-editor;
    verify the orange "Edit Card" admin button on card/[id] still appears for an admin
    user — that's the only useIsAdmin consumer behaviour). Documented in convoy file §
    Verification step 5.

Risks (full discussion in convoy file)

  • R1 — Shape parity gap. Mitigated by D1 grep audit.
  • R2 — SSR mismatch from removing <AuthProvider>. useEffect-guarded localStorage
    read in useAuth keeps SSR shape identical pre/post; build passes.
  • R3 — Missed importer. Post-delete grep + successful build would have surfaced any miss.
  • R4 — Verify-roundtrip dedup creates a regression where a page never re-verifies.
    refreshAuth() preserved on the canonical hook for that purpose; no consumer needs it
    today.
  • R5 — Stale useAuth cache across components. Pre-existing pattern, called out as a
    follow-up rather than addressed here.

Conflict-with-parallel-PR awareness

Parallel single-sql-client convoy may also touch some pages/** files. Conflicts possible
at the import block of any page that uses both legacy auth and legacy SQL clients; merge-time
rebase will handle.

Follow-ups

  • Component-level useAuth cache audit (the original motivation for the legacy context — a
    thin re-introduction may be the right answer if shared state across components on the same
    page becomes a measured cost).
  • Rate-limit-aware re-auth on 429 in lib/use-auth.js::checkAuth.
  • Server-side hydration of user (HTTP-only cookie + getServerSideProps) to eliminate the
    page-mount verify roundtrip entirely. Larger architectural conversation.
  • Doc-writer cleanup post-merge: stamp .convoys/ship-readiness.md § P1 → entry 9 RESOLVED
    with squash SHA.

Made with Cursor

## Summary P1 quality (launch sequence step 9 — `.convoys/ship-readiness.md` § P1 entry 9). Collapses the three parallel client-side auth implementations onto **`lib/use-auth.js`** as the canonical single surface. Pre-convoy, a worst-case page mount issued **3** identical `GET /api/auth/verify` roundtrips (one per provider/hook). Post-convoy: **1** verify per page mount. The other two surfaces (`lib/auth-context.js` and `lib/admin-auth.js`) are deleted; every importer is migrated; the `<AuthProvider>` wrapper is removed from `pages/_app.js`. No tests change. Convoy file: [.convoys/single-auth-provider.md](.convoys/single-auth-provider.md). ## Decisions (full text in convoy file) - **D1 — Shape parity.** No extension to `lib/use-auth.js`. Zero call sites read `login()` / `register()` from `useAuth()`; those flows live in `pages/login.js` / `pages/signup.js` which hit `/api/auth/{login,register}` directly and write the token to `localStorage`. Preserving the legacy methods would have been cargo-culting. - **D2 — `useIsAdmin()` migration.** `pages/card/[id].js` is the only consumer. Replaced with `const isAdmin = user?.role === 'admin'` derived from the existing `useAuth()` call. Render condition byte-identical. - **D3 — `_app.js` provider tree.** `<ThemeProvider><AuthProvider>{children}</AuthProvider></ThemeProvider>` → `<ThemeProvider>{children}</ThemeProvider>`. `useAuth` is hook-only; no replacement Provider needed. - **D4 — Verify-roundtrip dedup.** 3 → 1 on `card/[id].js`; 2 → 1 on every other page-load. - **D5 — Test impact.** Zero test files modified. The 21-test vitest suite is either server-side (auth-secret / permission-middleware / auth-utils — 16 tests) or prop-driven (`Layout.test.js` — 5 tests; passes `user` as a prop, never imports a hook). ## Importer inventory ### `lib/auth-context.js` → `lib/use-auth.js` (6 source files) | File | Symbol | Migration | | --- | --- | --- | | `pages/_app.js` | `AuthProvider` | Wrapper deleted (D3) | | `pages/index.js` | `useAuth` | Path swap | | `pages/scanner.js` | `useAuth` | Path swap | | `pages/decks.js` | `useAuth` | Path swap | | `pages/deck/[id].js` | `useAuth` | Path swap | | `pages/deck-builder.js` | `useAuth` | Path swap | ### `lib/admin-auth.js` → consolidated onto `useAuth` (1 source file) | File | Symbol | Migration | | --- | --- | --- | | `pages/card/[id].js` | `useIsAdmin` | Inlined as `user?.role === 'admin'` from existing `useAuth()` (D2) | `AdminProvider` and `useAdmin()` had **zero** importers — confirmed dead exports. ### Adjacent doc / config sweeps - `.github/CODEOWNERS` — dropped 2 lines for deleted files. - `AGENTS.md` § 2 + § 3 — architecture row + "Auth (client)" convention rewritten. - `.cursor/rules/auth-and-permissions.mdc` — § Legacy reframed as "deleted by this convoy"; § "Authentication state on the client" updated to post-convoy shape + direct-fetch login flow. - `.cursor/rules/no-go-zones.mdc` — auth-refactors bullet drops deleted files. - `.cursor/skills/add-page/SKILL.md` — checklist + anti-pattern row updated. ## Provider tree (before / after) ```jsx // before <ThemeProvider> <AuthProvider> <Component {...pageProps} /> </AuthProvider> </ThemeProvider> // after <ThemeProvider> <Component {...pageProps} /> </ThemeProvider> ``` `<AdminProvider>` was never wired in `_app.js` to begin with (verified pre-convoy), so no removal needed there. ## Verification - [x] `rg "lib/auth-context|lib/admin-auth" --type js` → **0 hits** in `pages/`, `lib/`, `components/`. - [x] `npm run lint` → **128 → 125 problems** (3 fewer errors, from deleted unused-import lines; no regression). - [x] `npm run test:run` → **21/21 pass**, including the 5 Layout regression locks from `fix-layout-default-user` (prop-driven, unaffected). - [x] `npm run build` → succeeds end-to-end; all 26 pages compile (10 dynamic API routes + 16 `pages/**` views including every file modified). No SSR / static-generation breakage that would have surfaced if a page tried to use the legacy context hook unwrapped. - [ ] Manual smoke — deferred to operator post-merge (`npm run dev`, log in, click around dashboard / profile / settings / collections / cards / `card/[id]` / admin/card-editor; verify the orange "Edit Card" admin button on `card/[id]` still appears for an admin user — that's the only `useIsAdmin` consumer behaviour). Documented in convoy file § Verification step 5. ## Risks (full discussion in convoy file) - **R1 — Shape parity gap.** Mitigated by D1 grep audit. - **R2 — SSR mismatch from removing `<AuthProvider>`.** `useEffect`-guarded `localStorage` read in `useAuth` keeps SSR shape identical pre/post; build passes. - **R3 — Missed importer.** Post-delete grep + successful build would have surfaced any miss. - **R4 — Verify-roundtrip dedup creates a regression where a page never re-verifies.** `refreshAuth()` preserved on the canonical hook for that purpose; no consumer needs it today. - **R5 — Stale `useAuth` cache across components.** Pre-existing pattern, called out as a follow-up rather than addressed here. ## Conflict-with-parallel-PR awareness Parallel `single-sql-client` convoy may also touch some `pages/**` files. Conflicts possible at the import block of any page that uses both legacy auth and legacy SQL clients; merge-time rebase will handle. ## Follow-ups - Component-level `useAuth` cache audit (the original motivation for the legacy context — a thin re-introduction may be the right answer if shared state across components on the same page becomes a measured cost). - Rate-limit-aware re-auth on 429 in `lib/use-auth.js::checkAuth`. - Server-side hydration of user (HTTP-only cookie + `getServerSideProps`) to eliminate the page-mount verify roundtrip entirely. Larger architectural conversation. - Doc-writer cleanup post-merge: stamp `.convoys/ship-readiness.md` § P1 → entry 9 RESOLVED with squash SHA. Made with [Cursor](https://cursor.com)
vercel[bot] commented 2026-05-26 23:55:48 -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 27, 2026 3:55am

Request Review

[vc]: #Dsw6H2WGzAYF5w/MYeiHJTBc7QWF2GibE0IiZN8dGxU=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJ0Y2ctdmF1bHQiLCJwcm9qZWN0SWQiOiJwcmpfRjZXOEVvRkd3Y0g3aWVGcnRvRlNlOXdVVkFhNSIsImxpdmVGZWVkYmFjayI6eyJyZXNvbHZlZCI6MCwidW5yZXNvbHZlZCI6MCwidG90YWwiOjAsImxpbmsiOiJ0Y2ctdmF1bHQtZ2l0LWNvbnZveS1zaW5nbGUtZmRjNmU5LXJhbmRhbGwtc3RpbGx3ZWxscy1wcm9qZWN0cy52ZXJjZWwuYXBwIn0sImluc3BlY3RvclVybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS9yYW5kYWxsLXN0aWxsd2VsbHMtcHJvamVjdHMvdGNnLXZhdWx0LzlaQW90cWFNc1dRVTNVaUpRbVRlREZUdmZlRFMiLCJwcmV2aWV3VXJsIjoidGNnLXZhdWx0LWdpdC1jb252b3ktc2luZ2xlLWZkYzZlOS1yYW5kYWxsLXN0aWxsd2VsbHMtcHJvamVjdHMudmVyY2VsLmFwcCIsIm5leHRDb21taXRTdGF0dXMiOiJERVBMT1lFRCJ9XSwicmVxdWVzdFJldmlld1VybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS92ZXJjZWwtYWdlbnQvcmVxdWVzdC1yZXZpZXc/b3duZXI9dmFydXRhc3UmcmVwbz10Y2ctdmF1bHQmcHI9MzEifQ== 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/9ZAotqaMsWQU3UiJQmTeDFTvfeDS) | [Preview](https://tcg-vault-git-convoy-single-fdc6e9-randall-stillwells-projects.vercel.app), [Comment](https://vercel.live/open-feedback/tcg-vault-git-convoy-single-fdc6e9-randall-stillwells-projects.vercel.app?via=pr-comment-feedback-link) | May 27, 2026 3:55am | <a href="https://vercel.com/vercel-agent/request-review?owner=varutasu&repo=tcg-vault&pr=31" 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-26 23:55:53 -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 pass
Visual diff pass

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 | ✅ pass | | Visual diff | ✅ pass | _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-26 23:57:00 -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/26489785225) 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.