# 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 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 volumes: - ./authentik:/blueprints/ai-tax-agent 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:/blueprints/ai-tax-agent 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-prod/.well-known/openid-configuration" MINIO_IDENTITY_OPENID_CLIENT_ID: "minio-prod" 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"