# Multi-Tenant Optimized Docker Compose
# Supports running multiple isolated app instances with direct Docker host port binding
# Each instance: ~50MB base + 20-30MB per 20 users
# 
# Usage:
#   docker-compose -f docker-compose-multitenant.yml up -d
#
# Example: Start the stack and expose the app on host port 10000
#   INVENTAR_HTTP_PORT=10000 docker-compose -f docker-compose-multitenant.yml up -d

services:
  # Management Container for multi-tenant scripts
  tenant-manager:
    image: python:3.12-alpine
    container_name: tenant-manager
    restart: "no"
    profiles:
      - tools
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - .:/workspace
    entrypoint: >
      sh -c "apk add --no-cache bash docker-cli docker-cli-compose && cd /workspace && ./manage-tenant.sh \"$$@\"" --

  redis:
    image: redis:7-alpine
    container_name: inventarsystem-redis
    restart: unless-stopped
    command: redis-server --appendonly yes --maxmemory 512mb --maxmemory-policy allkeys-lru
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    networks:
      - inventar-net
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  mongodb:
    image: mongo:7.0
    container_name: inventarsystem-mongodb
    restart: unless-stopped
    expose:
      - "27017"
    volumes:
      - mongodb_data:/data/db
      - ./docker/mongo:/docker-entrypoint-initdb.d:ro
    networks:
      - inventar-net
    healthcheck:
      test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"]
      interval: 10s
      timeout: 5s
      retries: 10
    environment:
      MONGO_INITDB_DATABASE: inventar_default

  app:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        PYTHON_VERSION: "3.13"
        OPTIMIZATION_LEVEL: 2
    working_dir: /app/Web
    command: ["gunicorn", "app:app", "--bind", "0.0.0.0:8000", "--workers", "2", "--timeout", "30", "--graceful-timeout", "20", "--max-requests", "200", "--max-requests-jitter", "50", "--log-level", "info", "--access-logfile", "-", "--error-logfile", "-"]
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    depends_on:
      mongodb:
        condition: service_healthy
      redis:
        condition: service_healthy
    ports:
      - "${INVENTAR_HTTP_PORT:-10000}:8000"
    networks:
      - inventar-net
    expose:
      - "8000"
    volumes:
      - ./config.json:/app/config.json:ro
      - app_uploads:/app/Web/uploads:cached
      - app_thumbnails:/app/Web/thumbnails:cached
      - app_previews:/app/Web/previews:cached
      - app_qrcodes:/app/Web/QRCodes:cached
      - app_backups:/data/backups
      - app_logs:/data/logs
      - app_deleted_archives:/data/deleted-archives
    environment:
      # Database Configuration
      INVENTAR_MONGODB_HOST: mongodb
      INVENTAR_MONGODB_PORT: "27017"
      INVENTAR_MONGODB_DB: inventar_default
      
      # Redis Configuration (for sessions and caching)
      INVENTAR_REDIS_HOST: redis
      INVENTAR_REDIS_PORT: "6379"
      INVENTAR_REDIS_DB: "0"
      INVENTAR_TENANT_PORT_MAP: "${INVENTAR_TENANT_PORT_MAP:-}"
      
      # Storage Configuration
      INVENTAR_BACKUP_FOLDER: /data/backups
      INVENTAR_LOGS_FOLDER: /data/logs
      INVENTAR_DELETED_ARCHIVE_FOLDER: /data/deleted-archives
      
      # Performance Tuning
      INVENTAR_WORKER_CLASS: ${INVENTAR_WORKER_CLASS:-gevent}
      INVENTAR_WORKERS: "${INVENTAR_WORKERS:-4}"
      INVENTAR_THREADS: "${INVENTAR_THREADS:-2}"
      INVENTAR_WORKER_TIMEOUT: "${INVENTAR_WORKER_TIMEOUT:-30}"
      INVENTAR_WORKER_CONNECTIONS: "${INVENTAR_WORKER_CONNECTIONS:-100}"
      
      # Auto-scaled runtime settings
      INVENTAR_APP_CPUS: ${INVENTAR_APP_CPUS:-1.0}
      INVENTAR_APP_MEM_LIMIT: ${INVENTAR_APP_MEM_LIMIT:-256m}
      INVENTAR_APP_MEM_SWAP_LIMIT: ${INVENTAR_APP_MEM_SWAP_LIMIT:-512m}
      
      # Multi-Tenant
      INVENTAR_MULTITENANT_ENABLED: "true"
      INVENTAR_SESSION_BACKEND: redis
      
      # Logging
      INVENTAR_LOG_LEVEL: WARNING
      
      # Flask
      FLASK_ENV: production
      FLASK_DEBUG: "0"
      
      # Python Optimization
      PYTHONOPTIMIZE: "2"
      PYTHONDONTWRITEBYTECODE: "1"
      PYTHONUNBUFFERED: "1"
    
    # Resource Limits (per instance)
    # With 10 instances: each gets ~150MB, totaling ~1.5GB
    # Adjust based on server resources
    mem_limit: "${INVENTAR_APP_MEM_LIMIT:-256m}"
    memswap_limit: "${INVENTAR_APP_MEM_SWAP_LIMIT:-512m}"
    cpus: "${INVENTAR_APP_CPUS:-1.0}"
    
    # Health check for load balancer
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

volumes:
  mongodb_data:
    driver: local
  redis_data:
    driver: local
  app_uploads:
    driver: local
  app_thumbnails:
    driver: local
  app_previews:
    driver: local
  app_qrcodes:
    driver: local
  app_backups:
    driver: local
  app_logs:
    driver: local
  app_deleted_archives:
    driver: local

networks:
  inventar-net:
    driver: bridge

# Scale guidance:
# 1 tenant (20 users): 1 app instance + redis + mongodb = ~500MB
# 5 tenants: 5 app instances + shared redis/mongodb = ~1.5GB
# 10 tenants: 10 app instances + shared redis/mongodb = ~2.5GB
# 20 tenants: 20 app instances + shared redis/mongodb = ~4.5GB
#
# Server sizing recommendations:
# - Small (1-2 tenants): 2GB RAM, 1-2 CPU cores
# - Medium (5-10 tenants): 4GB RAM, 2-4 CPU cores  
# - Large (10-20 tenants): 8GB RAM, 4-8 CPU cores
# - Jumbo (20+ tenants): 16GB+ RAM, 8+ CPU cores with clustering

