services: router: build: context: ./services/router dockerfile: Dockerfile container_name: dagi-router-node2 ports: - "127.0.0.1:9102:8000" environment: - NODE_ID=NODA2 - DAGI_ROUTER_CONFIG=/app/router-config.yml - MEMORY_SERVICE_URL=http://memory-service:8000 - NATS_URL=nats://dagi-nats:4222 - QDRANT_HOST=qdrant-node2 - QDRANT_PORT=6333 - DATABASE_URL=postgresql://daarion:daarion_secret_node2@postgres-node2:5432/daarion_memory - NEO4J_BOLT_URL=bolt://neo4j-node2:7687 - NEO4J_USER=neo4j - NEO4J_PASSWORD=daarion_node2_secret - CITY_SERVICE_URL=http://city-service:7001 - PIECES_OS_URL=http://host.docker.internal:39300 - NOTION_API_KEY=${NOTION_API_KEY:-} - XAI_API_KEY=${XAI_API_KEY} - GROK_API_KEY=${XAI_API_KEY} - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY:-} # ── Fabric Layer (NCS + Node Worker, no Swapper dependency) ────────── - NODE_CAPABILITIES_URL=http://node-capabilities:8099/capabilities - ENABLE_GLOBAL_CAPS_NATS=true - OLLAMA_URL=http://host.docker.internal:11434 - PREFER_NODE_WORKER=true # ── Persistence backends ────────────────────────────────────────────── - ALERT_BACKEND=postgres - ALERT_DATABASE_URL=${ALERT_DATABASE_URL:-${DATABASE_URL}} - RISK_HISTORY_BACKEND=auto - BACKLOG_BACKEND=auto - INCIDENT_BACKEND=auto - AUDIT_BACKEND=auto - CALENDAR_SERVICE_URL=http://calendar-service:8001 volumes: - ./services/router/router-config.node2.yml:/app/router-config.yml:ro - ./tools:/app/tools:ro - ./config:/config:ro - ./logs:/app/logs extra_hosts: - "host.docker.internal:host-gateway" - "city-service:host-gateway" - "daarion-city-service:host-gateway" depends_on: - dagi-nats - node-capabilities - calendar-service networks: - dagi-network - dagi-memory-network restart: unless-stopped gateway: build: context: ./gateway-bot dockerfile: Dockerfile container_name: dagi-gateway-node2 ports: - "0.0.0.0:9300:9300" environment: - ROUTER_URL=http://router:8000 - DAARWIZZ_NAME=DAARWIZZ - DAARWIZZ_PROMPT_PATH=/app/gateway-bot/daarwizz_prompt.txt - MEMORY_SERVICE_URL=http://memory-service:8000 - SOFIIA_NAME=SOFIIA - SOFIIA_PROMPT_PATH=/app/gateway-bot/sofiia_prompt.txt - SOFIIA_TELEGRAM_BOT_TOKEN=${SOFIIA_TELEGRAM_BOT_TOKEN} volumes: - ./gateway-bot:/app/gateway-bot:ro - ./logs:/app/logs depends_on: - router networks: - dagi-network - dagi-memory-network restart: unless-stopped aurora-service: build: context: ./services/aurora-service dockerfile: Dockerfile container_name: aurora-service-node2 ports: - "127.0.0.1:9401:9401" environment: - AURORA_DATA_DIR=/data/aurora - AURORA_PUBLIC_BASE_URL=http://127.0.0.1:9401 - AURORA_CORS_ORIGINS=* - AURORA_MODELS_DIR=/data/aurora/models - AURORA_FORCE_CPU=false - AURORA_PREFER_MPS=true - AURORA_ENABLE_VIDEOTOOLBOX=true volumes: - sofiia-data:/data networks: - dagi-network restart: unless-stopped radicale: image: tomsquest/docker-radicale:latest container_name: daarion-radicale-node2 ports: - "127.0.0.1:5232:5232" environment: - RADICALE_HOST=0.0.0.0 - RADICALE_PORT=5232 - RADICALE_LOG_LEVEL=INFO volumes: - radicale-data:/data - radicale-config:/config networks: - dagi-network restart: unless-stopped calendar-service: build: context: ./services/calendar-service dockerfile: Dockerfile container_name: calendar-service-node2 ports: - "127.0.0.1:8001:8001" environment: - DATABASE_URL=sqlite:////data/calendar.db - RADICALE_URL=http://radicale:5232 - PYTHONUNBUFFERED=1 depends_on: - radicale volumes: - sofiia-data:/data networks: - dagi-network restart: unless-stopped dagi-nats: image: nats:2.10-alpine container_name: dagi-nats-node2 ports: - "4222:4222" - "8222:8222" command: -c /etc/nats/nats-server.conf volumes: - ./nats-server.conf:/etc/nats/nats-server.conf:ro networks: - dagi-network restart: unless-stopped swapper-service: build: context: ./services/swapper-service dockerfile: Dockerfile container_name: swapper-service-node2 ports: - "127.0.0.1:8890:8890" extra_hosts: - "host.docker.internal:host-gateway" environment: - OLLAMA_BASE_URL=http://host.docker.internal:11434 - SWAPPER_CONFIG_PATH=/app/config/swapper_config_node2.yaml - SWAPPER_MODE=single-active - MODEL_SWAP_TIMEOUT=300 volumes: - ./services/swapper-service/config:/app/config:ro - ./logs:/app/logs networks: - dagi-network restart: unless-stopped node-capabilities: build: context: ./services/node-capabilities dockerfile: Dockerfile container_name: node-capabilities-node2 ports: - "127.0.0.1:8099:8099" extra_hosts: - "host.docker.internal:host-gateway" volumes: - ~/.ollama/models:/host_models/ollama:ro - ~/.cache/huggingface/hub:/host_models/hf_cache:ro environment: - NODE_ID=NODA2 - OLLAMA_BASE_URL=http://host.docker.internal:11434 - SWAPPER_URL= - LLAMA_SERVER_URL=http://host.docker.internal:11435 - CACHE_TTL_SEC=15 - ENABLE_NATS_CAPS=true - NATS_URL=nats://dagi-nats:4222 - NODE_WORKER_URL=http://node-worker:8109 - DISK_SCAN_PATHS=/host_models/ollama,/host_models/hf_cache depends_on: - swapper-service - dagi-nats networks: - dagi-network restart: unless-stopped node-worker: build: context: ./services/node-worker dockerfile: Dockerfile container_name: node-worker-node2 ports: - "127.0.0.1:8109:8109" extra_hosts: - "host.docker.internal:host-gateway" environment: - NODE_ID=noda2 - NATS_URL=nats://dagi-nats:4222 - OLLAMA_BASE_URL=http://host.docker.internal:11434 - NODE_DEFAULT_LLM=qwen3:14b - NODE_DEFAULT_VISION=llava:13b - NODE_WORKER_MAX_CONCURRENCY=2 - NCS_REPORT_URL=http://node-capabilities:8099 # Capability providers: delegate STT/TTS to Memory Service (Phase 1) # Set to mlx_whisper/mlx_kokoro for Phase 2 MLX upgrade - STT_PROVIDER=memory_service - TTS_PROVIDER=memory_service - MEMORY_SERVICE_URL=http://memory-service:8000 - OCR_PROVIDER=vision_prompted - IMAGE_PROVIDER=none # Voice HA: dedicated concurrency limits for voice.*.request subjects - VOICE_MAX_CONCURRENT_TTS=4 - VOICE_MAX_CONCURRENT_LLM=2 - VOICE_MAX_CONCURRENT_STT=2 depends_on: - dagi-nats networks: - dagi-network restart: unless-stopped sofiia-console: build: context: ./services/sofiia-console dockerfile: Dockerfile container_name: sofiia-console ports: - "127.0.0.1:8002:8002" environment: - PORT=8002 - ENV=${ENV:-prod} - NODE_ID=NODA2 - ROUTER_URL=http://router:8000 - CONFIG_DIR=/app/config - NODES_NODA2_ROUTER_URL=http://router:8000 - NODES_NODA1_ROUTER_URL=http://144.76.224.179:9102 - MEMORY_SERVICE_URL=http://memory-service:8000 - OLLAMA_URL=${OLLAMA_URL:-http://host.docker.internal:11434} - NOTION_API_KEY=${NOTION_API_KEY:-} - OPENCODE_URL=${OPENCODE_URL:-} - AURORA_SERVICE_URL=http://aurora-service:9401 # P1 SECURITY: SSH_PASSWORD removed — use key file instead # NODES_NODA1_SSH_PASSWORD is NO LONGER passed; sofiia-console reads from key file - NODES_NODA1_SSH_PRIVATE_KEY=/run/secrets/noda1_ssh_key - SUPERVISOR_API_KEY=${SUPERVISOR_API_KEY} - SOFIIA_CONSOLE_API_KEY=${SOFIIA_CONSOLE_API_KEY} - CORS_ORIGINS=${CORS_ORIGINS:-} # Voice HA feature flag (default: false = legacy direct path to memory-service) - VOICE_HA_ENABLED=${VOICE_HA_ENABLED:-false} - VOICE_HA_ROUTER_URL=${VOICE_HA_ROUTER_URL:-http://router:8000} # Projects / Documents / Sessions / Dialog Map (SQLite) - SOFIIA_DATA_DIR=/app/data - UPLOAD_MAX_IMAGE_MB=${UPLOAD_MAX_IMAGE_MB:-10} - UPLOAD_MAX_VIDEO_MB=${UPLOAD_MAX_VIDEO_MB:-200} - UPLOAD_MAX_DOC_MB=${UPLOAD_MAX_DOC_MB:-50} # Phase 2 feature flags (disabled by default) - USE_FABRIC_OCR=${USE_FABRIC_OCR:-false} - USE_EMBEDDINGS=${USE_EMBEDDINGS:-false} # Supervisor proxy (LangGraph workflows) - SUPERVISOR_URL=${SUPERVISOR_URL:-http://sofiia-supervisor:8080} volumes: - ./config:/app/config - ./secrets/noda1_id_ed25519:/run/secrets/noda1_ssh_key:ro - sofiia-data:/app/data depends_on: - router networks: - dagi-network - dagi-memory-network restart: unless-stopped networks: dagi-network: driver: bridge name: dagi-network-node2 dagi-memory-network: external: true name: dagi-memory-network-node2 volumes: sofiia-data: driver: local radicale-data: driver: local radicale-config: driver: local