Files
route-commerce/ENVIRONMENT.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

8.8 KiB
Raw Blame History

Environment Setup

This guide documents every environment variable the platform uses, what each one does, where to get it, and any gotchas.

Copy .env.example.env.local and fill in the values.


Public Variables

These are safe to commit and can be used in client bundles. Prefix with NEXT_PUBLIC_.

NEXT_PUBLIC_BASE_URL

The base URL of your deployment. Used for OAuth redirects and webhook URLs.

  • Local: http://localhost:3000
  • Production: https://yourdomain.com

NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY

Stripe publishable key for Stripe.js in the client.

  • Where to get: Stripe Dashboard → Developers → API Keys → Publishable key
  • Format: pk_live_... or pk_test_...

NEXT_PUBLIC_SINGLE_BRAND

Set to a brand slug to hide other brand routes in single-brand mode.

  • Example: tuxedo
  • Default: empty (multi-brand mode)

Server-Only Variables

Never prefix with NEXT_PUBLIC_. These must only be accessed in Server Components, Server Actions, or API Routes.

Database

DATABASE_URL

Full Postgres connection string. The app uses this exclusively (no Supabase, no JS client) for every server-side query — server actions and API routes import a shared pg Pool from src/lib/db.ts and call SECURITY DEFINER PL/pgSQL functions.

  • Where to get: Neon Dashboard → Project → Connection Details → Connection string (pooled)
  • Example: postgresql://user:pass@ep-xxx.us-east-2.aws.neon.tech/routecommerce?sslmode=require
  • Format: postgres://user:pass@host:port/dbname?sslmode=require

DATABASE_ADMIN_URL (optional)

Same connection string but with elevated perms (typically the direct, non-pooled Neon connection). Only used by scripts/migrate.js for DDL — fall back to DATABASE_URL if unset.

Stripe

STRIPE_SECRET_KEY

Stripe secret key for backend API calls (creating sessions, webhooks, etc.).

  • Where to get: Stripe Dashboard → Developers → API Keys → Secret key
  • Format: sk_live_... or sk_test_...

STRIPE_WEBHOOK_SECRET

Signing secret for Stripe webhook payloads.

  • Where to get: Stripe Dashboard → Developers → Webhooks → select endpoint → Signing secret
  • Format: whsec_...

Stripe Price IDs

Create these as recurring prices in your Stripe Dashboard first. Each maps to a plan tier or add-on.

Variable What it is Stripe Dashboard
STRIPE_PRICE_STARTER $49/mo Starter plan Create a Product → Price at $49/mo
STRIPE_PRICE_FARM $149/mo Farm plan Create a Product → Price at $149/mo
STRIPE_PRICE_ENTERPRISE $399/mo Enterprise plan Create a Product → Price at $399/mo
STRIPE_PRICE_HARVEST_REACH $79/mo Harvest Reach add-on Create a Product → Price at $79/mo recurring
STRIPE_PRICE_WHOLESALE_PORTAL $99/mo Wholesale Portal add-on Create a Product → Price at $99/mo recurring
STRIPE_PRICE_WATER_LOG $39/mo Water Log add-on Create a Product → Price at $39/mo recurring
STRIPE_PRICE_AI_TOOLS $59/mo AI Intelligence add-on Create a Product → Price at $59/mo recurring
STRIPE_PRICE_SQUARE_SYNC $39/mo Square Sync add-on Create a Product → Price at $39/mo recurring
STRIPE_PRICE_SMS_CAMPAIGNS $29/mo SMS Campaigns add-on Create a Product → Price at $29/mo recurring

Note: Annual pricing requires separate annual prices (e.g., $441/yr for Starter = $49 × 12 × 0.75). Use different price IDs and pass annual=true to checkout actions.

Email (Resend)

RESEND_API_KEY

API key for sending transactional email via Resend.

  • Where to get: Resend.com → API Keys → Create API key
  • Format: re_...

RESEND_WEBHOOK_SECRET

Signing secret for Resend webhook payloads.

  • Where to get: Resend Dashboard → Webhooks → select endpoint → Signing secret
  • Format: whsec_...

AI

The platform supports five AI providers. Each brand can override per-provider keys in the admin AI Provider panel (/admin/settings/ai). Env vars here are fallbacks for when no per-brand key is configured.

OPENAI_API_KEY

OpenAI API key for AI features (AI Intelligence Pack add-on).

  • Where to get: OpenAI Platform → API Keys → Create secret key
  • Format: sk-...

OPENAI_ORG_ID

OpenAI organization ID (optional — for workspace-level usage tracking).

  • Where to get: OpenAI Platform → Settings → Organization ID
  • Format: org-...

MINIMAX_API_KEY

MiniMax (MiniMax) API key — OpenAI-compatible. Pre-launch default provider.

  • Where to get: MiniMax Platform → API Keys
  • Format: ey... (JWT-style)
  • Used by: getAIClient() falls back to this when no per-brand key is set. ai-import.ts Import Center also prefers this over OPENAI_API_KEY when both are set.

MINIMAX_BASE_URL (optional)

Override the MiniMax API base URL.

  • Default: https://api.minimax.io/v1 (global)
  • China: https://api.minimaxi.com/v1 (mainland endpoint, lower latency inside China)

Other providers

The admin panel also accepts per-brand keys for Anthropic (sk-ant-...), Google Gemini (AIza...), xAI (xai-...), and custom OpenAI-compatible endpoints. These can also be set globally via ANTHROPIC_API_KEY, GOOGLE_API_KEY, XAI_API_KEY.

Square

SQUARE_APP_SECRET

Square app secret for Square API authentication.

  • Where to get: Square Developer Dashboard → Your App → Credentials → Application Secret
  • Format: sq0...

SQUARE_ENVIRONMENT

Controls whether to use Square sandbox or production.

  • Values: sandbox (default for dev) or production
  • ⚠️ Note: Production credentials and sandbox credentials are separate. Make sure this matches which credentials you're using.

Webhook Setup

Stripe

Dashboard: Stripe Dashboard → Developers → Webhooks → Add endpoint

  • URL: https://yourdomain.com/api/stripe/webhook
  • Events to listen for:
    • checkout.session.completed
    • customer.subscription.updated
    • customer.subscription.deleted
    • invoice.payment_succeeded
    • invoice.payment_failed

Resend

Dashboard: Resend → Webhooks → Add webhook

  • URL: https://yourdomain.com/api/resend/webhook
  • Events: email_delivered, email_bounced, email_complained

Local vs Production

Variable Local (.env.local) Production (hosting dashboard)
NEXT_PUBLIC_BASE_URL http://localhost:3000 https://yourdomain.com
STRIPE_SECRET_KEY sk_test_... sk_live_...
STRIPE_PUBLISHABLE_KEY pk_test_... pk_live_...
SQUARE_ENVIRONMENT sandbox production

Gotchas

  • Wrong Stripe key type: Using sk_live_ in development or sk_test_ in production will silently fail. Always match key type to environment.
  • Stripe price IDs drift: If you create new prices in Stripe Dashboard but forget to update .env.local, billing will fail. Keep them in sync.
  • SQUARE_ENVIRONMENT mismatch: Production Square credentials won't work with sandbox. Match it to your app secret type.
  • OPENAI_API_KEY for AI features: AI features won't work without this. The AI Intelligence Pack add-on requires a valid OpenAI key.

Authentication

Production (HTTPS Required)

Neon Auth session cookies use the __Secure- prefix, which requires HTTPS. In production, the auth flow works as follows:

  1. User submits credentials to /api/auth/sign-in
  2. Neon Auth server sets session cookie with secure: true
  3. Browser stores the cookie and sends it with subsequent requests
  4. Middleware validates the session cookie

Local Development (HTTP)

For local development over HTTP (e.g., http://localhost:4000), the platform provides a dev_session bypass:

  1. Via Login Page: Visit /login - you'll see "Dev Mode — Quick Access" buttons for Platform Admin, Brand Admin, and Store Employee roles.
  2. Via Browser Console: document.cookie = 'dev_session=platform_admin; path=/; max-age=86400'
  3. Via curl: curl -b "dev_session=platform_admin" http://localhost:4000/admin

The dev_session cookie is automatically recognized by:

  • The middleware (src/proxy.ts)
  • The getAdminUser() function (src/lib/admin-permissions.ts)

Note: The dev_session bypass only works when NODE_ENV !== "production". In production, only Neon Auth session cookies are accepted.

HTTPS for Local Development

If you prefer to test with real auth over HTTPS locally, you can use a tool like mkcert:

# Install mkcert
brew install mkcert

# Create local CA and install it
mkcert -install

# Generate certificate for localhost
mkcert localhost 127.0.0.1 ::1

# Update next.config.ts to use HTTPS

For most development work, the dev_session bypass is sufficient.