version: '3.9' services: # ============================================================================= # DATABASE - TimescaleDB (PostgreSQL with time-series superpowers) # ============================================================================= db: image: timescale/timescaledb:latest-pg16 container_name: marketscanner-db restart: unless-stopped environment: POSTGRES_DB: ${POSTGRES_DB:-marketscanner} POSTGRES_USER: ${POSTGRES_USER:-marketscanner} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required} volumes: - postgres_data:/var/lib/postgresql/data - ./docker/db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro ports: - "5433:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-marketscanner}"] interval: 10s timeout: 5s retries: 5 networks: - marketscanner-network # ============================================================================= # CACHE - Redis # ============================================================================= redis: image: redis:7-alpine container_name: marketscanner-redis restart: unless-stopped command: redis-server --requirepass ${REDIS_PASSWORD:-changeme} volumes: - redis_data:/data ports: - "6380:6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 networks: - marketscanner-network # ============================================================================= # MESSAGE QUEUE - RabbitMQ # ============================================================================= rabbitmq: image: rabbitmq:3-management-alpine container_name: marketscanner-rabbitmq restart: unless-stopped environment: RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-marketscanner} RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-changeme} volumes: - rabbitmq_data:/var/lib/rabbitmq ports: - "5673:5672" - "15673:15672" # Management UI healthcheck: test: ["CMD", "rabbitmq-diagnostics", "check_running"] interval: 30s timeout: 10s retries: 5 networks: - marketscanner-network # ============================================================================= # BACKEND - FastAPI # ============================================================================= backend: build: context: ./backend dockerfile: Dockerfile container_name: marketscanner-backend restart: unless-stopped env_file: - .env environment: - POSTGRES_HOST=db - REDIS_HOST=redis - RABBITMQ_HOST=rabbitmq volumes: - ./backend:/app - backend_logs:/app/logs ports: - "${BACKEND_PORT:-8000}:8000" depends_on: db: condition: service_healthy redis: condition: service_healthy rabbitmq: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s retries: 3 networks: - marketscanner-network # ============================================================================= # CELERY WORKER - Background Tasks # ============================================================================= celery-worker: build: context: ./backend dockerfile: Dockerfile container_name: marketscanner-celery-worker restart: unless-stopped command: celery -A app.workers.celery_app worker --loglevel=info --concurrency=4 env_file: - .env environment: - POSTGRES_HOST=db - REDIS_HOST=redis - RABBITMQ_HOST=rabbitmq volumes: - ./backend:/app - backend_logs:/app/logs depends_on: db: condition: service_healthy redis: condition: service_healthy rabbitmq: condition: service_healthy backend: condition: service_healthy networks: - marketscanner-network # ============================================================================= # CELERY BEAT - Scheduled Tasks # ============================================================================= celery-beat: build: context: ./backend dockerfile: Dockerfile container_name: marketscanner-celery-beat restart: unless-stopped command: celery -A app.workers.celery_app beat --loglevel=info env_file: - .env environment: - POSTGRES_HOST=db - REDIS_HOST=redis - RABBITMQ_HOST=rabbitmq volumes: - ./backend:/app - backend_logs:/app/logs depends_on: db: condition: service_healthy redis: condition: service_healthy rabbitmq: condition: service_healthy backend: condition: service_healthy networks: - marketscanner-network # ============================================================================= # FRONTEND - React Dashboard # ============================================================================= frontend: build: context: ./frontend dockerfile: Dockerfile args: - VITE_API_URL=${VITE_API_URL:-http://localhost:8000} container_name: marketscanner-frontend restart: unless-stopped ports: - "${FRONTEND_PORT:-3010}:80" depends_on: - backend networks: - marketscanner-network # ============================================================================= # OPTIONAL: Ollama for local LLM (if USE_LOCAL_LLM=true) # ============================================================================= # ollama: # image: ollama/ollama:latest # container_name: marketscanner-ollama # restart: unless-stopped # volumes: # - ollama_data:/root/.ollama # ports: # - "11434:11434" # deploy: # resources: # reservations: # devices: # - driver: nvidia # count: all # capabilities: [gpu] # networks: # - marketscanner-network # ============================================================================= # NETWORKS # ============================================================================= networks: marketscanner-network: driver: bridge # ============================================================================= # VOLUMES # ============================================================================= volumes: postgres_data: redis_data: rabbitmq_data: backend_logs: # ollama_data: