services: # ── Databases ───────────────────────────────────────────────── db: image: postgres:17.2-alpine container_name: madbase_db restart: unless-stopped environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres} POSTGRES_DB: postgres command: ["postgres", "-c", "wal_level=logical"] ports: - "5432:5432" volumes: - madbase_db_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 5s timeout: 3s retries: 10 control_db: image: postgres:17.2-alpine container_name: madbase_control_db restart: unless-stopped environment: POSTGRES_USER: admin POSTGRES_PASSWORD: ${CONTROL_DB_PASSWORD:-admin_password} POSTGRES_DB: madbase_control ports: - "5433:5432" volumes: - madbase_control_db_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U admin -d madbase_control"] interval: 5s timeout: 3s retries: 10 # ── Infrastructure ──────────────────────────────────────────── redis: image: redis:7.2.4-alpine container_name: madbase_redis restart: unless-stopped command: redis-server --appendonly yes ports: - "6379:6379" volumes: - madbase_redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5 minio: image: quay.io/minio/minio:RELEASE.2024-03-07T00-43-48Z container_name: madbase_minio restart: unless-stopped command: server /data --console-address ":9001" ports: - "9000:9000" - "9001:9001" environment: MINIO_ROOT_USER: ${S3_ACCESS_KEY:-minioadmin} MINIO_ROOT_PASSWORD: ${S3_SECRET_KEY:-minioadmin} volumes: - madbase_minio_data:/data healthcheck: test: ["CMD-SHELL", "true"] # Fallback for now, or use a better check if we know one. interval: 5s timeout: 3s retries: 5 # ── Application ─────────────────────────────────────────────── worker: build: context: . target: worker-runtime container_name: madbase_worker restart: unless-stopped ports: - "8002:8002" env_file: - .env environment: DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:-postgres}@db:5432/postgres CONTROL_DB_URL: postgres://admin:${CONTROL_DB_PASSWORD:-admin_password}@control_db:5432/madbase_control DEFAULT_TENANT_DB_URL: postgres://postgres:${POSTGRES_PASSWORD:-postgres}@db:5432/postgres REDIS_URL: redis://redis:6379 S3_ENDPOINT: http://minio:9000 S3_ACCESS_KEY: ${S3_ACCESS_KEY:-minioadmin} S3_SECRET_KEY: ${S3_SECRET_KEY:-minioadmin} S3_BUCKET: ${S3_BUCKET:-madbase} S3_REGION: ${S3_REGION:-us-east-1} AUTH_AUTO_CONFIRM: ${AUTH_AUTO_CONFIRM:-true} ALLOWED_ORIGINS: ${ALLOWED_ORIGINS:-http://localhost:3000,http://localhost:8000} RUST_LOG: ${RUST_LOG:-info} JWT_SECRET: ${JWT_SECRET} JWT_ISSUER: ${JWT_ISSUER:-madbase} depends_on: db: condition: service_healthy redis: condition: service_healthy minio: condition: service_healthy system: build: context: . target: control-runtime container_name: madbase_system restart: unless-stopped ports: - "8001:8001" env_file: - .env environment: DATABASE_URL: postgres://admin:${CONTROL_DB_PASSWORD:-admin_password}@control_db:5432/madbase_control DEFAULT_TENANT_DB_URL: postgres://postgres:${POSTGRES_PASSWORD:-postgres}@db:5432/postgres ADMIN_PASSWORD: ${ADMIN_PASSWORD} LOKI_URL: http://loki:3100 ALLOWED_ORIGINS: ${ALLOWED_ORIGINS:-http://localhost:3000,http://localhost:8000,http://localhost:8001} RUST_LOG: ${RUST_LOG:-info} depends_on: db: condition: service_healthy control_db: condition: service_healthy proxy: build: context: . target: proxy-runtime container_name: madbase_proxy restart: unless-stopped ports: - "8000:8000" env_file: - .env environment: CONTROL_UPSTREAM_URL: http://system:8001 WORKER_UPSTREAM_URLS: http://worker:8002 DATABASE_URL: postgres://admin:${CONTROL_DB_PASSWORD:-admin_password}@control_db:5432/madbase_control CONTROL_DB_URL: postgres://admin:${CONTROL_DB_PASSWORD:-admin_password}@control_db:5432/madbase_control RUST_LOG: ${RUST_LOG:-info} healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/"] interval: 10s timeout: 3s retries: 3 depends_on: system: condition: service_healthy worker: condition: service_healthy control_db: condition: service_healthy caddy: build: context: . target: proxy-runtime-caddy container_name: madbase_caddy restart: unless-stopped ports: - "80:80" - "443:443" volumes: - ./Caddyfile:/etc/caddy/Caddyfile - madbase_caddy_data:/data - madbase_caddy_config:/config environment: HETZNER_API_KEY: ${HETZNER_API_KEY} depends_on: proxy: condition: service_healthy # ── Observability ───────────────────────────────────────────── victoriametrics: image: victoriametrics/victoria-metrics:v1.101.0 container_name: madbase_vm ports: - "8428:8428" volumes: - madbase_vm_data:/victoria-metrics-data - ./config/prometheus.yml:/etc/prometheus/prometheus.yml command: - "--storageDataPath=/victoria-metrics-data" - "--httpListenAddr=:8428" - "--promscrape.config=/etc/prometheus/prometheus.yml" extra_hosts: - "host.docker.internal:host-gateway" loki: image: grafana/loki:2.9.6 container_name: madbase_loki ports: - "3100:3100" command: -config.file=/etc/loki/local-config.yaml volumes: - madbase_loki_data:/loki grafana: image: grafana/grafana:10.4.2 container_name: madbase_grafana ports: - "3030:3000" environment: - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:-admin} volumes: - madbase_grafana_data:/var/lib/grafana depends_on: - victoriametrics - loki volumes: madbase_db_data: madbase_control_db_data: madbase_minio_data: madbase_redis_data: madbase_vm_data: madbase_loki_data: madbase_grafana_data: madbase_caddy_data: madbase_caddy_config: