Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/docker-compose.staging.yml
T

232 lines
9.9 KiB
YAML

# Staging compose overlay (reference only).
#
# Coolify on the hivegrid-staging host does NOT consume this file directly —
# each service is provisioned through the Coolify UI. This overlay is the
# human-readable source of truth for how the staging stack is meant to be
# wired (PgBouncer in front of Postgres, apps depending on it being healthy)
# and can be applied locally for end-to-end smoke tests:
#
# docker compose -f docker-compose.yml -f docker-compose.staging.yml up \
# postgres pgbouncer api web worker-general worker-mail worker-import worker-webhook worker-plugin
#
# See docs/ops/pgbouncer.md for the matching Coolify deploy procedure.
services:
postgres:
image: postgres:16-alpine@sha256:57c72fd2a128e416c7fcc499958864df5301e940bca0a56f58fddf30ffc07777
environment:
POSTGRES_DB: ${POSTGRES_DB:-hivegrid_validation}
POSTGRES_USER: ${POSTGRES_USER:-hivegrid}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-hivegrid}
# Required so pg_authid stores SCRAM hashes that pgbouncer can copy
# into its userlist.txt. md5 would force a config-time rehash.
POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256 --auth-local=scram-sha-256"
command:
- postgres
- -c
- password_encryption=scram-sha-256
# Defensive max_connections so PgBouncer's default_pool_size (25)
# multiplied across app stacks stays well below the cap.
- -c
- max_connections=200
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-hivegrid} -d ${POSTGRES_DB:-hivegrid_validation}"]
interval: 10s
timeout: 3s
retries: 10
start_period: 20s
restart: unless-stopped
pgbouncer:
depends_on:
postgres:
condition: service_healthy
# Explicit one-shot authority. Run with:
# docker compose -f docker-compose.yml -f docker-compose.staging.yml --profile migrate run --rm migrator
# DIRECT_URL exists only in this short-lived container. Seeding is not part
# of the non-superuser migration authority.
migrator:
build:
context: .
target: web
entrypoint: ["./start.sh", "migrate"]
environment:
- DIRECT_URL=${MIGRATOR_DIRECT_URL:?MIGRATOR_DIRECT_URL is required}
depends_on:
postgres:
condition: service_healthy
profiles: ["migrate"]
restart: "no"
api:
build:
context: .
target: api
environment:
- DATABASE_URL=${APP_DATABASE_URL:?APP_DATABASE_URL is required}
- DATABASE_RUNTIME_ROLE=hivegrid_app
- RLS_RUNTIME_MODE=required
- REDIS_URL=${REDIS_URL:-redis://redis:6379/0}
- CHAT_GATEWAY_AUTH_SECRET=${CHAT_GATEWAY_AUTH_SECRET:?CHAT_GATEWAY_AUTH_SECRET is required}
- CLAMD_HOST=${CLAMD_HOST:-clamav}
- CLAMD_PORT=${CLAMD_PORT:-3310}
- CLAMD_TIMEOUT_MS=${CLAMD_TIMEOUT_MS:-30000}
- STORAGE_ENDPOINT=${STORAGE_ENDPOINT:-}
- STORAGE_REGION=${STORAGE_REGION:-}
- STORAGE_BUCKET=${STORAGE_BUCKET:-}
- STORAGE_ACCESS_KEY_ID=${STORAGE_ACCESS_KEY_ID:-}
- STORAGE_SECRET_ACCESS_KEY=${STORAGE_SECRET_ACCESS_KEY:-}
- STORAGE_SESSION_TOKEN=${STORAGE_SESSION_TOKEN:-}
- STORAGE_FORCE_PATH_STYLE=${STORAGE_FORCE_PATH_STYLE:-false}
depends_on:
pgbouncer:
condition: service_healthy
redis:
condition: service_healthy
clamav:
condition: service_healthy
web:
build:
context: .
target: web
environment:
- DATABASE_URL=${APP_DATABASE_URL:?APP_DATABASE_URL is required}
- DATABASE_RUNTIME_ROLE=hivegrid_app
- RLS_RUNTIME_MODE=required
# Dedicated callback-only capability. Never forward this DSN to API,
# Hocuspocus, workers, or the one-shot migrator.
- AUTHENTIK_ADMIN_JIT_DATABASE_URL=${AUTHENTIK_ADMIN_JIT_DATABASE_URL:-}
- REDIS_URL=${REDIS_URL:?REDIS_URL is required}
- BULLMQ_REDIS_URL=${BULLMQ_REDIS_URL:-redis://redis:6379/0}
- SCAN_QUEUE_ENABLED=${SCAN_QUEUE_ENABLED:-true}
- CLAMD_HOST=${CLAMD_HOST:-clamav}
- CLAMD_PORT=${CLAMD_PORT:-3310}
- CLAMD_TIMEOUT_MS=${CLAMD_TIMEOUT_MS:-30000}
- STORAGE_ENDPOINT=${STORAGE_ENDPOINT:?STORAGE_ENDPOINT is required}
- STORAGE_REGION=${STORAGE_REGION:?STORAGE_REGION is required}
- STORAGE_BUCKET=${STORAGE_BUCKET:?STORAGE_BUCKET is required}
- STORAGE_ACCESS_KEY_ID=${WEB_STORAGE_ACCESS_KEY_ID:?WEB_STORAGE_ACCESS_KEY_ID is required}
- STORAGE_SECRET_ACCESS_KEY=${WEB_STORAGE_SECRET_ACCESS_KEY:?WEB_STORAGE_SECRET_ACCESS_KEY is required}
- STORAGE_SESSION_TOKEN=${WEB_STORAGE_SESSION_TOKEN:-}
- STORAGE_FORCE_PATH_STYLE=${STORAGE_FORCE_PATH_STYLE:-false}
- GDPR_EXPORT_SSE_C_KEY_BASE64=${GDPR_EXPORT_SSE_C_KEY_BASE64:?GDPR_EXPORT_SSE_C_KEY_BASE64 is required}
- AIRCALL_CLIENT_ID=${AIRCALL_CLIENT_ID:-}
- AIRCALL_CLIENT_SECRET=${AIRCALL_CLIENT_SECRET:-}
- AIRCALL_REDIRECT_URI=${AIRCALL_REDIRECT_URI:-}
- AIRCALL_WEBHOOK_URL=${AIRCALL_WEBHOOK_URL:-}
- CHAT_GATEWAY_AUTH_SECRET=${CHAT_GATEWAY_AUTH_SECRET:?CHAT_GATEWAY_AUTH_SECRET is required}
- WEB_PUSH_VAPID_PUBLIC_KEY=${WEB_PUSH_VAPID_PUBLIC_KEY:?WEB_PUSH_VAPID_PUBLIC_KEY is required}
depends_on:
pgbouncer:
condition: service_healthy
redis:
condition: service_healthy
clamav:
condition: service_healthy
# Five group-specific workers receive only the NOBYPASSRLS worker DSN.
# Migrator and seed credentials are intentionally absent.
worker-general:
environment:
- DATABASE_URL=${WORKER_DATABASE_URL:?WORKER_DATABASE_URL is required}
- DATABASE_RUNTIME_ROLE=hivegrid_worker
- RLS_RUNTIME_MODE=required
- SCAN_QUEUE_ENABLED=true
- CLAMAV_HOST=${CLAMAV_HOST:-clamav}
- CLAMAV_PORT=${CLAMAV_PORT:-3310}
- CLAMAV_TIMEOUT_MS=${CLAMAV_TIMEOUT_MS:-30000}
- STORAGE_ENDPOINT=${STORAGE_ENDPOINT:?STORAGE_ENDPOINT is required}
- STORAGE_REGION=${STORAGE_REGION:?STORAGE_REGION is required}
- STORAGE_BUCKET=${STORAGE_BUCKET:?STORAGE_BUCKET is required}
- STORAGE_ACCESS_KEY_ID=${WORKER_GENERAL_STORAGE_ACCESS_KEY_ID:?WORKER_GENERAL_STORAGE_ACCESS_KEY_ID is required}
- STORAGE_SECRET_ACCESS_KEY=${WORKER_GENERAL_STORAGE_SECRET_ACCESS_KEY:?WORKER_GENERAL_STORAGE_SECRET_ACCESS_KEY is required}
- STORAGE_SESSION_TOKEN=${WORKER_GENERAL_STORAGE_SESSION_TOKEN:-}
- STORAGE_FORCE_PATH_STYLE=${STORAGE_FORCE_PATH_STYLE:-false}
- STORAGE_QUARANTINE_BUCKET=${STORAGE_QUARANTINE_BUCKET:-}
- MEILI_URL=${MEILI_URL:?MEILI_URL is required}
- MEILI_API_KEY=${MEILI_API_KEY:?MEILI_API_KEY is required}
- EXPORT_RETENTION_QUEUE_ENABLED=true
- OUTBOX_DISPATCHER_ENABLED=true
- OUTBOX_DISPATCHER_REQUIRED=true
- LAGO_API_URL=${LAGO_API_URL:?LAGO_API_URL is required}
- LAGO_API_KEY=${LAGO_API_KEY:?LAGO_API_KEY is required}
- LAGO_TIMEOUT_MS=${LAGO_TIMEOUT_MS:-10000}
- MOLLIE_API_KEY=${MOLLIE_API_KEY:?MOLLIE_API_KEY is required}
- MOLLIE_PROFILE_ID=${MOLLIE_PROFILE_ID:-}
- MOLLIE_TIMEOUT_MS=${MOLLIE_TIMEOUT_MS:-10000}
- BILLING_MOLLIE_WEBHOOK_URL=${BILLING_MOLLIE_WEBHOOK_URL:?BILLING_MOLLIE_WEBHOOK_URL is required}
- WORKFLOW_TRIGGER_OUTBOX_ENABLED=true
- WORKFLOW_TRIGGER_OUTBOX_REQUIRED=true
- KWP_HIVEGRID_TENANT_ID=${KWP_HIVEGRID_TENANT_ID:-}
depends_on:
pgbouncer:
condition: service_healthy
worker-mail:
environment:
- DATABASE_URL=${WORKER_DATABASE_URL:?WORKER_DATABASE_URL is required}
- DATABASE_RUNTIME_ROLE=hivegrid_worker
- RLS_RUNTIME_MODE=required
depends_on:
pgbouncer:
condition: service_healthy
worker-import:
environment:
- DATABASE_URL=${WORKER_DATABASE_URL:?WORKER_DATABASE_URL is required}
- DATABASE_RUNTIME_ROLE=hivegrid_worker
- RLS_RUNTIME_MODE=required
- IMPORT_QUEUE_ENABLED=false
- IMPORT_QUEUE_RUNTIME_READY=false
- PORTAL_GDPR_EXPORT_QUEUE_ENABLED=true
- STORAGE_ENDPOINT=${STORAGE_ENDPOINT:?STORAGE_ENDPOINT is required}
- STORAGE_REGION=${STORAGE_REGION:?STORAGE_REGION is required}
- STORAGE_BUCKET=${STORAGE_BUCKET:?STORAGE_BUCKET is required}
- STORAGE_ACCESS_KEY_ID=${WORKER_IMPORT_STORAGE_ACCESS_KEY_ID:?WORKER_IMPORT_STORAGE_ACCESS_KEY_ID is required}
- STORAGE_SECRET_ACCESS_KEY=${WORKER_IMPORT_STORAGE_SECRET_ACCESS_KEY:?WORKER_IMPORT_STORAGE_SECRET_ACCESS_KEY is required}
- STORAGE_SESSION_TOKEN=${WORKER_IMPORT_STORAGE_SESSION_TOKEN:-}
- STORAGE_FORCE_PATH_STYLE=${STORAGE_FORCE_PATH_STYLE:-false}
- GDPR_EXPORT_SSE_C_KEY_BASE64=${GDPR_EXPORT_SSE_C_KEY_BASE64:?GDPR_EXPORT_SSE_C_KEY_BASE64 is required}
- KWP_HIVEGRID_TENANT_ID=${KWP_HIVEGRID_TENANT_ID:-}
depends_on:
pgbouncer:
condition: service_healthy
worker-webhook:
environment:
- DATABASE_URL=${WORKER_DATABASE_URL:?WORKER_DATABASE_URL is required}
- DATABASE_RUNTIME_ROLE=hivegrid_worker
- RLS_RUNTIME_MODE=required
- WEB_PUSH_VAPID_SUBJECT=${WEB_PUSH_VAPID_SUBJECT:?WEB_PUSH_VAPID_SUBJECT is required}
- WEB_PUSH_VAPID_PUBLIC_KEY=${WEB_PUSH_VAPID_PUBLIC_KEY:?WEB_PUSH_VAPID_PUBLIC_KEY is required}
- WEB_PUSH_VAPID_PRIVATE_KEY=${WEB_PUSH_VAPID_PRIVATE_KEY:?WEB_PUSH_VAPID_PRIVATE_KEY is required}
depends_on:
pgbouncer:
condition: service_healthy
worker-plugin:
environment:
- DATABASE_URL=${WORKER_DATABASE_URL:?WORKER_DATABASE_URL is required}
- DATABASE_RUNTIME_ROLE=hivegrid_worker
- RLS_RUNTIME_MODE=required
depends_on:
pgbouncer:
condition: service_healthy
hocuspocus:
environment:
- NODE_ENV=production
- HOCUSPOCUS_PORT=1234
- HOCUSPOCUS_HOST=0.0.0.0
- HOCUSPOCUS_AUTH_SECRET=${HOCUSPOCUS_AUTH_SECRET:-}
- DATABASE_URL=${APP_DATABASE_URL:?APP_DATABASE_URL is required}
- DATABASE_RUNTIME_ROLE=hivegrid_app
- RLS_RUNTIME_MODE=required
volumes:
postgres-data: