ShipVeryFastShipVeryFast
Documentation

Environment & services

ShipVeryFast connects to three external services: Supabase (database + auth), Stripe (payments) and Mailgun (email). Configure each one below.

Environment variables

All variables live in .env.local (copied from .env.example). They are validated at startup in libs/config.ts.

VariableWhere to get it
SUPABASE_URLSupabase → Project Settings → API → Project URL
SUPABASE_ANON_KEYSupabase → API → anon public key
SUPABASE_SERVICE_ROLE_KEYSupabase → API → service_role key (server only)
NEXTAUTH_SECRETGenerate with openssl rand -base64 32
NEXTAUTH_URLhttp://localhost:3000 in dev, your domain in prod
CSRF_SECRETopenssl rand -base64 32 (≥ 32 chars)
STRIPE_SECRET_KEY / STRIPE_PUBLIC_KEYStripe → Developers → API keys
STRIPE_WEBHOOK_SECRETFrom stripe listen or the Dashboard webhook
STRIPE_PRICE_BASIC / _PRO / _ENTERPRISEStripe → Products → price IDs
MAILGUN_API_KEY / MAILGUN_DOMAIN / MAILGUN_FROM_EMAILMailgun → Settings & Sending
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRETGoogle Cloud Console → OAuth credentials

Supabase (database)

The schema lives in supabase/migrations/0001_initial_schema.sql. It creates users, subscriptions, payments, email_verifications, password_resets and blog_posts, with Row Level Security and a trigger that mirrors auth.users into public.users.

Option A, Dashboard

  1. Open your project → SQL Editor → New query.
  2. Paste the migration file contents.
  3. Click Run, then check the Table Editor.

Option B, CLI

npm install -g supabase
supabase link --project-ref <your-project-ref>
supabase db push

The server uses the service role key (supabaseAdmin), which bypasses RLS; the policies protect direct anon/browser access.

Stripe (payments)

  1. Create products & prices in Stripe → Products, then paste the price IDs into the STRIPE_PRICE_* env vars. They map to plan IDs in libs/pricingPlans.ts.
  2. The client sends a planId; the server resolves the real price ID from env (no hardcoded IDs).
  3. Test webhooks locally:
stripe login
stripe listen --forward-to localhost:3000/api/webhooks/stripe

Copy the printed whsec_… into STRIPE_WEBHOOK_SECRET. In production, add the endpoint https://yourdomain.com/api/webhooks/stripe in the Dashboard. Handled events: customer.subscription.updated, invoice.payment_succeeded, invoice.payment_failed.

Mailgun (email)

  1. Add and verify your sending domain in Mailgun (add the DKIM, SPF and tracking DNS records they provide).
  2. Set MAILGUN_API_KEY, MAILGUN_DOMAIN, MAILGUN_FROM_EMAIL.
  3. Email is sent via libs/mailer.ts (Mailgun SMTP): verification, password reset, welcome, magic-link.

Until Mailgun is configured, magic-link URLs are logged to the server console so local auth still works.

Authentication

NextAuth with JWT sessions (app/api/auth/[...nextauth]/route.ts), with Email magic link and Google OAuth providers. For Google, set the redirect URI to https://yourdomain.com/api/auth/callback/google (and the localhost variant for dev).

Next: deploy to production.