# docker-compose-e2e.yml — Multi-replica E2E testing (Postgres) # # Three Armature replicas behind an nginx load balancer, # sharing a single Postgres instance. Tests cross-replica # broadcast via pg_notify and cluster registry (v0.6.0). # # Usage: # docker compose -f docker-compose-e2e.yml up --build -d # ./ci/e2e-chat-test.sh # chat E2E # ./ci/e2e-cluster-test.sh # cluster registry E2E # docker compose -f docker-compose-e2e.yml down -v services: postgres: image: postgres:16-alpine environment: POSTGRES_DB: armature_e2e POSTGRES_USER: armature POSTGRES_PASSWORD: e2e-password ports: - "5432:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U armature -d armature_e2e"] interval: 2s timeout: 5s retries: 10 armature-1: build: context: . dockerfile: Dockerfile environment: PORT: "8080" BASE_PATH: "" DB_DRIVER: postgres DATABASE_URL: postgres://armature:e2e-password@postgres:5432/armature_e2e?sslmode=disable JWT_SECRET: e2e-jwt-secret ENCRYPTION_KEY: e2e-encryption-key-32chars!!!!! ARMATURE_ADMIN_USERNAME: admin ARMATURE_ADMIN_PASSWORD: admin STORAGE_BACKEND: pvc STORAGE_PATH: /data/storage CORS_ALLOWED_ORIGINS: "*" EXT_ALLOW_PRIVATE_IPS: "true" LOG_FORMAT: text LOG_LEVEL: info SEED_USERS: "alice:password123:user,bob:password456:user,charlie:password789:user" CLUSTER_NODE_ID: "node-1" CLUSTER_HEARTBEAT_INTERVAL: "5s" CLUSTER_STALE_THRESHOLD: "15s" CLUSTER_ENDPOINT: "http://armature-1:8080" depends_on: postgres: condition: service_healthy ports: - "8081:80" armature-2: build: context: . dockerfile: Dockerfile environment: PORT: "8080" BASE_PATH: "" DB_DRIVER: postgres DATABASE_URL: postgres://armature:e2e-password@postgres:5432/armature_e2e?sslmode=disable JWT_SECRET: e2e-jwt-secret ENCRYPTION_KEY: e2e-encryption-key-32chars!!!!! ARMATURE_ADMIN_USERNAME: admin ARMATURE_ADMIN_PASSWORD: admin STORAGE_BACKEND: pvc STORAGE_PATH: /data/storage CORS_ALLOWED_ORIGINS: "*" EXT_ALLOW_PRIVATE_IPS: "true" LOG_FORMAT: text LOG_LEVEL: info SEED_USERS: "alice:password123:user,bob:password456:user,charlie:password789:user" CLUSTER_NODE_ID: "node-2" CLUSTER_HEARTBEAT_INTERVAL: "5s" CLUSTER_STALE_THRESHOLD: "15s" CLUSTER_ENDPOINT: "http://armature-2:8080" depends_on: postgres: condition: service_healthy ports: - "8082:80" armature-3: build: context: . dockerfile: Dockerfile environment: PORT: "8080" BASE_PATH: "" DB_DRIVER: postgres DATABASE_URL: postgres://armature:e2e-password@postgres:5432/armature_e2e?sslmode=disable JWT_SECRET: e2e-jwt-secret ENCRYPTION_KEY: e2e-encryption-key-32chars!!!!! ARMATURE_ADMIN_USERNAME: admin ARMATURE_ADMIN_PASSWORD: admin STORAGE_BACKEND: pvc STORAGE_PATH: /data/storage CORS_ALLOWED_ORIGINS: "*" EXT_ALLOW_PRIVATE_IPS: "true" LOG_FORMAT: text LOG_LEVEL: info SEED_USERS: "alice:password123:user,bob:password456:user,charlie:password789:user" CLUSTER_NODE_ID: "node-3" CLUSTER_HEARTBEAT_INTERVAL: "5s" CLUSTER_STALE_THRESHOLD: "15s" CLUSTER_ENDPOINT: "http://armature-3:8080" depends_on: postgres: condition: service_healthy ports: - "8083:80" lb: image: nginx:alpine volumes: - ./ci/e2e-nginx.conf:/etc/nginx/nginx.conf:ro ports: - "3000:80" depends_on: - armature-1 - armature-2 - armature-3