# Integration test stack — full pipeline end-to-end. # # Usage: # docker compose -f server/tests/docker-compose.integration.yml up -d --build # # Requires .env.integration in the repo root (generated by CI workflow). x-backend-env: &backend-env DATABASE_URL: postgresql+asyncpg://reflector:reflector@postgres:5432/reflector REDIS_HOST: redis CELERY_BROKER_URL: redis://redis:6379/1 CELERY_RESULT_BACKEND: redis://redis:6379/1 HATCHET_CLIENT_TOKEN: ${HATCHET_CLIENT_TOKEN:-} HATCHET_CLIENT_SERVER_URL: http://hatchet:8888 HATCHET_CLIENT_HOST_PORT: hatchet:7077 HATCHET_CLIENT_TLS_STRATEGY: none # ML backends — CPU-only, no external services TRANSCRIPT_BACKEND: whisper WHISPER_CHUNK_MODEL: tiny WHISPER_FILE_MODEL: tiny DIARIZATION_BACKEND: pyannote TRANSLATION_BACKEND: passthrough # Storage — local Garage S3 TRANSCRIPT_STORAGE_BACKEND: aws TRANSCRIPT_STORAGE_AWS_ENDPOINT_URL: http://garage:3900 TRANSCRIPT_STORAGE_AWS_BUCKET_NAME: reflector-media TRANSCRIPT_STORAGE_AWS_REGION: garage # Daily mock DAILY_API_URL: http://mock-daily:8080/v1 DAILY_API_KEY: fake-daily-key # Auth PUBLIC_MODE: "true" AUTH_BACKEND: none # LLM (injected from CI) LLM_URL: ${LLM_URL:-} LLM_API_KEY: ${LLM_API_KEY:-} LLM_MODEL: ${LLM_MODEL:-gpt-4o-mini} # HuggingFace (for pyannote gated models) HF_TOKEN: ${HF_TOKEN:-} # Garage S3 credentials — hardcoded test keys, containers are ephemeral TRANSCRIPT_STORAGE_AWS_ACCESS_KEY_ID: GK0123456789abcdef01234567 # gitleaks:allow TRANSCRIPT_STORAGE_AWS_SECRET_ACCESS_KEY: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" # gitleaks:allow # Email / SMTP — Mailpit captures emails without sending SMTP_HOST: mailpit SMTP_PORT: "1025" SMTP_FROM_EMAIL: test@reflector.local SMTP_USE_TLS: "false" # NOTE: DAILYCO_STORAGE_AWS_* intentionally NOT set — forces fallback to # get_transcripts_storage() which has ENDPOINT_URL pointing at Garage. # Setting them would bypass the endpoint and generate presigned URLs for AWS. services: postgres: image: postgres:17-alpine command: ["postgres", "-c", "max_connections=200"] environment: POSTGRES_USER: reflector POSTGRES_PASSWORD: reflector POSTGRES_DB: reflector volumes: - ../../server/docker/init-hatchet-db.sql:/docker-entrypoint-initdb.d/init-hatchet-db.sql:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U reflector"] interval: 5s timeout: 3s retries: 10 redis: image: redis:7.2-alpine healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5 hatchet: image: ghcr.io/hatchet-dev/hatchet/hatchet-lite:latest depends_on: postgres: condition: service_healthy environment: DATABASE_URL: "postgresql://reflector:reflector@postgres:5432/hatchet?sslmode=disable&connect_timeout=30" SERVER_AUTH_COOKIE_INSECURE: "t" SERVER_AUTH_COOKIE_DOMAIN: "localhost" SERVER_GRPC_BIND_ADDRESS: "0.0.0.0" SERVER_GRPC_INSECURE: "t" SERVER_GRPC_BROADCAST_ADDRESS: hatchet:7077 SERVER_GRPC_PORT: "7077" SERVER_AUTH_SET_EMAIL_VERIFIED: "t" SERVER_INTERNAL_CLIENT_INTERNAL_GRPC_BROADCAST_ADDRESS: hatchet:7077 healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8888/api/live"] interval: 10s timeout: 5s retries: 15 start_period: 30s garage: image: dxflrs/garage:v1.1.0 volumes: - ./integration/garage.toml:/etc/garage.toml:ro healthcheck: test: ["CMD", "/garage", "stats"] interval: 5s timeout: 3s retries: 10 start_period: 5s mailpit: image: axllent/mailpit:latest healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:8025/api/v1/messages"] interval: 5s timeout: 3s retries: 5 mock-daily: build: context: . dockerfile: integration/Dockerfile.mock-daily healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8080/v1/recordings/test')"] interval: 5s timeout: 3s retries: 5 server: build: context: ../../server dockerfile: Dockerfile environment: <<: *backend-env ENTRYPOINT: server WEBRTC_HOST: server WEBRTC_PORT_RANGE: "52000-52100" depends_on: postgres: condition: service_healthy redis: condition: service_healthy hatchet: condition: service_healthy garage: condition: service_healthy mock-daily: condition: service_healthy mailpit: condition: service_healthy volumes: - server_data:/app/data worker: build: context: ../../server dockerfile: Dockerfile environment: <<: *backend-env ENTRYPOINT: worker depends_on: postgres: condition: service_healthy redis: condition: service_healthy volumes: - server_data:/app/data hatchet-worker-cpu: build: context: ../../server dockerfile: Dockerfile environment: <<: *backend-env ENTRYPOINT: hatchet-worker-cpu depends_on: hatchet: condition: service_healthy postgres: condition: service_healthy redis: condition: service_healthy volumes: - server_data:/app/data hatchet-worker-llm: build: context: ../../server dockerfile: Dockerfile environment: <<: *backend-env ENTRYPOINT: hatchet-worker-llm depends_on: hatchet: condition: service_healthy postgres: condition: service_healthy redis: condition: service_healthy volumes: - server_data:/app/data test-runner: build: context: ../../server dockerfile: Dockerfile environment: <<: *backend-env # Override DATABASE_URL for sync driver (used by direct DB access in tests) DATABASE_URL_ASYNC: postgresql+asyncpg://reflector:reflector@postgres:5432/reflector DATABASE_URL: postgresql+asyncpg://reflector:reflector@postgres:5432/reflector SERVER_URL: http://server:1250 GARAGE_ENDPOINT: http://garage:3900 MAILPIT_URL: http://mailpit:8025 depends_on: server: condition: service_started worker: condition: service_started hatchet-worker-cpu: condition: service_started hatchet-worker-llm: condition: service_started volumes: - server_data:/app/data # Mount test files into the container - ./records:/app/tests/records:ro - ./integration:/app/tests/integration:ro entrypoint: ["sleep", "infinity"] volumes: server_data: networks: default: attachable: true