# 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_SUPABASE_URL`
Your Supabase project URL.
- **Where to get:** Supabase Dashboard → Project Settings → API → Project URL
- **Example:** `https://abc123.supabase.co`

### `NEXT_PUBLIC_SUPABASE_ANON_KEY`
Supabase anonymous (anon) key — safe for client-side use.
- **Where to get:** Supabase Dashboard → Project Settings → API → anon key

### `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.

### Supabase

#### `SUPABASE_SERVICE_ROLE_KEY`
Full service role key — grants DB admin access bypassing RLS.
- **Where to get:** Supabase Dashboard → Project Settings → API → service_role key
- **⚠️ Critical:** Never expose this to the client. Used only in server-side code.

### 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: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.
- **SUPABASE_SERVICE_ROLE_KEY in client:** If you ever see `SUPABASE_SERVICE_ROLE_KEY` in a browser bundle, it's a critical security incident. The key was exposed server-side. Rotate it immediately in Supabase Dashboard.
- **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.