# =============================================================================
# @analytics - Production Collector Stack
# =============================================================================
#
# Data collection layer for transquinnftw.com analytics.
# Runs on vps-0 alongside the lilith-platform backend.
#
# Services:
#   - TimescaleDB: Time-series analytics storage (port 25434 external)
#   - Redis: BullMQ job queues
#   - Collector: Event ingestion POST /collect (port 4001)
#   - Processor: BullMQ workers (internal)
#   - API: Query endpoints (port 4003)
#   - Realtime: WebSocket gateway (port 4004) — optional, start manually if needed
#   - Website BFF: Analytics proxy for website dashboard (port 4005)
#
# Memory budget (2GB VPS):
#   timescaledb  384m  redis       80m  collector  192m
#   processor    160m  api        192m  website-bff 64m
#   System+nginx ~200m  Total:  ~1272m (comfortable within 2GB; ~700MB headroom)
#
# DNS:
#   analytics.db.transquinnftw.com A → vps-0 IP (connects to port 25434)
#
# Usage:
#   cp .env.prod.example .env.prod
#   # Edit .env.prod with real secrets
#   docker compose -f docker-compose.prod.yaml --env-file .env.prod up -d
#
# Note: realtime service is excluded from default `up -d` — start explicitly:
#   docker compose ... up -d realtime
#

services:
  timescaledb:
    image: timescale/timescaledb:2.16.1-pg16
    container_name: analytics-timescaledb
    restart: unless-stopped
    mem_limit: 384m
    memswap_limit: 384m
    mem_reservation: 230m
    ports:
      - "127.0.0.1:25434:5432"
      # wg-only read path for the quinn-data MCP on black (analytics_ro role).
      # 10.9.0.1 is the vps wireguard address — unreachable from the internet.
      - "10.9.0.1:25434:5432"
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}
    volumes:
      - analytics-postgres-data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 10
      start_period: 30s
    networks:
      - analytics-net

  redis:
    image: redis:7.4-alpine
    container_name: analytics-redis
    restart: unless-stopped
    mem_limit: 80m
    memswap_limit: 80m
    mem_reservation: 48m
    command:
      - redis-server
      - --requirepass
      - "${REDIS_PASSWORD}"
      - --appendonly
      - "yes"
      - --maxmemory
      - "64mb"
      - --maxmemory-policy
      - "noeviction"
    volumes:
      - analytics-redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5
    networks:
      - analytics-net

  collector:
    build:
      context: ../services/collector
      dockerfile: Dockerfile
    container_name: analytics-collector
    restart: unless-stopped
    mem_limit: 384m
    memswap_limit: 384m
    mem_reservation: 192m
    ports:
      - "127.0.0.1:4001:4001"
    environment:
      NODE_ENV: production
      PORT: "4001"
      REDIS_HOST: redis
      REDIS_PORT: "6379"
      REDIS_PASSWORD: ${REDIS_PASSWORD}
      CORS_ORIGINS: ${CORS_ORIGINS}
      COLLECTOR_WRITE_KEY: ${COLLECTOR_WRITE_KEY}
      LOG_LEVEL: info
      DATABASE_HOST: timescaledb
      DATABASE_PORT: "5432"
      DATABASE_USER: ${POSTGRES_USER}
      DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
      DATABASE_NAME: ${POSTGRES_DB}
      DB_SYNCHRONIZE: "false"
    depends_on:
      timescaledb:
        condition: service_healthy
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "wget -q --spider http://localhost:4001/health || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s
    networks:
      - analytics-net

  processor:
    build:
      context: ../services/processor
      dockerfile: Dockerfile
    container_name: analytics-processor
    restart: unless-stopped
    mem_limit: 160m
    memswap_limit: 160m
    mem_reservation: 96m
    environment:
      NODE_ENV: production
      REDIS_HOST: redis
      REDIS_PORT: "6379"
      REDIS_PASSWORD: ${REDIS_PASSWORD}
      DATABASE_HOST: timescaledb
      DATABASE_PORT: "5432"
      DATABASE_USER: ${POSTGRES_USER}
      DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
      DATABASE_NAME: ${POSTGRES_DB}
      CONCURRENCY: "5"
      BATCH_SIZE: "100"
    depends_on:
      timescaledb:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - analytics-net

  api:
    build:
      context: ../services/api
      dockerfile: Dockerfile
    container_name: analytics-api
    restart: unless-stopped
    mem_limit: 192m
    memswap_limit: 192m
    mem_reservation: 115m
    ports:
      - "127.0.0.1:4003:4003"
    environment:
      NODE_ENV: production
      PORT: "4003"
      DATABASE_HOST: timescaledb
      DATABASE_PORT: "5432"
      DATABASE_USER: ${POSTGRES_USER}
      DATABASE_PASSWORD: ${POSTGRES_PASSWORD}
      DATABASE_NAME: ${POSTGRES_DB}
      REDIS_HOST: redis
      REDIS_PORT: "6379"
      REDIS_PASSWORD: ${REDIS_PASSWORD}
      API_KEYS: ${API_KEYS}
      DB_SYNCHRONIZE: "false"
    depends_on:
      timescaledb:
        condition: service_healthy
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "wget -q --spider http://localhost:4003/health || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s
    networks:
      - analytics-net

  # realtime is intentionally excluded from the default profile.
  # It handles SSE streams for the live dashboard widget only.
  # Start manually when needed: docker compose ... up -d realtime
  realtime:
    build:
      context: ../services/realtime
      dockerfile: Dockerfile
    container_name: analytics-realtime
    restart: unless-stopped
    mem_limit: 128m
    memswap_limit: 128m
    mem_reservation: 77m
    profiles:
      - realtime
    ports:
      - "127.0.0.1:4004:4004"
    environment:
      NODE_ENV: production
      PORT: "4004"
      REDIS_HOST: redis
      REDIS_PORT: "6379"
      REDIS_PASSWORD: ${REDIS_PASSWORD}
    depends_on:
      redis:
        condition: service_healthy
    networks:
      - analytics-net

  website-bff:
    build:
      context: ../services/website-bff
      dockerfile: Dockerfile
    container_name: analytics-website-bff
    restart: unless-stopped
    mem_limit: 64m
    memswap_limit: 64m
    mem_reservation: 38m
    ports:
      - "127.0.0.1:4005:4005"
    environment:
      NODE_ENV: production
      PORT: "4005"
      COLLECTOR_URL: http://collector:4001
      QUERY_API_URL: http://api:4003
      ADMIN_URL: ${ADMIN_URL:-http://localhost:3023}
    depends_on:
      collector:
        condition: service_healthy
      api:
        condition: service_healthy
    healthcheck:
      test: ["CMD-SHELL", "wget -q --spider http://localhost:4005/health || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 10s
    networks:
      - analytics-net

volumes:
  analytics-postgres-data:
    name: analytics-postgres-data
  analytics-redis-data:
    name: analytics-redis-data

networks:
  analytics-net:
    name: analytics-net
    driver: bridge
