# Конфигурация проекта inspections-backend Документ описывает все переменные окружения и способы конфигурирования сервиса. ## Способы конфигурирования Сервис настраивается **только через переменные окружения**. Разбор выполняется в `src/config.py` через библиотеку [`pydantic-settings`](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) (класс `Config` и вложенные `*Config`). Особенности разбора: - у приложения **нет единого общего префикса** — каждая секция задаётся собственным `env_prefix` в своём `SettingsConfigDict` (напр. `HTTP_APP_`, `DATABASE_`, `KAFKA_`, `OTEL_`, `JWT_AUTH_`, `NOTIFICATIONS_`, `SAREX_BACKEND_`, `EAV_`, `WORKFLOWS_`, `MOBILE_APP_`); - две переменные верхнего уровня (`DEBUG`, `SERVICE_URL`) читаются без префикса; - вложенности через разделитель нет — плоские имена вида ``, напр. `DATABASE_HOST` → `database.host`; - почти у всех полей есть значения по умолчанию, поэтому отсутствие переменной обычно не приводит к ошибке старта — берётся дефолт из кода. В таблицах ниже приведены дефолты из `src/config.py`. Отдельного конфиг-файла (yaml/toml) у приложения нет. Часовой пояс приложения зафиксирован в коде: `app_timezone = ZoneInfo("Europe/Moscow")`. Источники переменных по способам запуска: | Способ запуска | Откуда берутся переменные | | --- | --- | | Локально (uv) | `Makefile` через `SET_ENV` делает `set -a; source .env; set +a` перед запуском команд. Шаблон переменных — `.env.template` (в репозитории; `.env*` в `.gitignore`, кроме `.env.template`) | | Docker | `docker/http/Dockerfile` и `docker/kafka/Dockerfile` фиксируют `PYTHONPATH=src` и `PICCOLO_CONF=db.config`; прикладные переменные пробрасываются рантаймом (k8s) | | Kubernetes (Helm) | `.helm/values.yaml`: блоки `envs` (обычные значения) и `secretEnvs` (значения из k8s-секретов) для сервисов `api` и `kafka-app` | | CI/CD (GitLab) | `.gitlab-ci.yml`: переменные пайплайна (`workflow.rules`), сборка образа и деплой универсального чарта | Способы запуска процессов: | Команда (`Makefile`) | Точка входа | Назначение | | --- | --- | --- | | `make run` | `src/cmd/http/main.py` | HTTP API (uvicorn, `app.http:create_app`, `factory=True`) | | — (kafka-consumer) | `src/cmd/kafka/main.py` | Обработчик Kafka-событий (FastStream) | | `make migrate` | `piccolo migrations forwards all` | Применение миграций Piccolo | | `make migrations` | `piccolo migrations new inspections --auto` | Генерация новой миграции | | `make sync_eav` | `src/cmd/scripts/sync_eav.py` | Разовая синхронизация EAV | | `make playground` | `piccolo playground run` | Локальный playground Piccolo (sqlite) | | `make format` / `make format-check` | `ruff` | Форматирование/проверка кода | Порядок запуска в контейнере HTTP (`docker/http/entrypoint.sh`): сначала выполняются миграции (`piccolo migrations forwards all`), затем стартует `src/cmd/http/main.py`. Контейнер kafka-consumer (`docker/kafka/entrypoint.sh`) запускает только `src/cmd/kafka/main.py` (миграции не применяет). ## Переменные приложения В столбце «Переменная» указано полное имя (префикс + поле). Дефолт `—` означает, что значения по умолчанию у поля нет. ### App (верхний уровень) | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `DEBUG` | bool | `True` | Режим отладки: логирование SQL-запросов Piccolo, `reload=True` у uvicorn, непродакшн-режим админки | | `SERVICE_URL` | string | `https://stage.sarex.io` | Внешний базовый URL Sarex, используется при формировании ссылок (уведомления, экспорт) | ### HTTP App (`HTTP_APP_*`) | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `HTTP_APP_HOST` | string | `0.0.0.0` | Адрес прослушивания | | `HTTP_APP_PORT` | int | `8000` | Порт | | `HTTP_APP_ROOT_PATH` | string | `""` | Root path (префикс за реверс-прокси, напр. `/inspections`) | | `HTTP_APP_WORKERS` | int | `1` | Число воркеров uvicorn | | `HTTP_APP_ADMIN_ENABLE` | bool | `True` | Монтировать ли Piccolo-admin по пути `/admin/` | ### Database (`DATABASE_*`) PostgreSQL через Piccolo (`PostgresEngine`). | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `DATABASE_HOST` | string | `postgres` | Хост PostgreSQL | | `DATABASE_PORT` | int | `5432` | Порт PostgreSQL | | `DATABASE_NAME` | string | `postgres` | Имя базы данных | | `DATABASE_USER` | string | `postgres` | Пользователь БД | | `DATABASE_PASSWORD` | string | `postgres` | Пароль пользователя БД | ### Kafka (`KAFKA_*`) Используется FastStream (`KafkaBroker`). Продюсер — в HTTP-приложении (публикация событий инспекций), консьюмер — отдельный процесс (`kafka-app`), подписан на топик EAV-ассетов. | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `KAFKA_HOST` | string | `""` | Bootstrap-сервер (`bootstrap_servers=[host]`) | | `KAFKA_USERNAME` | string | `""` | Пользователь (SASL) | | `KAFKA_PASSWORD` | string | `""` | Пароль (SASL) | | `KAFKA_SSL_CERT` | string | `""` | CA-сертификат как строка (`cadata`). Если задан — HTTP-приложение подключается по `SASLScram512` поверх TLS, иначе без SSL | | `KAFKA_SSL_CAFILE` | string | `""` | Путь к CA-файлу (`cafile`). Если задан — kafka-consumer подключается по `SASLScram512` поверх TLS, иначе без SSL | | `KAFKA_EAV_ASSETS_TOPIC` | string | `""` | Топик событий EAV-ассетов, на который подписан consumer | > Механизм безопасности отличается между процессами: HTTP-приложение (`app/http.py`) смотрит на `KAFKA_SSL_CERT` (строка сертификата), а kafka-consumer (`app/kafka.py`) — на `KAFKA_SSL_CAFILE` (путь к файлу). ### OpenTelemetry (`OTEL_*`) | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `OTEL_ENABLE` | bool | `False` | Включить трейсинг/структурированное логирование. При `True` отключается `access_log` uvicorn | | `OTEL_URL` | string | `http://signoz-otel-collector-external.signoz.svc.cluster.local:4317` | Адрес OTLP-коллектора | | `OTEL_SERVICE_NAME` | string | `inspections-backend.inspections-stage` | Имя сервиса в трейсах | | `OTEL_INSECURE` | bool | `True` | Небезопасное (без TLS) подключение к коллектору | ### Auth (`JWT_AUTH_*`) | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `JWT_AUTH_ENABLE` | bool | `False` | Подключать ли middleware `TokenUserMiddleware`. При `False` используется дефолтный пользователь из `entity/context.py` (для локальной разработки) | > Middleware декодирует JWT **без проверки подписи** (`verify_signature: False`). При наличии заголовка `identity` полезная нагрузка берётся из него (метаданные Zitadel), иначе — из `authorization`. Роуты `/docs/`, `/openapi.json/`, `/admin/`, `/internal/` исключены из проверки. ### Notifications (`NOTIFICATIONS_*`) | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `NOTIFICATIONS_ENABLE` | bool | `False` | Включить отправку уведомлений об инспекциях | | `NOTIFICATIONS_EMAIL_FROM` | string | `hello@sarex.io` | Адрес отправителя писем | ### Sarex backend (`SAREX_BACKEND_*`) HTTP-клиент основного бэкенда Sarex (данные пользователей и т.п.). | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `SAREX_BACKEND_URL` | string | `https://stage.sarex.io` | Базовый URL | | `SAREX_BACKEND_TIMEOUT` | int | `30` | Таймаут запроса (сек) | | `SAREX_BACKEND_AUTH` | string (base64) | `base64(login:password)` | Basic-auth в виде base64(`login:password`) | ### EAV (`EAV_*`) HTTP-клиент сервиса атрибутов (EAV). | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `EAV_URL` | string | `https://stage-api.sarex.io/eav` | Базовый URL | | `EAV_TIMEOUT` | int | `30` | Таймаут запроса (сек) | ### Workflows (`WORKFLOWS_*`) HTTP-клиент сервиса процессов; используется, в т.ч. для запуска отправки email. | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `WORKFLOWS_URL` | string | `http://workflows-api-service.processing-stage` | Базовый URL | | `WORKFLOWS_TIMEOUT` | int | `30` | Таймаут запроса (сек) | | `WORKFLOWS_EMAIL_DOCKER_IMAGE` | string | `cr.yandex/crp3ccidau046kdj8g9q/notification:email` | Docker-образ шага отправки email | ### Mobile App (`MOBILE_APP_*`) Значения отдаются эндпоинтом `GET /api/v1/mobile-app/version/`. | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `MOBILE_APP_CURRENT_VERSION` | string | `""` | Текущая версия | | `MOBILE_APP_RECOMMENDED_VERSION` | string | `""` | Рекомендуемая версия | | `MOBILE_APP_REQUIRED_VERSION` | string | `""` | Минимально требуемая версия | ## Переменные инфраструктуры и сборки Не читаются кодом приложения через `pydantic-settings`, но участвуют в запуске/сборке/деплое. | Переменная | Где используется | Назначение | | --- | --- | --- | | `PYTHONPATH=src` | `.env.template`, `Dockerfile` | Корень пакета приложения | | `PICCOLO_CONF=db.config` | `.env.template`, `Dockerfile` | Модуль конфигурации Piccolo (`APP_REGISTRY`, `DB`, `ADMIN_ASGI_APP`) | ## Переменные из Helm-чарта (`.helm/values.yaml`) Чарт — обёртка над зависимостью `universal-chart` (`oci://cr.yandex/crp3ccidau046kdj8g9q/charts`, версия `0.1.7`). Описаны два сервиса: `api` (HTTP) и `kafka-app` (consumer), у каждого свои блоки `envs` и `secretEnvs`. Значения различаются по окружениям через ключи `_default`/`stage`/`preprod`/`production`. Обычные значения (`envs`) содержат те же переменные приложения, что и выше (различаются `SERVICE_URL`, `EAV_URL`, `WORKFLOWS_URL`, `OTEL_*`, `KAFKA_EAV_ASSETS_TOPIC`, `HTTP_APP_ROOT_PATH=/inspections`, `HTTP_APP_WORKERS=3`, `JWT_AUTH_ENABLE=true`, `NOTIFICATIONS_ENABLE` и т.п.). Отличия от дефолтов кода: в проде `DEBUG=false`, `OTEL_ENABLE=true`, `JWT_AUTH_ENABLE=true`. Значения из секретов (`secretEnvs`, монтируются как env через `secretKeyRef`): | Переменная | Секрет (`_default` / `stage`) | Ключ (`secretKey`) | | --- | --- | --- | | `DATABASE_USER` | `ya-pg-secret` / `inspections-postgresql-secret` | `username` | | `DATABASE_PORT` | `ya-pg-secret` / `inspections-postgresql-secret` | `port` | | `DATABASE_NAME` | `ya-pg-secret` / `inspections-postgresql-secret` | `database` | | `DATABASE_HOST` | `ya-pg-secret` / `inspections-postgresql-secret` | `host` | | `DATABASE_PASSWORD` | `ya-pg-secret` / `inspections-postgresql-secret` | `password` | | `KAFKA_HOST` | `yc-kafka-secret` / `inspections-kafka-secret` | `host` | | `KAFKA_USERNAME` | `yc-kafka-secret` / `inspections-kafka-secret` | `username` | | `KAFKA_PASSWORD` | `yc-kafka-secret` / `inspections-kafka-secret` | `password` | | `KAFKA_SSL_CERT` | `inspections-kafka-secret` | `cert` | | `SAREX_BACKEND_AUTH` | `sarex-backend-auth-secret` | `key` | Помимо env, у сервиса `kafka-app` смонтирован CA-сертификат Yandex как файл `/usr/local/share/ca-certificates/Yandex/YandexInternalRootCA.crt` (секрет `yc-ch-certificate`, ключ `certificate`) — на него указывает `KAFKA_SSL_CAFILE`. Прочие значения чарта (не переменные приложения): `deployment.*` (имя, реплики, ресурсы, probes), `image.*`, `service.*`, `imagePullSecrets`, у `kafka-app` — `command` (`python src/cmd/kafka/main.py`) и `volumes`. ## Переменные в CI (`.gitlab-ci.yml`) Пайплайн подключает шаблоны из `generic/common-ci` (`common-security-scan.yaml`, `universal-pipeline.yaml`, ref `apps-business`) и переключает окружение по ветке/тегу через `workflow.rules`: | Условие | STAND | Namespace | Release / Chart | | --- | --- | --- | --- | | ветка `stage` | `stage` | `proc` | `inspections-backend` | | ветка `master` | `preprod` | `inspections-preprod` | `inspections-backend` | | тег (`CI_COMMIT_TAG`) | `production` | `inspections-prod` | `sarex-inspections` | | `merge_request_event` | — | — | сборка образа отключена (`ENABLE_BUILD_IMAGE=false`) | Ключевые переменные пайплайна: `SERVICE_NAME=inspections-backend`, `DOCKERFILE_PATH=./docker/http/Dockerfile`, `CHART_VERSION`, `K8S_HUSTLER_BRANCH`, `HELM_SET_ARGS` (проброс `image.name`, `global.env`, метаданных коммита для сервисов `api` и `kafka-app`). Job `lint` прогоняет `ruff check` и `ruff format --check` на образе `uv 0.7.13 / python3.13`. ## Замечания - Приложение **не загружает `.env` автоматически** — переменные экспортируются в окружение (в `Makefile` — через `set -a; source .env; set +a`, в k8s — через env-блоки чарта). - Аутентификация в middleware декодирует JWT **без проверки подписи**; безопасность обеспечивается сетевым слоем/ingress. При `JWT_AUTH_ENABLE=false` активен захардкоженный дефолтный пользователь (`entity/context.py`), пригодный только для локальной разработки. - Большинство полей конфигурации имеют дефолты — при отсутствии переменной сервис стартует со значением из кода. Для реального окружения значения задаются в `.helm/values.yaml`. - Для экспорта поддерживается единственный формат — `xlsx` (`InspectionExportType`). ## Минимальный набор для локального запуска Скопировать `.env.template` в `.env`, поднять PostgreSQL и (при необходимости обработки событий) Kafka, применить миграции (`make migrate`) и запустить API (`make run`). Минимально стоит задать: - `DEBUG`, `SERVICE_URL` - `HTTP_APP_HOST`, `HTTP_APP_PORT` - `DATABASE_HOST`, `DATABASE_PORT`, `DATABASE_NAME`, `DATABASE_USER`, `DATABASE_PASSWORD` - `JWT_AUTH_ENABLE=false` (для дебага без токена) - `KAFKA_*` (если нужен consumer/публикация событий) - `SAREX_BACKEND_*`, `EAV_*`, `WORKFLOWS_*` (для интеграций) - `OTEL_ENABLE=false` локально