Files
route-commerce/REPORT.md
T
Nora 49b8e27219 chore(supabase): full purge — remove all Supabase references from codebase
- Delete supabase/ directory (config.toml, push-migrations.js,
  ADMIN_CREATE_STOP_FIX.sql, 137 archived migration files)
- Remove @supabase/ssr and @supabase/supabase-js from package.json
- Strip *.supabase.co from next.config.ts image hostnames
- Strip https://*.supabase.co from vercel.json CSP connect-src
- Remove 'supabase/**' ignore from eslint.config.mjs
- Clean supabase references from src/lib/db.ts, vitest.config.ts,
  db/seeds/2026-tuxedo-tour-stops.sql, src/actions/storefront.ts,
  scripts/import-tuxedo-stops.ts comments
- Rewrite env-var docs in README, ENVIRONMENT, PRODUCTION_SETUP,
  PRODUCTION_DEPLOYMENT_CHECKLIST, LAUNCH_CHECKLIST, CLAUDE,
  MEMORY, REPORT to drop NEXT_PUBLIC_SUPABASE_URL /
  SUPABASE_SERVICE_ROLE_KEY / supabase link / supabase CLI references

The canonical migration runner is now scripts/migrate.js (uses pg
directly via DATABASE_URL). Migrations live in db/migrations/. The
Supabase CLI is no longer in the codebase. The only remaining
'@supabase/*' in the dep tree is @supabase/auth-js as a transitive
of @neondatabase/auth (Neon Auth / Better Auth).

Final source scan: grep -rln '@supabase\|rest/v1\|supabase\.co'
src/ tests/ db/ scripts/ next.config.ts vercel.json eslint.config.mjs
package.json returns zero. Verification: npm install clean
(11 added, 21 removed, 12 changed), tsc shows same 17 pre-existing
errors (Stripe dahlia API version + fetch preconnect mocks),
vitest 172/175 (3 pre-existing failures in getAdminUser.test.ts),
lint shows same 14 pre-existing errors. Live-tested: dev server
boots in 248ms, public storefronts (/) (/login) (/pricing) (/tuxedo)
(/indian-river-direct) all return 200; /admin/v2?demo=1 reaches 200
after dev_session redirect; storefront renders real brand content.
2026-06-25 17:48:32 -06:00

216 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
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.
# YOLO Auth Migration — Final Report
**Date:** 2026-06-06 → 2026-06-07
**Mission:** Stand up a working Auth.js v5 + Google sign-in flow, then rip out
all Supabase references from the auth/admin path.
> **Note (2026-06-25):** Auth has since moved from Auth.js (NextAuth v5) to **Neon Auth (Better Auth)** — see `CLAUDE.md` for the current architecture. The Supabase purge described below is complete: `supabase/` directory deleted, `@supabase/*` deps removed from `package.json`, `next.config.ts` / `vercel.json` / `eslint.config.mjs` cleaned of Supabase hostnames and ignore patterns, and the remaining `*.supabase.co` references are limited to historical/educational comments in `MEMORY.md` and `docs/`.
---
## What was built
### 1. Auth.js v5 (NextAuth) integration — DONE
- **`src/lib/auth.ts`** — Auth.js v5 config. Google is the only provider
(no Supabase-backed Credentials provider). Sessions are JWTs; no DB
adapter. Exports `handlers`, `auth`, `signIn`, `signOut`.
- **`src/lib/admin-permissions.ts`** — `getAdminUser()` resolves the
current admin. Three branches in precedence order:
1. `NEXT_PUBLIC_USE_MOCK_DATA=true` → platform_admin dev shim
2. `dev_session` cookie → matching dev shim (platform/brand/store)
3. Auth.js session → `null` (no DB lookup yet — see Follow-ups)
- **`src/actions/auth-actions.ts`** — `signInWithGoogle()` and
`signOutAction()`. `signInWithPassword` was removed.
- **`src/app/login/LoginClient.tsx`** + **`page.tsx`** — Login page
renders "Continue with Google" (when configured) and three demo
buttons (Platform / Brand / Store Employee) via `?demo=1`. Email /
password form and "Forgot password" are gone.
- **`src/app/api/auth/[...nextauth]/route.ts`** — Auth.js route handler.
### 2. Direct Postgres connection (`src/lib/db.ts`) — DONE
- Single shared `pg.Pool` with lazy initialization. Throws a clear
error if `DATABASE_URL` is not set.
- Exports `getPool()`, a `pool` proxy alias, `query<T>()` helper, and
`withTx()` for transactions.
- Tuned for Vercel/serverless: 10 max conns, 30s idle, 10s connect
timeout. All overridable via `PG_POOL_*` env vars.
### 3. Server actions → `pg` (no Supabase) — DONE
- **`src/actions/admin/users.ts`** — Full rewrite. `getAdminUsers`,
`createAdminUser`, `updateAdminUser`, `deleteAdminUser`,
`setMustChangePassword`, `getBrands` now hit Postgres directly.
`sendPasswordResetEmail` returns a stub error (no auth service
anymore — the function is preserved for call-site compatibility).
- The `dev_session` cookie continues to be the demo-flow bypass.
### 4. Cleanup — DONE
- **`src/actions/admin/force-login.ts`** — Deleted (the
Emergency-Force-Login page and its `/api/force-admin` route were
removed in the previous session).
- **`src/actions/admin/users.ts`** — Removed the `DEV_FORCE_UID`
magic value, the `rc_auth_uid` cookie reads (×3), the
`headerStore` lookup, the `getServiceClient` / `getAuthClient` /
`callRpcWithAuth` helpers, and the `devListAdminUsers` auto-provision
branch. All Supabase imports gone.
- **`src/app/admin/me/AdminMeClient.tsx`** — Profile / email-change
handlers neutralized (return "contact a platform admin" — the
Supabase auth backend that backed them is gone).
- **`src/middleware.ts`** — `dev_session` auto-login preserved
(issues a `platform_admin` cookie on unauthed `/admin` so the rest
of the admin shell renders). `auth()` wrapper in place.
### 5. Test infrastructure — DONE
- **Vitest 2.1.9** with `@vitejs/plugin-react`, jsdom, manual
`@/* → src/*` alias. No `vite-tsconfig-paths` (ESM/require
incompatibility).
- **`tests/setup.ts`** — Mocks `next/navigation` (not in jsdom).
- **`tests/unit/getAdminUser.test.ts`** — 12 tests covering
dev_session, mock-data, Auth.js session, defensive error handling.
- **`tests/unit/auth-actions.test.ts`** — 2 tests for
`signInWithGoogle` + `signOutAction`.
- Both test files stub `server-only` with `vi.mock("server-only", () => ({}))`.
- **Playwright config** — `webServer` block for `npm run dev`,
`PLAYWRIGHT_URL` override, `reuseExistingServer: !process.env.CI`.
- **`tests/login/login-flow.spec.ts`** — Login form rendering +
demo mode (3 roles) tests.
- **`tests/e2e/auth.spec.ts`** — Auth.js endpoints, middleware
redirect behavior, /admin load with dev_session, logout.
### 6. `import "server-only"` markers — DONE
- Added to `src/lib/auth.ts`, `src/lib/admin-permissions.ts`,
`src/lib/db.ts`, `src/actions/auth-actions.ts`,
`src/actions/admin/users.ts`.
- ⚠️ In `"use server"` files, the directive must be first
(`"use server";` on line 1, then `import "server-only";`). The dev
build surfaced this; fixed in `auth-actions.ts` and `users.ts`.
---
## Verification status
| Check | Result |
|---|---|
| `npx tsc --noEmit` | ✅ 0 errors |
| `npx vitest run` | ✅ 14/14 tests pass |
| `npm run dev` | ✅ Boots in ~440ms |
| `GET /login` | ✅ 200 |
| `GET /login?demo=1` | ✅ 200 |
| `GET /api/auth/providers` | ✅ 200 (empty list — Google not configured) |
| `GET /` | ✅ 200 |
| `GET /admin` (unauthed) | ✅ 307 → `/admin?demo=1` + `dev_session` cookie |
| `GET /admin?demo=1` (with cookie) | ✅ 200 (admin layout renders) |
---
## Files changed
```
M src/actions/admin/users.ts # full rewrite, pg-only
M src/actions/auth-actions.ts # signInWithPassword removed
M src/app/admin/me/AdminMeClient.tsx # handlers stubbed
M src/app/login/LoginClient.tsx # email/password form removed
M src/app/login/page.tsx # passes hasGoogle prop
M src/lib/admin-permissions.ts # Supabase REST calls removed
M src/lib/auth.ts # Credentials provider removed
M tests/unit/auth-actions.test.ts # signInWithPassword tests removed
M tests/unit/getAdminUser.test.ts # reflects no-DB behavior
```
Plus deletions and creations recorded in the prior session.
---
## Follow-ups (the bigger fish)
The user's directive was: "git rid of all supabase references, we are
not using it for login or anything anymore." The auth/admin path is
now Supabase-free. **33 files** still import from Supabase — they use
it for **data fetching** (`supabase.from(...).select(...)`), not auth.
**Migrating those to `pg` is a follow-up.** The pattern is the same
in every file:
```ts
// Before
const { data } = await supabase.from("products").select("*").eq("brand_id", id);
// After
import { query } from "@/lib/db";
const { rows } = await query<ProductRow>(
"SELECT * FROM products WHERE brand_id = $1",
[id],
);
```
### 33 files still importing Supabase
```
src/app/admin/page.tsx, products/[id]/page.tsx, products/page.tsx,
orders/page.tsx, stops/[id]/page.tsx, stops/new/page.tsx,
stops/page.tsx, reports/page.tsx, taxes/page.tsx,
settings/billing/page.tsx, settings/integrations/page.tsx,
settings/shipping/page.tsx
src/app/tuxedo/page.tsx, about/page.tsx, contact/ContactClientPage.tsx,
stops/[slug]/page.tsx
src/app/indian-river-direct/page.tsx, faq/FAQClientPage.tsx,
contact/ContactClientPage.tsx, stops/[slug]/page.tsx
src/app/api/tuxedo/schedule-pdf/route.ts,
src/app/api/indian-river-direct/schedule-pdf/route.ts
src/app/reset-password/page.tsx, src/app/test/page.tsx
src/components/admin/AdminHeader.tsx, AdminSidebar.tsx
src/lib/supabase.ts, src/lib/supabase/server.ts # the client modules
src/actions/wholesale-auth.ts, reset-admin.ts, audit.ts
src/actions/ai/preferences.ts
```
### Additional follow-ups
1. **Provision a `pg` pool in production.** `DATABASE_URL` must be
set in the hosting dashboard (same env var as
`scripts/migrate.js` uses).
2. **Apply migration 204** if not already applied — adds
`email`, `auth_provider`, `auth_subject` columns to `admin_users`
and the `get_admin_user_for_session` RPC.
3. **Wire `getAdminUser()`'s Auth.js session branch** to call
`get_admin_user_for_session` via `pg` once a `DATABASE_URL` is
configured. Today it returns `null` (Access Denied) — correct for
an unprovisioned user, but a Google sign-in to a brand that
exists won't resolve yet.
4. **Drop the `next-auth` Credentials provider module path** in
`auth.ts` entirely once production confirms Google is the only
provider in use. Currently it's gated on env var presence.
5. **Re-implement `sendPasswordResetEmail`** if/when Auth.js v5 ships
its built-in email provider — until then, a platform admin must
handle resets manually.
6. **Decommission `src/lib/supabase.ts` and `src/lib/supabase/server.ts`**
once all 33 remaining files have been ported to `pg`. They are
the only remaining `@supabase/*` import surface.
7. **Delete `@supabase/ssr` and `@supabase/supabase-js` from
`package.json`** (last step once no file imports them).
### Resolution (2026-06-25)
Follow-ups 6 and 7 (and the data-fetching migration of all 33 files) are
complete. The codebase is now Supabase-free at the source-code level —
`grep -rln '@supabase\|rest/v1' src/` returns zero matches. The only
remaining mentions of "Supabase" are in this report, `MEMORY.md`, and a
handful of historical `docs/superpowers/{plans,specs}/` files, all kept
as historical record of the migration.
---
## Commands
```bash
npm run dev # Dev server (boots in ~440ms)
npm test # Vitest: 14/14 pass
npx tsc --noEmit # Typecheck: 0 errors
npx playwright test # E2E (skips credentials tests if env unset)
```