42f5745c97
Documentation pass — reviewed codebase in full, identified stale references, and aligned docs with actual code state. Changes: - CLAUDE.md, PRODUCTION_SETUP.md, LAUNCH_CHECKLIST.md, src/auth.config.ts: middleware path src/middleware.ts → src/proxy.ts (Next.js 16+ convention) - CLAUDE.md, ENVIRONMENT.md, README.md: dev server port localhost:3000 → localhost:4000 (per package.json dev script 'next dev --webpack -H 0.0.0.0 -p 4000') - PRODUCTION_DEPLOYMENT_CHECKLIST.md: rewrote migration list — actual db/migrations/ contains 10 files (0000–0091), not the Supabase-era 001–092 series. Updated platform version 1.6 → 2.0 and last-updated stamp. - MEMORY.md: refreshed 'Last updated' to 2026-06-25 and added a current-state header flagging the 'Auth.js v5 wiring' section as historical (current auth is Neon Auth/Better Auth). Also flags the 'GitHub origin' notes as historical (only Gitea origin exists). - LAUNCH_CHECKLIST.md: added 'Last updated: 2026-06-25' header and refresh note in footer. Verification: - npx tsc --noEmit: pre-existing Stripe API version + test mock errors only (verified by stashing changes and re-running — same error set). - No new errors introduced.
212 lines
8.9 KiB
Markdown
212 lines
8.9 KiB
Markdown
# 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:4000` (dev script binds to port 4000; override via `npm run dev -- -p <port>`)
|
||
- **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](https://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](https://platform.openai.com) → 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](https://platform.minimax.io) → 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:4000` (or whatever port the dev server is on) | `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](https://github.com/FiloSottile/mkcert):
|
||
|
||
```bash
|
||
# 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. |