name: st-messages services: postgresql: image: postgres:16.6 ports: - "8912:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] interval: 1s timeout: 2s retries: 300 env_file: - env.d/development/postgresql.defaults - env.d/development/postgresql.local redis: image: redis:5 ports: - "8913:6379" opensearch: image: opensearchproject/opensearch:2.19.2 environment: - discovery.type=single-node - bootstrap.memory_lock=true - "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m" - "DISABLE_INSTALL_DEMO_CONFIG=true" - "DISABLE_SECURITY_PLUGIN=true" # - http.cors.enabled=true # - "http.cors.allow-origin=/.*/" ports: - "8914:9200" # REST API - "8915:9600" # Performance Analyzer healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9200"] interval: 1s timeout: 5s retries: 60 ulimits: memlock: soft: -1 # Set memlock to unlimited (no soft or hard limit) hard: -1 nofile: soft: 65536 # Maximum number of open files for the opensearch user - set to at least 65536 hard: 65536 mailcatcher: image: maildev/maildev:2.2.1 ports: - "8904:1080" - "8917:1025" objectstorage: # user: ${DOCKER_USER:-1000} image: rustfs/rustfs:1.0.0-alpha.83 environment: - RUSTFS_ACCESS_KEY=st-messages - RUSTFS_SECRET_KEY=password - RUSTFS_CONSOLE_ENABLE=true - RUSTFS_ADDRESS=0.0.0.0:9000 - RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9001 - RUSTFS_CORS_ALLOWED_ORIGINS=* - RUSTFS_CONSOLE_CORS_ALLOWED_ORIGINS=* ports: - "8906:9000" - "8907:9001" healthcheck: test: [ "CMD", "sh", "-c", "curl -f http://127.0.0.1:9000/health && curl -f http://127.0.0.1:9001/rustfs/console/health", ] interval: 1s timeout: 5s retries: 60 start_period: 0s volumes: - objectstorage-data:/data backend-base: build: context: src/backend additional_contexts: jmap-email: ./src/jmap-email target: runtime-dev args: DOCKER_USER: ${DOCKER_USER:-1000} user: ${DOCKER_USER:-1000} volumes: - ./src/backend:/app - ./data/static:/data/static # Live-mount the jmap-email package over the frozen install so # source edits propagate without a rebuild. The wheel installed # at ``/venv/lib/${PYTHON_VERSION}/site-packages/jmap_email`` is # overlaid with the editable source. Override ``PYTHON_VERSION`` # in the environment when the backend's Python floor moves. - ./src/jmap-email/jmap_email:/venv/lib/${PYTHON_VERSION:-python3.14}/site-packages/jmap_email healthcheck: test: ["CMD", "python", "-c", "import urllib.request as u; u.urlopen('http://localhost:8000/__heartbeat__/', timeout=1)"] interval: 3s retries: 3 start_period: 10s backend-dev: extends: backend-base environment: - PYLINTHOME=/app/.pylint.d - DJANGO_CONFIGURATION=Development env_file: - env.d/development/backend.defaults - env.d/development/backend.local ports: - "8901:8000" depends_on: postgresql: condition: service_healthy # restart: true objectstorage: condition: service_healthy redis: condition: service_started opensearch: condition: service_healthy keycloak: condition: service_started mailcatcher: condition: service_started backend-db: extends: backend-base profiles: - tools environment: - DJANGO_CONFIGURATION=DevelopmentMinimal env_file: - env.d/development/backend.defaults - env.d/development/backend.local ports: - "8901:8000" depends_on: postgresql: condition: service_healthy # restart: true backend-uv: profiles: - tools volumes: - ./src/backend:/app # Sibling package for path-based uv dependency. Both `backend` # and `jmap-email` must be visible at the SAME relative path # from /app as they are on the host (../jmap-email), so the # ``[tool.uv.sources]`` declaration in src/backend/pyproject.toml # resolves correctly inside the container. - ./src/jmap-email:/jmap-email build: context: src/backend additional_contexts: jmap-email: ./src/jmap-email target: uv pull_policy: build worker-dev: build: context: src/backend additional_contexts: jmap-email: ./src/jmap-email target: runtime-dev args: DOCKER_USER: ${DOCKER_USER:-1000} user: ${DOCKER_USER:-1000} command: ["python", "worker.py", "--loglevel=DEBUG"] environment: - DJANGO_CONFIGURATION=Development env_file: - env.d/development/backend.defaults - env.d/development/backend.local volumes: - ./src/backend:/app - ./data/static:/data/static mem_limit: 2G depends_on: - backend-dev worker-ui: build: context: src/backend additional_contexts: jmap-email: ./src/jmap-email target: runtime-dev args: DOCKER_USER: ${DOCKER_USER:-1000} user: ${DOCKER_USER:-1000} depends_on: - redis environment: - FLOWER_UNAUTHENTICATED_API=true - DJANGO_CONFIGURATION=Development env_file: - env.d/development/backend.defaults - env.d/development/backend.local volumes: - ./src/backend:/app ports: - "8903:8803" command: celery -A messages.celery_app flower --port=8803 frontend-base: user: "${DOCKER_USER:-1000}" build: context: ./src/frontend dockerfile: Dockerfile target: frontend-deps args: DOCKER_USER: ${DOCKER_USER:-1000} frontend-dev: extends: frontend-base env_file: - env.d/development/frontend.defaults - env.d/development/frontend.local command: ["npm", "run", "dev"] volumes: - ./src/frontend/:/home/frontend/ ports: - "8900:3000" frontend-tools: extends: frontend-base profiles: - frontend-tools volumes: - ./src/backend/core/api/openapi.json:/home/backend/core/api/openapi.json - ./src/frontend/:/home/frontend/ frontend-tools-amd64: extends: frontend-tools platform: linux/amd64 crowdin: image: crowdin/cli:4.11.0 volumes: - ".:/app" env_file: - env.d/development/crowdin.defaults - env.d/development/crowdin.local user: "${DOCKER_USER:-1000}" working_dir: /app mta-in: build: context: src/mta-in target: runtime-prod env_file: - env.d/development/mta-in.defaults - env.d/development/mta-in.local ports: - "8910:25" depends_on: - backend-dev mta-in-test: profiles: - tools build: context: src/mta-in target: runtime-dev env_file: - env.d/development/mta-in.defaults - env.d/development/mta-in.local environment: - EXEC_CMD=true - MDA_API_BASE_URL=http://localhost:8000/api/mail/ - MTA_HOST=localhost command: pytest -vvs tests/ volumes: - ./src/mta-in:/app mta-in-uv: profiles: - tools volumes: - ./src/mta-in:/app build: context: src/mta-in target: uv pull_policy: build mta-out: build: context: src/mta-out target: runtime-prod env_file: - env.d/development/mta-out.defaults - env.d/development/mta-out.local ports: - "8911:587" depends_on: mailcatcher: condition: service_started mta-out-test: profiles: - tools build: context: src/mta-out target: runtime-dev env_file: - env.d/development/mta-out.defaults - env.d/development/mta-out.local environment: - EXEC_CMD=true - MTA_OUT_SMTP_HOST=localhost:587 - MTA_OUT_SMTP_USERNAME=user - MTA_OUT_SMTP_PASSWORD=pass - SMTP_RELAY_HOST=localhost:2525 command: pytest -vvs tests/ volumes: - ./src/mta-out:/app socks-proxy: build: context: src/socks-proxy target: runtime env_file: - env.d/development/socks-proxy.defaults - env.d/development/socks-proxy.local ports: - "8916:1080" socks-proxy-test: profiles: - tools build: context: src/socks-proxy/tests environment: - SOCKS_PROXY1=user1:pwd1@socks-proxy:1080 - SOCKS_PROXY2=user2:pwd2@socks-proxy:1080 depends_on: socks-proxy: condition: service_started mta-out-uv: profiles: - tools volumes: - ./src/mta-out:/app build: context: src/mta-out target: uv pull_policy: build keycloak: image: quay.io/keycloak/keycloak:26.6.1 volumes: - ./src/keycloak/realm.json:/opt/keycloak/data/import/realm.json:ro - ./src/keycloak/themes/dsfr-2.2.1.jar:/opt/keycloak/providers/keycloak-theme.jar:ro - ./src/keycloak/bulk-role-membership/bulk-role-membership.jar:/opt/keycloak/providers/bulk-role-membership.jar:ro environment: - HOST=http://localhost:8902 - ADMIN_HOST=http://localhost:8902 command: - start-dev - --features=preview - --import-realm - --proxy-headers=xforwarded - --http-enabled=true - --hostname=$${HOST} - --hostname-admin=$${ADMIN_HOST} - --http-port=8802 env_file: - env.d/development/keycloak.defaults - env.d/development/keycloak.local ports: - "8902:8802" depends_on: - postgresql mpa: build: context: src/mpa/rspamd environment: - RSPAMD_password=password - PORT=8010 ports: - "8918:8010" depends_on: redis: condition: service_started mpa-test: profiles: - tools build: context: src/mpa/tests environment: - RSPAMD_URL=http://mpa:8010/_api - RSPAMD_AUTH=Bearer password command: pytest -vvs tests/ volumes: - ./src/mpa/tests:/app/tests depends_on: mpa: condition: service_started redis: condition: service_started # Self-contained jmap-email package tests. Zero infrastructure # dependencies (no DB, no opensearch, no redis) — the library has # no runtime deps. Source is mounted for instant feedback during # development. jmap-email-test: profiles: - tools build: context: src/jmap-email command: pytest -q tests/ volumes: - ./src/jmap-email/jmap_email:/app/jmap_email - ./src/jmap-email/tests:/app/tests - ./src/jmap-email/pyproject.toml:/app/pyproject.toml volumes: objectstorage-data: