π Authentication
Auth is already wired. You mostly need to decide how it should look and which signup flow you want.
GoShipped ships email signup, confirmation, login, logout, and password reset. Users persist in Postgres. Chat and settings stay behind a session.
You do not add an auth library. You decide who can register, where redirects go, and how the screens look.
Register / login UI
β
Supabase Auth
β
public.users + API JWT
β
/chatWhat you already have
| Flow | What happens |
|---|---|
| Signup | Email + password on /register. Confirmation email from Supabase Auth. |
| Email confirmation | Link hits /auth/callback or /auth/confirm, then the app. |
| Login | /login β session cookie β /chat |
| Logout | Sign out from the user menu / account settings β /login |
| Password reset | /forgot-password β email β /update-password |
| Protected routes | /chat, /settings, and related prefixes require a session |
| User row | Trigger handle_new_user inserts public.users from auth.users (the API can also create the row if it is missing) |
Optional invite-only: set ALLOWED_EMAILS in apps/api/.env. Non-empty means only those addresses may call the API.
Auth email is not Resend
Two different inboxes
Supabase Auth sends confirmation and password-reset mail.
Resend sends product mail (welcome, trial, payment failed) when you turn EMAIL_ENABLED on.
EMAIL_ENABLED=false does not stop signup confirmation. See Emails.
Local Auth mail shows up in Mailpit (pnpm supabase:status prints the URL). Hosted Auth uses the Supabase inbox / your project's Auth SMTP.
Signup flag vs the real gate
features.signup only hides /register (the proxy sends people to /login).
To actually stop new accounts, disable βAllow new users to sign upβ in the Supabase dashboard (local: enable_signup in supabase/config.toml). Use ALLOWED_EMAILS if the API should reject everyone else.
Onboarding
After the first confirmed login, /chat can show a first-run overlay.
- Flag:
features.onboarding - Copy and steps:
apps/api/app/onboarding/config.py - Chrome:
apps/web/src/components/onboarding/
When the flag is false, the API treats onboarding as completed. Welcome email is independent β it still uses Resend if product email is on.
Redirect URLs
pnpm dev serves HTTPS at https://localhost:3000. Confirmation links that open http://localhost:3000 will fail.
Set these in Supabase Auth URL configuration:
| Environment | Set these |
|---|---|
| Local (hosted Supabase) | Site URL https://localhost:3000. Allow /auth/callback and /auth/confirm on HTTPS (and HTTP if you still need it). |
| Local Supabase | Already in supabase/config.toml (site_url + additional_redirect_urls) |
| Production | Site URL = your web origin. Redirects: https://<web>/auth/callback and https://<web>/auth/confirm |
After you change URLs, request a new email. Old links keep the old host.
The deploy wizard reminds you to set Production Auth URLs. They are not applied automatically.
What you probably want to customize
| What | Where |
|---|---|
| Auth screens and copy | apps/web/src/components/auth/ |
| Brand on those screens | starter.config.json (name + logo) |
| Signup UI on/off | features.signup |
| Redirects / Site URL | Supabase dashboard or supabase/config.toml |
| Confirmation / reset HTML (local) | supabase/templates/confirmation.html, recovery.html |
| Confirmation / reset HTML (hosted) | Dashboard β Auth β Email templates |
| Password minimum | apps/web/src/config/auth.ts β keep in sync with minimum_password_length in config.toml |
| Invite-only | Disable Supabase signup + optional ALLOWED_EMAILS |
Session refresh lives in apps/web/src/proxy.ts (Next.js 16). You rarely need to touch it.
Try it locally
pnpm supabase:start # if you use local Auth + Mailpit
pnpm dev- Open
/register - Confirm in Mailpit (or the hosted inbox)
- Land on
/chat - Sign out, then
/forgot-password
π Customize the Landing Page
Turn the starter marketing site inside GoShipped into your product website. Copy, sections, pricing, and legal β not the public docs you are reading now.
π Database & Storage
Postgres, pgvector, migrations, and Supabase Storage. Add product tables the same way GoShipped already does.