# Конфигурация проекта transmittal-api

Документ описывает все переменные окружения и способы конфигурирования сервиса.

## Способы конфигурирования

Сервис настраивается **только через переменные окружения**. Разбор выполняется в `src/transmittal_service/infra/settings.py` через библиотеку [`pydantic-settings`](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) (класс `AppSettings`).

Особенности разбора (`SettingsConfigDict`):

- `env_prefix="TRANSMITTAL_SERVICE_"` — все переменные приложения начинаются с этого префикса;
- `env_nested_delimiter="__"` — вложенные секции задаются двойным подчёркиванием, напр. `TRANSMITTAL_SERVICE_DATABASE__HOST` → `database.host`;
- `env_ignore_empty=False` — пустая строка считается заданным значением (не игнорируется), поэтому пустое обязательное поле-строка проходит валидацию, а вот отсутствие обязательного поля приводит к ошибке старта.

Отдельного конфиг-файла (yaml/toml) у приложения нет. Настройки Uvicorn читаются отдельным классом `UvicornSettings` (тот же префикс/делимитер).

Источники переменных по способам запуска:

| Способ запуска | Откуда берутся переменные |
| --- | --- |
| Локально (бинарник) | Переменные окружения процесса. `make config` копирует `.example.env` → `.env` как шаблон, но приложение **не загружает `.env` автоматически** (в коде нет `env_file`/`dotenv`) — файл нужно экспортировать самому, напр. `set -a && . ./.env && set +a` |
| Локально (контейнеры) | `makefile`: цели `container-run`, `container-run-database`, `container-run-rabbitmq` пробрасывают переменные хоста через `--env` |
| Kubernetes (Helm) | `.helm/values-<env>.yaml`: блок `envs` (обычные значения) и `secrets` (значения из k8s-секретов); шаблоны `deployment.yaml`, `worker.yaml`, `crontab_periodic.yaml` |
| CI/CD (GitLab) | `.gitlab-ci.yml`: переменные пайплайна (`workflow.rules`) и переменные job-а `test-unit` для запуска тестов |

Способы запуска процессов (`[project.scripts]` в `pyproject.toml`):

| Команда | Точка входа | Назначение |
| --- | --- | --- |
| `start_api` (`make run-api`) | `cmd/api.py` | HTTP API (uvicorn/gunicorn) |
| `taskiq worker …` (`make run-worker`) | `tasks.broker:broker` | Обработчик фоновых задач |
| `process_expired_transmittals` | `cmd/process_expired_transmittals.py` | Разовая задача обработки просроченных трансмитталов (в k8s — CronJob `0 3 * * *`) |
| `create_system_values` | `cmd/create_system_values.py` | Создание системных значений |
| `generate-act` | `cmd/generate_act.py` | Генерация акта |

Порядок запуска в контейнере (`scripts/entrypoint.sh`): сначала выполняются миграции (`alembic upgrade heads`), затем стартует gunicorn с воркерами `ConfigurableWorker`.

## Переменные приложения

Все перечисленные ниже переменные имеют префикс `TRANSMITTAL_SERVICE_`. В столбце «Переменная» указано полное имя. Дефолт `—` означает, что значение обязательно (иначе ошибка старта).

### App (`app.*`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `TRANSMITTAL_SERVICE_APP__NAME` | string | `Transmittal Service` | Имя приложения |
| `TRANSMITTAL_SERVICE_APP__LOG_LEVEL` | enum | `INFO` | Уровень логирования: `CRITICAL`/`FATAL`/`ERROR`/`WARNING`/`WARN`/`INFO`/`DEBUG`/`NOTSET` |
| `TRANSMITTAL_SERVICE_APP__ENVIRONMENT` | enum | — | Окружение развёртывания: `stage`/`preprod`/`prod` |
| `TRANSMITTAL_SERVICE_APP__HOST` | string | — | Внешний базовый URL сервиса (используется в письмах/ссылках) |

### Auth (`auth.*`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `TRANSMITTAL_SERVICE_AUTH__PUBLIC_KEY` | string | — | Публичный RSA-ключ для проверки JWT. Экранированные `\n` автоматически заменяются на реальные переводы строк |

### CORS (`cors.*`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `TRANSMITTAL_SERVICE_CORS__ALLOW_ORIGINS` | list[str] (JSON) | — | Разрешённые Origin, напр. `["*"]` |
| `TRANSMITTAL_SERVICE_CORS__ALLOW_METHODS` | list[str] (JSON) | — | Разрешённые HTTP-методы |
| `TRANSMITTAL_SERVICE_CORS__ALLOW_HEADERS` | list[str] (JSON) | — | Разрешённые заголовки |
| `TRANSMITTAL_SERVICE_CORS__ALLOW_CREDENTIALS` | bool | — | Разрешить передачу учётных данных |

### Uvicorn (`uvicorn.*`)

Читаются отдельным классом `UvicornSettings`.

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `TRANSMITTAL_SERVICE_UVICORN__HOST` | string | `127.0.0.1` | Адрес прослушивания |
| `TRANSMITTAL_SERVICE_UVICORN__PORT` | int | `8001` | Порт |
| `TRANSMITTAL_SERVICE_UVICORN__ENABLE_AUTO_RELOAD` | bool | `False` | Live/hot-reload (для разработки) |
| `TRANSMITTAL_SERVICE_UVICORN__LOG_LEVEL` | enum | `info` | `critical`/`error`/`warning`/`info`/`debug`/`trace` |
| `TRANSMITTAL_SERVICE_UVICORN__NUM_WORKERS` | int | `1` | Число воркеров gunicorn |
| `TRANSMITTAL_SERVICE_UVICORN__ROOT_PATH` | string | `""` | Root path (префикс за реверс-прокси) |

### Database (`database.*`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `TRANSMITTAL_SERVICE_DATABASE__HOST` | string | — | Хост PostgreSQL |
| `TRANSMITTAL_SERVICE_DATABASE__PORT` | int | — | Порт PostgreSQL |
| `TRANSMITTAL_SERVICE_DATABASE__USER` | string | — | Пользователь БД |
| `TRANSMITTAL_SERVICE_DATABASE__PASSWORD` | string | — | Пароль пользователя БД |
| `TRANSMITTAL_SERVICE_DATABASE__NAME` | string | — | Имя базы данных |
| `TRANSMITTAL_SERVICE_DATABASE__POOL_SIZE` | int | `5` | Размер пула соединений |
| `TRANSMITTAL_SERVICE_DATABASE__MAX_POOL_OVERFLOW` | int | `5` | Доп. соединения сверх пула |
| `TRANSMITTAL_SERVICE_DATABASE__ENABLE_SSL` | bool | — | Подключение к БД по TLS |
| `TRANSMITTAL_SERVICE_DATABASE__SSL_MODE` | enum | — | `verify-full`/`verify-ca`/`""`. Обязателен при `ENABLE_SSL=true` |
| `TRANSMITTAL_SERVICE_DATABASE__SSL_ROOT_CERT_PATH` | string | — | Путь к CA-сертификату. Обязателен при `ENABLE_SSL=true` |

> При `ENABLE_SSL=true` валидатор требует непустые `SSL_MODE` и `SSL_ROOT_CERT_PATH`, иначе — ошибка старта. Итоговый DSN собирается в `database.uri`.

### RabbitMQ (`rabbitmq.*`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `TRANSMITTAL_SERVICE_RABBITMQ__USER` | string | — | Пользователь |
| `TRANSMITTAL_SERVICE_RABBITMQ__PASSWORD` | string | — | Пароль |
| `TRANSMITTAL_SERVICE_RABBITMQ__VHOST` | string | — | Виртуальный хост |
| `TRANSMITTAL_SERVICE_RABBITMQ__HOST` | string | — | Хост |
| `TRANSMITTAL_SERVICE_RABBITMQ__PORT` | int | — | Порт |

### HTTP-клиенты внешних сервисов

Все клиенты наследуют общий набор полей (`HttpClient`): `BASE_URL`, `MAX_CONNECTIONS`, `MAX_KEEPALIVE_CONNECTIONS`, `TIMEOUT`. Все четыре поля обязательны (дефолтов нет).

| Секция / префикс | Назначение | Доп. поля |
| --- | --- | --- |
| `TRANSMITTAL_SERVICE_SAREX_BACKEND_REPOSITORY__*` | Основной backend Sarex | `BASIC_AUTH_ENCODED` — base64 от `login:password` (обязателен), декодируется в пару login/password |
| `TRANSMITTAL_SERVICE_RESOURCE_REPOSITORY__*` | Сервис ресурсов (IAM/resources) | — |
| `TRANSMITTAL_SERVICE_DOCUMENTATIONS_REPOSITORY__*` | Сервис документаций | — |
| `TRANSMITTAL_SERVICE_FLOWS_REPOSITORY__*` | Сервис flows | — |
| `TRANSMITTAL_SERVICE_HTML_TO_PDF_CONVERTER__*` | Конвертер HTML→PDF (export-project) | — |
| `TRANSMITTAL_SERVICE_MARKINGS__*` | Сервис PDF-маркировок | — |

Для каждого — четыре переменные, напр. для markings:

| Переменная | Тип | Назначение |
| --- | --- | --- |
| `TRANSMITTAL_SERVICE_MARKINGS__BASE_URL` | string | Базовый URL сервиса |
| `TRANSMITTAL_SERVICE_MARKINGS__MAX_CONNECTIONS` | int | Макс. число соединений |
| `TRANSMITTAL_SERVICE_MARKINGS__MAX_KEEPALIVE_CONNECTIONS` | int | Макс. keep-alive соединений |
| `TRANSMITTAL_SERVICE_MARKINGS__TIMEOUT` | int | Таймаут запроса (сек) |

Для `SAREX_BACKEND_REPOSITORY` дополнительно:

| Переменная | Тип | Назначение |
| --- | --- | --- |
| `TRANSMITTAL_SERVICE_SAREX_BACKEND_REPOSITORY__BASIC_AUTH_ENCODED` | string (base64) | Basic-auth в виде base64(`login:password`) |

### S3 (`s3_client.*`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `TRANSMITTAL_SERVICE_S3_CLIENT__ENDPOINT` | string | — | Эндпоинт S3. Если без `http(s)://` — префикс добавляется автоматически по `USE_SSL` |
| `TRANSMITTAL_SERVICE_S3_CLIENT__REGION_NAME` | string | — | Регион |
| `TRANSMITTAL_SERVICE_S3_CLIENT__DEFAULT_BUCKET` | string | — | Бакет по умолчанию |
| `TRANSMITTAL_SERVICE_S3_CLIENT__ACCESS_KEY` | string | — | Access key |
| `TRANSMITTAL_SERVICE_S3_CLIENT__SECRET_KEY` | string | — | Secret key |
| `TRANSMITTAL_SERVICE_S3_CLIENT__USE_SSL` | bool | — | Использовать SSL |
| `TRANSMITTAL_SERVICE_S3_CLIENT__VERIFY` | bool | — | Проверять TLS-сертификат |
| `TRANSMITTAL_SERVICE_S3_CLIENT__MAX_POOL_CONNECTIONS` | int | `10` | Размер пула соединений |
| `TRANSMITTAL_SERVICE_S3_CLIENT__CONNECT_TIMEOUT` | int | `10` | Таймаут подключения (сек) |
| `TRANSMITTAL_SERVICE_S3_CLIENT__READ_TIMEOUT` | int | `30` | Таймаут чтения (сек) |
| `TRANSMITTAL_SERVICE_S3_CLIENT__USE_PATH_STYLE` | bool | `True` | Path-style адресация |
| `TRANSMITTAL_SERVICE_S3_CLIENT__REQUEST_CHECKSUM_CALCULATION` | enum | `when_required` | `when_supported`/`when_required` |
| `TRANSMITTAL_SERVICE_S3_CLIENT__RESPONSE_CHECKSUM_VALIDATION` | enum | `when_required` | `when_supported`/`when_required` |

### Почта: Mailgun или SMTP

Должен быть настроен **ровно один** из двух сервисов (валидатор `check_mailing_service`), иначе — ошибка старта. По умолчанию используется Mailgun.

Mailgun (`mailgun.*`) — наследует поля `HttpClient` плюс:

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `TRANSMITTAL_SERVICE_MAILGUN__BASE_URL` | string | — | URL API, напр. `https://api.mailgun.net/v3/<domain>` |
| `TRANSMITTAL_SERVICE_MAILGUN__MAX_CONNECTIONS` | int | — | Макс. соединений |
| `TRANSMITTAL_SERVICE_MAILGUN__MAX_KEEPALIVE_CONNECTIONS` | int | — | Макс. keep-alive |
| `TRANSMITTAL_SERVICE_MAILGUN__TIMEOUT` | int | — | Таймаут (сек) |
| `TRANSMITTAL_SERVICE_MAILGUN__EMAIL` | string | — | Адрес отправителя |
| `TRANSMITTAL_SERVICE_MAILGUN__API_KEY` | string | — | API-ключ Mailgun |

SMTP (`smtp.*`) — альтернатива Mailgun:

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `TRANSMITTAL_SERVICE_SMTP__HOST` | string | — | SMTP-хост |
| `TRANSMITTAL_SERVICE_SMTP__PORT` | int | — | SMTP-порт |
| `TRANSMITTAL_SERVICE_SMTP__EMAIL` | string | — | Адрес отправителя |
| `TRANSMITTAL_SERVICE_SMTP__ENABLE_TLS` | bool | `False` | Включить TLS |
| `TRANSMITTAL_SERVICE_SMTP__LOGIN` | string \| null | `None` | Логин |
| `TRANSMITTAL_SERVICE_SMTP__PASSWORD` | string \| null | `None` | Пароль |

### OpenTelemetry (`otel.*`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `TRANSMITTAL_SERVICE_OTEL__ENABLE` | bool | `False` | Включить трейсинг |
| `TRANSMITTAL_SERVICE_OTEL__HOST` | string | — | Адрес OTLP-коллектора |
| `TRANSMITTAL_SERVICE_OTEL__SERVICE_NAME` | string | — | Имя сервиса в трейсах |
| `TRANSMITTAL_SERVICE_OTEL__INSECURE` | bool | `False` | Небезопасное (без TLS) подключение к коллектору |

## Переменные инфраструктуры, сборки и вспомогательных утилит

Не читаются кодом приложения, но участвуют в запуске/сборке/деплое.

| Переменная | Где используется | Назначение |
| --- | --- | --- |
| `TRANSMITTAL_SERVICE_PGDATA` | `.example.env` (закомментировано) | Каталог данных локального PostgreSQL |
| `TRANSMITTAL_SERVICE_PGHOST` | `.example.env` (закомментировано) | Хост локального PostgreSQL |
| `TRANSMITTAL_SERVICE_PGPORT` | `makefile` (`container-run-database`) | Внутренний порт контейнера Postgres при пробросе |
| `OCI` | `makefile` | Инструмент контейнеризации (`docker`/`podman`), по умолчанию `docker` |
| `TRANSMITTAL_SERVICE_IMAGE_NAME` / `TRANSMITTAL_SERVICE_IMAGE_VERSION` | `makefile` | Имя/тег собираемого образа |
| `TRANSMITTAL_SERVICE_CONTAINER__NETWORK_NAME` | `makefile` | Имя docker-сети |
| `TRANSMITTAL_SERVICE_DATABASE_CONTAINER__*` | `makefile` | Параметры контейнера Postgres (образ, имя, volume) |
| `TRANSMITTAL_SERVICE_RABBITMQ_CONATINER__*` | `makefile` | Параметры контейнера RabbitMQ |
| `PIP_INDEX_URL`, `PIP_TRUSTED_HOST` | `Dockerfile` (build-arg) | Приватный индекс пакетов при сборке |
| `TRANSMITTAL_SERVICE_PYTHON_IMAGE_NAME`, `TRANSMITTAL_SERVICE_PYTHON_IMAGE_TAG` | `Dockerfile` (build-arg) | Базовый образ Python (по умолчанию `python:3.12-slim`) |
| `UID`, `GID`, `USERNAME` | `Dockerfile` (build-arg) | Пользователь внутри образа (по умолчанию `10000`/`10001`/`transmittal_service`) |

## Переменные из Helm-чарта (`.helm/values-<env>.yaml`)

Обычные значения задаются в блоке `envs` для каждого окружения (`stage`/`preprod`/`production`) и содержат те же переменные приложения `TRANSMITTAL_SERVICE_*`, что описаны выше (различаются адресами БД/сервисов, портами, `LOG_LEVEL`, `ROOT_PATH`, бакетом, доменом Mailgun и т.п.).

Значения из секретов (блок `secrets`, монтируются как env через `secretKeyRef`):

| Переменная | Секрет (`secret_name`) | Ключ (`secret_key`) |
| --- | --- | --- |
| `TRANSMITTAL_SERVICE_DATABASE__USER` | `ya-pg-secret` | `username` |
| `TRANSMITTAL_SERVICE_DATABASE__PASSWORD` | `ya-pg-secret` | `password` |
| `YC-PG-CERTIFICATE` | `ya-pg-secret` | `certificate` |
| `TRANSMITTAL_SERVICE_AUTH__PUBLIC_KEY` | `public-key` | `key` |
| `TRANSMITTAL_SERVICE_SAREX_BACKEND_REPOSITORY__BASIC_AUTH_ENCODED` | `django-auth` | `key` |
| `TRANSMITTAL_SERVICE_S3_CLIENT__ACCESS_KEY` | `s3-secret` | `access_key` |
| `TRANSMITTAL_SERVICE_S3_CLIENT__SECRET_KEY` | `s3-secret` | `secret_key` |
| `TRANSMITTAL_SERVICE_RABBITMQ__USER` | `rabbitmq-cred` | `username` |
| `TRANSMITTAL_SERVICE_RABBITMQ__PASSWORD` | `rabbitmq-cred` | `password` |
| `TRANSMITTAL_SERVICE_MAILGUN__API_KEY` | `mailgun-cred` | `api_key` |

Помимо env, чарт монтирует CA-сертификат PostgreSQL из секрета `ya-pg-secret` (ключ `certificate`) как файл `/opt/.postgresql/root.crt` — именно на него указывает `TRANSMITTAL_SERVICE_DATABASE__SSL_ROOT_CERT_PATH` в prod-конфигурации.

Прочие значения чарта (не переменные приложения): `deployment.*` (имя, образ, порт, реплики, ресурсы), `api.*` (host/prefix/path ingress), `worker.*`, `job.name_periodic`, `imagePullSecrets`.

## Переменные в CI (`.gitlab-ci.yml`)

Пайплайн подключает общие шаблоны из `generic/common-ci` и переключает окружение по ветке/тегу через `workflow.rules`:

| Условие | STAND | Namespace |
| --- | --- | --- |
| ветка `master` | `preprod` | `transmittal-api-preprod` |
| ветка `stage` | `stage` | `transmittal-api-stage` |
| тег (`CI_COMMIT_TAG`) | `prod` | `transmittal-api-prod` |

Ключевые переменные пайплайна: `RELEASE_NAME`, `CHART_NAME`, `CHART_VERSION`, `DOCKERFILE_PATH`, `HELM_SET_ARGS` (`--set deployment.image=…`), флаги `ENABLE_LINTER`/`ENABLE_BUILD_CHART`/`ENABLE_BUILD_IMAGE`/`ENABLE_DEPLOY`. Job `test-unit` задаёт полный набор `TRANSMITTAL_SERVICE_*` переменных для прогона юнит-тестов.

## Замечания и потенциальные проблемы

- Переменные БД в `.example.env` должны иметь префикс `TRANSMITTAL_SERVICE_DATABASE__*` — код читает их именно так. Ранее в файле они были записаны без префикса (`DATABASE__USER` и т.д.) и не подхватывались; сейчас исправлено. В `makefile`, `.gitlab-ci.yml` и Helm имена с префиксом корректны.
- Приложение **не загружает `.env` автоматически** (в `settings.py` не задан `env_file`, зависимости `python-dotenv` нет). `make config` лишь создаёт файл-шаблон; переменные нужно экспортировать в окружение вручную либо задавать через `--env` (см. `make container-run`).
- `env_ignore_empty=False`: пустая строка воспринимается как заданное значение. Например `TRANSMITTAL_SERVICE_AUTH__PUBLIC_KEY=''` — валидное (пустой ключ), а вот полностью отсутствующая обязательная переменная вызовет ошибку старта.
- Переменная `YC-PG-CERTIFICATE` прокидывается из секрета в окружение, но **кодом приложения не читается** — сертификат используется как смонтированный файл (`root.crt`). Имя с дефисами не соответствует схеме `TRANSMITTAL_SERVICE_*`.
- Почтовый сервис: должен быть задан ровно один из `mailgun`/`smtp`. Если заданы оба или ни одного — сервис не стартует.
- В `.example.env` секция `FLOWS_REPOSITORY__BASE_URL` пустая, но поле обязательно — для реального запуска его нужно заполнить.

## Минимальный набор для локального запуска

Postgres и RabbitMQ поднимаются через `make container-deps`, приложение — через `make run-api` / `make run-worker`. Минимально необходимо задать (с префиксом `TRANSMITTAL_SERVICE_`):

- `APP__ENVIRONMENT`, `APP__HOST`
- `AUTH__PUBLIC_KEY` (можно пустой для локальной разработки)
- `CORS__ALLOW_ORIGINS`, `CORS__ALLOW_METHODS`, `CORS__ALLOW_HEADERS`, `CORS__ALLOW_CREDENTIALS`
- `DATABASE__HOST`, `DATABASE__PORT`, `DATABASE__USER`, `DATABASE__PASSWORD`, `DATABASE__NAME`, `DATABASE__ENABLE_SSL` (`false` локально), `DATABASE__SSL_MODE`, `DATABASE__SSL_ROOT_CERT_PATH`
- `RABBITMQ__USER`, `RABBITMQ__PASSWORD`, `RABBITMQ__VHOST`, `RABBITMQ__HOST`, `RABBITMQ__PORT`
- `BASE_URL`/`MAX_CONNECTIONS`/`MAX_KEEPALIVE_CONNECTIONS`/`TIMEOUT` для всех шести HTTP-клиентов (`SAREX_BACKEND_REPOSITORY` + `BASIC_AUTH_ENCODED`, `RESOURCE_REPOSITORY`, `DOCUMENTATIONS_REPOSITORY`, `FLOWS_REPOSITORY`, `HTML_TO_PDF_CONVERTER`, `MARKINGS`)
- `S3_CLIENT__*` (эндпоинт, регион, бакет, ключи, `USE_SSL`, `VERIFY`)
- один из почтовых сервисов: `MAILGUN__*` **или** `SMTP__*`
- `OTEL__ENABLE` (`False` локально), при `True` — `OTEL__HOST`, `OTEL__SERVICE_NAME`

Готовые значения-примеры для всех переменных приведены в `.example.env` (с учётом замечаний выше по префиксу БД).