version: '3.9' services: # ─── Rust autonomous agent ─────────────────────────────────── agent: build: context: ./agent dockerfile: Dockerfile container_name: sentinel-agent restart: unless-stopped env_file: .env environment: - SENTINEL_ENV=testnet - RUST_LOG=sentinel=info volumes: - ./config:/app/config:ro - audit_logs:/app/logs/audit ports: - "9090:9090" # Prometheus metrics depends_on: - api healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9090/metrics"] interval: 30s timeout: 5s retries: 3 # ─── TypeScript API bridge ─────────────────────────────────── api: build: context: ./api dockerfile: Dockerfile container_name: sentinel-api restart: unless-stopped env_file: .env environment: - NODE_ENV=production - PORT=3001 volumes: - audit_logs:/app/logs/audit:ro ports: - "3001:3001" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3001/health"] interval: 15s timeout: 5s retries: 3 # ─── React dashboard ───────────────────────────────────────── dashboard: build: context: ./dashboard dockerfile: Dockerfile container_name: sentinel-dashboard restart: unless-stopped environment: - VITE_API_URL=http://localhost:3001 ports: - "5173:80" depends_on: - api # ─── Prometheus (optional observability) ───────────────────── prometheus: image: prom/prometheus:v2.50.1 container_name: sentinel-prometheus restart: unless-stopped volumes: - ./docker/prometheus.yml:/etc/prometheus/prometheus.yml:ro ports: - "9091:9090" profiles: - observability # ─── Grafana (optional observability) ──────────────────────── grafana: image: grafana/grafana:10.3.3 container_name: sentinel-grafana restart: unless-stopped environment: - GF_AUTH_ANONYMOUS_ENABLED=true volumes: - ./docker/grafana:/etc/grafana/provisioning:ro - grafana_data:/var/lib/grafana ports: - "3000:3000" profiles: - observability volumes: audit_logs: grafana_data: