# Local Development Setup

## Stripe Webhook Forwarding

When developing locally, Stripe cannot send webhooks directly to localhost. You must use the Stripe CLI to forward webhooks.

### Quick Start (Recommended)

```bash
npm run power-cycle
```

This handles everything: kills processes, clears cache, starts dev server + Stripe webhook forwarding.

### Manual Setup (Two Terminals)

```bash
# Terminal 1: Dev server
npm run dev

# Terminal 2: Stripe webhook forwarding
npm run stripe:listen
```

### How It Works

1. Stripe CLI connects to Stripe's API
2. Listens for webhook events in test mode
3. Forwards events to `http://localhost:3000/api/webhooks/stripe`
4. Signs events with the local webhook secret

### Verification

When webhook forwarding is active:

```
Ready! You are using Stripe API Version [2016-07-06].
Your webhook signing secret is whsec_...
```

When a webhook is received:

```
2025-11-06 15:57:30  --> checkout.session.completed [evt_...]
2025-11-06 15:57:30  <--  [200] POST http://localhost:3000/api/webhooks/stripe
```

### Without Webhook Forwarding

If you forget to run Stripe forwarding:

- Checkout completes successfully in Stripe
- User redirected to `/registration/welcome`
- Page shows "Setting Up Your Account..." indefinitely
- After 30 seconds, timeout error is shown

**Always use `npm run power-cycle` for local development.**

## Webhook Environment Routing

In Stripe test mode, webhook events are broadcast to ALL registered endpoints simultaneously (staging server, dev server, every developer's localhost). This can cause duplicate processing, confusing logs, and race conditions.

### Solution: Environment-Based Routing

Each environment sets a unique `WEBHOOK_ENVIRONMENT` value in `.env.local`. When a checkout session is created, this value is stored in the session metadata. The webhook handler then only processes events matching its environment.

### Setup

Add to your `.env.local`:

```bash
# Use a unique identifier for your local environment
WEBHOOK_ENVIRONMENT="localhost-yourname"
```

### Environment Values by Server

| Environment                      | WEBHOOK_ENVIRONMENT Value |
| -------------------------------- | ------------------------- |
| Production (amsoil.aimclear.com) | `production`              |
| Staging (aimclear.biz)           | `staging`                 |
| Dev server (acdev3.com)          | `dev-server`              |
| Local dev (Tim)                  | `localhost-tim`           |
| Local dev (other)                | `localhost-{name}`        |

### How It Works

1. **Checkout session creation**: The `WEBHOOK_ENVIRONMENT` value is embedded in the session metadata
2. **Webhook received**: All environments receive the webhook from Stripe
3. **Environment check**: Each environment compares the event's `webhook_environment` metadata with its own `WEBHOOK_ENVIRONMENT`
4. **Skip or process**: If they don't match, the event is skipped with a 200 response (so Stripe doesn't retry)

### Backwards Compatibility

- Events without `webhook_environment` metadata are processed by all environments (for in-flight checkouts)
- Subscription and invoice events (which don't carry checkout metadata) are processed normally
- Existing deduplication via `stripeWebhookEvent` table prevents duplicate database operations
- Comparison is case-insensitive (`localhost-Tim` matches `LOCALHOST-TIM`)

### Production Mode

For production environments using Stripe **live mode** (not test mode), setting `WEBHOOK_ENVIRONMENT` is optional but recommended:

- **Live mode**: Stripe only sends webhooks to registered production endpoints, so environment routing isn't strictly necessary
- **Test mode**: Environment routing prevents cross-environment interference
- **Recommendation**: Set `WEBHOOK_ENVIRONMENT="production"` in production for consistency and future-proofing

### Migration Path

To roll out environment routing across all environments:

1. **Deploy the code changes** to all environments first (backwards compatible)
2. **Add `WEBHOOK_ENVIRONMENT`** to each environment's configuration:
   - Production: `WEBHOOK_ENVIRONMENT=production`
   - Staging: `WEBHOOK_ENVIRONMENT=staging`
   - Dev server: `WEBHOOK_ENVIRONMENT=dev-server`
   - Local developers: Each adds their own to `.env.local`
3. **In-flight checkouts** created before step 2 will still process (no environment metadata = process everywhere)
4. **New checkouts** after step 2 will only process in their originating environment

**Timeline**: Steps 1-2 can happen over days/weeks. The feature is fully backwards compatible.

### Debugging

Check your server logs for environment routing:

```
# Event skipped (different environment)
Skipping webhook event for different environment { eventEnv: 'localhost-tim', thisEnv: 'dev-server' }

# Event processed (matching environment)
Webhook received { eventType: 'checkout.session.completed', eventId: 'evt_...' }

# Event processed (no environment metadata - backwards compatible)
Webhook received { eventType: 'checkout.session.completed', eventId: 'evt_...' }
```

### Troubleshooting

#### Events not being processed

1. **Check WEBHOOK_ENVIRONMENT value**: Ensure it matches exactly (case-insensitive) with what was set when the checkout was created
2. **Check logs**: Look for "Skipping webhook event for different environment"
3. **Verify metadata**: In Stripe Dashboard, check the checkout session's metadata for `webhook_environment`

#### Events being processed multiple times

1. **Check all environments have unique WEBHOOK_ENVIRONMENT values**
2. **For old checkouts**: Events without metadata are processed everywhere - this is expected and handled by deduplication
3. **Subscription events**: These don't carry checkout metadata and rely on the existing deduplication table

#### "Event already processed" for new checkouts

This is normal when multiple environments share a Stripe account. The first environment to receive the webhook records it in `stripeWebhookEvent` table, preventing duplicate processing.

#### Environment mismatch after deployment

If you deployed new code but forgot to set `WEBHOOK_ENVIRONMENT`:
- Falls back to `NODE_ENV` (usually `development`, `production`, or `test`)
- May cause unexpected routing behavior
- Solution: Set `WEBHOOK_ENVIRONMENT` explicitly in all environments
