version: '3.8'

services:
  # BZZZ v2 Main Agent
  bzzz-agent:
    image: registry.home.deepblack.cloud/bzzz:v2.0.0
    networks:
      - tengig
      - bzzz-internal
    ports:
      - "9000-9100:9000-9100"
    volumes:
      - /rust/bzzz-v2/data:/app/data
      - /rust/bzzz-v2/config:/app/config:ro
    environment:
      - BZZZ_VERSION=2.0.0
      - BZZZ_PROTOCOL=bzzz://
      - DHT_BOOTSTRAP_NODES=walnut:9101,ironwood:9102,acacia:9103
      - CONTENT_STORE_PATH=/app/data/blobs
      - POSTGRES_HOST=postgres
      - REDIS_HOST=redis
      - LOG_LEVEL=info
    secrets:
      - postgres_password
      - openai_api_key
    configs:
      - source: bzzz_config
        target: /app/config/config.yaml
    deploy:
      replicas: 3
      placement:
        max_replicas_per_node: 1
        constraints:
          - node.labels.bzzz.role == agent
      resources:
        limits:
          memory: 4G
          cpus: '2.0'
        reservations:
          memory: 2G
          cpus: '1.0'
      restart_policy:
        condition: on-failure
        delay: 10s
        max_attempts: 3
      update_config:
        parallelism: 1
        delay: 30s
        failure_action: rollback
        order: stop-first
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.bzzz-agent.rule=Host(`bzzz.deepblack.cloud`)"
        - "traefik.http.services.bzzz-agent.loadbalancer.server.port=9000"
        - "traefik.http.routers.bzzz-agent.tls=true"
        - "traefik.http.routers.bzzz-agent.tls.certresolver=letsencrypt"

  # MCP Server for external tool integration
  mcp-server:
    image: registry.home.deepblack.cloud/bzzz-mcp:v2.0.0
    networks:
      - tengig
      - bzzz-internal
    ports:
      - "3001:3001"
    environment:
      - MCP_VERSION=1.0.0
      - BZZZ_ENDPOINT=http://bzzz-agent:9000
      - MAX_CONNECTIONS=1000
      - TIMEOUT_SECONDS=30
    configs:
      - source: mcp_config
        target: /app/config/mcp.yaml
    deploy:
      replicas: 3
      placement:
        max_replicas_per_node: 1
      resources:
        limits:
          memory: 2G
          cpus: '1.0'
        reservations:
          memory: 512M
          cpus: '0.5'
      restart_policy:
        condition: on-failure
        delay: 5s
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.mcp-server.rule=Host(`mcp.deepblack.cloud`)"
        - "traefik.http.services.mcp-server.loadbalancer.server.port=3001"
        - "traefik.http.routers.mcp-server.tls=true"

  # OpenAI Proxy with rate limiting and cost tracking
  openai-proxy:
    image: registry.home.deepblack.cloud/bzzz-openai-proxy:v2.0.0
    networks:
      - tengig
      - bzzz-internal
    ports:
      - "3002:3002"
    environment:
      - RATE_LIMIT_RPM=1000
      - RATE_LIMIT_TPM=100000
      - COST_TRACKING_ENABLED=true
      - REDIS_HOST=redis
      - POSTGRES_HOST=postgres
      - LOG_REQUESTS=true
    secrets:
      - openai_api_key
      - postgres_password
    configs:
      - source: proxy_config
        target: /app/config/proxy.yaml
    deploy:
      replicas: 2
      placement:
        max_replicas_per_node: 1
      resources:
        limits:
          memory: 2G
          cpus: '1.0'
        reservations:
          memory: 1G
          cpus: '0.5'
      restart_policy:
        condition: on-failure
        delay: 10s
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.openai-proxy.rule=Host(`openai.deepblack.cloud`)"
        - "traefik.http.services.openai-proxy.loadbalancer.server.port=3002"
        - "traefik.http.routers.openai-proxy.tls=true"

  # Content Resolver for bzzz:// address resolution
  content-resolver:
    image: registry.home.deepblack.cloud/bzzz-resolver:v2.0.0
    networks:
      - bzzz-internal
      - tengig
    ports:
      - "3003:3003"
    volumes:
      - /rust/bzzz-v2/data/blobs:/app/blobs:ro
    environment:
      - BLAKE3_INDEX_PATH=/app/blobs/index
      - DHT_BOOTSTRAP_NODES=walnut:9101,ironwood:9102,acacia:9103
      - CACHE_SIZE_MB=512
    deploy:
      replicas: 3
      placement:
        max_replicas_per_node: 1
      resources:
        limits:
          memory: 1G
          cpus: '1.0'
        reservations:
          memory: 512M
          cpus: '0.5'
      restart_policy:
        condition: on-failure
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.content-resolver.rule=Host(`resolve.deepblack.cloud`)"

  # DHT Bootstrap Nodes (one per physical node)
  dht-bootstrap-walnut:
    image: registry.home.deepblack.cloud/bzzz-dht:v2.0.0
    networks:
      - bzzz-internal
    ports:
      - "9101:9101"
    volumes:
      - /rust/bzzz-v2/data/dht/walnut:/app/data
    environment:
      - DHT_PORT=9101
      - NODE_NAME=walnut
      - PEER_STORE_PATH=/app/data/peers
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.hostname == walnut
      resources:
        limits:
          memory: 1G
          cpus: '1.0'
      restart_policy:
        condition: on-failure

  dht-bootstrap-ironwood:
    image: registry.home.deepblack.cloud/bzzz-dht:v2.0.0
    networks:
      - bzzz-internal
    ports:
      - "9102:9102"
    volumes:
      - /rust/bzzz-v2/data/dht/ironwood:/app/data
    environment:
      - DHT_PORT=9102
      - NODE_NAME=ironwood
      - PEER_STORE_PATH=/app/data/peers
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.hostname == ironwood
      resources:
        limits:
          memory: 1G
          cpus: '1.0'
      restart_policy:
        condition: on-failure

  dht-bootstrap-acacia:
    image: registry.home.deepblack.cloud/bzzz-dht:v2.0.0
    networks:
      - bzzz-internal
    ports:
      - "9103:9103"
    volumes:
      - /rust/bzzz-v2/data/dht/acacia:/app/data
    environment:
      - DHT_PORT=9103
      - NODE_NAME=acacia
      - PEER_STORE_PATH=/app/data/peers
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.hostname == acacia
      resources:
        limits:
          memory: 1G
          cpus: '1.0'
      restart_policy:
        condition: on-failure

  # PostgreSQL for metadata and conversation threading
  postgres:
    image: postgres:15-alpine
    networks:
      - bzzz-internal
    environment:
      - POSTGRES_DB=bzzz_v2
      - POSTGRES_USER=bzzz
      - POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password
      - POSTGRES_INITDB_ARGS=--auth-host=scram-sha-256
    volumes:
      - /rust/bzzz-v2/data/postgres:/var/lib/postgresql/data
      - /rust/bzzz-v2/config/postgres/init:/docker-entrypoint-initdb.d:ro
    secrets:
      - postgres_password
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.hostname == walnut
      resources:
        limits:
          memory: 4G
          cpus: '2.0'
        reservations:
          memory: 2G
          cpus: '1.0'
      restart_policy:
        condition: on-failure
        delay: 10s
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U bzzz -d bzzz_v2"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Redis for caching and DHT coordination
  redis:
    image: redis:7-alpine
    networks:
      - bzzz-internal
    volumes:
      - /rust/bzzz-v2/data/redis:/data
    configs:
      - source: redis_config
        target: /usr/local/etc/redis/redis.conf
    command: redis-server /usr/local/etc/redis/redis.conf
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.hostname == ironwood
      resources:
        limits:
          memory: 2G
          cpus: '1.0'
        reservations:
          memory: 512M
          cpus: '0.5'
      restart_policy:
        condition: on-failure
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Conversation Thread Manager
  conversation-manager:
    image: registry.home.deepblack.cloud/bzzz-conversation:v2.0.0
    networks:
      - bzzz-internal
    environment:
      - POSTGRES_HOST=postgres
      - REDIS_HOST=redis
      - LAMPORT_CLOCK_PRECISION=microsecond
    volumes:
      - /rust/bzzz-v2/data/conversations:/app/conversations
    secrets:
      - postgres_password
    deploy:
      replicas: 2
      placement:
        max_replicas_per_node: 1
      resources:
        limits:
          memory: 2G
          cpus: '1.0'
      restart_policy:
        condition: on-failure

  # Content Store Manager
  content-store:
    image: registry.home.deepblack.cloud/bzzz-content-store:v2.0.0
    networks:
      - bzzz-internal
    volumes:
      - /rust/bzzz-v2/data/blobs:/app/blobs
    environment:
      - BLAKE3_SHARD_DEPTH=2
      - REPLICATION_FACTOR=3
      - GARBAGE_COLLECTION_INTERVAL=24h
    deploy:
      replicas: 3
      placement:
        max_replicas_per_node: 1
      resources:
        limits:
          memory: 8G
          cpus: '2.0'
        reservations:
          memory: 4G
          cpus: '1.0'
      restart_policy:
        condition: on-failure

networks:
  tengig:
    external: true
  bzzz-internal:
    driver: overlay
    internal: true
    attachable: false
    ipam:
      driver: default
      config:
        - subnet: 10.200.0.0/16

volumes:
  postgres_data:
    driver: local
    driver_opts:
      type: nfs
      o: addr=192.168.1.27,rw,sync
      device: ":/rust/bzzz-v2/data/postgres"
  
  redis_data:
    driver: local
    driver_opts:
      type: nfs
      o: addr=192.168.1.27,rw,sync
      device: ":/rust/bzzz-v2/data/redis"

secrets:
  openai_api_key:
    external: true
    name: bzzz_openai_api_key
  postgres_password:
    external: true
    name: bzzz_postgres_password

configs:
  bzzz_config:
    external: true
    name: bzzz_v2_config
  mcp_config:
    external: true
    name: bzzz_mcp_config
  proxy_config:
    external: true
    name: bzzz_proxy_config
  redis_config:
    external: true
    name: bzzz_redis_config