# FILE: infra/base/infrastructure.yaml
# Infrastructure Services for AI Tax Agent
# Environment-agnostic - use with environment-specific .env files
# Deploy with: ./infra/scripts/deploy.sh <environment> infrastructure

networks:
  frontend:
    external: true
    name: apa-frontend
  backend:
    external: true
    name: apa-backend

volumes:
  postgres_data:
  neo4j_data:
  neo4j_logs:
  qdrant_data:
  minio_data:
  vault_data:
  redis_data:
  nats_data:
  authentik_data:

services:
  # Edge Gateway & SSO
  apa-traefik:
    image: docker.io/library/traefik:v3.5.1
    container_name: apa-traefik
    restart: unless-stopped
    networks:
      - frontend
      - backend
    ports:
      - "8090:80"
      - "8444:443"
      - "8091:8080" # Dashboard
    env_file:
      - ./.provider.env
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik/config/traefik.yml:/etc/traefik/traefik.yml:ro
      - ./traefik/config/traefik-dynamic.yml:/etc/traefik/conf.d/01-base.yml:ro
      - ../compose/traefik/traefik-dynamic.local.yml:/etc/traefik/conf.d/02-local.yml:ro
      - ./certs/:/var/traefik/certs/:rw
    labels:
      - "traefik.enable=true"
      - "traefik.constraint-label=app"
      - "traefik.http.routers.dashboard.rule=Host(`traefik.app.harkon.co.uk`)"
      - "traefik.http.routers.dashboard.entrypoints=websecure"
      - "traefik.http.routers.dashboard.tls=true"
      - "traefik.http.routers.dashboard.tls.certresolver=godaddy"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.middlewares=authentik-forwardauth@file"

  # Identity & SSO (Authentik)
  apa-authentik-db:
    image: postgres:15-alpine
    container_name: apa-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}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U authentik"]
      interval: 30s
      timeout: 10s
      retries: 3

  apa-authentik-redis:
    image: redis:7-alpine
    container_name: apa-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

  apa-authentik-server:
    image: ghcr.io/goauthentik/server:2025.8.3
    container_name: apa-authentik-server
    restart: unless-stopped
    networks:
      - backend
      - frontend
    command: server
    environment:
      AUTHENTIK_REDIS__HOST: apa-authentik-redis
      AUTHENTIK_POSTGRESQL__HOST: apa-authentik-db
      AUTHENTIK_POSTGRESQL__USER: authentik
      AUTHENTIK_POSTGRESQL__NAME: authentik
      AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD}
      AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
      AUTHENTIK_ERROR_REPORTING__ENABLED: false
    depends_on:
      - apa-authentik-db
      - apa-authentik-redis
    labels:
      - "traefik.enable=true"
      - "traefik.constraint-label=app"
      - "traefik.docker.network=apa-backend"
      - "traefik.http.routers.authentik.rule=Host(`auth.${DOMAIN}`)"
      - "traefik.http.routers.authentik.entrypoints=websecure"
      - "traefik.http.routers.authentik.tls=true"
      - "traefik.http.routers.authentik.tls.certresolver=${TRAEFIK_CERT_RESOLVER}"
      - "traefik.http.services.authentik.loadbalancer.server.port=9000"

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

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

  # Secrets Management
  apa-vault:
    image: hashicorp/vault:1.15
    container_name: apa-vault
    restart: unless-stopped
    networks:
      - backend
      - frontend
    volumes:
      - vault_data:/vault/data
    environment:
      VAULT_DEV_ROOT_TOKEN_ID: ${VAULT_DEV_ROOT_TOKEN_ID}
      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
    extra_hosts:
      - "auth.local.lan:host-gateway"
      - "vault.local.lan:host-gateway"
      - "minio.local.lan:host-gateway"
      - "api.local.lan:host-gateway"
      - "traefik.local.lan:host-gateway"
    labels:
      - "traefik.enable=true"
      - "traefik.constraint-label=app"
      - "traefik.docker.network=apa-backend"
      - "traefik.http.routers.vault.rule=Host(`vault.${DOMAIN}`)"
      - "traefik.http.routers.vault.entrypoints=websecure"
      - "traefik.http.routers.vault.tls=true"
      - "traefik.http.routers.vault.tls.certresolver=${TRAEFIK_CERT_RESOLVER}"
      - "traefik.http.services.vault.loadbalancer.server.port=8200"

  # Object Storage
  apa-minio:
    image: minio/minio:RELEASE.2025-04-22T22-12-26Z
    container_name: apa-minio
    restart: unless-stopped
    networks:
      - backend
      - frontend
    volumes:
      - minio_data:/data
    environment:
      MINIO_ROOT_USER: ${MINIO_ROOT_USER}
      MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
      MINIO_BROWSER_REDIRECT_URL: https://minio.${DOMAIN}
      MINIO_IDENTITY_OPENID_CONFIG_URL: "https://auth.${DOMAIN}/application/o/minio-oidc/.well-known/openid-configuration"
      MINIO_IDENTITY_OPENID_CLIENT_ID: "minio"
      MINIO_IDENTITY_OPENID_CLIENT_SECRET: ${AUTHENTIK_MINIO_CLIENT_SECRET}
      MINIO_IDENTITY_OPENID_SCOPES: "openid,profile,email,minio"
      MINIO_IDENTITY_OPENID_REDIRECT_URI: "https://minio.${DOMAIN}/oauth_callback"
      MINIO_IDENTITY_OPENID_DISPLAY_NAME: "Login with Authentik"
    command: server /data --address ":9092" --console-address ":9093"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9092/minio/health/live"]
      interval: 30s
      timeout: 20s
      retries: 3
    extra_hosts:
      - "auth.local.lan:host-gateway"
      - "minio.local.lan:host-gateway"
      - "api.local.lan:host-gateway"
      - "traefik.local.lan:host-gateway"
    labels:
      - "traefik.enable=true"
      - "traefik.constraint-label=app"
      - "traefik.docker.network=apa-backend"
      - "traefik.http.routers.minio-api.rule=Host(`minio-api.${DOMAIN}`)"
      - "traefik.http.routers.minio-api.entrypoints=websecure"
      - "traefik.http.routers.minio-api.tls=true"
      - "traefik.http.routers.minio-api.tls.certresolver=${TRAEFIK_CERT_RESOLVER}"
      - "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}`)"
      - "traefik.http.routers.minio-console.entrypoints=websecure"
      - "traefik.http.routers.minio-console.tls=true"
      - "traefik.http.routers.minio-console.tls.certresolver=${TRAEFIK_CERT_RESOLVER}"
      - "traefik.http.routers.minio-console.service=minio-console"
      - "traefik.http.services.minio-console.loadbalancer.server.port=9093"

  # Vector Database
  apa-qdrant:
    image: qdrant/qdrant:v1.7.4
    container_name: apa-qdrant
    restart: unless-stopped
    networks:
      - backend
      - frontend
    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.constraint-label=app"
      - "traefik.docker.network=apa-backend"
      - "traefik.http.routers.qdrant.rule=Host(`qdrant.${DOMAIN}`)"
      - "traefik.http.routers.qdrant.entrypoints=websecure"
      - "traefik.http.routers.qdrant.tls=true"
      - "traefik.http.routers.qdrant.tls.certresolver=${TRAEFIK_CERT_RESOLVER}"
      - "traefik.http.routers.qdrant.middlewares=authentik-forwardauth@file"
      - "traefik.http.services.qdrant.loadbalancer.server.port=6333"

  # Knowledge Graph Database
  apa-neo4j:
    image: neo4j:5.15-community
    container_name: apa-neo4j
    restart: unless-stopped
    networks:
      - backend
      - frontend
    volumes:
      - neo4j_data:/data
      - neo4j_logs:/logs
    environment:
      NEO4J_AUTH: neo4j/${NEO4J_PASSWORD}
      NEO4J_PLUGINS: '["apoc", "graph-data-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.constraint-label=app"
      - "traefik.docker.network=apa-backend"
      - "traefik.http.routers.neo4j.rule=Host(`neo4j.${DOMAIN}`)"
      - "traefik.http.routers.neo4j.entrypoints=websecure"
      - "traefik.http.routers.neo4j.tls=true"
      - "traefik.http.routers.neo4j.tls.certresolver=${TRAEFIK_CERT_RESOLVER}"
      - "traefik.http.routers.neo4j.middlewares=authentik-forwardauth@file"
      - "traefik.http.services.neo4j.loadbalancer.server.port=7474"

  # Secure Client Data Store
  apa-postgres:
    image: postgres:15-alpine
    container_name: apa-postgres
    restart: unless-stopped
    networks:
      - backend
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: tax_system
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      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
  apa-redis:
    image: redis:7-alpine
    container_name: apa-redis
    restart: unless-stopped
    networks:
      - backend
    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
  apa-nats:
    image: nats:2.10-alpine
    container_name: apa-nats
    restart: unless-stopped
    networks:
      - backend
      - frontend
    ports:
      - "4222:4222" # Client connections (for local testing)
    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.constraint-label=app"
      - "traefik.docker.network=apa-backend"
      - "traefik.http.routers.nats-monitor.rule=Host(`nats.${DOMAIN}`)"
      - "traefik.http.routers.nats-monitor.entrypoints=websecure"
      - "traefik.http.routers.nats-monitor.tls=true"
      - "traefik.http.routers.nats-monitor.tls.certresolver=${TRAEFIK_CERT_RESOLVER}"
      - "traefik.http.routers.nats-monitor.middlewares=authentik-forwardauth@file"
      - "traefik.http.services.nats-monitor.loadbalancer.server.port=8222"
