version: "3.9" x-app-env: &app-env POSTGRES_HOST: postgres POSTGRES_PORT: "5432" POSTGRES_DB: stonks POSTGRES_USER: stonks POSTGRES_PASSWORD: stonks_dev REDIS_HOST: redis REDIS_PORT: "6379" MINIO_ENDPOINT: minio:9000 MINIO_ACCESS_KEY: minioadmin MINIO_SECRET_KEY: minioadmin OLLAMA_BASE_URL: http://ollama:11434 services: # ── Infrastructure ────────────────────────────────────────────── postgres: image: postgres:16-alpine environment: POSTGRES_DB: stonks POSTGRES_USER: stonks POSTGRES_PASSWORD: stonks_dev ports: - "5432:5432" volumes: - pgdata:/var/lib/postgresql/data - ./infra/migrations:/docker-entrypoint-initdb.d healthcheck: test: ["CMD-SHELL", "pg_isready -U stonks"] interval: 5s retries: 5 redis: image: redis:7-alpine ports: - "6379:6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s retries: 5 minio: image: minio/minio:latest command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: minioadmin MINIO_ROOT_PASSWORD: minioadmin ports: - "9000:9000" - "9001:9001" volumes: - miniodata:/data healthcheck: test: ["CMD", "mc", "ready", "local"] interval: 5s retries: 5 minio-init: image: minio/mc:latest depends_on: minio: condition: service_healthy entrypoint: > /bin/sh -c " mc alias set local http://minio:9000 minioadmin minioadmin; mc mb --ignore-existing local/stonks-raw-market; mc mb --ignore-existing local/stonks-raw-news; mc mb --ignore-existing local/stonks-raw-filings; mc mb --ignore-existing local/stonks-normalized; mc mb --ignore-existing local/stonks-llm-prompts; mc mb --ignore-existing local/stonks-llm-results; mc mb --ignore-existing local/stonks-lakehouse; mc mb --ignore-existing local/stonks-audit; exit 0; " ollama: image: ollama/ollama:latest ports: - "11434:11434" volumes: - ollama_models:/root/.ollama deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] trino: image: trinodb/trino:latest ports: - "8080:8080" environment: MINIO_ACCESS_KEY: minioadmin MINIO_SECRET_KEY: minioadmin volumes: - ./infra/trino/catalog:/etc/trino/catalog depends_on: - minio - hive-metastore hive-metastore: image: apache/hive:4.0.0 environment: SERVICE_NAME: metastore DB_DRIVER: derby ports: - "9083:9083" volumes: - hive_data:/opt/hive/data - ./infra/hive/core-site.xml:/opt/hive/conf/core-site.xml:ro - ./infra/hive/metastore-site.xml:/opt/hive/conf/metastore-site.xml:ro depends_on: - minio superset: image: apache/superset:latest ports: - "8088:8088" environment: SUPERSET_SECRET_KEY: stonks-dev-secret-key-change-me ADMIN_USERNAME: admin ADMIN_PASSWORD: admin ADMIN_EMAIL: admin@stonks.local volumes: - superset_data:/app/superset_home depends_on: - trino # ── Application Services ──────────────────────────────────────── scheduler: build: context: . dockerfile: docker/Dockerfile.scheduler environment: <<: *app-env depends_on: postgres: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD-SHELL", "pgrep -f 'python -m services.scheduler.app' || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 15s restart: unless-stopped symbol-registry: build: context: . dockerfile: docker/Dockerfile args: SERVICE_CMD: "uvicorn services.symbol_registry.app:app --host 0.0.0.0 --port 8000" environment: <<: *app-env ports: - "8001:8000" depends_on: postgres: condition: service_healthy healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 15s restart: unless-stopped ingestion: build: context: . dockerfile: docker/Dockerfile args: SERVICE_CMD: "python -m services.ingestion.worker" environment: <<: *app-env env_file: - .env depends_on: postgres: condition: service_healthy redis: condition: service_healthy minio: condition: service_healthy healthcheck: test: ["CMD-SHELL", "pgrep -f 'python -m services.ingestion.worker' || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 15s restart: unless-stopped parser: build: context: . dockerfile: docker/Dockerfile args: SERVICE_CMD: "python -m services.parser.worker" environment: <<: *app-env depends_on: postgres: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD-SHELL", "pgrep -f 'python -m services.parser.worker' || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 15s restart: unless-stopped extractor: build: context: . dockerfile: docker/Dockerfile args: SERVICE_CMD: "python -m services.extractor.main" environment: <<: *app-env depends_on: postgres: condition: service_healthy redis: condition: service_healthy ollama: condition: service_started healthcheck: test: ["CMD-SHELL", "pgrep -f 'python -m services.extractor.main' || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 15s restart: unless-stopped aggregation: build: context: . dockerfile: docker/Dockerfile args: SERVICE_CMD: "python -m services.aggregation.main" environment: <<: *app-env depends_on: postgres: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD-SHELL", "pgrep -f 'python -m services.aggregation.main' || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 15s restart: unless-stopped recommendation: build: context: . dockerfile: docker/Dockerfile args: SERVICE_CMD: "python -m services.recommendation.main" environment: <<: *app-env depends_on: postgres: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD-SHELL", "pgrep -f 'python -m services.recommendation.main' || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 15s restart: unless-stopped trading-engine: build: context: . dockerfile: docker/Dockerfile args: SERVICE_CMD: "uvicorn services.trading.app:app --host 0.0.0.0 --port 8000" environment: <<: *app-env env_file: - .env ports: - "8002:8000" depends_on: postgres: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 15s restart: unless-stopped risk-engine: build: context: . dockerfile: docker/Dockerfile args: SERVICE_CMD: "uvicorn services.risk.app:app --host 0.0.0.0 --port 8000" environment: <<: *app-env ports: - "8003:8000" networks: default: aliases: - risk depends_on: postgres: condition: service_healthy healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 15s restart: unless-stopped broker-adapter: build: context: . dockerfile: docker/Dockerfile args: SERVICE_CMD: "python -m services.adapters.broker_service" environment: <<: *app-env env_file: - .env depends_on: postgres: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD-SHELL", "pgrep -f 'python -m services.adapters.broker_service' || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 15s restart: unless-stopped lake-publisher: build: context: . dockerfile: docker/Dockerfile args: SERVICE_CMD: "python -m services.lake_publisher.jobs" environment: <<: *app-env depends_on: postgres: condition: service_healthy minio: condition: service_healthy healthcheck: test: ["CMD-SHELL", "pgrep -f 'python -m services.lake_publisher.jobs' || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 15s restart: unless-stopped query-api: build: context: . dockerfile: docker/Dockerfile args: SERVICE_CMD: "uvicorn services.api.app:app --host 0.0.0.0 --port 8000" environment: <<: *app-env ports: - "8004:8000" depends_on: postgres: condition: service_healthy redis: condition: service_healthy minio: condition: service_healthy healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 15s restart: unless-stopped dashboard: build: context: ./frontend dockerfile: Dockerfile ports: - "3000:8080" depends_on: query-api: condition: service_healthy healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:8080/ || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 10s restart: unless-stopped volumes: pgdata: miniodata: ollama_models: hive_data: superset_data: