services: db: image: postgres:16-alpine environment: POSTGRES_DB: ${POSTGRES_DB:-rehearsalhub} POSTGRES_USER: ${POSTGRES_USER:-rh_user} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-default_secure_password} volumes: - pg_data:/var/lib/postgresql/data networks: - rh_net healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-rh_user} -d ${POSTGRES_DB:-rehearsalhub} || exit 1"] interval: 15s timeout: 10s retries: 30 start_period: 45s restart: unless-stopped command: ["postgres", "-c", "max_connections=200", "-c", "shared_buffers=256MB"] redis: image: redis:7-alpine command: redis-server --save 60 1 --loglevel warning volumes: - redis_data:/data networks: - rh_net healthcheck: test: ["CMD-SHELL", "redis-cli ping || exit 1"] interval: 10s timeout: 5s retries: 15 start_period: 25s restart: unless-stopped deploy: resources: limits: memory: 256M api: build: context: ./api target: production image: rehearsalhub/api:latest environment: DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-rh_user}:${POSTGRES_PASSWORD:-default_secure_password}@db:5432/${POSTGRES_DB:-rehearsalhub} NEXTCLOUD_URL: ${NEXTCLOUD_URL:-https://cloud.example.com} NEXTCLOUD_USER: ${NEXTCLOUD_USER:-rh_service} NEXTCLOUD_PASS: ${NEXTCLOUD_PASS:-default_password} REDIS_URL: redis://redis:6379/0 SECRET_KEY: ${SECRET_KEY:-replace_me_with_32_byte_hex_default} INTERNAL_SECRET: ${INTERNAL_SECRET:-replace_me_with_32_byte_hex_default} DOMAIN: ${DOMAIN:-localhost} networks: - rh_net depends_on: db: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD-SHELL", "uv run python -c \"import httpx; exit(0 if httpx.get('http://localhost:8000/api/health').status_code == 200 else 1)\" || exit 1"] interval: 20s timeout: 10s retries: 5 start_period: 60s restart: unless-stopped deploy: resources: limits: memory: 512M audio-worker: build: context: ./worker target: production image: rehearsalhub/audio-worker:latest environment: DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER:-rh_user}:${POSTGRES_PASSWORD:-default_secure_password}@db:5432/${POSTGRES_DB:-rehearsalhub} REDIS_URL: redis://redis:6379/0 NEXTCLOUD_URL: ${NEXTCLOUD_URL:-https://cloud.example.com} NEXTCLOUD_USER: ${NEXTCLOUD_USER:-rh_service} NEXTCLOUD_PASS: ${NEXTCLOUD_PASS:-default_password} ANALYSIS_VERSION: "1.0.0" volumes: - audio_tmp:/tmp/audio networks: - rh_net depends_on: db: condition: service_healthy redis: condition: service_healthy api: condition: service_started restart: unless-stopped nc-watcher: build: context: ./watcher target: production image: rehearsalhub/nc-watcher:latest environment: NEXTCLOUD_URL: ${NEXTCLOUD_URL:-https://cloud.example.com} NEXTCLOUD_USER: ${NEXTCLOUD_USER:-rh_service} NEXTCLOUD_PASS: ${NEXTCLOUD_PASS:-default_password} API_URL: http://api:8000 REDIS_URL: redis://redis:6379/0 POLL_INTERVAL: "30" networks: - rh_net depends_on: db: condition: service_healthy redis: condition: service_healthy api: condition: service_started restart: unless-stopped web: build: context: ./web target: production image: rehearsalhub/web:latest ports: - "8080:80" networks: - frontend - rh_net depends_on: - api restart: unless-stopped networks: frontend: external: name: proxy rh_net: volumes: pg_data: redis_data: audio_tmp: