# Production Deployment Guide

## Target Environment

**Server**: Linode VPS (ssh akamai)
- Ubuntu 24.04 LTS
- 8GB RAM / 160GB disk
- Docker + Nginx Proxy Manager pre-configured

**Domain**: `gameplay.sba.manticorum.com` (or similar)

## Architecture

```
┌─────────────────────────────────────────────────────┐
│                    Linode VPS                       │
├─────────────────────────────────────────────────────┤
│  Nginx Proxy Manager (:80/:443)                     │
│    └─ gameplay.sba.manticorum.com                   │
│        ├─ /api/* → backend:8000                     │
│        ├─ /socket.io/* → backend:8000 (WebSocket)   │
│        └─ /* → frontend:3000                        │
├─────────────────────────────────────────────────────┤
│  strat-gameplay-webapp                              │
│    ├─ backend (FastAPI + Socket.io) :8000           │
│    └─ frontend-sba (Nuxt 3 SSR) :3000               │
├─────────────────────────────────────────────────────┤
│  Shared Services (existing)                         │
│    ├─ sba_postgres :5432 (database: sba_gameplay)   │
│    └─ sba_redis :6379                               │
└─────────────────────────────────────────────────────┘
```

## Why Docker Compose?

Evaluated options for this deployment:

| Option | Verdict | Reason |
|--------|---------|--------|
| **Docker Compose** | ✅ Selected | Existing infra, compose files ready, NPM network integration |
| Bare metal (systemd) | ❌ | No isolation, manual dependency management, harder rollbacks |
| Docker Swarm | ❌ | Overkill for single node |
| Kubernetes/K3s | ❌ | Significant complexity for minimal benefit at this scale |

## Pre-Deployment Checklist

### 1. Discord OAuth Setup
- [ ] Add redirect URI in [Discord Developer Portal](https://discord.com/developers/applications):
  - `https://gameplay.sba.manticorum.com/api/auth/discord/callback/server`

### 2. Database Setup
```bash
# SSH to server
ssh akamai

# Create database
docker exec -it sba_postgres psql -U sba -c "CREATE DATABASE sba_gameplay;"
```

### 3. DNS Configuration
- [ ] Add A record: `gameplay.sba.manticorum.com` → Linode IP

## Deployment Steps

### Step 1: Prepare Server Directory

```bash
ssh akamai
mkdir -p ~/container-data/strat-gameplay-webapp
cd ~/container-data/strat-gameplay-webapp
```

### Step 2: Clone Repository

```bash
git clone https://github.com/calcorum/strat-gameplay-webapp.git .
# Or use deploy key for private repo
```

### Step 3: Create Production Environment Files

**Backend** (`backend/.env`):
```bash
# Database - use existing SBA postgres
DATABASE_URL=postgresql+asyncpg://sba:PASSWORD@sba_postgres:5432/sba_gameplay

# Security
SECRET_KEY=generate-a-secure-64-char-key-here

# Discord OAuth
DISCORD_CLIENT_ID=your-client-id
DISCORD_CLIENT_SECRET=your-client-secret
DISCORD_SERVER_REDIRECT_URI=https://gameplay.sba.manticorum.com/api/auth/discord/callback/server
FRONTEND_URL=https://gameplay.sba.manticorum.com

# CORS
CORS_ORIGINS=["https://gameplay.sba.manticorum.com"]

# Redis - use existing SBA redis
REDIS_URL=redis://sba_redis:6379

# League APIs
SBA_API_URL=https://api.sba.manticorum.com
SBA_API_KEY=your-sba-api-key

# Access Control (empty = all users, or comma-separated Discord IDs)
ALLOWED_DISCORD_IDS=
```

**Frontend** (`frontend-sba/.env`):
```bash
# API URLs (same domain, proxied by NPM)
NUXT_PUBLIC_API_URL=https://gameplay.sba.manticorum.com
NUXT_PUBLIC_WS_URL=https://gameplay.sba.manticorum.com

# Discord OAuth
NUXT_PUBLIC_DISCORD_CLIENT_ID=your-client-id
NUXT_PUBLIC_DISCORD_REDIRECT_URI=https://gameplay.sba.manticorum.com/auth/callback

# Internal API URL for SSR (Docker network)
NUXT_API_URL_INTERNAL=http://backend:8000
```

### Step 4: Create Production Docker Compose Override

Create `docker-compose.production.yml`:
```yaml
# Production overrides for Linode deployment
# Usage: docker compose -f docker-compose.yml -f docker-compose.production.yml up -d

services:
  backend:
    build:
      context: ./backend
      target: production
    environment:
      - APP_ENV=production
      - DEBUG=false
    networks:
      - sba-database_default
      - nginx-proxy-manager_npm_network
    restart: always
    # Don't expose port externally - NPM handles routing
    ports: !reset []
    expose:
      - "8000"

  frontend-sba:
    build:
      context: ./frontend-sba
      target: production
    environment:
      - NODE_ENV=production
    networks:
      - nginx-proxy-manager_npm_network
    restart: always
    ports: !reset []
    expose:
      - "3000"
    depends_on:
      - backend

  # Don't need local redis - use existing sba_redis
  redis:
    profiles:
      - disabled

networks:
  sba-database_default:
    external: true
  nginx-proxy-manager_npm_network:
    external: true
```

### Step 5: Run Database Migrations

```bash
# Build backend first
docker compose -f docker-compose.yml -f docker-compose.production.yml build backend

# Run migrations
docker compose -f docker-compose.yml -f docker-compose.production.yml run --rm backend \
  alembic upgrade head
```

### Step 6: Start Services

```bash
docker compose -f docker-compose.yml -f docker-compose.production.yml up -d
```

### Step 7: Configure Nginx Proxy Manager

Access NPM at `http://LINODE_IP:81` and create proxy host:

**Proxy Host Settings**:
- Domain: `gameplay.sba.manticorum.com`
- Scheme: `http`
- Forward Hostname: `strat-gameplay-webapp-frontend-sba-1`
- Forward Port: `3000`
- Websockets Support: ✅ Enabled
- SSL: Request new Let's Encrypt certificate

**Custom Locations** (for API routing):
| Location | Scheme | Forward Host | Port |
|----------|--------|--------------|------|
| `/api` | http | strat-gameplay-webapp-backend-1 | 8000 |
| `/socket.io` | http | strat-gameplay-webapp-backend-1 | 8000 |

### Step 8: Verify Deployment

```bash
# Health check
curl https://gameplay.sba.manticorum.com/api/health

# Check logs
docker compose -f docker-compose.yml -f docker-compose.production.yml logs -f
```

## Maintenance Commands

```bash
cd ~/container-data/strat-gameplay-webapp

# View logs
docker compose -f docker-compose.yml -f docker-compose.production.yml logs -f backend
docker compose -f docker-compose.yml -f docker-compose.production.yml logs -f frontend-sba

# Restart services
docker compose -f docker-compose.yml -f docker-compose.production.yml restart

# Pull updates and redeploy
git pull
docker compose -f docker-compose.yml -f docker-compose.production.yml build
docker compose -f docker-compose.yml -f docker-compose.production.yml up -d

# Run migrations after update
docker compose -f docker-compose.yml -f docker-compose.production.yml run --rm backend \
  alembic upgrade head
```

## Rollback Procedure

```bash
# Check previous commits
git log --oneline -10

# Rollback to specific commit
git checkout <commit-hash>

# Rebuild and restart
docker compose -f docker-compose.yml -f docker-compose.production.yml build
docker compose -f docker-compose.yml -f docker-compose.production.yml up -d
```

## Monitoring

### Health Endpoints
- Backend: `https://gameplay.sba.manticorum.com/api/health`
- Frontend: `https://gameplay.sba.manticorum.com` (200 OK)

### Log Locations
```bash
# Container logs
docker logs strat-gameplay-webapp-backend-1

# Application logs (if volume mounted)
~/container-data/strat-gameplay-webapp/backend/logs/
```

## Resource Estimates

| Service | RAM | CPU | Notes |
|---------|-----|-----|-------|
| Backend | ~200MB | Low | Increases with concurrent games |
| Frontend | ~150MB | Low | Nuxt SSR |
| **Total** | ~350MB | Low | Well within 5.8GB available |

## Security Considerations

- [ ] Use strong `SECRET_KEY` (64+ characters)
- [ ] Restrict `ALLOWED_DISCORD_IDS` for beta testing
- [ ] SSL enforced via NPM
- [ ] Database credentials not exposed externally
- [ ] Redis not exposed externally (Docker network only)

## Future Scaling Options

If load increases beyond single-server capacity:

1. **Vertical**: Upgrade Linode plan (easy, immediate)
2. **Database**: Migrate to managed PostgreSQL (Linode, Neon, Supabase)
3. **Horizontal**: Add second app server behind load balancer
4. **CDN**: Cloudflare for static assets and DDoS protection