# Deployment Guide

This guide covers deploying ThrillWiki to production environments, including configuration, security, and monitoring setup.

## Pre-Deployment Checklist

### Configuration

- [ ] All required environment variables set
- [ ] `DEBUG=False`
- [ ] Strong `SECRET_KEY` (50+ characters, randomly generated)
- [ ] `ALLOWED_HOSTS` properly configured
- [ ] `CSRF_TRUSTED_ORIGINS` set
- [ ] Database URL points to production database
- [ ] Redis URL configured for caching

### Security

- [ ] `SECURE_SSL_REDIRECT=True`
- [ ] `SESSION_COOKIE_SECURE=True`
- [ ] `CSRF_COOKIE_SECURE=True`
- [ ] `SECURE_HSTS_SECONDS` set (31536000 recommended)
- [ ] `SECURE_HSTS_INCLUDE_SUBDOMAINS=True`
- [ ] No debug tools enabled
- [ ] Turnstile keys configured

### Validation

Run the configuration validator:

```bash
python manage.py validate_settings --strict
python manage.py check --deploy
```

## Environment Configuration

### Required Environment Variables

```bash
# Core Django
SECRET_KEY=<generate-secure-key>
DEBUG=False
DJANGO_SETTINGS_MODULE=config.django.production
ALLOWED_HOSTS=thrillwiki.com,www.thrillwiki.com
CSRF_TRUSTED_ORIGINS=https://thrillwiki.com,https://www.thrillwiki.com

# Database
DATABASE_URL=postgis://user:pass@db-host:5432/thrillwiki

# Cache
REDIS_URL=redis://:password@redis-host:6379/1

# Email
EMAIL_BACKEND=django_forwardemail.backends.ForwardEmailBackend
FORWARD_EMAIL_API_KEY=your-api-key
FORWARD_EMAIL_DOMAIN=thrillwiki.com

# Security
TURNSTILE_SITE_KEY=your-site-key
TURNSTILE_SECRET_KEY=your-secret-key
SECURE_SSL_REDIRECT=True
SESSION_COOKIE_SECURE=True
CSRF_COOKIE_SECURE=True

# Cloudflare Images
CLOUDFLARE_IMAGES_ACCOUNT_ID=your-account-id
CLOUDFLARE_IMAGES_API_TOKEN=your-api-token
CLOUDFLARE_IMAGES_ACCOUNT_HASH=your-account-hash

# Road Trip Service
ROADTRIP_USER_AGENT=ThrillWiki/1.0 (https://thrillwiki.com)

# Frontend
FRONTEND_DOMAIN=https://thrillwiki.com
```

### Optional Production Settings

```bash
# Monitoring
SENTRY_DSN=https://xxx@xxx.ingest.sentry.io/xxx
SENTRY_ENVIRONMENT=production
SENTRY_TRACES_SAMPLE_RATE=0.1

# Secret rotation
SECRET_ROTATION_ENABLED=True
SECRET_KEY_VERSION=1

# Performance tuning
DATABASE_CONN_MAX_AGE=600
REDIS_MAX_CONNECTIONS=100
```

## Deployment Platforms

### Docker Deployment

Create a production Dockerfile:

```dockerfile
FROM python:3.11-slim

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
    libpq-dev \
    libgdal-dev \
    libgeos-dev \
    && rm -rf /var/lib/apt/lists/*

# Install Python dependencies
COPY backend/pyproject.toml backend/uv.lock ./
RUN pip install uv && uv sync --frozen

# Copy application
COPY backend/ .

# Collect static files
RUN python manage.py collectstatic --noinput

# Run with Gunicorn
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "4", "thrillwiki.wsgi:application"]
```

Docker Compose for production:

```yaml
version: '3.8'

services:
  web:
    build: .
    environment:
      - DJANGO_SETTINGS_MODULE=config.django.production
    env_file:
      - .env
    ports:
      - "8000:8000"
    depends_on:
      - db
      - redis

  db:
    image: postgis/postgis:14-3.3
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=thrillwiki
      - POSTGRES_USER=thrillwiki
      - POSTGRES_PASSWORD=${DB_PASSWORD}

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data

  celery:
    build: .
    command: celery -A config.celery worker -l info
    env_file:
      - .env
    depends_on:
      - db
      - redis

  celery-beat:
    build: .
    command: celery -A config.celery beat -l info
    env_file:
      - .env
    depends_on:
      - db
      - redis

volumes:
  postgres_data:
  redis_data:
```

### Heroku Deployment

```bash
# Create app
heroku create thrillwiki

# Add buildpacks
heroku buildpacks:add heroku/python
heroku buildpacks:add https://github.com/heroku/heroku-geo-buildpack.git

# Add add-ons
heroku addons:create heroku-postgresql:standard-0
heroku addons:create heroku-redis:premium-0

# Set environment variables
heroku config:set DJANGO_SETTINGS_MODULE=config.django.production
heroku config:set SECRET_KEY=$(python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())")
heroku config:set DEBUG=False
# ... set other variables

# Deploy
git push heroku main

# Run migrations
heroku run python manage.py migrate
```

### AWS ECS Deployment

Task definition example:

```json
{
  "family": "thrillwiki",
  "containerDefinitions": [
    {
      "name": "web",
      "image": "your-ecr-repo/thrillwiki:latest",
      "portMappings": [
        {
          "containerPort": 8000,
          "protocol": "tcp"
        }
      ],
      "environment": [
        {
          "name": "DJANGO_SETTINGS_MODULE",
          "value": "config.django.production"
        }
      ],
      "secrets": [
        {
          "name": "SECRET_KEY",
          "valueFrom": "arn:aws:secretsmanager:region:account:secret:thrillwiki/SECRET_KEY"
        },
        {
          "name": "DATABASE_URL",
          "valueFrom": "arn:aws:secretsmanager:region:account:secret:thrillwiki/DATABASE_URL"
        }
      ]
    }
  ]
}
```

## Database Setup

### PostgreSQL with PostGIS

```sql
-- Create database
CREATE DATABASE thrillwiki;

-- Enable PostGIS
\c thrillwiki
CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology;

-- Create user
CREATE USER thrillwiki_app WITH ENCRYPTED PASSWORD 'secure-password';
GRANT ALL PRIVILEGES ON DATABASE thrillwiki TO thrillwiki_app;
```

### Run Migrations

```bash
python manage.py migrate
python manage.py createsuperuser
```

## Static Files

### Collect Static Files

```bash
python manage.py collectstatic --noinput
```

### WhiteNoise Configuration

WhiteNoise is configured for production static file serving. No additional web server configuration needed for static files.

### CDN Integration (Optional)

For CDN, update `STATIC_URL`:

```bash
STATIC_URL=https://cdn.thrillwiki.com/static/
```

## Monitoring Setup

### Sentry Integration

```bash
SENTRY_DSN=https://xxx@xxx.ingest.sentry.io/xxx
SENTRY_ENVIRONMENT=production
SENTRY_TRACES_SAMPLE_RATE=0.1
```

### Health Checks

Health check endpoint: `/health/`

```bash
# Test health check
curl https://thrillwiki.com/health/
```

Configure load balancer health checks to use this endpoint.

### Logging

Production logging outputs JSON to stdout (suitable for log aggregation):

```json
{
  "levelname": "INFO",
  "asctime": "2024-01-15 10:30:00,000",
  "module": "views",
  "message": "Request processed"
}
```

## Performance Tuning

### Database Connection Pooling

```bash
DATABASE_CONN_MAX_AGE=600  # 10 minutes
DATABASE_CONNECT_TIMEOUT=10
DATABASE_STATEMENT_TIMEOUT=30000
```

### Redis Connection Pooling

```bash
REDIS_MAX_CONNECTIONS=100
REDIS_CONNECTION_TIMEOUT=20
```

### Gunicorn Configuration

```bash
# gunicorn.conf.py
workers = 4  # (2 * CPU cores) + 1
worker_class = "gevent"
worker_connections = 1000
timeout = 30
keepalive = 5
max_requests = 1000
max_requests_jitter = 50
```

## Celery Workers

### Start Workers

```bash
# Main worker
celery -A config.celery worker -l info

# Beat scheduler
celery -A config.celery beat -l info

# With specific queues
celery -A config.celery worker -l info -Q default,trending,analytics,cache
```

### Supervisor Configuration

```ini
[program:celery]
command=/app/.venv/bin/celery -A config.celery worker -l info
directory=/app
user=www-data
numprocs=1
autostart=true
autorestart=true
stdout_logfile=/var/log/celery/worker.log
stderr_logfile=/var/log/celery/worker-error.log

[program:celery-beat]
command=/app/.venv/bin/celery -A config.celery beat -l info
directory=/app
user=www-data
numprocs=1
autostart=true
autorestart=true
stdout_logfile=/var/log/celery/beat.log
stderr_logfile=/var/log/celery/beat-error.log
```

## SSL/TLS Configuration

### Nginx Configuration

```nginx
server {
    listen 443 ssl http2;
    server_name thrillwiki.com www.thrillwiki.com;

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

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;

    location / {
        proxy_pass http://127.0.0.1:8000;
        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;
    }
}

server {
    listen 80;
    server_name thrillwiki.com www.thrillwiki.com;
    return 301 https://$server_name$request_uri;
}
```

## Post-Deployment Verification

### Functional Tests

```bash
# API health
curl -s https://thrillwiki.com/api/health/ | jq

# Static files
curl -I https://thrillwiki.com/static/css/tailwind.css

# API endpoint
curl -s https://thrillwiki.com/api/v1/parks/ | jq
```

### Security Headers

```bash
# Check security headers
curl -I https://thrillwiki.com/ | grep -E "(Strict-Transport|X-Frame|X-Content|Content-Security)"
```

### Performance

```bash
# Response time
time curl -s https://thrillwiki.com/api/v1/parks/ > /dev/null
```

## Rollback Procedure

If deployment fails:

1. **Immediate rollback:**
   ```bash
   # Docker
   docker-compose down
   docker-compose -f docker-compose.previous.yml up -d

   # Heroku
   heroku rollback

   # Kubernetes
   kubectl rollout undo deployment/thrillwiki
   ```

2. **Database rollback (if needed):**
   ```bash
   python manage.py migrate app_name migration_number
   ```

3. **Investigate and fix:**
   - Check error logs
   - Review configuration differences
   - Test in staging environment

## Maintenance

### Regular Tasks

- **Daily:** Review error logs, check health endpoints
- **Weekly:** Review performance metrics, check disk usage
- **Monthly:** Rotate secrets, review security updates
- **Quarterly:** Full security audit, dependency updates

### Backup Procedures

```bash
# Database backup
pg_dump thrillwiki > backup_$(date +%Y%m%d).sql

# Media files backup
aws s3 sync /app/media s3://thrillwiki-backups/media/
```
