# Production Setup Guide

## Quick Start

### 1. Create Your .env File

Copy the template and fill in your secrets:
```bash
cp .env.example .env
```

Then edit `.env` with your actual values:

```bash
# === Frontend Variables ===
VITE_API_BASE_URL=https://puffinoffset.com/api
VITE_WREN_API_TOKEN=35c025d9-5dbb-404b-85aa-19b09da0578d
VITE_FORMSPREE_CONTACT_ID=xkgovnby
VITE_FORMSPREE_OFFSET_ID=xvgzbory
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_51SJc52Pdj1mnVT5k8a2NsdyywF6jlpR2VTAMeHOSoXskOQBNRyKpA35G6sJ2ckgv6UPXq9LbiIspFC6E4Yrppk9m00yAMX8K9Z

# === Backend Variables ===
NODE_ENV=production
PORT=3001
FRONTEND_URL=https://puffinoffset.com

# === Stripe Configuration (Test Mode) ===
STRIPE_SECRET_KEY=sk_test_51SJc52Pdj1mnVT5kkkJQgPpjQPkrf8D6Ik0yvdHgCYHOjZXwdRo3wCMZ4YjqaMDEQL0gyNhUgZZ0sAo4YIGTn6f500Or1vuuxJ
STRIPE_WEBHOOK_SECRET=whsec_6hNtwjRPUvxY3MKOJYfyOZRDZW7mlIsB

# === Wren API Configuration ===
WREN_API_TOKEN=35c025d9-5dbb-404b-85aa-19b09da0578d
WREN_DRY_RUN=true

# === Database Configuration ===
DATABASE_PATH=/app/data/orders.db
```

### 2. Deploy with Docker Compose

```bash
# Pull latest images
docker compose pull

# Start containers
docker compose up -d

# View logs
docker compose logs -f

# Check status
docker compose ps
```

### 3. Configure Nginx on Host

Update your `/etc/nginx/sites-available/puffinoffset.com` configuration:

```nginx
# Frontend
server {
    listen 443 ssl http2;
    server_name puffinoffset.com;

    ssl_certificate /etc/letsencrypt/live/puffinoffset.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/puffinoffset.com/privkey.pem;

    location / {
        proxy_pass http://localhost:3800;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# Backend API
server {
    listen 443 ssl http2;
    server_name puffinoffset.com;

    ssl_certificate /etc/letsencrypt/live/puffinoffset.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/puffinoffset.com/privkey.pem;

    # Stripe webhooks (MUST use raw body)
    location /api/webhooks/stripe {
        proxy_pass http://localhost:3801;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # CRITICAL: Don't buffer request body for webhook signature verification
        proxy_request_buffering off;
        proxy_buffering off;
        client_max_body_size 10m;
    }

    # All other API routes
    location /api/ {
        proxy_pass http://localhost:3801;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# HTTP redirect
server {
    listen 80;
    server_name puffinoffset.com;

    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}
```

Reload nginx:
```bash
sudo nginx -t
sudo systemctl reload nginx
```

## Architecture

```
Internet
   ↓
Host Nginx (SSL) :443
   ↓
   ├─→ Frontend Container :3800
   └─→ Backend Container :3801
```

**Port Mapping:**
- Frontend: Host 3800 → Container 3000
- Backend: Host 3801 → Container 3001

## Stripe Configuration

### Required Stripe Keys:
1. **Publishable Key** (Frontend): `pk_test_*` for test mode
2. **Secret Key** (Backend): `sk_test_*` for test mode
3. **Webhook Secret** (Backend): `whsec_*` from Stripe Dashboard

### Configure Webhooks in Stripe Dashboard:

1. Go to: https://dashboard.stripe.com/test/webhooks
2. Click "Add endpoint"
3. URL: `https://puffinoffset.com/api/webhooks/stripe`
4. Select these events:
   - `checkout.session.completed`
   - `checkout.session.async_payment_succeeded`
   - `checkout.session.async_payment_failed`
   - `checkout.session.expired`

### Test Mode Configuration:
- ✅ Using `sk_test_*` and `pk_test_*` keys
- ✅ Using `WREN_DRY_RUN=true` (no real offsets purchased)
- ✅ Test card: 4242 4242 4242 4242
- ✅ No real charges will occur

### Going Live:
When ready for production:
1. Get live Stripe keys (`sk_live_*` and `pk_live_*`)
2. Configure production webhook endpoint
3. Set `WREN_DRY_RUN=false`
4. Update `.env` with live keys

## Testing

### Test Stripe Integration:
```bash
# Use test card in checkout:
Card: 4242 4242 4242 4242
Date: Any future date
CVC: Any 3 digits
ZIP: Any 5 digits
```

### Verify Webhooks:
```bash
# Check backend logs
docker compose logs -f backend

# Should see:
# ✅ Checkout session completed
# 💳 Payment confirmed
# 🌱 Fulfilling order via Wren API
# ⚠️  DRY RUN MODE: No real offset will be created
```

### Check Health:
```bash
curl https://puffinoffset.com/api/health
```

## Troubleshooting

### Container won't start:
```bash
docker compose logs backend
docker compose logs web
```

### Webhook errors:
- Verify `STRIPE_WEBHOOK_SECRET` matches Stripe Dashboard
- Check nginx is not buffering webhook requests
- View webhook attempts in Stripe Dashboard

### Database issues:
```bash
# Check database volume
docker volume ls
docker volume inspect puffin-app_puffin-data

# Access database
docker compose exec backend sh
sqlite3 /app/data/orders.db
```

## Security Checklist

- ✅ `.env` excluded from git
- ✅ Webhook signature verification enabled
- ✅ CORS restricted to allowed origins
- ✅ Idempotency protection on webhooks
- ✅ SSL/TLS on host nginx
- ⚠️ Rotate Wren API token (it was previously committed to git)

## CI/CD Pipeline

Gitea Actions automatically builds and pushes images on push to `main`:
- Frontend: `code.puffinoffset.com/matt/puffin-app:frontend-latest`
- Backend: `code.puffinoffset.com/matt/puffin-app:backend-latest`

To deploy updates:
```bash
docker compose pull
docker compose up -d
```

## Files Overview

| File | Purpose | In Git? |
|------|---------|---------|
| `.env.example` | Template with placeholders | ✅ Yes |
| `.env` | Your actual secrets | ❌ No (gitignored) |
| `docker-compose.yml` | Production deployment | ✅ Yes |
| `nginx-host.conf` | Example nginx config | ✅ Yes |

**NEVER commit `.env` with real secrets!**
