Merged
Conversation
…g, staff PIN, customer magic-link Make authentication real, env-guarded like the data driver + payment rails: with no Supabase env the app runs SIMULATED auth (seeded demo session derived from memberships) so build + Vitest + preview stay green with zero env; with Supabase env present it uses REAL Supabase Auth. - Session plumbing via @supabase/ssr: browser + cookie-backed server clients, middleware that refreshes the session + coarse-gates protected routes, and getServerSession()/getCurrentUser() returning user + memberships + platform flag from the session (src/lib/auth/*). - Identity-bridge migration: trigger linking auth.users -> public.users (auth.uid() == users.id, links seed users by email via ON UPDATE CASCADE); adds staff.pin_hash + orders.staff_id. Idempotent; skipped on vanilla PG. - Auth flows/UI: /login (magic-link + optional password), /login/choose tenant chooser, /platform/login (admin-only), /forbidden, /auth/callback + /auth/ signout, sign-out controls. /shop customer magic-link now uses real Supabase OTP in real mode (stub fallback otherwise). - Role gating matrix (middleware + server guards): /admin owner|manager; /terminal+/kitchen operational roles; /platform platform_admin; /shop public. Gated pages are server components resolving session-derived tenant/location; tenant-scoped API routes re-check session/membership (src/lib/auth/api.ts). - Staff PIN quick-switch: device logs in (session), cashiers switch active staff by PIN verified server-side against staff.pin_hash (scrypt; hash never leaves server); orders attributed via staff_id. - Bootstrap script (npm run auth:bootstrap) creates owner + platform-admin Supabase Auth users linked to the seed. Docs + .env.example + seed updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this does
Makes authentication real in the multi-tenant POS, env-guarded exactly like the existing data-driver + payment-rail pattern:
memberships(not a hardcoded constant). Build + the full Vitest suite + the Vercel preview stay green with no env.Design
Session plumbing (
@supabase/ssr)src/lib/auth/supabase-browser.ts(browser client),supabase-server.ts(cookie-backed server client, RLS-as-user),src/middleware.ts(refreshes the session on every protected request + coarse-gates signed-out visitors to the right login).getServerSession()/getCurrentUser()(src/lib/auth/session.ts) → authed user + memberships (tenant_ids + roles) + platform-admin flag, all derived from the session.Identity-bridge migration (
supabase/migrations/20260606000000_auth_user_bridge.sql)auth.users(insert) upsertspublic.userswithid = auth.uid()+ email. Existing seed users are linked by email by re-pointing the seededpublic.users.idto the auth id (FKs madeON UPDATE CASCADE). Idempotent; the trigger is skipped on vanilla Postgres (noauthschema), so the RLS-isolation CI job still applies it cleanly.staff.pin_hash+orders.staff_id.Role-gating matrix (middleware + authoritative server checks)
/admin/terminal,/kitchen/platform/shopUnauthenticated →
/login(tenant) or/platform/login. Multi-tenant user →/login/choose. Gated pages are now server components that resolve the session-derived tenant/location (replacing the hardcoded demo context) and pass it to the existing client shells. Tenant-scoped API routes re-check the session/membership against the request's tenant (src/lib/auth/api.ts).Data-access model (user-RLS vs service-role)
PosDriver, filters every query bytenant_id/location_id) — reserved for trusted server ops (webhooks, platform-admin actions w/ explicit checks, the bootstrap script, system jobs). A user-scoped RLS client (getServerSupabase()) is wired and used by the auth flows; a full per-query RLS switch across the entire feature-complete app was intentionally not done in this pass (documented trade-off — RLS is the backstop, the session is the gate).Staff PIN quick-switch
/api/terminal/pinagainststaff.pin_hash(scrypt,node:crypto, no new dep). The hash never leaves the server (listStaffstrips it; onlygetStaffByIdcarries it). Orders attribute to the active staff viaorders.staff_id.Customer magic-link
/shopstays PUBLIC. The optional customer account sign-in now sends a real Supabase Auth magic link in real mode (returns to/shop/<slug>?signedin=1); falls back to the legacy returns-the-link stub with zero env.Verification
typecheck,lint,build,test:runall green (122 tests, +16 new for PIN, roles matrix, identity resolution).Post-merge steps the orchestrator must run on the LIVE project
npm run db:apply(applies migrations incl. the identity bridge + seed).https://<domain>/auth/callback+https://<domain>/shop/*, configure SMTP.npm run auth:bootstrap(withNEXT_PUBLIC_SUPABASE_URL+SUPABASE_SERVICE_ROLE_KEY; optionalBOOTSTRAP_*_PASSWORD) → creates the demo owner (tony@tonys-pizza.example) + platform admin (ops@pizzapos.example) Auth users, linked to the seed by the bridge./login(owner) and/platform/login(admin). Demo staff PINs: Tony 1111 · Carmela 2222 · Christopher 3333 · Furio 4444.Full walkthrough in
docs/PRODUCTION_READINESS.md§1a.🤖 Generated with Claude Code