version: '3.9' services: # SurrealDB - Multi-model database surrealdb: image: surrealdb/surrealdb:latest container_name: vapora-surrealdb command: start --bind 0.0.0.0:8000 file:///data/database.db ports: - "8000:8000" volumes: - surrealdb_data:/data environment: SURREAL_LOG: debug RUST_LOG: debug networks: - vapora healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped {% if nats.enabled %} # NATS JetStream - Message broker for agent coordination nats: image: nats:latest container_name: vapora-nats command: -js -m 8222 -D ports: - "4222:4222" - "8222:8222" volumes: - nats_data:/data networks: - vapora healthcheck: test: ["CMD", "nc", "-z", "localhost", "4222"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped {% endif %} {% if llm_router.providers.ollama_enabled %} # Ollama - Local LLM provider ollama: image: ollama/ollama:latest container_name: vapora-ollama ports: - "11434:11434" volumes: - ollama_data:/root/.ollama environment: OLLAMA_HOST: "0.0.0.0:11434" networks: - vapora profiles: - llm healthcheck: test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"] interval: 30s timeout: 10s retries: 3 restart: unless-stopped {% endif %} # VAPORA Backend - REST API and orchestration backend: build: context: . dockerfile: crates/vapora-backend/Dockerfile container_name: vapora-backend ports: - "{{ backend.port }}:{{ backend.port }}" environment: DEPLOYMENT_MODE: "{{ deployment_mode }}" WORKSPACE_NAME: "{{ workspace_name }}" BACKEND_HOST: "{{ backend.host }}" BACKEND_PORT: "{{ backend.port }}" BACKEND_WORKERS: "{{ backend.workers }}" BACKEND_REQUEST_TIMEOUT: "{{ backend.request_timeout }}" DATABASE_URL: "{{ backend.database.url }}" DATABASE_USER: "{{ backend.database.username }}" DATABASE_PASSWORD: "{{ backend.database.password }}" DATABASE_POOL_SIZE: "{{ backend.database.pool_size }}" STORAGE_PATH: "{{ backend.storage.path }}" LOG_LEVEL: "{{ monitoring.log_level }}" JWT_SECRET: "{{ security.jwt_secret }}" PROMETHEUS_ENABLED: "{{ monitoring.prometheus_enabled|lower }}" {% if nats.enabled %} NATS_ENABLED: "true" NATS_URL: "{{ nats.url }}" {% else %} NATS_ENABLED: "false" {% endif %} CLAUDE_ENABLED: "{{ llm_router.providers.claude_enabled|lower }}" OPENAI_ENABLED: "{{ llm_router.providers.openai_enabled|lower }}" OLLAMA_ENABLED: "{{ llm_router.providers.ollama_enabled|lower }}" OLLAMA_URL: "{{ llm_router.providers.ollama_url }}" volumes: - vapora_storage:/var/lib/vapora/storage - ./vapora.toml:/etc/vapora/config/vapora.toml:ro networks: - vapora depends_on: surrealdb: condition: service_healthy {% if nats.enabled %} nats: condition: service_healthy {% endif %} healthcheck: test: ["CMD", "curl", "-f", "http://localhost:{{ backend.port }}/health"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped # VAPORA Agents - Task orchestration and execution agents: build: context: . dockerfile: crates/vapora-agents/Dockerfile container_name: vapora-agents ports: - "{{ agents.port }}:{{ agents.port }}" environment: AGENTS_HOST: "{{ agents.host }}" AGENTS_PORT: "{{ agents.port }}" AGENTS_MAX_INSTANCES: "{{ agents.max_instances }}" AGENTS_HEARTBEAT_INTERVAL: "{{ agents.heartbeat_interval }}" LEARNING_ENABLED: "{{ agents.learning.enabled|lower }}" RECENCY_WINDOW_DAYS: "{{ agents.learning.recency_window_days }}" KNOWLEDGE_GRAPH_ENABLED: "{{ agents.knowledge_graph.enabled|lower }}" KNOWLEDGE_GRAPH_RETENTION_DAYS: "{{ agents.knowledge_graph.retention_days }}" {% if agents.nats.enabled %} NATS_ENABLED: "true" NATS_URL: "nats://nats:4222" {% else %} NATS_ENABLED: "false" {% endif %} LOG_LEVEL: "{{ monitoring.log_level }}" networks: - vapora depends_on: backend: condition: service_healthy {% if agents.nats.enabled %} nats: condition: service_healthy {% endif %} healthcheck: test: ["CMD", "curl", "-f", "http://localhost:{{ agents.port }}/health"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped # VAPORA LLM Router - Multi-provider LLM orchestration llm-router: build: context: . dockerfile: crates/vapora-llm-router/Dockerfile container_name: vapora-llm-router ports: - "{{ llm_router.port }}:{{ llm_router.port }}" environment: LLM_ROUTER_HOST: "{{ llm_router.host }}" LLM_ROUTER_PORT: "{{ llm_router.port }}" COST_TRACKING_ENABLED: "{{ llm_router.cost_tracking.enabled|lower }}" BUDGET_ENFORCEMENT_ENABLED: "{{ llm_router.budget_enforcement.enabled|lower }}" BUDGET_WINDOW: "{{ llm_router.budget_enforcement.window }}" CLAUDE_ENABLED: "{{ llm_router.providers.claude_enabled|lower }}" OPENAI_ENABLED: "{{ llm_router.providers.openai_enabled|lower }}" GEMINI_ENABLED: "{{ llm_router.providers.gemini_enabled|lower }}" OLLAMA_ENABLED: "{{ llm_router.providers.ollama_enabled|lower }}" OLLAMA_URL: "{{ llm_router.providers.ollama_url }}" ROUTING_STRATEGY: "{{ llm_router.routing.strategy }}" LOG_LEVEL: "{{ monitoring.log_level }}" networks: - vapora depends_on: backend: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:{{ llm_router.port }}/health"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped # VAPORA Frontend - React/WASM UI frontend: build: context: . dockerfile: crates/vapora-frontend/Dockerfile container_name: vapora-frontend ports: - "{{ frontend.port }}:{{ frontend.port }}" environment: FRONTEND_HOST: "{{ frontend.host }}" FRONTEND_PORT: "{{ frontend.port }}" API_URL: "http://backend:{{ backend.port }}" ENABLE_WASM: "{{ frontend.enable_wasm|lower }}" networks: - vapora depends_on: backend: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:{{ frontend.port }}/"] interval: 10s timeout: 5s retries: 5 restart: unless-stopped {% if monitoring.prometheus_enabled %} # Prometheus - Metrics collection and alerting prometheus: image: prom/prometheus:latest container_name: vapora-prometheus ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro - prometheus_data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' - '--storage.tsdb.retention.time=30d' networks: - vapora restart: unless-stopped # Grafana - Metrics visualization grafana: image: grafana/grafana:latest container_name: vapora-grafana ports: - "3001:3000" environment: GF_SECURITY_ADMIN_PASSWORD: "admin" GF_SECURITY_ADMIN_USER: "admin" volumes: - grafana_data:/var/lib/grafana - ./grafana/dashboards:/etc/grafana/provisioning/dashboards:ro networks: - vapora depends_on: - prometheus restart: unless-stopped {% endif %} volumes: surrealdb_data: driver: local vapora_storage: driver: local {% if nats.enabled %} nats_data: driver: local {% endif %} {% if llm_router.providers.ollama_enabled %} ollama_data: driver: local {% endif %} {% if monitoring.prometheus_enabled %} prometheus_data: driver: local grafana_data: driver: local {% endif %} networks: vapora: driver: bridge ipam: config: - subnet: 172.28.0.0/16