38 KiB
arch-03. Docker Compose blueprint
Термины (имена бакетов S3, идентификаторы) — в
arch-00-glossary.md. Контракт Message Safety Service — вarch-02-api-contracts.md, раздел «api-backend ↔ message-safety». Переменные окружения и настройки — вarch-04-settings-and-content.md.
Назначение
Этот документ описывает целевой Docker Compose контур для первой production-like среды. Он не заменяет будущий docker-compose.yml, но задает требования, которым он должен соответствовать.
Требования к безопасности на уровне приложения и данных — в arch-01-system-architecture.md, раздел «Принципы безопасности». Настоящий документ описывает только инфраструктурную реализацию этих принципов в compose/nginx: TLS, маршрутизация, сетевые границы, rate limits на edge. Значения переменных окружения — в arch-04-settings-and-content.md. Дублировать прикладные требования (JWT, валидация, CORS в API, PII в логах и т.п.) здесь не нужно — они остаются в arch-01.
Единый compose-контур (обязательно)
Это зафиксированное архитектурное требование, а не рекомендация.
Принцип единого входа
- Весь backend-контур поднимается одной командой
docker compose up -dиз корня репозитория (backend/). - Корневой
docker-compose.yml— единственный источник правды для production-like среды. Отдельных compose-файлов для production-деплоя отдельных сервисов не должно быть. - Один
nginxподнимается из корневогоdocker-compose.ymlи является единой публичной точкой входа с маршрутизацией на все сервисы:/api/*→api-backend(REST иWS /api/v1/realtime; отдельный path/realtime/*не используется);/auth/*→keycloak;/bitrix/*(public:/bitrix/handler,/bitrix/install,/bitrix/placement,/health/*дляbitrix-local-app) →bitrix-local-app;/bitrix/sync/*(public: webhook CRM sync дляbitrix-sync) →bitrix-sync;- exact
POST /callbacks/idgtl/sms→sms-service; остальные методы и SMS paths не публикуются; - web-сборка frontend или прокси на dev-сервер;
/internal/openlines/*,/internal/safety/*,/internal/sync/*,/internal/sms/*не публикуются наружу — доступны только из внутренней Docker-сети.
- Никакой другой
nginx(ни в контейнере сервиса, ни на хосте) не терминирует внешний HTTPS для backend-контура. Site-конфигtohin.ruна хосте, если используется, должен проксировать весь трафик на корневойnginxконтейнера, а не на порты отдельных сервисов напрямую.
Структура compose через include
Каждый сервис описывается в собственном docker-compose.yml внутри папки сервиса и подключается в корневой файл директивой include:
backend/
docker-compose.yml # корневой: nginx + include сервисов + общие networks/volumes
.env
nginx/
docker-compose.yml # описание сервиса nginx (или секция в корневом)
nginx.conf
conf.d/
certs/
.gitkeep
api-backend/
docker-compose.yml # описание сервиса api-backend
message-safety/
docker-compose.yml # описание сервиса message-safety
bitrix-sync/
docker-compose.yml # описание сервиса bitrix-sync
bitrix-local-app/
docker-compose.yml # описание сервиса bitrix-local-app
keycloak/
docker-compose.yml # описание сервиса keycloak (или секция в корневом)
observability/
docker-compose.yml # otel-collector и т.п.
Корневой backend/docker-compose.yml (принципиальная схема):
name: han-chat
include:
- nginx/docker-compose.yml
- api-backend/docker-compose.yml
- message-safety/docker-compose.yml
- bitrix-sync/docker-compose.yml
- bitrix-local-app/docker-compose.yml
- keycloak/docker-compose.yml
- sms-service/docker-compose.yml
- redis/docker-compose.yml
- observability/docker-compose.yml
networks:
public:
backend:
egress:
observability:
volumes:
redis-data:
nginx-certs:
Правила для сервисных compose-файлов
- Сервисный
docker-compose.ymlописывает только сервис(ы) своего модуля: образ, build context,environment(через${VAR}из корневого.env), порты (только внутренние, кроме случаев ниже),depends_on, healthcheck, подключение к сетямpublic/backend/observability(объявленным в корневом файле). - Сервисный файл не объявляет сети и volumes верхнего уровня — они объявляются в корневом
docker-compose.yml. Сервис только ссылается на них черезnetworks:/volumes:(external-стиль не нужен, т.к.includeобъединяет файлы в один проект). - Публикация портов наружу (
ports:) разрешена только дляnginx(80/443). Все остальные сервисы используютexpose:для внутренних портов и общаются через Docker-сети. bitrix-local-appне публикует8080на хост (даже на127.0.0.1) — он доступенapi-backendиnginxчерез сетьbackend/public. Ранее применявшийся127.0.0.1:8080:8080считаем устаревшим; проверки через curl на127.0.0.1:8080заменяются наdocker compose exec bitrix-local-appили прокси черезnginx.- Каждый сервисный compose-файл должен запускаться и в составе корневого контура, и автономно (
docker compose -f bitrix-local-app/docker-compose.yml up) для локальной разработки сервиса — при условии, что переменные окружения заданы. Для автономного запуска сервис может объявлять заглушки сетей/volumes, но в составе корневого контура они переопределяются общими.
Команды разработки
docker compose up -d
docker compose logs -f nginx
docker compose logs -f api-backend
docker compose logs -f message-safety
docker compose logs -f bitrix-sync
docker compose logs -f bitrix-local-app
docker compose exec api-backend alembic upgrade head
docker compose exec api-backend pytest
docker compose exec api-backend ruff check .
docker compose exec api-backend ruff format .
Сервисы
nginx
Reverse proxy и единственная публичная точка входа в Docker Compose контур.
Требования:
- публикует наружу только
80и443(см. политику HTTP ниже); - принимает внешний HTTPS-трафик;
- выполняет TLS termination на reverse proxy; внутренний HTTP между контейнерами — только в закрытой Docker-сети
backend; - политика HTTP/HTTPS по доменам (каноническое правило —
arch-01-system-architecture.md, «Принципы безопасности»):- веб-домен (frontend, SPA, статика):
listen 80допускается только для безусловного редиректа301/308на HTTPS; обработка бизнес-логики по HTTP запрещена; - API-домен (если выделен отдельный host, напр.
api.example.ru): не слушает порт80; толькоlisten 443 ssl; HTTP-запросы к API-домену недоступны; - единый домен MVP (напр.
tohin.ruс путями/api/*,/auth/*, web): считается веб-доменом; порт80— только redirect на HTTPS для всего server block; после редиректа весь пользовательский трафик — HTTPS; - auth на том же host, что API (
/auth/*): следует политике host (redirect-only на :80 или HTTPS-only для выделенного API-host); - Bitrix callbacks (
/bitrix/*,/bitrix/sync/*): только HTTPS; порт80не обслуживает эти location — только redirect;
- веб-домен (frontend, SPA, статика):
- маршрутизирует
/api/*вapi-backend(включая WebSocket upgrade для/api/v1/realtime); - маршрутизирует
/auth/*вkeycloakили проксирует отдельный auth-домен; - маршрутизирует публичные
/bitrix/*endpoint вbitrix-local-app; - маршрутизирует
/bitrix/sync/*webhook endpoint вbitrix-sync; - маршрутизирует только exact
POST /callbacks/idgtl/smsвsms-service:8080; применяет HTTPS, подтверждённый allowlist source IP Direct, body/rate limits и redaction Basic Authorization; - закрывает
/internal/*(в т.ч.bitrix-local-app,message-safety,bitrix-syncops) от публичного доступа — только private network Docker/VPC; - не публикует
message-safetyнаружу; - production-like / production: отдаёт статическую сборку Expo web из volume или каталога (
/usr/share/nginx/htmlили аналог);index.html+ assets, SPA fallbacktry_files $uri /index.html; - local dev (опционально): при
FRONTEND_DEV_PROXY_ENABLED=trueпроксирует/на Expo dev server (EXPO_DEV_SERVER_URL, напр.http://host.docker.internal:8081); - передает upstream-сервисам
Host,X-Real-IP,X-Forwarded-For,X-Forwarded-Proto,X-Forwarded-Host,X-Request-ID; - если входящий запрос без
X-Request-ID, nginx генерирует UUID и устанавливает заголовок до proxy_pass (I3); - задает разумные
proxy_connect_timeout,proxy_read_timeout,client_max_body_size; - для
POST /api/v1/dialogs/*/messagesproxy_read_timeoutдолжен быть не меньшеMESSAGE_SAFETY_TASK_POLL_MAX_SEC + 30s, чтобы nginx не обрывал sync-wait при async file scan; - применяет edge rate limits для auth, API и download endpoints;
- ограничивает частоту соединений и размер тела запроса;
- разрешает только TLS 1.2/1.3 и запрещает слабые шифры;
- добавляет HSTS и базовые security headers;
- скрывает заголовки, раскрывающие внутренние технологии;
- кэширует публичные endpoint настроек и контента;
- не проксирует наружу managed PostgreSQL,
redis,otel-collector(БД вне compose, в VPC);
api-backend
Python FastAPI backend.
Требования:
- запускается после доступности managed PostgreSQL,
keycloak,redis; - применяет настройки из
.env; - отдает
/health/liveи/health/ready; - корректно работает за reverse proxy и доверяет proxy headers только от
nginx; - применяет API-level rate limits с состоянием в Redis;
- вызывает message safety pipeline для сообщений до отправки в Open Lines;
- вызывает
bitrix-local-appдля отправки сообщений в Open Lines; - принимает forward нормализованных событий оператора от
bitrix-local-app; - поддерживает realtime endpoint для сообщений оператора;
- работает с Selectel S3 для файлов и документов;
- экспортирует traces/logs в
otel-collector; - не хранит состояние внутри контейнера.
message-safety
Отдельный backend-сервис проверки входящих сообщений пользователя. HTTP-контракт — в arch-02-api-contracts.md, раздел «api-backend ↔ message-safety».
Требования:
- запускается после доступности managed PostgreSQL (схема
message_safety),redis; - не публикуется через
nginx— доступен только из внутренней Docker-сети; - отдаёт
/health/liveи/health/ready(ready проверяет PostgreSQL, Redis, workers, read-доступ к S3-quarantine); - exposing endpoints:
POST /internal/safety/v1/messages/check,GET /internal/safety/v1/messages/tasks/{task_id}(internal Docker network +X-Service-Token/MESSAGE_SAFETY_SERVICE_TOKEN); - read-only доступ к S3-quarantine (отдельный access key без прав записи);
- использует отдельную схему
message_safetyв managed PostgreSQL и отдельный DB-user; - использует Redis (отдельная DB, напр.
redis://redis:6379/2) для verdict cache и rate limits; - запускает async workers для file scan из S3-quarantine;
- экспортирует traces/logs в
otel-collector; - таймауты: POST check 5 s, GET task 2 s, file scan 60 s (см.
arch-04-settings-and-content.md, переменныеMESSAGE_SAFETY_*).
bitrix-sync
Python worker/service двусторонней синхронизации App DB ↔ Bitrix24 CRM.
Требования:
- запускается после готовности managed PostgreSQL,
redis; - читает задачи из
han_app.sync_queue(заполняется триггерами App DB); - имеет прямой доступ к
han_app(BITRIX_SYNC_APP_DATABASE_URL) и схемеbitrix_sync; - выполняет map/create Contact по телефону (интервал
BITRIX_SYNC_CONTACT_MAP_INTERVAL_SEC, default 60); - push обновлений Contact (интервал
BITRIX_SYNC_CONTACT_UPDATE_INTERVAL_SEC, default 30); - принимает webhook
POST /bitrix/sync/webhook/contactот роботов Bitrix24; - при записи в App DB от Bitrix использует GUC
han.sync_suppress=true; - поддерживает graceful shutdown и rate limiting Bitrix REST;
- не блокирует пользовательский API при ошибках Битрикс24;
- не участвует в OTP-flow, не создаёт
UserIdentity/ClientProfile; - не участвует в hot path чата Open Lines;
- включается/отключается флагом
BITRIX_SYNC_ENABLEDв.env(defaulttrue): приfalseсервис стартует в no-op/degraded режиме, но не обрабатываетsync_queueи не выполняет синхронизацию с Bitrix24 CRM.
bitrix-local-app
Локальное приложение Bitrix24 и custom connector han_mobile_app.
Требования:
- публикует наружу только
/bitrix/handler,/bitrix/install,/bitrix/placement,/health/live,/health/ready; - принимает
ONAPPINSTALLиONIMCONNECTOR*события от Bitrix24; - регистрирует и активирует connector
han_mobile_appдля открытой линии 8; - хранит OAuth-токены Bitrix24, inbox событий и
dialog_sessionsв managed PostgreSQL, схемаbitrix_local; - предоставляет internal API
POST /internal/openlines/v1/messagesиGET /internal/openlines/v1/dialogs/{external_chat_id}для api-backend; - защищает internal API через
Authorization: Bearer {BITRIX_INTERNAL_API_TOKEN}; - forward-ит нормализованные события Open Lines в API, если задан
BITRIX_API_FORWARD_URL; - не хранит бизнес-данные приложения и не пишет напрямую в App DB.
Managed PostgreSQL
Во всех средах (production, production-like, local dev) данные хранятся в managed PostgreSQL провайдера. Контейнер PostgreSQL в Docker Compose не используется — ни для production, ни для локальной разработки.
Прикладные данные, Keycloak, bitrix-sync, bitrix-local-app и message-safety подключаются к одной managed базе по URL из .env (HAN_PG_HOST, HAN_PG_PORT, HAN_PG_DATABASE и схемо-специфичные *_DATABASE_URL).
Требования:
- подключение только из приватной сети VPC (VM → managed PostgreSQL);
- одна managed база: схемы
han_app,bitrix_sync,message_safety,bitrix_local,keycloak,sms; - отдельные DB-пользователи с доступом только к своей схеме; исключение:
bitrix_sync_userдополнительно имеет ограниченный GRANT наhan_app(sync_queue,entity_external_mapping, tracked columns профиля — детали схемы TBD в спецификации database); - TLS к managed PostgreSQL обязателен;
- миграции Alembic выполняются отдельной командой при деплое;
- бэкапы и PITR — на стороне провайдера.
keycloak
Identity provider. Обязателен в compose-контуре с первого запуска.
Требования:
- отдельный realm для приложения;
- отдельный frontend client с PKCE (обязателен);
- confidential backend client — optional (не используется в hot path MVP; S2S между сервисами — service tokens);
- публичный issuer должен соответствовать HTTPS URL, видимому frontend-приложению;
- включены proxy settings для работы за
nginx; - импорт realm в local/dev;
- использует managed PostgreSQL, схема
keycloak(см. раздел «Managed PostgreSQL» выше); - OTP mock / SMS SPI — см. arch-04; real mode вызывает
sms-serviceпо сетиbackend, а единственный утверждённый внешний вызов Keycloak черезegress— server-side validation Yandex SmartCaptcha; - healthcheck;
- взаимодействия —
arch-02-api-contracts.md, «Frontend ↔ Keycloak», иarch-01-system-architecture.md, «Keycloak».
sms-service и sms-worker
sms-service: networksbackend,observabilityиegressтолько если тот же process принимает callback и выполняет worker;expose: 8080, без hostports.- При отдельном
sms-worker: networks толькоegress,observabilityи доступ к managed PG; HTTP port не exposed/published. - Оба используют
SMS_DATABASE_URLк schemasms; только worker получаетIDGTL_SMS_API_KEY. - Callback credentials получает receiver для проверки и worker для формирования callback URL; Keycloak получает только
KEYCLOAK_SMS_SERVICE_TOKEN. sms-serviceприменяет собственные versioned migrations/seed; DDL-on-start запрещён. Readiness проверяет DB/schema, active approvedauth_otptemplate, sender и API-key configuration.- Ожидание Direct до 70 секунд происходит только в worker.
uncertainне retry-ится автоматически; provider outage не создаёт restart loop и не отменяет active Keycloak challenge.
redis
Кэш, rate limiting, coordination (не единственное хранилище бизнес-событий).
Требования:
- не использовать как единственное надежное хранилище бизнес-событий;
- хранить счетчики API-level rate limits и idempotency keys (
api-backend); - поддерживать TTL для лимитных и idempotency ключей;
- не хранить OTP counters для
api-backend(OTP — зона Keycloak/SPI); - sync_queue хранится в PostgreSQL (
han_app), Redis может использоваться для wake-up/locking/queue optimization; - разделение DB index (I4): см. arch-04 (
REDIS_URL,MESSAGE_SAFETY_REDIS_URL).
otel-collector
Принимает telemetry от сервисов.
Требования:
- OTLP HTTP/gRPC receiver;
- экспорт traces/logs в stdout или платформенный collector;
- единые resource attributes:
service.name,deployment.environment.
Networks
Рекомендуемые сети:
public:nginx,keycloak(для прокси/auth/*), frontend static/dev access, внешний HTTPS entrypoint.backend:api-backend,message-safety,bitrix-sync,bitrix-local-app,keycloak,redis(managed PostgreSQL — вне compose, в VPC).egress: только сервисы с утверждёнными исходящими интеграциями;sms-workerобращается к Direct, Keycloak — только кsmartcaptcha.cloud.yandex.ruдля server-side validation. Production real mode требует фактический статический egress IP/NAT, записанный в inventory и переданный Direct для allowlist.observability:otel-collector+ сервисы, экспортирующие telemetry.
Базы данных, Redis, Keycloak internal port и API internal port не должны публиковаться наружу. message-safety доступен только внутри сети backend. Основной пользовательский путь должен идти через nginx и HTTPS.
Volumes
Минимальные volumes (production на одной VM):
redis-data(опционально, если нужна персистентность);- certbot / TLS volumes для
nginx.
Данные PostgreSQL не хранятся в Docker volumes — только managed PostgreSQL вне compose.
Переменные окружения
Корневой backend/.env читается всеми сервисами compose через ${VAR} в сервисных docker-compose.yml. Канонический .env.example и app_settings — в arch-04-settings-and-content.md; контракты service tokens — в arch-02-api-contracts.md.
HTTPS и TLS
Соответствует arch-01-system-architecture.md, «Принципы безопасности» (HTTPS, TLS, HSTS). Инфраструктурная реализация:
Домены и HTTP
| Host | Порт 80 | Порт 443 | Примечание |
|---|---|---|---|
| Веб-домен (frontend) | только 301/308 → HTTPS |
HTTPS, бизнес-логика | MVP: tohin.ru; staging/dev может использовать отдельный host |
| API-домен (если выделен) | не слушает | только HTTPS | Post-MVP: api.example.ru |
Bitrix callbacks (/bitrix/*, /bitrix/sync/*) |
не обслуживает API; только redirect на том же host | HTTPS | webhook и install URL |
Правила:
- все внешние пользовательские соединения — HTTPS;
- HTTP допускается только на веб-домене как вход для редиректа на HTTPS;
- для выделенного API-домена HTTP не допускается (нет listener на :80);
- при едином домене MVP redirect на :80 применяется ко всему host, включая
/api/*и/auth/*, после редиректа — только HTTPS.
TLS и заголовки
- cookies в web-клиенте:
Secure,HttpOnly, корректныйSameSite; - OIDC redirect URI в Keycloak — HTTPS;
KEYCLOAK_PUBLIC_URL, issuer и frontend auth discovery URL совпадают по схеме, host и path;- backend формирует внешние ссылки с учётом
X-Forwarded-Proto=https; - HSTS включается в production-like среде после проверки доменов и сертификатов;
- TLS 1.0/1.1 запрещены; минимум TLS 1.2, предпочтительно TLS 1.3;
- слабые шифры запрещены на уровне
nginx; nginxскрываетServer,X-Powered-Byи аналогичные технологические заголовки;- security headers:
Strict-Transport-Security,X-Content-Type-Options,Referrer-Policy,Content-Security-Policyдля web-приложения; - секретный ключ сертификата не коммитится в репозиторий;
- использовать сертификаты доверенного CA; автоматизировать выпуск и продление (Let's Encrypt + reload
nginx); - закрыть прямой доступ к внутренним портам контейнеров извне.
Nginx routing для Bitrix24 Local App
nginx должен поддерживать отдельные server/location rules для bitrix-local-app.
Рекомендуемая схема:
- веб-домен (MVP:
tohin.ru):/api/*(REST + WS realtime),/auth/*, web frontend;:80→ redirect HTTPS;:443— TLS + маршрутизация; - выделенный API-домен (post-MVP, опционально): отдельный
server { listen 443 ssl; ... }безlisten 80; только/api/*; - для
locationWebSocket (/api/v1/realtime):proxy_http_version 1.1,Upgrade/Connectionheaders, увеличенныйproxy_read_timeout; - домен или path
/bitrix/*→bitrix-local-app;/bitrix/sync/*→bitrix-sync; GET/POST /bitrix/handlerиGET/POST /bitrix/installдоступны публично для Bitrix24;/bitrix/placementдоступен публично как заглушка UI настроек коннектора;/health/liveи/health/readyдляbitrix-local-appдоступны только там, где это нужно для healthcheck и проверки Bitrix form URL;/internal/openlines/v1/*не публикуется наружу или защищается allowlist/private network плюсAuthorization: Bearer {BITRIX_INTERNAL_API_TOKEN};- для
/bitrix/*callbacks кэширование отключено; - для
/bitrix/*callbacks включены отдельные rate limits, но они не должны блокировать легитимные webhook-повторы Bitrix24.
Nginx routing для bitrix-sync (CRM webhook)
nginx маршрутизирует публичные webhook CRM sync в bitrix-sync:
POST /bitrix/sync/webhook/contact— исходящий webhook от роботов Bitrix24 при изменении Contact;- проверка
BITRIX_SYNC_WEBHOOK_TOKENвыполняется вbitrix-sync; - кэширование отключено; rate limits не должны блокировать легитимные повторы Bitrix24;
/internal/sync/v1/*не публикуется наружу (только internal network +BITRIX_SYNC_SERVICE_TOKEN).
Rate limits и защита от abuse
Rate limits должны быть распределены по двум слоям.
nginx:
- ограничивает частоту запросов до попадания в API;
- держит отдельные зоны лимитов для
/auth,/api, public endpoints, fallback polling и download endpoints; - ограничивает
client_max_body_size; - ограничивает загрузку файлов лимитом 5 МБ;
client_max_body_sizeдолжен быть чуть выше бизнес-лимита для учета overhead запроса; - применяет
limit_reqдля endpoint авторизации и fallback polling; - для публичных endpoint использует лимит не выше 60 запросов в минуту с одного IP, если настройки не говорят иначе;
- возвращает
429при превышении лимитов; - не должен использоваться для сложных пользовательских правил, завязанных на
user_id.
API:
- применяет лимиты после проверки JWT;
- считает лимиты по
user_id, IP, route, dialog id и service client; - хранит быстрые счетчики в Redis;
- пишет значимые превышения в audit/App DB;
- возвращает
Retry-After, если клиент может повторить запрос позже.
Проверка сообщений на prompt injection и вредоносные действия не должна выполняться в nginx: это задача отдельного сервиса message-safety, вызываемого из api-backend (см. arch-02-api-contracts.md).
WAF
WAF можно подключить внешним слоем перед nginx без изменения бизнес-кода, если соблюдены требования:
nginxи API корректно работают с цепочкой proxy headers и доверяют real IP только от доверенных прокси;- CORS разрешает только доверенные домены;
- публичные endpoint имеют rate limits и кэширование даже без WAF;
- схема TLS termination согласована с тем, где завершается TLS: WAF/CDN, load balancer или
nginx; - WAF не должен подменять тело запросов и ответы API без явной необходимости.
WAF не заменяет обязательные лимиты, валидацию схем, авторизацию и аудит внутри приложения.
Публичные endpoint
GET /api/v1/public/app-config и GET /api/v1/public/content являются публичными, поэтому для них обязательны:
limit_reqна уровнеnginx, базово 60 запросов в минуту с одного IP;- агрессивное кэширование на уровне
nginxили CDN; - заголовок
Cache-Control: public, max-age=3600; - строгая DTO-схема ответа на backend, без сериализации всех строк таблицы настроек;
- CORS только для доверенных доменов приложения;
- отсутствие секретов, внутренних URL, service tokens и приватных feature flags в ответе.
Подробнее — arch-04-settings-and-content.md, разделы «Публичный config endpoint» и «Публичный content endpoint».
Healthchecks
Минимальные проверки:
nginx: на веб-домене —301с:80на HTTPS; на API-домене (если выделен) —:80не слушает;:443— HTTP 200/301 и успешная TLS handshake;api-backend:/health/liveпроверяет процесс;/health/readyпроверяет PostgreSQLhan_app, Redis/0и/1, доступность JWKS/discovery Keycloak, S3 permissions для presign/promote и readinessmessage-safety;message-safety: HTTP 200 от/health/ready(проверяет PostgreSQL, Redis, workers, read S3-quarantine);bitrix-sync:/health/liveпроверяет процесс;/health/readyпроверяет PostgreSQL, доступ кsync_queue, worker state и CRM webhook config; приBITRIX_SYNC_ENABLED=falseready возвращает degraded/not-ready с причинойsync_disabled;bitrix-local-app:/health/liveпроверяет процесс;/health/readyпоказывает PostgreSQL, OAuth-токены после установки приложения, connector activation и возможность forward в API при включённомBITRIX_API_FORWARD_URL;keycloak: health endpoint Keycloak; readiness — подключение к managed PostgreSQL;sms-service: live — процесс; ready — schema/migrations, active approved template, sender/API key; Direct доступность — отдельный dependency status, не причина restart loop;redis:redis-cli ping;
Наружу через nginx публикуются только health endpoint, которые нужны Bitrix24 install/callback validation или внешнему мониторингу. Internal services (message-safety, internal bitrix-sync, Redis, otel) проверяются только из Docker/VPC-сети.
Порядок запуска
redis(managed PostgreSQL должна быть доступна до старта зависимых сервисов).otel-collector.api-backendи seed OTP settings.sms-service/worker после migrations/seed (Keycloak пока mock).keycloak.message-safety.bitrix-local-app.bitrix-sync.nginx.
Порядок rollout SMS подробнее задаёт module-11/module-10. Зависимости запуска не образуют цикл: Keycloak стартует при недоступном sms-service; это блокирует только новые real-mode orders, а verify уже active challenges продолжается по snapshot.
depends_on не заменяет проверку готовности. Сервисы должны уметь ждать зависимости или корректно завершаться с понятной ошибкой. api-backend должен ждать готовности message-safety (healthcheck), т.к. отправка сообщения синхронно зависит от POST /internal/safety/v1/messages/check.
Развёртывание на одной VM
Production-контур на tohin.ru:
- VM и managed PostgreSQL в одном VPC/кластере провайдера.
- Managed PostgreSQL без публичного IP; security group разрешает подключение только с VM.
docker compose up -dна VM поднимает все сервисы кроме БД.- Сервисы подключаются к managed PostgreSQL по приватному FQDN/IP.
Production-замечания
Frontend (Expo web)
| Режим | Поведение nginx |
|---|---|
| production-like / production | Статика Expo web (expo export / EAS web build), FRONTEND_DEV_PROXY_ENABLED=false |
| local dev | Опционально proxy на Expo dev server, FRONTEND_DEV_PROXY_ENABLED=true |
Переменные — arch-04-settings-and-content.md, блок «Frontend (nginx)».
Docker Compose на одной VM — production-контур первого этапа. Позже при росте нагрузки можно отдельно решить:
- вынос Redis в managed cache;
- managed object storage;
- secret manager;
- TLS, reverse proxy или managed ingress;
- backup и restore;
- централизованный мониторинг;
- горизонтальное масштабирование API и worker.
Backup, restore и cleanup
- Managed PostgreSQL должен иметь ежедневные backups и PITR; целевые RPO/RTO для MVP фиксируются в ops runbook до production-запуска.
- S3-data (
attachments,documents) хранит production-файлы; удаление выполняется только через lifecycle, retention или явный audit-backed процесс. - S3-quarantine очищается периодическим cleanup job: удаляются просроченные объекты без активного
MessageAttachment/safety_tasksили объекты с завершённым deny/failed lifecycle. - Redis не является единственным хранилищем бизнес-событий; потеря Redis не должна терять сообщения, sync tasks или audit.