# FILE: infra/compose/docker-compose.local.yml
# Traefik (with Authentik ForwardAuth), Authentik, Vault, MinIO, Qdrant, Neo4j, Postgres, Redis, Prometheus/Grafana, Loki, Unleash, all services

networks:
  frontend:
    external: true
    name: ai-tax-agent-frontend

  backend:
    external: true
    name: ai-tax-agent-backend

volumes:
  postgres_data:
  neo4j_data:
  neo4j_logs:
  qdrant_data:
  minio_data:
  vault_data:
  redis_data:
  nats_data:
  prometheus_data:
  grafana_data:
  loki_data:
  authentik_data:

services:
  # Edge Gateway & Load Balancer

  aia-traefik:
    image: docker.io/library/traefik:v3.5.1
    container_name: aia-traefik
    ports:
      - 80:80
      - 443:443
      # --> (Optional) Enable Dashboard, don't do in production
      - 8080:8080
      # <--
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ../traefik/config/:/etc/traefik/:ro
      - ../traefik/certs/:/var/traefik/certs/:rw
    environment: []
    env_file:
      - ../traefik/.provider.env # contains the GoDaddy API Key and Secret
    networks:
      - frontend
      - backend
    restart: unless-stopped

  # Identity & SSO
  aia-authentik-db:
    image: postgres:15-alpine
    container_name: aia-authentik-db
    restart: unless-stopped
    networks:
      - backend
    volumes:
      - authentik_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: authentik
      POSTGRES_USER: authentik
      POSTGRES_PASSWORD: ${AUTHENTIK_DB_PASSWORD:-authentik}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U authentik"]
      interval: 30s
      timeout: 10s
      retries: 3

  aia-authentik-redis:
    image: redis:7-alpine
    container_name: aia-authentik-redis
    restart: unless-stopped
    networks:
      - backend
    command: --save 60 1 --loglevel warning
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
      interval: 30s
      timeout: 10s
      retries: 3

  aia-authentik-server:
    image: ghcr.io/goauthentik/server:2025.8.3
    container_name: aia-authentik-server
    restart: unless-stopped
    networks:
      - backend
      - frontend
    command: server
    environment:
      AUTHENTIK_REDIS__HOST: aia-authentik-redis
      AUTHENTIK_POSTGRESQL__HOST: aia-authentik-db
      AUTHENTIK_POSTGRESQL__USER: authentik
      AUTHENTIK_POSTGRESQL__NAME: authentik
      AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD:-authentik}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:-changeme}
      AUTHENTIK_ERROR_REPORTING__ENABLED: false
      # Optional bootstrap for automated setup (create admin and API token)
      AUTHENTIK_BOOTSTRAP_EMAIL: ${AUTHENTIK_BOOTSTRAP_EMAIL:-admin@local.lan}
      AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD:-admin123}
      AUTHENTIK_BOOTSTRAP_TOKEN: ${AUTHENTIK_BOOTSTRAP_TOKEN:-}
    volumes:
      - ../authentik/media:/media
      - ../authentik/custom-templates:/templates
      - ../authentik/bootstrap.yaml:/blueprints/bootstrap.yaml
    depends_on:
      - aia-authentik-db
      - aia-authentik-redis
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.authentik.rule=Host(`auth.${DOMAIN:-local.lan}`)"
      - "traefik.http.routers.authentik.entrypoints=websecure"
      - "traefik.http.routers.authentik.tls=true"
      - "traefik.docker.network=ai-tax-agent-frontend"
      - "traefik.http.services.authentik.loadbalancer.server.port=9000"

  aia-authentik-worker:
    image: ghcr.io/goauthentik/server:2025.8.3
    container_name: aia-authentik-worker
    restart: unless-stopped
    networks:
      - backend
    command: worker
    environment:
      AUTHENTIK_REDIS__HOST: aia-authentik-redis
      AUTHENTIK_POSTGRESQL__HOST: aia-authentik-db
      AUTHENTIK_POSTGRESQL__USER: authentik
      AUTHENTIK_POSTGRESQL__NAME: authentik
      AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD:-authentik}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:-changeme}
      AUTHENTIK_ERROR_REPORTING__ENABLED: false
    volumes:
      - ../authentik/media:/media
      - ../authentik/custom-templates:/templates
    depends_on:
      - aia-authentik-db
      - aia-authentik-redis

  aia-authentik-outpost:
    image: ghcr.io/goauthentik/proxy:2025.8.3
    container_name: aia-authentik-outpost
    restart: unless-stopped
    networks:
      - backend
      - frontend
    environment:
      AUTHENTIK_HOST: http://aia-authentik-server:9000
      AUTHENTIK_INSECURE: true
      AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_TOKEN:-changeme}
      AUTHENTIK_REDIS__HOST: aia-authentik-redis
      AUTHENTIK_REDIS__PORT: 6379
    depends_on:
      - aia-authentik-server
      - aia-authentik-redis

  # Secrets Management
  aia-vault:
    image: hashicorp/vault:1.15
    container_name: aia-vault
    restart: unless-stopped
    networks:
      - backend
    ports:
      - "8200:8200"
    volumes:
      - vault_data:/vault/data
      - ../vault/config:/vault/config:ro
    environment:
      VAULT_DEV_ROOT_TOKEN_ID: ${VAULT_DEV_ROOT_TOKEN_ID:-root}
      VAULT_DEV_LISTEN_ADDRESS: 0.0.0.0:8200
    command: vault server -dev -dev-listen-address=0.0.0.0:8200
    cap_add:
      - IPC_LOCK
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.vault.rule=Host(`vault.${DOMAIN:-local.lan}`)"
      - "traefik.http.routers.vault.entrypoints=websecure"
      - "traefik.http.routers.vault.tls=true"
      - "traefik.http.routers.vault.middlewares=authentik-forwardauth@file"
      - "traefik.http.services.vault.loadbalancer.server.port=8200"

  # Object Storage
  aia-minio:
    image: minio/minio:RELEASE.2025-09-07T16-13-09Z
    container_name: aia-minio
    restart: unless-stopped
    networks:
      - backend
    ports:
      - "9092:9092"
      - "9093:9093"
    volumes:
      - minio_data:/data
    environment:
      MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minio}
      MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-miniopass}
      MINIO_BROWSER_REDIRECT_URL: https://minio.${DOMAIN:-local.lan}
    command: server /data --address ":9092" --console-address ":9093"
    healthcheck:
      test: ["CMD", "mc", "--version"]
      interval: 30s
      timeout: 20s
      retries: 3
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.minio-api.rule=Host(`minio-api.${DOMAIN:-local.lan}`)"
      - "traefik.http.routers.minio-api.entrypoints=websecure"
      - "traefik.http.routers.minio-api.tls=true"
      - "traefik.http.routers.minio-api.middlewares=authentik-forwardauth@file"
      - "traefik.http.routers.minio-api.service=minio-api"
      - "traefik.http.services.minio-api.loadbalancer.server.port=9092"
      - "traefik.http.routers.minio-console.rule=Host(`minio.${DOMAIN:-local.lan}`)"
      - "traefik.http.routers.minio-console.entrypoints=websecure"
      - "traefik.http.routers.minio-console.tls=true"
      - "traefik.http.routers.minio-console.middlewares=authentik-forwardauth@file"
      - "traefik.http.routers.minio-console.service=minio-console"
      - "traefik.http.services.minio-console.loadbalancer.server.port=9093"

  # Vector Database
  aia-qdrant:
    image: qdrant/qdrant:v1.7.4
    container_name: aia-qdrant
    restart: unless-stopped
    networks:
      - backend
    ports:
      - "6333:6333"
      - "6334:6334"
    volumes:
      - qdrant_data:/qdrant/storage
    environment:
      QDRANT__SERVICE__GRPC_PORT: ${QDRANT__SERVICE__GRPC_PORT:-6334}
      QDRANT__SERVICE__HTTP_PORT: 6333
      QDRANT__LOG_LEVEL: INFO
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.qdrant.rule=Host(`qdrant.${DOMAIN:-local.lan}`)"
      - "traefik.http.routers.qdrant.entrypoints=websecure"
      - "traefik.http.routers.qdrant.tls=true"
      - "traefik.http.routers.qdrant.middlewares=authentik-forwardauth@file"
      - "traefik.http.services.qdrant.loadbalancer.server.port=6333"

  # Knowledge Graph Database
  aia-neo4j:
    image: neo4j:5.15-community
    container_name: aia-neo4j
    restart: unless-stopped
    networks:
      - backend
    ports:
      - "7474:7474"
      - "7687:7687"
    volumes:
      - neo4j_data:/data
      - neo4j_logs:/logs
      - ../neo4j/plugins:/plugins
    environment:
      NEO4J_AUTH: neo4j/${NEO4J_PASSWORD:-neo4jpass}
      NEO4J_PLUGINS: '["apoc", "graph-daia-science"]'
      NEO4J_dbms_security_procedures_unrestricted: gds.*,apoc.*
      NEO4J_dbms_security_procedures_allowlist: gds.*,apoc.*
      NEO4J_apoc_export_file_enabled: true
      NEO4J_apoc_import_file_enabled: true
      NEO4J_apoc_import_file_use__neo4j__config: true
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.neo4j.rule=Host(`neo4j.${DOMAIN:-local.lan}`)"
      - "traefik.http.routers.neo4j.entrypoints=websecure"
      - "traefik.http.routers.neo4j.tls=true"
      - "traefik.http.routers.neo4j.middlewares=authentik-forwardauth@file"
      - "traefik.http.services.neo4j.loadbalancer.server.port=7474"

  # Secure Client Data Store
  aia-postgres:
    image: postgres:15-alpine
    container_name: aia-postgres
    restart: unless-stopped
    networks:
      - backend
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ../postgres/init:/docker-entrypoint-initdb.d
    environment:
      POSTGRES_DB: tax_system
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
      POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256"
    command: >
      postgres
      -c shared_preload_libraries=pg_stat_statements
      -c pg_stat_statements.track=all
      -c max_connections=200
      -c shared_buffers=256MB
      -c effective_cache_size=1GB
      -c maintenance_work_mem=64MB
      -c checkpoint_completion_target=0.9
      -c wal_buffers=16MB
      -c default_statistics_target=100
      -c random_page_cost=1.1
      -c effective_io_concurrency=200
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Cache & Session Store
  aia-redis:
    image: redis:7-alpine
    container_name: aia-redis
    restart: unless-stopped
    networks:
      - backend
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    command: >
      redis-server
      --appendonly yes
      --appendfsync everysec
      --maxmemory 512mb
      --maxmemory-policy allkeys-lru
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
      interval: 30s
      timeout: 10s
      retries: 3

  # Message Broker & Event Streaming
  aia-nats:
    image: nats:2.10-alpine
    container_name: aia-nats
    restart: unless-stopped
    networks:
      - backend
    ports:
      - "4222:4222" # NATS client connections
      - "8222:8222" # HTTP monitoring
      - "6222:6222" # Cluster routing (for future clustering)
    volumes:
      - nats_data:/data
    command: >
      --jetstream
      --store_dir=/data
      --http_port=8222
    environment:
      NATS_LOG_LEVEL: ${NATS_LOG_LEVEL:-info}
    healthcheck:
      test:
        [
          "CMD",
          "wget",
          "--no-verbose",
          "--tries=1",
          "--spider",
          "http://localhost:8222/healthz",
        ]
      interval: 30s
      timeout: 10s
      retries: 3
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.nats-monitor.rule=Host(`nats.${DOMAIN:-local.lan}`)"
      - "traefik.http.routers.nats-monitor.entrypoints=websecure"
      - "traefik.http.routers.nats-monitor.tls=true"
      - "traefik.http.routers.nats-monitor.middlewares=authentik-forwardauth@file"
      - "traefik.http.services.nats-monitor.loadbalancer.server.port=8222"

  # Monitoring & Observability
  aia-prometheus:
    image: prom/prometheus:v2.48.1
    container_name: aia-prometheus
    restart: unless-stopped
    networks:
      - backend
    ports:
      - "9090:9090"
    volumes:
      - prometheus_data:/prometheus
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.path=/prometheus"
      - "--web.console.libraries=/etc/prometheus/console_libraries"
      - "--web.console.templates=/etc/prometheus/consoles"
      - "--storage.tsdb.retention.time=30d"
      - "--web.enable-lifecycle"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.prometheus.rule=Host(`prometheus.${DOMAIN:-local.lan}`)"
      - "traefik.http.routers.prometheus.entrypoints=websecure"
      - "traefik.http.routers.prometheus.tls=true"
      - "traefik.http.routers.prometheus.middlewares=authentik-forwardauth@file"
      - "traefik.http.services.prometheus.loadbalancer.server.port=9090"

  aia-grafana:
    image: grafana/grafana:10.2.3
    container_name: aia-grafana
    restart: unless-stopped
    networks:
      - backend
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning:ro
      - ./grafana/dashboards:/var/lib/grafana/dashboards:ro
    environment:
      GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin}
      GF_USERS_ALLOW_SIGN_UP: false
      GF_USERS_AUTO_ASSIGN_ORG: true
      GF_USERS_AUTO_ASSIGN_ORG_ROLE: Viewer
      GF_AUTH_GENERIC_OAUTH_ENABLED: true
      GF_AUTH_GENERIC_OAUTH_NAME: Authentik
      GF_AUTH_GENERIC_OAUTH_CLIENT_ID: ${GRAFANA_OAUTH_CLIENT_ID:-grafana}
      GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: ${GRAFANA_OAUTH_CLIENT_SECRET:-changeme-grafana-secret}
      GF_AUTH_GENERIC_OAUTH_SCOPES: openid profile email groups
      GF_AUTH_GENERIC_OAUTH_AUTH_URL: https://auth.${DOMAIN:-local.lan}/application/o/authorize/
      GF_AUTH_GENERIC_OAUTH_TOKEN_URL: https://auth.${DOMAIN:-local.lan}/application/o/token/
      GF_AUTH_GENERIC_OAUTH_API_URL: https://auth.${DOMAIN:-local.lan}/application/o/userinfo/
      GF_AUTH_GENERIC_OAUTH_AUTO_LOGIN: false
      GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP: true
      GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH: role
      GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_STRICT: false
      GF_AUTH_GENERIC_OAUTH_GROUPS_ATTRIBUTE_PATH: groups
      GF_AUTH_OAUTH_AUTO_LOGIN: false
      GF_AUTH_DISABLE_LOGIN_FORM: false
      # Cookie and security settings
      GF_SERVER_ROOT_URL: https://grafana.${DOMAIN:-local.lan}
      GF_SERVER_SERVE_FROM_SUB_PATH: false
      GF_SECURITY_COOKIE_SECURE: false
      GF_SECURITY_COOKIE_SAMESITE: lax
      GF_AUTH_GENERIC_OAUTH_USE_PKCE: true
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.grafana.rule=Host(`grafana.${DOMAIN:-local.lan}`)"
      - "traefik.http.routers.grafana.entrypoints=websecure"
      - "traefik.http.routers.grafana.tls=true"
      - "traefik.http.services.grafana.loadbalancer.server.port=3000"

  aia-loki:
    image: grafana/loki:2.9.4
    container_name: aia-loki
    restart: unless-stopped
    networks:
      - backend
    ports:
      - "3100:3100"
    volumes:
      - loki_data:/loki
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.loki.rule=Host(`loki.${DOMAIN:-local.lan}`)"
      - "traefik.http.routers.loki.entrypoints=websecure"
      - "traefik.http.routers.loki.tls=true"
      - "traefik.http.routers.loki.middlewares=authentik-forwardauth@file"
      - "traefik.http.services.loki.loadbalancer.server.port=3100"

  # Feature Flags
  aia-unleash:
    image: unleashorg/unleash-server:5.7.3
    container_name: aia-unleash
    restart: unless-stopped
    networks:
      - frontend
      - backend
    ports:
      - "4242:4242"
    environment:
      DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:-postgres}@aia-postgres:5432/unleash
      DATABASE_SSL: false
      LOG_LEVEL: info
    depends_on:
      - aia-postgres
    labels:
      - "traefik.docker.network=ai-tax-agent-frontend"
      - "traefik.enable=true"
      - "traefik.http.routers.unleash.rule=Host(`unleash.${DOMAIN:-local.lan}`)"
      - "traefik.http.routers.unleash.entrypoints=websecure"
      - "traefik.http.routers.unleash.tls=true"
      - "traefik.http.routers.unleash.middlewares=authentik-forwardauth@file"
      - "traefik.http.services.unleash.loadbalancer.server.port=4242"

  # Application Services
  aia-svc-ingestion:
    build:
      context: ../../
      dockerfile: apps/svc_ingestion/Dockerfile
    container_name: aia-svc-ingestion
    restart: unless-stopped
    networks:
      - backend
    environment:
      - VAULT_ADDR=http://aia-vault:8200
      - VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
      - MINIO_ENDPOINT=aia-minio:9092
      - POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@aia-postgres:5432/tax_system
      - REDIS_URL=redis://aia-redis:6379
      - EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
      - NATS_SERVERS=${NATS_SERVERS:-nats://aia-nats:4222}
      - NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
      - NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
    depends_on:
      - aia-vault
      - aia-minio
      - aia-postgres
      - aia-redis
      - aia-nats
      - aia-neo4j
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.svc-ingestion.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/ingestion`)"
      - "traefik.http.routers.svc-ingestion.entrypoints=websecure"
      - "traefik.http.routers.svc-ingestion.tls=true"
      - "traefik.http.routers.svc-ingestion.middlewares=authentik-forwardauth@file,rate-limit@file"
      - "traefik.http.services.svc-ingestion.loadbalancer.server.port=8000"

  aia-svc-extract:
    build:
      context: ../../
      dockerfile: apps/svc_extract/Dockerfile
    container_name: aia-svc-extract
    restart: unless-stopped
    networks:
      - backend
    environment:
      - VAULT_ADDR=http://aia-vault:8200
      - VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
      - MINIO_ENDPOINT=aia-minio:9092
      - POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@aia-postgres:5432/tax_system
      - RAG_EMBEDDING_MODEL=${RAG_EMBEDDING_MODEL:-bge-small-en-v1.5}
      - EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
      - NATS_SERVERS=${NATS_SERVERS:-nats://aia-nats:4222}
      - NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
      - NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
    depends_on:
      - aia-vault
      - aia-minio
      - aia-postgres
      - aia-nats
      - aia-neo4j
      - aia-redis
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.svc-extract.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/extract`)"
      - "traefik.http.routers.svc-extract.entrypoints=websecure"
      - "traefik.http.routers.svc-extract.tls=true"
      - "traefik.http.routers.svc-extract.middlewares=authentik-forwardauth@file,rate-limit@file"
      - "traefik.http.services.svc-extract.loadbalancer.server.port=8000"

  aia-svc-kg:
    build:
      context: ../../
      dockerfile: apps/svc_kg/Dockerfile
    container_name: aia-svc-kg
    restart: unless-stopped
    networks:
      - backend
    environment:
      - VAULT_ADDR=http://aia-vault:8200
      - VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
      - NEO4J_URI=bolt://aia-neo4j:7687
      - NEO4J_USER=neo4j
      - NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4jpass}
      - EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
      - NATS_SERVERS=${NATS_SERVERS:-nats://aia-nats:4222}
      - NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
      - NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
    depends_on:
      - aia-vault
      - aia-neo4j
      - aia-nats
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.svc-kg.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/kg`)"
      - "traefik.http.routers.svc-kg.entrypoints=websecure"
      - "traefik.http.routers.svc-kg.tls=true"
      - "traefik.http.routers.svc-kg.middlewares=authentik-forwardauth@file,rate-limit@file"
      - "traefik.http.services.svc-kg.loadbalancer.server.port=8000"

  aia-svc-rag-retriever:
    build:
      context: ../../
      dockerfile: apps/svc_rag_retriever/Dockerfile
    container_name: aia-svc-rag-retriever
    restart: unless-stopped
    networks:
      - backend
    environment:
      - VAULT_ADDR=http://aia-vault:8200
      - VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
      - QDRANT_URL=http://aia-qdrant:6333
      - NEO4J_URI=bolt://aia-neo4j:7687
      - NEO4J_USER=neo4j
      - NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4jpass}
      - RAG_EMBEDDING_MODEL=${RAG_EMBEDDING_MODEL:-bge-small-en-v1.5}
      - RAG_RERANKER_MODEL=${RAG_RERANKER_MODEL:-cross-encoder/ms-marco-MiniLM-L-6-v2}
      - EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
      - NATS_SERVERS=${NATS_SERVERS:-nats://aia-nats:4222}
      - NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
      - NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
    depends_on:
      - aia-vault
      - aia-qdrant
      - aia-neo4j
      - aia-nats
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.svc-rag-retriever.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/rag`)"
      - "traefik.http.routers.svc-rag-retriever.entrypoints=websecure"
      - "traefik.http.routers.svc-rag-retriever.tls=true"
      - "traefik.http.routers.svc-rag-retriever.middlewares=authentik-forwardauth@file,rate-limit@file"
      - "traefik.http.services.svc-rag-retriever.loadbalancer.server.port=8000"

  aia-svc-coverage:
    build:
      context: ../../
      dockerfile: apps/svc_coverage/Dockerfile
    container_name: aia-svc-coverage
    restart: unless-stopped
    networks:
      - backend
    volumes:
      - ../../config:/app/config:ro
    environment:
      - VAULT_ADDR=http://aia-vault:8200
      - VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
      - NEO4J_URI=bolt://aia-neo4j:7687
      - NEO4J_USER=neo4j
      - NEO4J_PASSWORD=${NEO4J_PASSWORD:-neo4jpass}
      - POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@aia-postgres:5432/tax_system
      - RAG_SERVICE_URL=http://aia-svc-rag-retriever:8000
      - EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
      - NATS_SERVERS=${NATS_SERVERS:-nats://aia-nats:4222}
      - NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
      - NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
    depends_on:
      - aia-vault
      - aia-neo4j
      - aia-postgres
      - aia-nats
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.svc-coverage.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/coverage`)"
      - "traefik.http.routers.svc-coverage.entrypoints=websecure"
      - "traefik.http.routers.svc-coverage.tls=true"
      - "traefik.http.routers.svc-coverage.middlewares=authentik-forwardauth@file,rate-limit@file"
      - "traefik.http.services.svc-coverage.loadbalancer.server.port=8000"

  aia-svc-firm-connectors:
    build:
      context: ../../
      dockerfile: apps/svc_firm_connectors/Dockerfile
    container_name: aia-svc-firm-connectors
    restart: unless-stopped
    networks:
      - backend
    volumes:
      - ../../config:/app/config:ro
    environment:
      - VAULT_ADDR=http://aia-vault:8200
      - VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
      - POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@aia-postgres:5432/tax_system
      - NEO4J_URL=bolt://aia-neo4j:7687
      - NEO4J_USER=neo4j
      - NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
      - REDIS_URL=redis://aia-redis:6379
      - MINIO_ENDPOINT=aia-minio:9092
      - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
      - MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
      - QDRANT_URL=http://aia-qdrant:6333
      - EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
      - KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
      - NATS_SERVERS=${NATS_SERVERS:-nats://aia-nats:4222}
      - NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
      - NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
    depends_on:
      - aia-postgres
      - aia-neo4j
      - aia-minio
      - aia-qdrant
      - aia-nats
      - aia-traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.svc-firm-connectors.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/firm-connectors`)"
      - "traefik.http.routers.svc-firm-connectors.entrypoints=websecure"
      - "traefik.http.routers.svc-firm-connectors.tls=true"
      - "traefik.http.routers.svc-firm-connectors.middlewares=authentik-forwardauth@file,rate-limit@file"
      - "traefik.http.services.svc-firm-connectors.loadbalancer.server.port=8000"

  aia-svc-forms:
    build:
      context: ../../
      dockerfile: apps/svc_forms/Dockerfile
    container_name: aia-svc-forms
    restart: unless-stopped
    networks:
      - backend
    volumes:
      - ../../config:/app/config:ro
    environment:
      - VAULT_ADDR=http://aia-vault:8200
      - VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
      - POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@aia-postgres:5432/tax_system
      - NEO4J_URL=bolt://aia-neo4j:7687
      - NEO4J_USER=neo4j
      - NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
      - REDIS_URL=redis://aia-redis:6379
      - MINIO_ENDPOINT=aia-minio:9092
      - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
      - MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
      - QDRANT_URL=http://aia-qdrant:6333
      - EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
      - KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
      - NATS_SERVERS=${NATS_SERVERS:-nats://aia-nats:4222}
      - NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
      - NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
    depends_on:
      - aia-postgres
      - aia-neo4j
      - aia-minio
      - aia-qdrant
      - aia-nats
      - aia-traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.svc-forms.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/forms`)"
      - "traefik.http.routers.svc-forms.entrypoints=websecure"
      - "traefik.http.routers.svc-forms.tls=true"
      - "traefik.http.routers.svc-forms.middlewares=authentik-forwardauth@file,rate-limit@file"
      - "traefik.http.services.svc-forms.loadbalancer.server.port=8000"

  aia-svc-hmrc:
    build:
      context: ../../
      dockerfile: apps/svc_hmrc/Dockerfile
    container_name: aia-svc-hmrc
    restart: unless-stopped
    networks:
      - backend
    volumes:
      - ../../config:/app/config:ro
    environment:
      - VAULT_ADDR=http://aia-vault:8200
      - VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
      - POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@aia-postgres:5432/tax_system
      - NEO4J_URL=bolt://aia-neo4j:7687
      - NEO4J_USER=neo4j
      - NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
      - REDIS_URL=redis://aia-redis:6379
      - MINIO_ENDPOINT=aia-minio:9092
      - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
      - MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
      - QDRANT_URL=http://aia-qdrant:6333
      - EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
      - KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
      - NATS_SERVERS=${NATS_SERVERS:-nats://aia-nats:4222}
      - NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
      - NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
    depends_on:
      - aia-postgres
      - aia-neo4j
      - aia-minio
      - aia-qdrant
      - aia-nats
      - aia-traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.svc-hmrc.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/hmrc`)"
      - "traefik.http.routers.svc-hmrc.entrypoints=websecure"
      - "traefik.http.routers.svc-hmrc.tls=true"
      - "traefik.http.routers.svc-hmrc.middlewares=authentik-forwardauth@file,rate-limit@file"
      - "traefik.http.services.svc-hmrc.loadbalancer.server.port=8000"

  aia-svc-normalize-map:
    build:
      context: ../../
      dockerfile: apps/svc_normalize_map/Dockerfile
    container_name: aia-svc-normalize-map
    restart: unless-stopped
    networks:
      - backend
    volumes:
      - ../../config:/app/config:ro
    environment:
      - VAULT_ADDR=http://aia-vault:8200
      - VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
      - POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@aia-postgres:5432/tax_system
      - NEO4J_URL=bolt://aia-neo4j:7687
      - NEO4J_USER=neo4j
      - NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
      - REDIS_URL=redis://aia-redis:6379
      - MINIO_ENDPOINT=aia-minio:9092
      - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
      - MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
      - QDRANT_URL=http://aia-qdrant:6333
      - EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
      - KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
      - NATS_SERVERS=${NATS_SERVERS:-nats://aia-nats:4222}
      - NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
      - NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
    depends_on:
      - aia-postgres
      - aia-neo4j
      - aia-minio
      - aia-qdrant
      - aia-nats
      - aia-traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.svc-normalize-map.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/normalize-map`)"
      - "traefik.http.routers.svc-normalize-map.entrypoints=websecure"
      - "traefik.http.routers.svc-normalize-map.tls=true"
      - "traefik.http.routers.svc-normalize-map.middlewares=authentik-forwardauth@file,rate-limit@file"
      - "traefik.http.services.svc-normalize-map.loadbalancer.server.port=8000"

  aia-svc-ocr:
    build:
      context: ../../
      dockerfile: apps/svc_ocr/Dockerfile
    container_name: aia-svc-ocr
    restart: unless-stopped
    networks:
      - backend
    volumes:
      - ../../config:/app/config:ro
    environment:
      - VAULT_ADDR=http://aia-vault:8200
      - VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
      - POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@aia-postgres:5432/tax_system
      - NEO4J_URL=bolt://aia-neo4j:7687
      - NEO4J_USER=neo4j
      - NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
      - REDIS_URL=redis://aia-redis:6379
      - MINIO_ENDPOINT=aia-minio:9092
      - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
      - MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
      - QDRANT_URL=http://aia-qdrant:6333
      - EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
      - KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
      - NATS_SERVERS=${NATS_SERVERS:-nats://aia-nats:4222}
      - NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
      - NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
    depends_on:
      - aia-postgres
      - aia-neo4j
      - aia-minio
      - aia-qdrant
      - aia-nats
      - aia-traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.svc-ocr.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/ocr`)"
      - "traefik.http.routers.svc-ocr.entrypoints=websecure"
      - "traefik.http.routers.svc-ocr.tls=true"
      - "traefik.http.routers.svc-ocr.middlewares=authentik-forwardauth@file,rate-limit@file"
      - "traefik.http.services.svc-ocr.loadbalancer.server.port=8000"

  aia-svc-rag-indexer:
    build:
      context: ../../
      dockerfile: apps/svc_rag_indexer/Dockerfile
    container_name: aia-svc-rag-indexer
    restart: unless-stopped
    networks:
      - backend
    volumes:
      - ../../config:/app/config:ro
    environment:
      - VAULT_ADDR=http://aia-vault:8200
      - VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
      - POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@aia-postgres:5432/tax_system
      - NEO4J_URL=bolt://aia-neo4j:7687
      - NEO4J_USER=neo4j
      - NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
      - REDIS_URL=redis://aia-redis:6379
      - MINIO_ENDPOINT=aia-minio:9092
      - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
      - MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
      - QDRANT_URL=http://aia-qdrant:6333
      - EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
      - KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
      - NATS_SERVERS=${NATS_SERVERS:-nats://aia-nats:4222}
      - NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
      - NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
    depends_on:
      - aia-postgres
      - aia-neo4j
      - aia-minio
      - aia-qdrant
      - aia-nats
      - aia-traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.svc-rag-indexer.rule=Host(`api.${DOMAIN:-.lan}`) && PathPrefix(`/rag-indexer`)"
      - "traefik.http.routers.svc-rag-indexer.entrypoints=websecure"
      - "traefik.http.routers.svc-rag-indexer.tls=true"
      - "traefik.http.routers.svc-rag-indexer.middlewares=authentik-forwardauth@file,rate-limit@file"
      - "traefik.http.services.svc-rag-indexer.loadbalancer.server.port=8000"

  aia-svc-reason:
    build:
      context: ../../
      dockerfile: apps/svc_reason/Dockerfile
    container_name: aia-svc-reason
    restart: unless-stopped
    networks:
      - backend
    volumes:
      - ../../config:/app/config:ro
    environment:
      - VAULT_ADDR=http://aia-vault:8200
      - VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
      - POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@aia-postgres:5432/tax_system
      - NEO4J_URL=bolt://aia-neo4j:7687
      - NEO4J_USER=neo4j
      - NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
      - REDIS_URL=redis://aia-redis:6379
      - MINIO_ENDPOINT=aia-minio:9092
      - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
      - MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
      - QDRANT_URL=http://aia-qdrant:6333
      - EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
      - KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
      - NATS_SERVERS=${NATS_SERVERS:-nats://aia-nats:4222}
      - NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
      - NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}

    depends_on:
      - aia-postgres
      - aia-neo4j
      - aia-minio
      - aia-qdrant
      - aia-nats
      - aia-traefik

    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.svc-reason.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/reason`)"
      - "traefik.http.routers.svc-reason.entrypoints=websecure"
      - "traefik.http.routers.svc-reason.tls=true"
      - "traefik.http.routers.svc-reason.middlewares=authentik-forwardauth@file,rate-limit@file"
      - "traefik.http.services.svc-reason.loadbalancer.server.port=8000"

  aia-svc-rpa:
    build:
      context: ../../
      dockerfile: apps/svc_rpa/Dockerfile
    container_name: aia-svc-rpa
    restart: unless-stopped
    networks:
      - backend
    volumes:
      - ../../config:/app/config:ro
    environment:
      - VAULT_ADDR=http://aia-vault:8200
      - VAULT_TOKEN=${VAULT_DEV_ROOT_TOKEN_ID:-root}
      - POSTGRES_URL=postgresql://postgres:${POSTGRES_PASSWORD:-postgres}@aia-postgres:5432/tax_system
      - NEO4J_URL=bolt://aia-neo4j:7687
      - NEO4J_USER=neo4j
      - NEO4J_PASSWORD=${NEO4J_PASSWORD:-password}
      - REDIS_URL=redis://aia-redis:6379
      - MINIO_ENDPOINT=aia-minio:9092
      - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY:-minioadmin}
      - MINIO_SECRET_KEY=${MINIO_SECRET_KEY:-minioadmin}
      - QDRANT_URL=http://aia-qdrant:6333
      - EVENT_BUS_TYPE=${EVENT_BUS_TYPE:-memory}
      - KAFKA_BOOTSTRAP_SERVERS=${KAFKA_BOOTSTRAP_SERVERS:-}
      - NATS_SERVERS=${NATS_SERVERS:-nats://aia-nats:4222}
      - NATS_STREAM_NAME=${NATS_STREAM_NAME:-TAX_AGENT_EVENTS}
      - NATS_CONSUMER_GROUP=${NATS_CONSUMER_GROUP:-tax-agent}
    depends_on:
      - aia-postgres
      - aia-neo4j
      - aia-minio
      - aia-qdrant
      - aia-nats
      - aia-traefik
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.svc-rpa.rule=Host(`api.${DOMAIN:-local.lan}`) && PathPrefix(`/rpa`)"
      - "traefik.http.routers.svc-rpa.entrypoints=websecure"
      - "traefik.http.routers.svc-rpa.tls=true"
      - "traefik.http.routers.svc-rpa.middlewares=authentik-forwardauth@file,rate-limit@file"
      - "traefik.http.services.svc-rpa.loadbalancer.server.port=8000"

  aia-ui-review:
    build:
      context: ../../ui-review
      dockerfile: Dockerfile
    container_name: aia-ui-review
    restart: unless-stopped
    networks:
      - frontend
    environment:
      - NEXTAUTH_URL=https://review.${DOMAIN:-local.lan}
      - NEXTAUTH_SECRET=${NEXTAUTH_SECRET:-changeme}
      - API_BASE_URL=https://api.${DOMAIN:-local.lan}
    depends_on:
      - aia-traefik
    labels:
      - "traefik.docker.network=ai-tax-agent-frontend"
      - "traefik.enable=true"
      - "traefik.http.routers.ui-review.rule=Host(`review.${DOMAIN:-local.lan}`)"
      - "traefik.http.routers.ui-review.entrypoints=websecure"
      - "traefik.http.routers.ui-review.tls=true"
      - "traefik.http.routers.ui-review.middlewares=authentik-forwardauth@file"
      - "traefik.http.services.ui-review.loadbalancer.server.port=3030"
