iac/apps/flows/CONFIGURATION.md

294 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Конфигурация проекта flows-backend
Документ описывает все переменные окружения и способы конфигурирования сервиса.
## Способы конфигурирования
Сервис настраивается **только через переменные окружения**. Разбор выполняется в `src/flow/config.py` через библиотеку [`pydantic-settings`](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) (класс `Settings` и набор вложенных классов `*Settings`).
Особенности разбора:
- у верхнеуровневого класса `Settings` **префикса нет** и не задан `env_nested_delimiter`его собственные поля задаются переменными с именем поля в верхнем регистре (напр. `BASE_HOST`, `SERVICE_PORT`, `PROXY_PATH_PREFIX`);
- каждая вложенная секция — это **отдельный класс** `BaseSettings` со своим `env_prefix` (`class Config: env_prefix = "..."`), который читает переменные окружения независимо. Поэтому переменные «плоские» с префиксами: `PG_HOST`, `DJANGO_HOST`, `RABBITMQ_PORT`, `TRACING_USE` и т.д. — двойного подчёркивания для вложенности здесь нет;
- отсутствие обязательного поля без дефолта приводит к ошибке старта; большинство полей приложения имеют дефолты (см. таблицы ниже).
Отдельного конфиг-файла (yaml/toml) у приложения нет. Приложение **не загружает `.env` автоматически**`config.py` не задан `env_file`, зависимости `python-dotenv` нет) — переменные нужно экспортировать в окружение самому, напр. `set -a && . ./.env && set +a`.
Воркер (`src/worker`) использует **собственные** классы настроек (`src/worker/notifications_config.py`, `src/worker/sync_config.py`, `src/worker/celery.py`) с частично другими префиксами (`FLOWS_DB_`, `ISSUES_DB_`, `RFI_DB_`, `RESOURCES_`, `MAILGUN_`, `WORKFLOWS_NOTIFICATIONS_` и т.д.).
Источники переменных по способам запуска:
| Способ запуска | Откуда берутся переменные |
| --- | --- |
| Локально | Переменные окружения процесса. `.env.example` — шаблон; приложение его **не** загружает автоматически, экспортируйте вручную |
| Контейнер | `Dockerfile` / `Dockerfile.worker`; запуск через `entrypoint.sh` (сначала `alembic upgrade head`, затем gunicorn) |
| Kubernetes (Helm, репозиторий) | `.helm/values.yaml` (`universal-chart`): блоки `envs` (обычные значения) и `secretEnvs` (значения из k8s-секретов) для сервисов `backend`, `worker`, `scheduler` |
| Kubernetes (kustomize, infra) | `iac/apps/flows/base/*.yaml`: env в `backend-deployment.yaml` / `celery-deployment.yaml`; секреты инжектируются агентом **HashiCorp Vault** (`vault.hashicorp.com/agent-inject-*`) и подгружаются в окружение перед стартом |
| CI/CD (GitLab) | `.gitlab-ci.yml`: переменные пайплайна (`workflow.rules`), общий шаблон `generic/common-ci` (`universal-pipeline.yaml`) |
Способы запуска процессов:
| Процесс | Команда | Назначение |
| --- | --- | --- |
| HTTP API | `gunicorn ... flow.main:app` (`entrypoint.sh`) | Публичный и внутренний REST API (FastAPI) |
| Celery worker | `celery -A src.worker worker` | Обработчик фоновых задач (рассылки, синхронизация) |
| Celery beat (scheduler) | `celery -A src.worker beat -l INFO` | Периодические задачи (см. `beat_schedule` ниже) |
| Alembic | `alembic upgrade head``entrypoint.sh`) | Миграции БД при старте контейнера |
Порядок запуска в контейнере (`entrypoint.sh`): миграции (`alembic upgrade head`), затем `gunicorn -w 3 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000 --timeout $TIMEOUT ... flow.main:app`.
Периодические задачи воркера (`src/worker/celery.py`, `beat_schedule`):
| Задача | Расписание (UTC) | Назначение |
| --- | --- | --- |
| `sync_reviews` | `*/7` минут | Синхронизация review |
| `notify_users` | пн–пт, 06:00 | Рассылка уведомлений пользователям |
| `notify_admins_about_empty_steps` | пн–пт, 05:30 | Уведомление админов о пустых шагах |
## Переменные приложения (API)
Дефолт `—` означает, что значение обязательно (иначе ошибка старта).
### Общие (`Settings`, без префикса)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `SERVICE_NAME` | string | `review-service` | Имя сервиса |
| `SERVICE_HOST` | string | `0.0.0.0` | Адрес прослушивания (в кластере переопределяется внешним URL API) |
| `SERVICE_PORT` | int | `8000` | Порт |
| `PROXY_PATH_PREFIX` | string | `""` | Root path за реверс-прокси (в кластере `/flows`). Влияет на `root_path` FastAPI и на префикс админки |
| `API_PREFIX` | string | `/api/v1` | Префикс публичного API |
| `API_INTERNAL_PREFIX` | string | `/internal/v1` | Префикс внутреннего API |
| `BASE_HOST` | string | `https://lk.sarex.io` | Базовый внешний URL (для ссылок/писем) |
| `GATEWAY_URL` | string | `https://stage-api.sarex.io/gateway` | URL gateway (используется при `SYNC_RESOURCE_ID=1`) |
| `RESOURCE_URL` | string | `https://stage-api.sarex.io/resources` | URL сервиса ресурсов/IAM (используется при `SYNC_RESOURCE_ID=1`) |
| `REGISTRY` | string | `cr.yandex/crp3ccidau046kdj8g9q` | Реестр образов |
| `JWT_AUTH_ENABLE` | bool | `True` | Включить аутентификацию по JWT. `False` — все запросы идут от дефолтного пользователя (удобно локально) |
| `DEBUG` | bool | `False` | Режим отладки |
| `ENABLE_MAILINGS` | bool | `True` | Включить рассылки |
| `ENABLE_MAILGUN` | bool | `True` | Использовать Mailgun (иначе — SMTP) |
| `ENABLE_CELERY` | bool | `True` | Включить постановку задач в Celery |
| `ENABLE_EVENTS` | bool | `True` | Включить событийную шину |
| `ENABLE_ANALYTICS` | bool | `False` | Отправлять данные в аналитику |
| `SYNC_RESOURCE_ID` | bool | `False` | Определять `resource_id` через gateway/resources при создании review/документов |
| `SMTP_HOST` | string \| null | `None` | SMTP-хост (альтернатива Mailgun) |
| `SMTP_PORT` | int \| null | `None` | SMTP-порт |
| `FROM_EMAIL` | string \| null | `None` | Адрес отправителя писем |
### Logger (`LoggerSettings`, префикс `LOG_`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `LOG_LEVEL` | string | `INFO` | Уровень логирования (`INFO`/`DEBUG`/…); JSON-формат вывода |
| `LOG_FORMAT` | string | JSON-шаблон | Формат строки лога |
### Auth
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `JWT_PUBLIC_KEY` | string | — | Публичный RSA-ключ для проверки подписи JWT. В кластере монтируется из секрета и экспортируется как `JWT_PUBLIC_KEY` перед стартом (см. `entrypoint`/Vault) |
> Аутентификация выполняется в `src/flow/middleware.py` (`TokenUserMiddleware`). При наличии заголовка `identity` полезная нагрузка берётся из Zitadel-токена (`urn:zitadel:iam:user:metadata`), иначе — из основного `Authorization: Bearer <jwt>`. Подпись проверяется публичным ключом. Пути `/docs/`, `/openapi.json/`, `/internal/` из проверки исключены.
### Database — основной PostgreSQL (`PostgresSettings`, префикс `PG_`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `PG_HOST` | string | `""` | Хост PostgreSQL |
| `PG_PORT` | string | `6432` | Порт PostgreSQL (обычно pgbouncer) |
| `PG_LOGIN` | string | `""` | Пользователь БД |
| `PG_PASSWORD` | string | `""` | Пароль БД |
| `PG_DB` | string | `""` | Имя базы данных |
> Итоговый DSN собирается свойством `PostgresSettings.url`: `postgresql://{login}:{password}@{host}:{port}/{db}`.
### Documentation PG (`DocumentationDBSettings`, префикс `DOCUMENTATION_PG_`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `DOCUMENTATION_PG_HOST` | string | `""` | Хост БД документаций |
| `DOCUMENTATION_PG_PORT` | string | `""` | Порт |
| `DOCUMENTATION_PG_USERNAME` | string | `""` | Пользователь |
| `DOCUMENTATION_PG_PASSWORD` | string | `""` | Пароль |
| `DOCUMENTATION_PG_DATABASE` | string | `""` | Имя базы |
### RabbitMQ (`RabbitSettings`, префикс `RABBITMQ_`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `RABBITMQ_HOST` | string | `localhost` | Хост |
| `RABBITMQ_PORT` | string | `5672` | Порт |
| `RABBITMQ_USERNAME` | string | `flow` | Пользователь |
| `RABBITMQ_PASSWORD` | string | `flow` | Пароль |
| `RABBITMQ_VHOST` | string | `api` | Виртуальный хост (в кластере `flows`/`flow_preprod`/`flow_prod`) |
### Celery (`CelerySettings`, префикс `CELERY_`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `CELERY_QUEUE` | string | `flow` | Очередь задач. Брокер — из `RABBITMQ_*` |
### HTTP-клиенты внешних сервисов
Каждый клиент — отдельный класс с полями `use`/`host`/`timeout` (и своим префиксом). Соединение создаётся httpx-клиентом.
| Секция / префикс | Переменные | Назначение |
| --- | --- | --- |
| Sarex backend (Django) — `DJANGO_` | `DJANGO_USE` (`True`), `DJANGO_HOST` (`http://localhost:8000/api`), `DJANGO_TIMEOUT` (`60`), `DJANGO_TOKEN` (base64 `login:password` для Basic-auth) | Основной backend Sarex |
| Documentations — `DOCUMENTATION_` | `DOCUMENTATION_USE` (`True`), `DOCUMENTATION_HOST`, `DOCUMENTATION_EXTERNAL_HOST`, `DOCUMENTATION_TIMEOUT` (`60`) | Сервис документаций (внутренний и внешний хост) |
| EAV — `EAV_` | `EAV_HOST` (`http://eav-service.eav-prod`), `EAV_TIMEOUT` (`60`) | Сервис EAV (атрибуты) |
| Planning / MSP — `PLANNING_` | `PLANNING_USE` (`True`), `PLANNING_HOST` (`https://api.sarex.io/api/pm/msp`), `PLANNING_TIMEOUT` (`60`) | Планирование |
| Checklists — `CHECKLIST_` | `CHECKLIST_USE` (`True`), `CHECKLIST_HOST`, `CHECKLIST_TIMEOUT` (`60`) | Сервис чек-листов |
| Workflows — `WORKFLOWS_` | `WORKFLOWS_USE` (`True`), `WORKFLOWS_HOST` (`https://lk.sarex.io/workflows/api/v1`), `WORKFLOWS_TIMEOUT` (`60`) | Сервис workflows |
### Event bus (`EventBusSettings`, префикс `EVENTS_`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `EVENTS_HOST` | string | `ws://localhost:8000/ws` | Адрес WebSocket событийной шины |
| `EVENTS_CONNECTION_TIMEOUT` | int | `5` | Таймаут подключения (сек) |
| `EVENTS_COUNT_RETRIES` | int | `100` | Число попыток переподключения |
### Admin panel (`AdminPanelSettings`, префикс `ADMIN_PANEL_`)
Админка (`sqladmin`) монтируется по пути `/api/admin/` (с учётом `PROXY_PATH_PREFIX`).
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `ADMIN_PANEL_SECRET_KEY` | string | `hex` | Секретный ключ сессии админки |
| `ADMIN_PANEL_TOKEN_MAX_AGE` | int | `86400` | Время жизни токена (сек) |
### Sentry (`SentrySettings`, префикс `SENTRY_`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `SENTRY_DSN` | string | `""` | DSN Sentry |
| `SENTRY_ENVIRONMENT` | string | `production` | Окружение |
| `SENTRY_TRACES_SAMPLE_RATE` | float | `1.0` | Доля трейсов |
| `SENTRY_SEND_DEFAULT_PII` | bool | `True` | Отправлять PII |
### OpenTelemetry / трейсинг (`TraceSettings`, префикс `TRACING_`)
| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `TRACING_USE` | bool | `False` | Включить трейсинг (при `True` инициализируется OTLP + middleware) |
| `TRACING_HOST` | string | `localhost:4317` | Адрес OTLP-коллектора |
| `TRACING_INSECURE` | bool | `False` | Подключение без TLS |
| `TRACING_SERVICE_NAME` | string | `flows` | Имя сервиса в трейсах |
| `TRACING_ENVIRONMENT` | string | `prod` | Окружение (`stage`/`preprod`/`prod`) |
| `TRACING_MODULE` | string | `flows` | Атрибут `module` |
| `TRACING_TEAM` | string | `team_proc` | Атрибут `team` |
| `TRACING_COMPONENT` | string | `backend` | Атрибут `component` |
## Переменные только для воркера и scheduler
Читаются классами из `src/worker/*`, а не основным приложением.
### Базы данных воркера
| Секция / префикс | Переменные | Назначение |
| --- | --- | --- |
| Flows DB — `FLOWS_DB_` | `FLOWS_DB_HOST`, `FLOWS_DB_PORT`, `FLOWS_DB_DB`, `FLOWS_DB_USERNAME`, `FLOWS_DB_PASSWORD` | БД flows (для задач синхронизации/рассылок) |
| Issues DB — `ISSUES_DB_` | `ISSUES_DB_HOST`, `ISSUES_DB_PORT`, `ISSUES_DB_DB`, `ISSUES_DB_USERNAME`, `ISSUES_DB_PASSWORD` | БД issues |
| RFI DB — `RFI_DB_` | `RFI_DB_HOST`, `RFI_DB_PORT`, `RFI_DB_DB`, `RFI_DB_USERNAME`, `RFI_DB_PASSWORD` | БД RFI |
Все пять полей каждой БД обязательны (без дефолтов).
### Клиенты и рассылки воркера
| Секция / префикс | Переменные | Назначение |
| --- | --- | --- |
| Django-клиент — `DJANGO_` | `DJANGO_BASE_HOST`, `DJANGO_HOST`, `DJANGO_AUTH` (Basic-auth) | Получение пользователей/токенов |
| Resources-клиент — `RESOURCES_` | `RESOURCES_HOST` | Пользователи, сгруппированные по ресурсам |
| Flows-клиент — `FLOWS_` | `FLOWS_HOST` | Внутренние вызовы flows API (`switch_to_next_step`) |
| Глобальные настройки рассылок — `NOTIFICATION_SETTINGS_` | `NOTIFICATION_SETTINGS_ENABLE_MAILINGS` (`True`), `NOTIFICATION_SETTINGS_USE_MAILGUN` (`True`) | Флаги рассылок |
| Mailgun — `MAILGUN_` | `MAILGUN_HOST`, `MAILGUN_API_KEY`, `MAILGUN_SENT_FROM` (`hello@sarex.io`) | Отправка писем через Mailgun |
| Workflows — `WORKFLOWS_` | `WORKFLOWS_HOST`, `WORKFLOWS_TIMEOUT` (`60`) | Постановка job в workflows |
| Уведомления через Workflows — `WORKFLOWS_NOTIFICATIONS_` | `WORKFLOWS_NOTIFICATIONS_TAG` (`email`), `WORKFLOWS_NOTIFICATIONS_REGISTRY`, `WORKFLOWS_NOTIFICATIONS_SMTP_HOST`, `WORKFLOWS_NOTIFICATIONS_SMTP_PORT`, `WORKFLOWS_NOTIFICATIONS_FROM_EMAIL` | Параметры job-рассылки |
## Переменные инфраструктуры, сборки и деплоя
Не читаются кодом приложения, но участвуют в запуске/сборке/деплое.
| Переменная | Где используется | Назначение |
| --- | --- | --- |
| `TIMEOUT` | `entrypoint.sh` | Таймаут gunicorn-воркеров (сек), напр. `120` (stage) / `900` (prod) |
| `ENABLE_METRICS` | `.helm/values.yaml` | Флаг метрик (`0`/`1`), кодом не читается |
| `PIP_INDEX_URL` / `--extra-index-url` | `requirements.txt` | Приватный индекс пакетов Nexus (`fastapi-otel-tools`) |
| `SERVICE_HOST` (в кластере) | `.helm/values.yaml`, kustomize | В кластере в `SERVICE_HOST` кладётся внешний URL API (`https://api.sarex.io/flows/api/v1`), переопределяя дефолт `0.0.0.0` |
| `SAREX_MAILER_HOST` | `.helm/values.yaml` | Хост mailer-сервиса |
## Переменные из Helm-чарта (`.helm/values.yaml`)
Чарт `universal-chart` описывает три сервиса — `backend`, `worker`, `scheduler`. Обычные значения задаются в блоке `envs` (с ключами по окружениям `_default`/`stage`/`preprod`/`production`), значения из секретов — в блоке `secretEnvs` (монтируются как env через `secretKeyRef`).
Значения из секретов (backend):
| Переменная | Секрет (`secretName`) | Ключ (`secretKey`) |
| --- | --- | --- |
| `PG_DB` | `postgres-secret` / `flows-postgresql-secret` | `database` |
| `PG_LOGIN` | `postgres-secret` / `flows-postgresql-secret` | `username` |
| `PG_PASSWORD` | `postgres-secret` / `flows-postgresql-secret` | `password` |
| `PG_HOST` | `postgres-secret` / `flows-postgresql-secret` | `host` |
| `SENTRY_DSN` | `sentry-secret` | `dsn` |
| `SENTRY_ENVIRONMENT` | `sentry-secret` | `env` |
| `DJANGO_TOKEN` | `django-secret` | `token` |
| `RABBITMQ_USERNAME` | `rabbitmq-secret` / `flows-rabbitmq-secret` | `username` |
| `RABBITMQ_PASSWORD` | `rabbitmq-secret` / `flows-rabbitmq-secret` | `password` |
| `ADMIN_PANEL_SECRET_KEY` | `admin-secret` | `key` |
| `JWT_PUBLIC_KEY` | `jwt-secret` | `public_key` |
| `DOCUMENTATION_PG_*` | `documentations-postgresql-secret` / `documentations-postgres-secret` | `database`/`host`/`port`/`username`/`password` |
Воркер дополнительно получает секреты `FLOWS_DB_*`, `ISSUES_DB_*`, `RFI_DB_*` (из соответствующих postgres-секретов), `DJANGO_AUTH` (`django-secret.token`), `MAILGUN_API_KEY` (`mailgun-secret.api-key`).
Чарт также монтирует CA-сертификат PostgreSQL (`pg-cert` → `/root/.postgresql/root.crt`).
## Переменные из kustomize-манифестов (`iac/apps/flows`)
Инфраструктурный репозиторий разворачивает те же образы через kustomize (`base` + оверлеи `brusnika-stage`, `brusnika-prod`, `yc-k8s-test`). Секреты инжектируются агентом **HashiCorp Vault** (аннотации `vault.hashicorp.com/agent-inject-*`) и подгружаются в окружение из файлов `/vault/secrets/*` перед запуском `entrypoint.sh`:
| Секрет Vault | Переменные |
| --- | --- |
| `secrets/data/postgresql/apps/flows` | `PG_DB`, `PG_LOGIN`, `PG_HOST`, `PG_PORT`, `PG_PASSWORD`, `DOCUMENTATION_PG_*` |
| `secrets/data/rabbitmq/apps/flows` | `RABBITMQ_USERNAME`, `RABBITMQ_PASSWORD`, `RABBITMQ_VHOST`, `RABBITMQ_HOST`, `RABBITMQ_PORT` |
| `secrets/data/vault/common/django_auth` | `DJANGO_TOKEN` |
| `secrets/data/vault/common/rsa_keys` | `JWT_PUBLIC_KEY` (public_key) |
Остальные значения (`LOG_LEVEL`, `BASE_HOST`, `DJANGO_HOST`, `DOCUMENTATION_HOST`, `EAV_HOST`, `GATEWAY_URL`, `RESOURCE_URL`, `SERVICE_HOST`, `WORKFLOWS_HOST`, `CHECKLIST_HOST`, `SMTP_HOST`/`SMTP_PORT`, `FROM_EMAIL`, `ENABLE_*`, `SYNC_RESOURCE_ID`, `TIMEOUT` и т.д.) задаются напрямую в блоке `env` deployment-манифеста оверлея.
## Переменные в CI (`.gitlab-ci.yml`)
Пайплайн подключает общие шаблоны из `generic/common-ci` (`common-security-scan.yaml`, `universal-pipeline.yaml`) и переключает окружение по ветке/тегу через `workflow.rules`:
| Условие | STAND | Namespace | CHART_VERSION |
| --- | --- | --- | --- |
| ветка `stage` | `stage` | `proc` | `0.0.1-stage` |
| ветка `master` | `preprod` | `flows-preprod` | `0.0.1-preprod` |
| тег (`CI_COMMIT_TAG`) | `production` | `flows-prod` | `0.0.1-prod` |
Ключевые переменные пайплайна: `SERVICE_NAME=flows-backend`, `DOCKERFILE_PATH=Dockerfile`, `IMAGE_NAME_WORKER` (образ воркера, собирается job-ом `build_worker` из `Dockerfile.worker`), `HELM_SET_ARGS` (проброс образов backend/worker/scheduler и метаданных коммита в чарт).
## Замечания и потенциальные проблемы
- Приложение **не загружает `.env` автоматически** — переменные нужно экспортировать в окружение (см. `.env.example`).
- У `Settings` нет `env_nested_delimiter`, поэтому вложенные секции конфигурируются **плоскими** переменными со своими префиксами (`PG_`, `DJANGO_`, `RABBITMQ_`, …), а не через `__`.
- Поле `service_host` (дефолт `0.0.0.0`) и переменная `SERVICE_HOST` совпадают по имени: в кластере в `SERVICE_HOST` кладётся внешний URL API, что переопределяет адрес прослушивания в объекте настроек. Реальный адрес/порт прослушивания при запуске в контейнере задаёт gunicorn (`-b 0.0.0.0:8000` в `entrypoint.sh`), а не поле настроек.
- Почта: при `ENABLE_MAILGUN=1` используется Mailgun (`MAILGUN_*` — в основном на стороне воркера), иначе — SMTP (`SMTP_HOST`/`SMTP_PORT`/`FROM_EMAIL`).
- Healthcheck-эндпоинта у сервиса нет; в чарте probes (`liveness`/`readiness`) отключены.
- Воркер использует отдельные классы настроек (pydantic v1 стиль `class Config`), у которых поля БД **обязательны** — при запуске воркера без `FLOWS_DB_*`/`ISSUES_DB_*`/`RFI_DB_*` будет ошибка.
## Минимальный набор для локального запуска
Минимально необходимо задать:
- `SERVICE_PORT` (по умолчанию `8000`), `PROXY_PATH_PREFIX` (пусто локально)
- `JWT_AUTH_ENABLE=False` (чтобы не требовался `JWT_PUBLIC_KEY`) — иначе задайте `JWT_PUBLIC_KEY`
- `PG_HOST`, `PG_PORT`, `PG_LOGIN`, `PG_PASSWORD`, `PG_DB`
- `RABBITMQ_HOST`, `RABBITMQ_PORT`, `RABBITMQ_USERNAME`, `RABBITMQ_PASSWORD`, `RABBITMQ_VHOST` (если `ENABLE_CELERY=1`/`ENABLE_EVENTS=1`)
- хосты внешних сервисов, которые реально используются: `DJANGO_HOST`, `DOCUMENTATION_HOST`, `EAV_HOST`, `CHECKLIST_HOST`, `WORKFLOWS_HOST`, `PLANNING_HOST`
- при `SYNC_RESOURCE_ID=1``GATEWAY_URL`, `RESOURCE_URL`
- `TRACING_USE=False` (иначе — `TRACING_HOST`, `TRACING_SERVICE_NAME`)
- для воркера — `FLOWS_DB_*`, `ISSUES_DB_*`, `RFI_DB_*`, `MAILGUN_*` или SMTP
Готовые значения-примеры для всех переменных приведены в `.env.example`.