# ================================================== # DOCKER COMPOSE - VERSIÓN DETALLADA # Plataforma de Estudio de Matemáticas # ================================================== # Este archivo contiene configuraciones detalladas para # desarrollo, testing y producción. # # Uso: # docker-compose -f docker/docker-compose.yml up -d # ================================================== version: '3.9' services: # ================================================== # POSTGRESQL - Base de Datos Principal # ================================================== postgres: image: postgres:15.4-alpine container_name: math-postgres restart: unless-stopped environment: POSTGRES_USER: mathuser POSTGRES_PASSWORD: ${DB_PASSWORD:-math_secure_password_2024} POSTGRES_DB: mathdb POSTGRES_INITDB_ARGS: "-E UTF8 --locale=C" volumes: # Persistencia de datos - postgres_data:/var/lib/postgresql/data # Scripts de inicialización - ./init-scripts:/docker-entrypoint-initdb.d:ro ports: - "${POSTGRES_PORT:-5432}:5432" command: [ "postgres", "-c", "max_connections=200", "-c", "shared_buffers=256MB", "-c", "effective_cache_size=1GB", "-c", "maintenance_work_mem=64MB", "-c", "checkpoint_completion_target=0.9", "-c", "wal_buffers=16MB", "-c", "default_statistics_target=100", "-c", "random_page_cost=1.1", "-c", "effective_io_concurrency=200", "-c", "work_mem=1310kB", "-c", "min_wal_size=1GB", "-c", "max_wal_size=4GB", "-c", "log_statement=all", "-c", "log_duration=on" ] healthcheck: test: ["CMD-SHELL", "pg_isready -U mathuser -d mathdb"] interval: 10s timeout: 5s retries: 5 start_period: 10s networks: - math-network labels: - "com.math-platform.description=PostgreSQL Database" - "com.math-platform.priority=1" # ================================================== # REDIS - Cache & Message Queue # ================================================== redis: image: redis:7.2.3-alpine container_name: math-redis restart: unless-stopped command: > redis-server --appendonly yes --appendfsync everysec --requirepass ${REDIS_PASSWORD:-redis_secure_password_2024} --maxmemory 256mb --maxmemory-policy allkeys-lru --tcp-backlog 511 --timeout 0 --tcp-keepalive 300 volumes: - redis_data:/data ports: - "${REDIS_PORT:-6379}:6379" healthcheck: test: ["CMD", "redis-cli", "--raw", "incr", "ping"] interval: 10s timeout: 3s retries: 5 start_period: 5s networks: - math-network labels: - "com.math-platform.description=Redis Cache & Queue" - "com.math-platform.priority=2" # ================================================== # BACKEND API - Node.js + Express + TypeScript # ================================================== backend: build: context: .. dockerfile: docker/Dockerfile.backend target: runner args: NODE_VERSION: "20" container_name: math-backend restart: unless-stopped environment: # Node.js NODE_ENV: ${NODE_ENV:-production} PORT: 3001 # Database DATABASE_URL: postgresql://mathuser:${DB_PASSWORD:-math_secure_password_2024}@postgres:5432/mathdb DB_PASSWORD: ${DB_PASSWORD:-math_secure_password_2024} # Redis REDIS_HOST: redis REDIS_PORT: 6379 REDIS_PASSWORD: ${REDIS_PASSWORD:-redis_secure_password_2024} # AI (MiniMax-M2.5 via Aliyun DashScope) AI_API_BASE_URL: ${AI_API_BASE_URL:-https://coding-intl.dashscope.aliyuncs.com/v1} AI_API_KEY: ${AI_API_KEY:-your-dashscope-api-key-here} AI_MODEL: ${AI_MODEL:-MiniMax-M2.5} AI_MAX_TOKENS: ${AI_MAX_TOKENS:-2000} AI_TEMPERATURE: ${AI_TEMPERATURE:-0.7} # Telegram TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN} TELEGRAM_ADMIN_CHAT_ID: ${TELEGRAM_ADMIN_CHAT_ID} # JWT JWT_SECRET: ${JWT_SECRET:-jwt_secret_key_change_in_production} JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d} JWT_REFRESH_EXPIRES_IN: ${JWT_REFRESH_EXPIRES_IN:-30d} # CORS CORS_ORIGIN: ${CORS_ORIGIN:-http://localhost:3000} # Rate Limiting RATE_LIMIT_AUTH: ${RATE_LIMIT_AUTH:-5} RATE_LIMIT_API: ${RATE_LIMIT_API:-10} RATE_LIMIT_WINDOW_MS: ${RATE_LIMIT_WINDOW_MS:-60000} volumes: # Code mounting (for development without rebuild) - ../backend:/app - /app/node_modules # PDFs directory (read-only) - ../pdfs:/app/pdfs:ro # Logs - ./logs/backend:/app/logs ports: - "${BACKEND_PORT:-3001}:3001" depends_on: postgres: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - math-network deploy: resources: limits: cpus: '1.0' memory: 512M reservations: cpus: '0.25' memory: 128M labels: - "com.math-platform.description=Backend API" - "com.math-platform.priority=3" # ================================================== # FRONTEND - Next.js 14 App Router # ================================================== frontend: build: context: .. dockerfile: docker/Dockerfile.frontend target: runner args: NODE_VERSION: "20" container_name: math-frontend restart: unless-stopped environment: NODE_ENV: ${NODE_ENV:-production} PORT: 3000 # API URL NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://backend:3001} NEXT_PUBLIC_APP_NAME: ${NEXT_PUBLIC_APP_NAME:-Plataforma de Álgebra Lineal} # Next.js NEXT_TELEMETRY_DISABLED: "1" volumes: # Code mounting (for development) - ../frontend:/app - /app/node_modules - /app/.next # Logs - ./logs/frontend:/app/logs ports: - "${FRONTEND_PORT:-3000}:3000" depends_on: backend: condition: service_healthy healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - math-network deploy: resources: limits: cpus: '1.0' memory: 512M reservations: cpus: '0.25' memory: 128M labels: - "com.math-platform.description=Frontend (Next.js)" - "com.math-platform.priority=4" # ================================================== # PDF WORKER - Procesamiento de PDFs # ================================================== pdf-worker: build: context: .. dockerfile: docker/Dockerfile.worker target: pdf-worker container_name: math-pdf-worker restart: unless-stopped environment: NODE_ENV: ${NODE_ENV:-production} WORKER_TYPE: pdf # Database DATABASE_URL: postgresql://mathuser:${DB_PASSWORD:-math_secure_password_2024}@postgres:5432/mathdb # Redis REDIS_HOST: redis REDIS_PORT: 6379 REDIS_PASSWORD: ${REDIS_PASSWORD:-redis_secure_password_2024} # PDF Processing PDF_PROCESSING_BATCH_SIZE: ${PDF_PROCESSING_BATCH_SIZE:-5} PDF_PROCESSING_TIMEOUT: ${PDF_PROCESSING_TIMEOUT:-300000} PDF_STORAGE_PATH: /app/pdfs PDF_PROCESSED_PATH: /app/pdfs/processed # Worker WORKER_RETRY_ATTEMPTS: ${WORKER_RETRY_ATTEMPTS:-3} WORKER_RETRY_DELAY: ${WORKER_RETRY_DELAY:-5000} volumes: - ../backend:/app - /app/node_modules - ../pdfs:/app/pdfs:ro - ../pdfs/processed:/app/pdfs/processed - ./logs/pdf-worker:/app/logs depends_on: postgres: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD", "node", "-e", "console.log('healthy')"] interval: 60s timeout: 10s retries: 3 start_period: 30s networks: - math-network deploy: resources: limits: cpus: '0.5' memory: 256M reservations: cpus: '0.1' memory: 64M replicas: ${PDF_WORKER_REPLICAS:-1} labels: - "com.math-platform.description=PDF Processing Worker" - "com.math-platform.priority=5" # ================================================== # EXERCISE WORKER - Generación de Ejercicios con IA # ================================================== exercise-worker: build: context: .. dockerfile: docker/Dockerfile.worker target: exercise-worker container_name: math-exercise-worker restart: unless-stopped environment: NODE_ENV: ${NODE_ENV:-production} WORKER_TYPE: exercise # Database DATABASE_URL: postgresql://mathuser:${DB_PASSWORD:-math_secure_password_2024}@postgres:5432/mathdb # Redis REDIS_HOST: redis REDIS_PORT: 6379 REDIS_PASSWORD: ${REDIS_PASSWORD:-redis_secure_password_2024} # AI AI_API_BASE_URL: ${AI_API_BASE_URL:-https://coding-intl.dashscope.aliyuncs.com/v1} AI_API_KEY: ${AI_API_KEY} AI_MODEL: ${AI_MODEL:-MiniMax-M2.5} AI_MAX_TOKENS: ${AI_MAX_TOKENS:-2000} AI_TEMPERATURE: ${AI_TEMPERATURE:-0.7} # Worker WORKER_RETRY_ATTEMPTS: ${WORKER_RETRY_ATTEMPTS:-3} WORKER_RETRY_DELAY: ${WORKER_RETRY_DELAY:-5000} volumes: - ../backend:/app - /app/node_modules - ./logs/exercise-worker:/app/logs depends_on: postgres: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD", "node", "-e", "console.log('healthy')"] interval: 60s timeout: 10s retries: 3 start_period: 30s networks: - math-network deploy: resources: limits: cpus: '0.5' memory: 256M reservations: cpus: '0.1' memory: 64M replicas: ${EXERCISE_WORKER_REPLICAS:-2} labels: - "com.math-platform.description=Exercise Generation Worker (AI)" - "com.math-platform.priority=6" # ================================================== # NOTIFICATION WORKER - Envío de Notificaciones Telegram # ================================================== notification-worker: build: context: .. dockerfile: docker/Dockerfile.worker target: notification-worker container_name: math-notification-worker restart: unless-stopped environment: NODE_ENV: ${NODE_ENV:-production} WORKER_TYPE: notification # Database DATABASE_URL: postgresql://mathuser:${DB_PASSWORD:-math_secure_password_2024}@postgres:5432/mathdb # Redis REDIS_HOST: redis REDIS_PORT: 6379 REDIS_PASSWORD: ${REDIS_PASSWORD:-redis_secure_password_2024} # Telegram TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN} TELEGRAM_ADMIN_CHAT_ID: ${TELEGRAM_ADMIN_CHAT_ID} # Worker WORKER_RETRY_ATTEMPTS: ${WORKER_RETRY_ATTEMPTS:-3} WORKER_RETRY_DELAY: ${WORKER_RETRY_DELAY:-5000} volumes: - ../backend:/app - /app/node_modules - ./logs/notification-worker:/app/logs depends_on: postgres: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD", "node", "-e", "console.log('healthy')"] interval: 60s timeout: 10s retries: 3 start_period: 30s networks: - math-network deploy: resources: limits: cpus: '0.25' memory: 128M reservations: cpus: '0.05' memory: 32M replicas: ${NOTIFICATION_WORKER_REPLICAS:-1} labels: - "com.math-platform.description=Notification Worker (Telegram)" - "com.math-platform.priority=7" # ================================================== # NGINX - Reverse Proxy + Load Balancer # ================================================== nginx: image: nginx:1.25-alpine container_name: math-nginx restart: unless-stopped volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./logs/nginx:/var/log/nginx # SSL certificates (uncomment for production) # - ./ssl:/etc/nginx/ssl:ro ports: - "${NGINX_HTTP_PORT:-80}:80" - "${NGINX_HTTPS_PORT:-443}:443" depends_on: - frontend - backend healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost/health"] interval: 30s timeout: 10s retries: 3 start_period: 10s networks: - math-network deploy: resources: limits: cpus: '0.5' memory: 128M reservations: cpus: '0.1' memory: 32M labels: - "com.math-platform.description=Nginx Reverse Proxy" - "com.math-platform.priority=8" # ================================================== # VOLUMES - Persistencia de Datos # ================================================== volumes: postgres_data: driver: local driver_opts: type: none o: bind device: ./data/postgres redis_data: driver: local driver_opts: type: none o: bind device: ./data/redis # ================================================== # NETWORKS - Comunicación entre Servicios # ================================================== networks: math-network: driver: bridge driver_opts: com.docker.network.bridge.name: math_br ipam: driver: default config: - subnet: 172.20.0.0/16 # ================================================== # CONFIGURACIÓN ADICIONAL # ================================================== # # Perfiles de ejecución: # # Desarrollo: # docker-compose -f docker/docker-compose.yml --profile dev up # # Producción: # docker-compose -f docker/docker-compose.yml --profile prod up -d # # Escalado de workers: # docker-compose -f docker/docker-compose.yml up -d --scale exercise-worker=3 # # Logs en tiempo real: # docker-compose -f docker/docker-compose.yml logs -f backend # # Reconstrucción completa: # docker-compose -f docker/docker-compose.yml build --no-cache # # Backup de base de datos: # docker-compose -f docker/docker-compose.yml exec postgres \ # pg_dump -U mathuser mathdb > backup_$(date +%Y%m%d).sql # # Restauración de base de datos: # docker-compose -f docker/docker-compose.yml exec -T postgres \ # psql -U mathuser mathdb < backup_20240323.sql