Ctrl K
ComunidadGuías…

docker-compose.src.yml

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
name: pneumatic

services:
  postgres:
    image: postgres:15-bookworm
    container_name: pneumatic-postgres
    environment:
      PGDATA: ${PGDATA:-var/lib/postgresql/data}
      POSTGRES_HOST: ${POSTGRES_HOST:-postgres}
      POSTGRES_USER: ${POSTGRES_USER:-postgres_user}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres_password}
      POSTGRES_DB: ${POSTGRES_DB:-postgres_db}
      POSTGRES_REPLICA_HOST: ${POSTGRES_REPLICA_HOST:-postgres}
      POSTGRES_REPLICA_USER: ${POSTGRES_REPLICA_USER:-postgres_user}
      POSTGRES_REPLICA_PASSWORD: ${POSTGRES_REPLICA_PASSWORD:-postgres_password}
      POSTGRES_REPLICA_DB: ${POSTGRES_REPLICA_DB:-postgres_db}
      FILE_POSTGRES_USER: ${FILE_POSTGRES_USER:-pneumatic}
      FILE_POSTGRES_PASSWORD: ${FILE_POSTGRES_PASSWORD:-pneumatic}
      FILE_POSTGRES_DB: ${FILE_POSTGRES_DB:-pneumatic}
    volumes:
      - ./postgres/data:/var/lib/postgresql/data:rw
      - ./postgres/backups:/backups:rw
      - ./scripts/postgres-init:/docker-entrypoint-initdb.d:ro
    expose:
      - 5432
    healthcheck:
      test: ["CMD", "pg_isready", "-h", "localhost"]
      interval: 5s
      start_period: 60s
    networks:
      - pneumatic
    restart: always

  redis:
    image: redis:8.10.2-trixie
    container_name: pneumatic-redis
    mem_limit: 512m
    memswap_limit: 512m # swap disabled
    command: >
      --loglevel warning
      --databases 16
      --dbfilename dump.rdb
      --dir /data
      --requirepass ${REDIS_PASSWORD:-redis_password}
      --save "20 1 300 100 60 10000"
      --stop-writes-on-bgsave-error yes
      --maxmemory 256mb
      --maxmemory-policy volatile-lru
      --maxmemory-samples 10
      --maxmemory-clients 10%
      --lazyfree-lazy-eviction yes
      --lazyfree-lazy-expire yes
      --lazyfree-lazy-server-del yes
      --activedefrag yes
      --timeout 300
      --tcp-keepalive 300
    volumes:
      - ./redis/data:/data
    expose:
      - 6379
    networks:
      - pneumatic
    restart: always

  rabbitmq:
    container_name: pneumatic-rabbitmq
    image: rabbitmq:3.13-management
    expose:
      - 5672    # broker url
    ports:
      - 15672:15672  # admin panel
    volumes:
      - ./rabbitmq/data/:/var/lib/rabbitmq/
      - ./rabbitmq/log/:/var/log/rabbitmq
    environment:
      RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-rabbitmq_user}
      RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-rabbitmq_password}
    networks:
      - pneumatic

  backend:
    build:
      context: ./backend
    image: pneumaticworkflow/pneumatic-backend:${TAG:-src}
    container_name: pneumatic-backend
    command: >
      sh -c "python manage.py migrate &&
             python manage.py collectstatic --no-input &&
             python manage.py init_periodic_tasks &&
             python manage.py compilemessages &&
             gunicorn src.asgi:application --workers ${WORKERS_COUNT:-2} -k uvicorn.workers.UvicornWorker --worker-tmp-dir /dev/shm --bind unix:/tmp/gunicorn/pneumatic-backend.sock --timeout 200"
    environment:
      BACKEND_URL: ${BACKEND_URL:-http://localhost:8001}
      FRONTEND_URL: ${FRONTEND_URL:-http://localhost}
      FORMS_URL: ${FORMS_URL:-http://localhost/forms}
      ENVIRONMENT: ${ENVIRONMENT:-Production}
      RELEASE: ${RELEASE:-1.0.0}
      LANGUAGE_CODE: ${LANGUAGE_CODE:-en} # Allowed values: en, fr, de, es, ru
      CAPTCHA: ${CAPTCHA:-no}
      RECAPTCHA_SITE_KEY: ${RECAPTCHA_SITE_KEY:-}
      RECAPTCHA_SECRET_KEY: ${RECAPTCHA_SECRET_KEY:-}
      RECAPTCHA_TESTING: ${RECAPTCHA_TESTING:-no}
      ANALYTICS: ${ANALYTICS:-no}
      ANALYTICS_DEBUG: ${ANALYTICS_DEBUG:-no}
      ANALYTICS_WRITE_KEY: ${ANALYTICS_WRITE_KEY:-}
      BILLING: ${BILLING:-no}
      STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}
      STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}
      STRIPE_WEBHOOK_IP_WHITELIST: ${STRIPE_WEBHOOK_IP_WHITELIST:-}
      SIGNUP: ${SIGNUP:-yes}
      MS_AUTH: ${MS_AUTH:-no}
      MS_CLIENT_ID: ${MS_CLIENT_ID:-}
      MS_CLIENT_SECRET: ${MS_CLIENT_SECRET:-}
      MS_AUTHORITY: ${MS_AUTHORITY:-}
      GOOGLE_AUTH: ${GOOGLE_AUTH:-no}
      GOOGLE_OAUTH2_CLIENT_ID: ${GOOGLE_OAUTH2_CLIENT_ID:-}
      GOOGLE_OAUTH2_CLIENT_SECRET: ${GOOGLE_OAUTH2_CLIENT_SECRET:-}
      GOOGLE_OAUTH2_REDIRECT_URI: ${GOOGLE_OAUTH2_REDIRECT_URI:-}
      SSO_AUTH: ${SSO_AUTH:-no}
      SSO_PROVIDER: ${SSO_PROVIDER:-} # Allowed values: okta, auth0
      OKTA_DOMAIN: ${OKTA_DOMAIN:-}
      OKTA_CLIENT_ID: ${OKTA_CLIENT_ID:-}
      OKTA_CLIENT_SECRET: ${OKTA_CLIENT_SECRET:-}
      OKTA_REDIRECT_URI: ${OKTA_REDIRECT_URI:-}
      AUTH0_CLIENT_ID: ${AUTH0_CLIENT_ID:-}
      AUTH0_CLIENT_SECRET: ${AUTH0_CLIENT_SECRET:-}
      AUTH0_DOMAIN: ${AUTH0_DOMAIN:-}
      AUTH0_REDIRECT_URI: ${AUTH0_REDIRECT_URI:-}
      EMAIL: ${EMAIL:-no}           # Disable send emails
      EMAIL_PROVIDER: ${EMAIL_PROVIDER:-}
      CIO_WEBHOOK_API_VERSION: ${CIO_WEBHOOK_API_VERSION:-}
      CIO_WEBHOOK_API_KEY: ${CIO_WEBHOOK_API_KEY:-}
      CIO_TRANSACTIONAL_API_KEY: ${CIO_TRANSACTIONAL_API_KEY:-}
      CIO_TEMPLATE__RESET_PASSWORD: ${CIO_TEMPLATE__RESET_PASSWORD:-}
      CIO_TEMPLATE__INVITE: ${CIO_TEMPLATE__INVITE:-}
      CIO_TEMPLATE__USER_DEACTIVATED: ${CIO_TEMPLATE__USER_DEACTIVATED:-}
      CIO_TEMPLATE__NEW_TASK: ${CIO_TEMPLATE__NEW_TASK:-}
      CIO_TEMPLATE__TASK_RETURNED: ${CIO_TEMPLATE__TASK_RETURNED:-}
      CIO_TEMPLATE__ACCOUNT_VERIFICATION: ${CIO_TEMPLATE__ACCOUNT_VERIFICATION:-}
      CIO_TEMPLATE__WORKFLOWS_DIGEST: ${CIO_TEMPLATE__WORKFLOWS_DIGEST:-}
      CIO_TEMPLATE__TASKS_DIGEST: ${CIO_TEMPLATE__TASKS_DIGEST:-}
      CIO_TEMPLATE__USER_TRANSFER: ${CIO_TEMPLATE__USER_TRANSFER:-}
      CIO_TEMPLATE__UNREAD_NOTIFICATIONS: ${CIO_TEMPLATE__UNREAD_NOTIFICATIONS:-}
      CIO_TEMPLATE__GUEST_NEW_TASK: ${CIO_TEMPLATE__GUEST_NEW_TASK:-}
      CIO_TEMPLATE__OVERDUE_TASK: ${CIO_TEMPLATE__OVERDUE_TASK:-}
      CIO_TEMPLATE__MENTION: ${CIO_TEMPLATE__MENTION:-}
      CIO_TEMPLATE__TASK_REMINDER: ${CIO_TEMPLATE__TASK_REMINDER:-}
      CIO_TEMPLATE__COMPLETE_WORKFLOW: ${CIO_TEMPLATE__COMPLETE_WORKFLOW:-}
      CIO_TEMPLATE__VACATION_DELEGATION: ${CIO_TEMPLATE__VACATION_DELEGATION:-}
      EMAIL_HOST: ${EMAIL_HOST:-}
      EMAIL_PORT: ${EMAIL_PORT:-}
      EMAIL_HOST_USER: ${EMAIL_HOST_USER:-}
      EMAIL_HOST_PASSWORD: ${EMAIL_HOST_PASSWORD:-}
      EMAIL_USE_TLS: ${EMAIL_USE_TLS:-}
      EMAIL_USE_SSL: ${EMAIL_USE_SSL:-}
      EMAIL_TIMEOUT: ${EMAIL_TIMEOUT:-}
      AI: ${AI:-no}
      AI_PROVIDER: ${AI_PROVIDER:-}
      OPENAI_API_KEY: ${OPENAI_API_KEY:-}
      OPENAI_API_ORG: ${OPENAI_API_ORG:-}
      AI_HTTP_PROXY: ${AI_HTTP_PROXY:-}
      AI_HTTPS_PROXY: ${AI_HTTPS_PROXY:-}
      PUSH: ${PUSH:-no}
      PUSH_PROVIDER: ${PUSH_PROVIDER:-}
      FIREBASE_PUSH_APPLICATION_CREDENTIALS: ${FIREBASE_PUSH_APPLICATION_CREDENTIALS:-/pneumatic_backend/firebase-push.json}
      SENTRY_DSN: ${SENTRY_DSN:-}
      POSTGRES_HOST: ${POSTGRES_HOST:-postgres}
      POSTGRES_USER: ${POSTGRES_USER:-postgres_user}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres_password}
      POSTGRES_DB: ${POSTGRES_DB:-postgres_db}
      POSTGRES_REPLICA_HOST: ${POSTGRES_REPLICA_HOST:-postgres}
      POSTGRES_REPLICA_USER: ${POSTGRES_REPLICA_USER:-postgres_user}
      POSTGRES_REPLICA_PASSWORD: ${POSTGRES_REPLICA_PASSWORD:-postgres_password}
      POSTGRES_REPLICA_DB: ${POSTGRES_REPLICA_DB:-postgres_db}
      DJANGO_DEBUG: ${DJANGO_DEBUG:-no}
      ADMIN_PATH: ${ADMIN_PATH:-admin}
      DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-django_secret_django_secret_django_secret}
      DJANGO_SETTINGS_MODULE: src.settings
      AUTH_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/1"
      CACHE_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/0"
      CHANNELS_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/2"
      SESSION_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/3"
      CELERY_BROKER_URL: "amqp://${RABBITMQ_USER:-rabbitmq_user}:${RABBITMQ_PASSWORD:-rabbitmq_password}@rabbitmq:5672"
      ALLOWED_HOSTS: "pneumatic-nginx"
      VERIFICATION_CHECK: no
      CORS_ORIGIN_ALLOW_ALL: no
      CORS_ALLOW_CREDENTIALS: yes
      CORS_ORIGIN_WHITELIST: "http://localhost:8000"
      ENABLE_LOGGING: ${ENABLE_LOGGING:-no}
      FILE_SERVICE_URL: ${FILE_SERVICE_URL:-http://localhost/files}
      # Migration only: direct DB access for sync_files_to_file_service / run_file_migration.
      # Can be removed after all accounts are migrated to file-service.
      FILE_POSTGRES_USER: ${FILE_POSTGRES_USER:-pneumatic}
      FILE_POSTGRES_PASSWORD: ${FILE_POSTGRES_PASSWORD:-pneumatic}
      FILE_POSTGRES_DB: ${FILE_POSTGRES_DB:-pneumatic}
      FILE_POSTGRES_HOST: ${FILE_POSTGRES_HOST:-postgres}
      FILE_POSTGRES_PORT: ${FILE_POSTGRES_PORT:-5432}
      LOGS_BACKEND: ${LOGS_BACKEND:-}
      LOGS_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/4"
      LOGS_OTLP_ENDPOINT: ${LOGS_OTLP_ENDPOINT:-http://otel-collector:4318}
      LOGS_STREAM_MAXLEN: ${LOGS_STREAM_MAXLEN:-250000}
      LOGS_CONSUMER_BATCH_SIZE: ${LOGS_CONSUMER_BATCH_SIZE:-1000}
    expose:
      - 8000
    volumes:
      - ./backend:/pneumatic_backend
      - backend-socket:/tmp/gunicorn
      - backend-staticfiles:/pneumatic_backend/staticfiles
    depends_on:
      - postgres
      - rabbitmq
      - redis
    healthcheck:
      test: ["CMD", "pg_isready", "-h", postgres]
      interval: 5s
      timeout: 5s
      retries: 10
    networks:
      - pneumatic
    restart: always

  celery:
    build:
      context: ./backend
    image: pneumaticworkflow/pneumatic-celery:${TAG:-src}
    container_name: pneumatic-celery
    environment:
      BACKEND_URL: ${BACKEND_URL:-http://localhost:8001}
      FRONTEND_URL: ${FRONTEND_URL:-http://localhost}
      FORMS_URL: ${FORMS_URL:-http://localhost/forms}
      ENVIRONMENT: ${ENVIRONMENT:-Production}
      RELEASE: ${RELEASE:-1.0.0}
      LANGUAGE_CODE: ${LANGUAGE_CODE:-en} # Allowed values: en, fr, de, es, ru
      CAPTCHA: ${CAPTCHA:-no}
      RECAPTCHA_SITE_KEY: ${RECAPTCHA_SITE_KEY:-}
      RECAPTCHA_SECRET_KEY: ${RECAPTCHA_SECRET_KEY:-}
      RECAPTCHA_TESTING: ${RECAPTCHA_TESTING:-no}
      ANALYTICS: ${ANALYTICS:-no}
      ANALYTICS_DEBUG: ${ANALYTICS_DEBUG:-no}
      ANALYTICS_WRITE_KEY: ${ANALYTICS_WRITE_KEY:-}
      BILLING: ${BILLING:-no}
      STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}
      STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}
      STRIPE_WEBHOOK_IP_WHITELIST: ${STRIPE_WEBHOOK_IP_WHITELIST:-}
      SIGNUP: ${SIGNUP:-yes}
      MS_AUTH: ${MS_AUTH:-no}
      MS_CLIENT_ID: ${MS_CLIENT_ID:-}
      MS_CLIENT_SECRET: ${MS_CLIENT_SECRET:-}
      MS_AUTHORITY: ${MS_AUTHORITY:-}
      GOOGLE_AUTH: ${GOOGLE_AUTH:-no}
      GOOGLE_OAUTH2_CLIENT_ID: ${GOOGLE_OAUTH2_CLIENT_ID:-}
      GOOGLE_OAUTH2_CLIENT_SECRET: ${GOOGLE_OAUTH2_CLIENT_SECRET:-}
      GOOGLE_OAUTH2_REDIRECT_URI: ${GOOGLE_OAUTH2_REDIRECT_URI:-}
      SSO_AUTH: ${SSO_AUTH:-no}
      SSO_PROVIDER: ${SSO_PROVIDER:-} # Allowed values: okta, auth0
      OKTA_DOMAIN: ${OKTA_DOMAIN:-}
      OKTA_CLIENT_ID: ${OKTA_CLIENT_ID:-}
      OKTA_CLIENT_SECRET: ${OKTA_CLIENT_SECRET:-}
      OKTA_REDIRECT_URI: ${OKTA_REDIRECT_URI:-}
      AUTH0_CLIENT_ID: ${AUTH0_CLIENT_ID:-}
      AUTH0_CLIENT_SECRET: ${AUTH0_CLIENT_SECRET:-}
      AUTH0_DOMAIN: ${AUTH0_DOMAIN:-}
      AUTH0_REDIRECT_URI: ${AUTH0_REDIRECT_URI:-}
      EMAIL: ${EMAIL:-no}           # Disable send emails
      EMAIL_PROVIDER: ${EMAIL_PROVIDER:-}
      CIO_WEBHOOK_API_VERSION: ${CIO_WEBHOOK_API_VERSION:-}
      CIO_WEBHOOK_API_KEY: ${CIO_WEBHOOK_API_KEY:-}
      CIO_TRANSACTIONAL_API_KEY: ${CIO_TRANSACTIONAL_API_KEY:-}
      CIO_TEMPLATE__RESET_PASSWORD: ${CIO_TEMPLATE__RESET_PASSWORD:-}
      CIO_TEMPLATE__INVITE: ${CIO_TEMPLATE__INVITE:-}
      CIO_TEMPLATE__USER_DEACTIVATED: ${CIO_TEMPLATE__USER_DEACTIVATED:-}
      CIO_TEMPLATE__NEW_TASK: ${CIO_TEMPLATE__NEW_TASK:-}
      CIO_TEMPLATE__TASK_RETURNED: ${CIO_TEMPLATE__TASK_RETURNED:-}
      CIO_TEMPLATE__ACCOUNT_VERIFICATION: ${CIO_TEMPLATE__ACCOUNT_VERIFICATION:-}
      CIO_TEMPLATE__WORKFLOWS_DIGEST: ${CIO_TEMPLATE__WORKFLOWS_DIGEST:-}
      CIO_TEMPLATE__TASKS_DIGEST: ${CIO_TEMPLATE__TASKS_DIGEST:-}
      CIO_TEMPLATE__USER_TRANSFER: ${CIO_TEMPLATE__USER_TRANSFER:-}
      CIO_TEMPLATE__UNREAD_NOTIFICATIONS: ${CIO_TEMPLATE__UNREAD_NOTIFICATIONS:-}
      CIO_TEMPLATE__GUEST_NEW_TASK: ${CIO_TEMPLATE__GUEST_NEW_TASK:-}
      CIO_TEMPLATE__OVERDUE_TASK: ${CIO_TEMPLATE__OVERDUE_TASK:-}
      CIO_TEMPLATE__MENTION: ${CIO_TEMPLATE__MENTION:-}
      CIO_TEMPLATE__TASK_REMINDER: ${CIO_TEMPLATE__TASK_REMINDER:-}
      CIO_TEMPLATE__COMPLETE_WORKFLOW: ${CIO_TEMPLATE__COMPLETE_WORKFLOW:-}
      CIO_TEMPLATE__VACATION_DELEGATION: ${CIO_TEMPLATE__VACATION_DELEGATION:-}
      EMAIL_HOST: ${EMAIL_HOST:-}
      EMAIL_PORT: ${EMAIL_PORT:-}
      EMAIL_HOST_USER: ${EMAIL_HOST_USER:-}
      EMAIL_HOST_PASSWORD: ${EMAIL_HOST_PASSWORD:-}
      EMAIL_USE_TLS: ${EMAIL_USE_TLS:-}
      EMAIL_USE_SSL: ${EMAIL_USE_SSL:-}
      EMAIL_TIMEOUT: ${EMAIL_TIMEOUT:-}
      AI: ${AI:-no}
      AI_PROVIDER: ${AI_PROVIDER:-}
      OPENAI_API_KEY: ${OPENAI_API_KEY:-}
      OPENAI_API_ORG: ${OPENAI_API_ORG:-}
      AI_HTTP_PROXY: ${AI_HTTP_PROXY:-}
      AI_HTTPS_PROXY: ${AI_HTTPS_PROXY:-}
      PUSH: ${PUSH:-no}
      PUSH_PROVIDER: ${PUSH_PROVIDER:-}
      FIREBASE_PUSH_APPLICATION_CREDENTIALS: ${FIREBASE_PUSH_APPLICATION_CREDENTIALS:-/pneumatic_backend/firebase-push.json}
      SENTRY_DSN: ${SENTRY_DSN:-}
      POSTGRES_HOST: ${POSTGRES_HOST:-postgres}
      POSTGRES_USER: ${POSTGRES_USER:-postgres_user}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres_password}
      POSTGRES_DB: ${POSTGRES_DB:-postgres_db}
      POSTGRES_REPLICA_HOST: ${POSTGRES_REPLICA_HOST:-postgres}
      POSTGRES_REPLICA_USER: ${POSTGRES_REPLICA_USER:-postgres_user}
      POSTGRES_REPLICA_PASSWORD: ${POSTGRES_REPLICA_PASSWORD:-postgres_password}
      POSTGRES_REPLICA_DB: ${POSTGRES_REPLICA_DB:-postgres_db}
      DJANGO_DEBUG: ${DJANGO_DEBUG:-no}
      ADMIN_PATH: ${ADMIN_PATH:-admin}
      DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-django_secret_django_secret_django_secret}
      DJANGO_SETTINGS_MODULE: src.settings
      AUTH_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/1"
      CACHE_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/0"
      CHANNELS_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/2"
      SESSION_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/3"
      CELERY_BROKER_URL: "amqp://${RABBITMQ_USER:-rabbitmq_user}:${RABBITMQ_PASSWORD:-rabbitmq_password}@rabbitmq:5672"
      ALLOWED_HOSTS: "pneumatic-nginx"
      VERIFICATION_CHECK: no
      CORS_ORIGIN_ALLOW_ALL: no
      CORS_ALLOW_CREDENTIALS: yes
      CORS_ORIGIN_WHITELIST: "http://localhost:8000"
      ENABLE_LOGGING: ${ENABLE_LOGGING:-no}
      FILE_SERVICE_URL: ${FILE_SERVICE_URL:-http://localhost/files}
      # Migration only: direct DB access for sync_files_to_file_service / run_file_migration.
      # Can be removed after all accounts are migrated to file-service.
      FILE_POSTGRES_USER: ${FILE_POSTGRES_USER:-pneumatic}
      FILE_POSTGRES_PASSWORD: ${FILE_POSTGRES_PASSWORD:-pneumatic}
      FILE_POSTGRES_DB: ${FILE_POSTGRES_DB:-pneumatic}
      FILE_POSTGRES_HOST: ${FILE_POSTGRES_HOST:-postgres}
      FILE_POSTGRES_PORT: ${FILE_POSTGRES_PORT:-5432}
      LOGS_BACKEND: ${LOGS_BACKEND:-}
      LOGS_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/4"
      LOGS_OTLP_ENDPOINT: ${LOGS_OTLP_ENDPOINT:-http://otel-collector:4318}
      LOGS_STREAM_MAXLEN: ${LOGS_STREAM_MAXLEN:-250000}
      LOGS_CONSUMER_BATCH_SIZE: ${LOGS_CONSUMER_BATCH_SIZE:-1000}
    volumes:
      - ./backend:/pneumatic_backend
    command: >
      sh -c "celery --app src.celery_app:app worker -l warning"
    depends_on:
      - postgres
      - rabbitmq
      - redis
    networks:
      - pneumatic
    restart: always

  celery-beat:
    build:
      context: ./backend
    image: pneumaticworkflow/pneumatic-celery-beat:${TAG:-src}
    container_name: pneumatic-celery-beat
    environment:
      BACKEND_URL: ${BACKEND_URL:-http://localhost:8001}
      FRONTEND_URL: ${FRONTEND_URL:-http://localhost}
      FORMS_URL: ${FORMS_URL:-http://localhost/forms}
      ENVIRONMENT: ${ENVIRONMENT:-Production}
      RELEASE: ${RELEASE:-1.0.0}
      LANGUAGE_CODE: ${LANGUAGE_CODE:-en} # Allowed values: en, fr, de, es, ru
      CAPTCHA: ${CAPTCHA:-no}
      RECAPTCHA_SITE_KEY: ${RECAPTCHA_SITE_KEY:-}
      RECAPTCHA_SECRET_KEY: ${RECAPTCHA_SECRET_KEY:-}
      RECAPTCHA_TESTING: ${RECAPTCHA_TESTING:-no}
      ANALYTICS: ${ANALYTICS:-no}
      ANALYTICS_DEBUG: ${ANALYTICS_DEBUG:-no}
      ANALYTICS_WRITE_KEY: ${ANALYTICS_WRITE_KEY:-}
      BILLING: ${BILLING:-no}
      STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-}
      STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-}
      STRIPE_WEBHOOK_IP_WHITELIST: ${STRIPE_WEBHOOK_IP_WHITELIST:-}
      SIGNUP: ${SIGNUP:-yes}
      MS_AUTH: ${MS_AUTH:-no}
      MS_CLIENT_ID: ${MS_CLIENT_ID:-}
      MS_CLIENT_SECRET: ${MS_CLIENT_SECRET:-}
      MS_AUTHORITY: ${MS_AUTHORITY:-}
      GOOGLE_AUTH: ${GOOGLE_AUTH:-no}
      GOOGLE_OAUTH2_CLIENT_ID: ${GOOGLE_OAUTH2_CLIENT_ID:-}
      GOOGLE_OAUTH2_CLIENT_SECRET: ${GOOGLE_OAUTH2_CLIENT_SECRET:-}
      GOOGLE_OAUTH2_REDIRECT_URI: ${GOOGLE_OAUTH2_REDIRECT_URI:-}
      SSO_AUTH: ${SSO_AUTH:-no}
      SSO_PROVIDER: ${SSO_PROVIDER:-} # Allowed values: okta, auth0
      OKTA_DOMAIN: ${OKTA_DOMAIN:-}
      OKTA_CLIENT_ID: ${OKTA_CLIENT_ID:-}
      OKTA_CLIENT_SECRET: ${OKTA_CLIENT_SECRET:-}
      OKTA_REDIRECT_URI: ${OKTA_REDIRECT_URI:-}
      AUTH0_CLIENT_ID: ${AUTH0_CLIENT_ID:-}
      AUTH0_CLIENT_SECRET: ${AUTH0_CLIENT_SECRET:-}
      AUTH0_DOMAIN: ${AUTH0_DOMAIN:-}
      AUTH0_REDIRECT_URI: ${AUTH0_REDIRECT_URI:-}
      EMAIL: ${EMAIL:-no}           # Disable send emails
      EMAIL_PROVIDER: ${EMAIL_PROVIDER:-}
      CIO_WEBHOOK_API_VERSION: ${CIO_WEBHOOK_API_VERSION:-}
      CIO_WEBHOOK_API_KEY: ${CIO_WEBHOOK_API_KEY:-}
      CIO_TRANSACTIONAL_API_KEY: ${CIO_TRANSACTIONAL_API_KEY:-}
      CIO_TEMPLATE__RESET_PASSWORD: ${CIO_TEMPLATE__RESET_PASSWORD:-}
      CIO_TEMPLATE__INVITE: ${CIO_TEMPLATE__INVITE:-}
      CIO_TEMPLATE__USER_DEACTIVATED: ${CIO_TEMPLATE__USER_DEACTIVATED:-}
      CIO_TEMPLATE__NEW_TASK: ${CIO_TEMPLATE__NEW_TASK:-}
      CIO_TEMPLATE__TASK_RETURNED: ${CIO_TEMPLATE__TASK_RETURNED:-}
      CIO_TEMPLATE__ACCOUNT_VERIFICATION: ${CIO_TEMPLATE__ACCOUNT_VERIFICATION:-}
      CIO_TEMPLATE__WORKFLOWS_DIGEST: ${CIO_TEMPLATE__WORKFLOWS_DIGEST:-}
      CIO_TEMPLATE__TASKS_DIGEST: ${CIO_TEMPLATE__TASKS_DIGEST:-}
      CIO_TEMPLATE__USER_TRANSFER: ${CIO_TEMPLATE__USER_TRANSFER:-}
      CIO_TEMPLATE__UNREAD_NOTIFICATIONS: ${CIO_TEMPLATE__UNREAD_NOTIFICATIONS:-}
      CIO_TEMPLATE__GUEST_NEW_TASK: ${CIO_TEMPLATE__GUEST_NEW_TASK:-}
      CIO_TEMPLATE__OVERDUE_TASK: ${CIO_TEMPLATE__OVERDUE_TASK:-}
      CIO_TEMPLATE__MENTION: ${CIO_TEMPLATE__MENTION:-}
      CIO_TEMPLATE__TASK_REMINDER: ${CIO_TEMPLATE__TASK_REMINDER:-}
      CIO_TEMPLATE__COMPLETE_WORKFLOW: ${CIO_TEMPLATE__COMPLETE_WORKFLOW:-}
      CIO_TEMPLATE__VACATION_DELEGATION: ${CIO_TEMPLATE__VACATION_DELEGATION:-}
      EMAIL_HOST: ${EMAIL_HOST:-}
      EMAIL_PORT: ${EMAIL_PORT:-}
      EMAIL_HOST_USER: ${EMAIL_HOST_USER:-}
      EMAIL_HOST_PASSWORD: ${EMAIL_HOST_PASSWORD:-}
      EMAIL_USE_TLS: ${EMAIL_USE_TLS:-}
      EMAIL_USE_SSL: ${EMAIL_USE_SSL:-}
      EMAIL_TIMEOUT: ${EMAIL_TIMEOUT:-}
      AI: ${AI:-no}
      AI_PROVIDER: ${AI_PROVIDER:-}
      OPENAI_API_KEY: ${OPENAI_API_KEY:-}
      OPENAI_API_ORG: ${OPENAI_API_ORG:-}
      AI_HTTP_PROXY: ${AI_HTTP_PROXY:-}
      AI_HTTPS_PROXY: ${AI_HTTPS_PROXY:-}
      PUSH: ${PUSH:-no}
      PUSH_PROVIDER: ${PUSH_PROVIDER:-}
      FIREBASE_PUSH_APPLICATION_CREDENTIALS: ${FIREBASE_PUSH_APPLICATION_CREDENTIALS:-/pneumatic_backend/firebase-push.json}
      SENTRY_DSN: ${SENTRY_DSN:-}
      POSTGRES_HOST: ${POSTGRES_HOST:-postgres}
      POSTGRES_USER: ${POSTGRES_USER:-postgres_user}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres_password}
      POSTGRES_DB: ${POSTGRES_DB:-postgres_db}
      POSTGRES_REPLICA_HOST: ${POSTGRES_REPLICA_HOST:-postgres}
      POSTGRES_REPLICA_USER: ${POSTGRES_REPLICA_USER:-postgres_user}
      POSTGRES_REPLICA_PASSWORD: ${POSTGRES_REPLICA_PASSWORD:-postgres_password}
      POSTGRES_REPLICA_DB: ${POSTGRES_REPLICA_DB:-postgres_db}
      DJANGO_DEBUG: ${DJANGO_DEBUG:-no}
      ADMIN_PATH: ${ADMIN_PATH:-admin}
      DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-django_secret_django_secret_django_secret}
      DJANGO_SETTINGS_MODULE: src.settings
      AUTH_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/1"
      CACHE_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/0"
      CHANNELS_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/2"
      SESSION_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/3"
      CELERY_BROKER_URL: "amqp://${RABBITMQ_USER:-rabbitmq_user}:${RABBITMQ_PASSWORD:-rabbitmq_password}@rabbitmq:5672"
      ALLOWED_HOSTS: "pneumatic-nginx"
      VERIFICATION_CHECK: no
      CORS_ORIGIN_ALLOW_ALL: no
      CORS_ALLOW_CREDENTIALS: yes
      CORS_ORIGIN_WHITELIST: "http://localhost:8000"
      ENABLE_LOGGING: ${ENABLE_LOGGING:-no}
      FILE_SERVICE_URL: ${FILE_SERVICE_URL:-http://localhost/files}
      # Migration only: direct DB access for sync_files_to_file_service / run_file_migration.
      # Can be removed after all accounts are migrated to file-service.
      FILE_POSTGRES_USER: ${FILE_POSTGRES_USER:-pneumatic}
      FILE_POSTGRES_PASSWORD: ${FILE_POSTGRES_PASSWORD:-pneumatic}
      FILE_POSTGRES_DB: ${FILE_POSTGRES_DB:-pneumatic}
      FILE_POSTGRES_HOST: ${FILE_POSTGRES_HOST:-postgres}
      FILE_POSTGRES_PORT: ${FILE_POSTGRES_PORT:-5432}
      LOGS_BACKEND: ${LOGS_BACKEND:-}
      LOGS_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/4"
      LOGS_OTLP_ENDPOINT: ${LOGS_OTLP_ENDPOINT:-http://otel-collector:4318}
      LOGS_STREAM_MAXLEN: ${LOGS_STREAM_MAXLEN:-250000}
      LOGS_CONSUMER_BATCH_SIZE: ${LOGS_CONSUMER_BATCH_SIZE:-1000}
    volumes:
      - ./backend:/pneumatic_backend
    command: celery --app src.celery_app:app beat -l warning -S django
    depends_on:
      - postgres
      - rabbitmq
      - redis
    networks:
      - pneumatic
    restart: always

  frontend:
    build:
      context: ./frontend
    image: pneumaticworkflow/pneumatic-frontend:${TAG:-src}
    container_name: pneumatic-frontend
    environment:
      BACKEND_PRIVATE_URL: ${BACKEND_PRIVATE_URL:-http://pneumatic-nginx/}
      BACKEND_URL: ${BACKEND_URL:-http://localhost:8001}
      FRONTEND_URL: ${FRONTEND_URL:-http://localhost}
      WSS_URL: ${WSS_URL:-ws://localhost:8001/}
      FORM_DOMAIN: ${FORM_DOMAIN:-}
      MCS_RUN_ENV: ${MCS_RUN_ENV:-prod}
      NODE_OPTIONS: ${NODE_OPTIONS:---max-old-space-size=3072}
      LANGUAGE_CODE: ${LANGUAGE_CODE:-en} # Allowed values: en, fr, de, es, ru
      CAPTCHA: ${CAPTCHA:-no}
      ANALYTICS: ${ANALYTICS:-no}
      ANALYTICS_WRITE_KEY: ${ANALYTICS_WRITE_KEY:-}
      BILLING: ${BILLING:-no}
      SIGNUP: ${SIGNUP:-yes}
      MS_AUTH: ${MS_AUTH:-no}
      GOOGLE_AUTH: ${GOOGLE_AUTH:-no}
      SSO_AUTH: ${SSO_AUTH:-no}
      SSO_PROVIDER: ${SSO_PROVIDER:-} # Allowed values: okta, auth0
      AI: ${AI:-no}
      PUSH: ${PUSH:-no}
      FILE_SERVICE_URL: ${FILE_SERVICE_URL:-http://localhost/files}
      RELEASE: ${RELEASE:-1.0.0}
      SENTRY_DSN: ${SENTRY_FRONTEND_DSN:-}
      SENTRY_RELEASE: ${RELEASE:-1.0.0}
      FIREBASE_VAPID_KEY: ${FIREBASE_VAPID_KEY:-}
      FIREBASE_API_KEY: ${FIREBASE_API_KEY:-}
      FIREBASE_AUTH_DOMAIN: ${FIREBASE_AUTH_DOMAIN:-}
      FIREBASE_PROJECT_ID: ${FIREBASE_PROJECT_ID:-}
      FIREBASE_STORAGE_BUCKET: ${FIREBASE_STORAGE_BUCKET:-}
      FIREBASE_SENDER_ID: ${FIREBASE_SENDER_ID:-}
      FIREBASE_APP_ID: ${FIREBASE_APP_ID:-}
      FIREBASE_MEASUREMENT_ID: ${FIREBASE_MEASUREMENT_ID:-}
      RECAPTCHA_SITE_KEY: ${RECAPTCHA_SITE_KEY:-}
    command: pm2-runtime start pm2.json
    expose:
      - 8000
    networks:
      - pneumatic
    restart: always

  nginx:
    image: nginx:1.25.4
    container_name: pneumatic-nginx
    environment:
      SSL: ${SSL:-no}
      SERVER_ADDRESS: ${SERVER_ADDRESS:-localhost}
      FORM_DOMAIN: ${FORM_DOMAIN:-}
      NGINX_ENVSUBST_OUTPUT_DIR: /etc/nginx/
      NGINX_ENVSUBST_TEMPLATE_DIR: /etc/nginx/templates
    volumes:
      - ./nginx/logs/:/var/log/nginx/
      - ./nginx/keys/:/etc/keys/:ro
      - ./nginx/www/:/var/www/:ro
      - ${NGINX_CONF_TEMPLATE:-./nginx/templates/}:/etc/nginx/templates
      - ./nginx/includes/:/etc/nginx/includes/:ro
      - backend-socket:/tmp/gunicorn/
      - backend-staticfiles:/tmp/backend-staticfiles/
    ports:
      - 80:80
      - 443:443
      - 8001:8001
    networks:
      - pneumatic
    depends_on:
      - backend
      - frontend
      - file-service
    restart: always

  file-service:
    build:
      context: ./storage
    image: pneumaticworkflow/pneumatic-file-service:${TAG:-src}
    container_name: pneumatic-file-service
    environment:
      DEBUG: ${FILE_DEBUG:-false}
      CONFIG: ${FILE_CONFIG:-Production}
      WORKERS: ${FILE_WORKERS:-1}
      PORT: ${FILE_PORT:-8000}
      FRONTEND_URL: ${FRONTEND_URL:-http://localhost}
      FORMS_URL: ${FORMS_URL:-http://localhost/forms}
      POSTGRES_USER: ${FILE_POSTGRES_USER:-pneumatic}
      POSTGRES_PASSWORD: ${FILE_POSTGRES_PASSWORD:-pneumatic}
      POSTGRES_DB: ${FILE_POSTGRES_DB:-pneumatic}
      POSTGRES_HOST: ${FILE_POSTGRES_HOST:-postgres}
      POSTGRES_PORT: ${FILE_POSTGRES_PORT:-5432}
      STORAGE_TYPE: ${FILE_STORAGE_TYPE:-local}
      SEAWEEDFS_S3_ENDPOINT: ${FILE_SEAWEEDFS_S3_ENDPOINT:-http://seaweedfs-filer:8333}
      SEAWEEDFS_S3_ACCESS_KEY: ${FILE_SEAWEEDFS_S3_ACCESS_KEY:-any-secret-key-will-work}
      SEAWEEDFS_S3_SECRET_KEY: ${FILE_SEAWEEDFS_S3_SECRET_KEY:-any-secret-key-will-work}
      SEAWEEDFS_S3_REGION: ${FILE_SEAWEEDFS_S3_REGION:-us-central1}
      SEAWEEDFS_S3_USE_SSL: ${FILE_SEAWEEDFS_S3_USE_SSL:-false}
      GCS_S3_ENDPOINT: ${FILE_GCS_S3_ENDPOINT:-}
      GCS_S3_ACCESS_KEY: ${FILE_GCS_S3_ACCESS_KEY:-}
      GCS_S3_SECRET_KEY: ${FILE_GCS_S3_SECRET_KEY:-}
      GCS_S3_REGION: ${FILE_GCS_S3_REGION:-}
      FASTAPI_BASE_URL: ${FILE_FASTAPI_BASE_URL:-http://localhost/files}
      BUCKET_PREFIX: ${FILE_BUCKET_PREFIX:-pneumatic-dev-test}
      MAX_FILE_SIZE: ${FILE_MAX_FILE_SIZE:-104857600}
      CHUNK_SIZE: ${FILE_CHUNK_SIZE:-1048576}
      AUTH_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/1"
      KEY_PREFIX_REDIS: ${FILE_KEY_PREFIX_REDIS:-:1:}
      DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY:-django_secret_django_secret_django_secret}
      AUTH_TOKEN_ITERATIONS: ${FILE_AUTH_TOKEN_ITERATIONS:-1}
      BACKEND_PRIVATE_URL: ${BACKEND_PRIVATE_URL:-http://pneumatic-nginx/}
      SENTRY_DSN: ${SENTRY_FILE_DSN:-}
      SENTRY_ENVIRONMENT: ${ENVIRONMENT:-Production}
      LOGS_BACKEND: ${LOGS_BACKEND:-}
      LOGS_REDIS_URL: "redis://:${REDIS_PASSWORD:-redis_password}@redis:6379/4"
      LOGS_STREAM_MAXLEN: ${LOGS_STREAM_MAXLEN:-250000}
    command: >
      sh -c "poetry run alembic -c src/shared_kernel/database/alembic.ini upgrade head &&
             poetry run uvicorn src.main:app --host 0.0.0.0 --port ${FILE_PORT:-8000} --workers ${FILE_WORKERS:-1}"
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    expose:
      - 8000
    networks:
      - pneumatic
    restart: always

  seaweedfs-master:
    image: chrislusf/seaweedfs:3.95
    container_name: pneumatic-seaweedfs-master
    command: master -ip=seaweedfs-master -port=9333
    expose:
      - 9333
    volumes:
      - ./seaweedfs/master/data:/data:rw
    networks:
      - pneumatic

  seaweedfs-volume:
    image: chrislusf/seaweedfs:3.95
    container_name: pneumatic-seaweedfs-volume
    command:
      - volume
      - -mserver=seaweedfs-master:9333
      - -port=8080
      - -ip=seaweedfs-volume
      - -publicUrl=localhost:8080
    expose:
      - 8080
    depends_on:
      - seaweedfs-master
    volumes:
      - ./seaweedfs/volume/data:/data:rw
    networks:
      - pneumatic

  seaweedfs-filer:
    image: chrislusf/seaweedfs:3.95
    container_name: pneumatic-seaweedfs-filer
    command: filer -master="seaweedfs-master:9333" -s3 -s3.port=8333 -s3.config=/etc/seaweedfs/s3.json
    expose:
      - 8333
    depends_on:
      - seaweedfs-master
      - seaweedfs-volume
    volumes:
      - ./storage/seaweedfs/filer.toml:/etc/seaweedfs/filer.toml
      - ./storage/seaweedfs/s3.json:/etc/seaweedfs/s3.json:ro
      - ./seaweedfs/filer/data:/data:rw
    networks:
      - pneumatic

  # The collector of the audit journal. Off by default: it starts only
  # with the profile named after LOGS_BACKEND, which start.sh passes on
  # its own (by hand: COMPOSE_PROFILES, see default.env). The store it
  # writes into lives on a machine of its own - logging/grafana for Loki
  # and Grafana, logging/elasticsearch for Elasticsearch and Kibana.
  otel-collector:
    image: otel/opentelemetry-collector-contrib:0.160.0
    container_name: pneumatic-otel-collector
    profiles: ["logs-otlp", "logs-elasticsearch"]
    command:
      - --config=/etc/otel/base.yaml
      - --config=/etc/otel/backend-${LOGS_BACKEND:-}.yaml
    environment:
      LOGS_OTLP_EXPORT_ENDPOINT: ${LOGS_OTLP_EXPORT_ENDPOINT:-}
      LOGS_OTLP_EXPORT_AUTH: ${LOGS_OTLP_EXPORT_AUTH:-}
      LOGS_ELASTICSEARCH_URL: ${LOGS_ELASTICSEARCH_URL:-}
      LOGS_ELASTICSEARCH_API_KEY: ${LOGS_ELASTICSEARCH_API_KEY:-}
      LOGS_ELASTICSEARCH_USER: ${LOGS_ELASTICSEARCH_USER:-}
      LOGS_ELASTICSEARCH_PASSWORD: ${LOGS_ELASTICSEARCH_PASSWORD:-}
      LOGS_ELASTICSEARCH_CA_FILE: ${LOGS_ELASTICSEARCH_CA_FILE:-/etc/otel/es-ca.crt}
      LOGS_ELASTICSEARCH_QUEUE_DIR: ${LOGS_ELASTICSEARCH_QUEUE_DIR:-/var/lib/otelcol/queue}
      LOGS_ELASTICSEARCH_INDEX: ${LOGS_ELASTICSEARCH_INDEX:-logs-pneumatic.events.otel-default}
    volumes:
      - ./otel-collector:/etc/otel:ro
      # The disk queue of LOGS_BACKEND=elasticsearch, see default.env
      - otel-queue:/var/lib/otelcol
    expose:
      - 4318     # OTLP/HTTP receiver
      - 13133    # health_check extension
    networks:
      - pneumatic
    restart: always

networks:
  pneumatic:

volumes:
  backend-staticfiles:
  backend-socket:
  otel-queue: