# Конфигурация проекта issues-backend Документ описывает все переменные окружения и способы конфигурирования сервиса замечаний (Issues). ## Способы конфигурирования Сервис настраивается **через переменные окружения**. Это Django-приложение; настройки читаются в `src/config/settings/base.py` и `src/config/settings/production.py` напрямую через `os.getenv(...)`. В начале `base.py` вызывается `load_dotenv()` ([`python-dotenv`](https://pypi.org/project/python-dotenv/)), поэтому при локальном запуске файл `.env` из рабочего каталога **подхватывается автоматически**. Активный модуль настроек задаётся переменной `DJANGO_SETTINGS_MODULE` (в контейнере/Helm — `config.settings.production`) либо флагом `--settings=config.settings.production` у `manage.py`. Модуль `production.py` импортирует всё из `base.py` и переопределяет `DEBUG=False`, `ALLOWED_HOSTS`, `SIMPLE_JWT`, `LOGGING` и часть внешних хостов. Отдельного конфиг-файла (yaml/toml) у приложения нет. Дополнительно на инфраструктурном уровне используются `config/settings/base.py` для Celery/Kafka/OTel и Helm-чарт для задания переменных в Kubernetes. Источники переменных по способам запуска: | Способ запуска | Откуда берутся переменные | | --- | --- | | Локально | Переменные окружения процесса и файл `.env` (грузится `load_dotenv()` в `base.py`) | | Локально (Kafka) | `docker compose --file local-kafka-docker-compose.yml up -d` поднимает брокер; консьюмер — `manage.py consume_kafka` | | Kubernetes (Helm) | `.helm/values.yaml`: блоки `envs` (обычные значения) и `secretEnvs` (значения из k8s-секретов) для каждого сервиса (`api`, `celery`, `celery-beat`, `kafka-app`) | | CI/CD (GitLab) | `.gitlab-ci.yml`: общий шаблон `generic/common-ci` (`universal-pipeline.yaml`, ref `apps-business`); окружение выбирается по ветке/тегу | Способы запуска процессов: | Процесс | Команда | Назначение | | --- | --- | --- | | HTTP API | `uwsgi` (entrypoint) / `manage.py runserver` | REST API (DRF), OpenAPI-схема через drf-spectacular | | Celery worker | `celery -A config worker -l info -E --concurrency=2` | Обработчик фоновых задач (`issues.tasks`, `issues.notifications`, `prescriptions.tasks`) | | Celery beat | `celery -A config beat -l info` | Периодические задачи (ежедневный инкремент счётчиков, отчёт о просрочках) | | Kafka consumer | `python3 run_kafka_app.py` / `manage.py consume_kafka` | Консьюмер Kafka (топики ассетов и замечаний) | Порядок старта в контейнере задаётся `compose/server/entrypoint.sh` (миграции + запуск uWSGI по `compose/server/uwsgi.ini`). Базовый образ — `python:3.10-slim-bookworm` (`compose/server/Dockerfile`). ## Переменные приложения Дефолт `—` означает, что явного значения по умолчанию в коде нет (`os.getenv` вернёт `None`); для корректной работы переменную нужно задать. ### Django и окружение | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `DJANGO_SETTINGS_MODULE` | string | `config.settings.production` (Helm) | Модуль настроек Django | | `DJANGO_ADMIN_SECRET_KEY` | string | `''` | `SECRET_KEY` Django | | `DJANGO_TOKEN` | string | `django-token` | Служебный токен | | `ENVIRONMENT` | string | `production` | Окружение развёртывания (в т.ч. атрибут OTel) | | `ENVIRONMENT_CLIENT` | string | `production` | Клиентское окружение (`stage`/`preprod`/`production`) | ### База данных (PostgreSQL) | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `DATABASE_NAME` | string | — | Имя базы данных | | `DATABASE_USER` | string | — | Пользователь БД | | `DATABASE_PASSWORD` | string | — | Пароль пользователя БД | | `DATABASE_HOST` | string | — | Хост PostgreSQL | | `DATABASE_PORT` | int | — | Порт PostgreSQL | > Движок — `django.db.backends.postgresql`. В Kubernetes значения приходят из секрета (`issues-postgresql-secret` для stage, `ya-pg-secret` для preprod/production), CA-сертификат монтируется как `/root/.postgresql/ca.crt`. ### Внешние сервисы (URL) | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `SAREX_API` | string | — | Базовый API Sarex (`SAREX_HOST` по умолчанию равен ему) | | `SAREX_HOST` | string | `= SAREX_API` | Хост Sarex | | `AERO_HOST` | string | `https://stage.sarex.io` | Хост Aero | | `AERO_PUBLIC_HOST` | string | `https://stage.sarex.io` (в `production.py` — из env) | Публичный хост Aero | | `BASE_AERO_URL` | string | `https://lk.sarex.io` | Базовый URL Aero | | `BASE_AUTH_URL` | string | `https://lk.sarex.io` | Базовый URL аутентификации | | `SERVICE_URL` | string | `https://lk.sarex.io` | URL сервиса | | `GATEWAY_URL` | string | `https://lk.sarex.io` | URL gateway | | `DOCUMENTATIONS_URL` | string | `https://lk.sarex.io` | URL сервиса документаций | | `WORKFLOWS_URL` | string | `https://lk.sarex.io` | URL сервиса workflows | | `WORKFLOWS_HOST` | string | `https://lk.sarex.io` | Хост workflows | | `RESOURCES_API_HOST` | string | `https://lk.sarex.io` (в `production.py` — `http://sarex-resources-service.resources-prod`) | Хост сервиса ресурсов (IAM) | | `REVIEW_HOST` | string | `https://lk.sarex.io` | Хост сервиса review/flows | | `INSPECTION_HOST` | string | `https://lk.sarex.io` | Хост сервиса инспекций | | `EAV_HOST` | string | `http://eav-service.eav-stage` | Хост сервиса атрибутов (EAV) | | `SAREX_USERNAME` | string | — | Логин для basic-auth Sarex | | `SAREX_PASSWORD` | string | — | Пароль для basic-auth Sarex | ### RabbitMQ и Celery | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `RABBITMQ_USERNAME` | string | `mcc` | Пользователь брокера | | `RABBITMQ_PASSWORD` | string | `mcc` | Пароль брокера | | `RABBITMQ_HOSTNAME` | string | `rabbitmq-service` | Хост брокера | | `RABBITMQ_VHOST` | string | `api` | Виртуальный хост | | `REDIS_HOST` | string | `redis` | Хост Redis (result backend) | | `REDIS_DB` | int | `0` | Номер БД Redis | > `CELERY_BROKER_URL` собирается как `amqp://{user}:{password}@{hostname}/{vhost}` + `?heartbeat=30`. `CELERY_RESULT_BACKEND` — `redis://{REDIS_HOST}:6379/{REDIS_DB}`. Расписание beat: инкремент счётчиков `1:00`, отчёт о просрочках `6:00` (`Europe/Moscow`). ### Kafka | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `KAFKA_HOST` | string | — | Адрес брокера Kafka | | `KAFKA_USERNAME` | string | — | Пользователь | | `KAFKA_PASSWORD` | string | — | Пароль | | `KAFKA_SSL_CAFILE` | string | — | Путь к CA-сертификату (в Helm — YandexInternalRootCA) | | `KAFKA_EAV_ASSETS_TOPIC` | string | — | Топик трансляции ассетов (EAV) | | `KAFKA_ISSUES_TOPIC` | string | — | Топик трансляции замечаний | ### S3 (Yandex Cloud) Основное хранилище (`django-storages`, `S3Boto3Storage`): | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `YC_S3_ACCESS_KEY_ID` | string | — | Access key | | `YC_S3_SECRET_ACCESS_KEY` | string | — | Secret key | | `YC_S3_BUCKET_NAME` | string | — | Имя бакета | | `YC_S3_ENDPOINT_URL` | string | — | Эндпоинт S3 | | `YC_S3_VERIFY` | bool | `None` | Проверять TLS-сертификат (`"true"` → `True`) | Хранилище предписаний (отдельный бакет): | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `PRESCRIPTION_S3_ACCESS_KEY_ID` | string | — | Access key | | `PRESCRIPTION_S3_SECRET_ACCESS_KEY` | string | — | Secret key | | `PRESCRIPTION_S3_BUCKET` | string | — | Имя бакета | | `PRESCRIPTION_S3_ENDPOINT_URL` | string | — | Эндпоинт S3 | ### Почта (Mailgun / SMTP) | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `ENABLE_MAILGUN` | bool | `True` | Использовать Mailgun | | `MAILGUN_BASE_URL` | string | `https://api.mailgun.net/v3/mg.sarex.io` | URL API Mailgun | | `MAILGUN_API_KEY` | string | (задан дефолт в коде) | API-ключ Mailgun (в проде — из секрета) | | `EMAIL_FROM` | string | `hello@sarex.io` | Адрес отправителя | | `EMAIL_DOCKER_IMAGE` | string | `cr.yandex/.../notification:email` | Образ сервиса нотификаций | | `USE_NOTIFICATIONS` | bool | `True` | Включить отправку уведомлений (`False`/`false`/`0` → выкл.) | | `SMTP_HOST` | string | `None` (в `production.py` — `""`) | SMTP-хост (альтернатива Mailgun) | | `SMTP_PORT` | int | `None` | SMTP-порт | ### Предписания (workflow) | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `PRESCRIPTION_WF_IMAGE` | string | — | Образ workflow генерации предписаний | | `DOCX_TO_PDF_IMAGE` | string | — | Образ конвертера DOCX→PDF | | `PRESCRIPTION_WF_RESULT_PATH` | string | — | Путь/бакет результата | | `PRESCRIPTION_WF_CALLBACK` | string | — | Образ webhook-caller | | `PRESCRIPTION_INTERNAL_HOST` | string | — | Внутренний хост колбэков предписаний | | `EXPORT_WF_CROPPING_DOCKER_IMAGE` | string | `cr.yandex/.../crop-issue-pin-area:prod` | Образ кропа области пина для экспорта | ### OpenTelemetry Трейсинг подключается только если `USE_OTEL` истинно (`django_otel_tools`). | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `USE_OTEL` | bool | `False` | Включить трейсинг/логирование через OTel | | `SERVICE_NAME` | string | `issues-backend.sarex-issues` | Имя сервиса в трейсах | | `TRACER_ENDPOINT` | string | `localhost:4375` | Адрес OTLP-коллектора | | `USE_INSECURE` | bool | `False` | Небезопасное (без TLS) подключение к коллектору | | `MODULE` | string | `issues` | Атрибут трейсов | | `TEAM` | string | `proc_team` | Атрибут трейсов | | `COMPONENT` | string | `backend` | Атрибут трейсов | ## Переменные инфраструктуры Не читаются кодом приложения напрямую (или используются вспомогательными компонентами), но участвуют в запуске/деплое. | Переменная | Где используется | Назначение | | --- | --- | --- | | `API_ADDRESS` | Helm (`envs`) | Порт uWSGI (`8000`) | | `SENTRY_KEY` | Helm (`envs`) | DSN Sentry (задан для stage) | | `SAREX_MAILER_URL` | Helm (`envs`) | URL сервиса рассылок (`http://mailer-service.mailer:8000`) | | `MAILGUN_HOST` | Helm (`envs`) | Хост Mailgun на уровне чарта | | `NPM_TOKEN`, `BUILD_ENV` | CI/Dockerfile | Сборка (актуально для фронтенда) | ## Переменные из Helm-чарта (`.helm/values.yaml`) Чарт — обёртка над `universal-chart`. Определены четыре сервиса: `api`, `celery`, `celery-beat`, `kafka-app`. Обычные значения (`envs`) задаются для окружений `_default`/`stage`/`preprod`/`production` (различаются адресами БД/сервисов, топиками Kafka, образами, `SERVICE_NAME`, `TRACER_ENDPOINT`). Значения из секретов (блок `secretEnvs`, монтируются через `secretKeyRef`): | Переменная | Секрет (stage / preprod-prod) | Ключ | | --- | --- | --- | | `KAFKA_USERNAME` | `issues-kafka-secret` / `yc-kafka-secret` | `username` | | `KAFKA_PASSWORD` | `issues-kafka-secret` / `yc-kafka-secret` | `password` | | `KAFKA_HOST` | `issues-kafka-secret` / `yc-kafka-secret` | `host` | | `SAREX_USERNAME` | `sarex-auth` | `username` | | `SAREX_PASSWORD` | `sarex-auth` | `password` | | `DATABASE_HOST` | `issues-postgresql-secret` / `ya-pg-secret` | `host` | | `DATABASE_NAME` | `issues-postgresql-secret` / `ya-pg-secret` | `database` | | `DATABASE_PORT` | `issues-postgresql-secret` / `ya-pg-secret` | `port` | | `DATABASE_USER` | `issues-postgresql-secret` / `ya-pg-secret` | `username` | | `DATABASE_PASSWORD` | `issues-postgresql-secret` / `ya-pg-secret` | `password` | | `YC_S3_ACCESS_KEY_ID` | `issues-s3-secret` / `yc-s3-secret` | `key_id` | | `YC_S3_SECRET_ACCESS_KEY` | `issues-s3-secret` / `yc-s3-secret` | `access_key` | | `YC_S3_BUCKET_NAME` | `issues-s3-secret` / `yc-s3-secret` | `storage_bucket_name` | | `YC_S3_ENDPOINT_URL` | `issues-s3-secret` / `yc-s3-secret` | `endpoint_url` | | `RABBITMQ_VHOST` | `issues-rabbitmq-secret` / `rabbitmq-secret` | `vhost` | | `RABBITMQ_USERNAME` | `issues-rabbitmq-secret` / `rabbitmq-secret` | `user` | | `RABBITMQ_HOSTNAME` | `issues-rabbitmq-secret` / `rabbitmq-secret` | `host` | | `RABBITMQ_PASSWORD` | `issues-rabbitmq-secret` / `rabbitmq-secret` | `password` | | `MAILGUN_API_KEY` | `mailgun-secret` | `api-key` | | `DJANGO_TOKEN` | `django-secret` | `token` | | `DJANGO_ADMIN_SECRET_KEY` | `django-admin-secret` | `secret_key` | | `PRESCRIPTION_S3_ACCESS_KEY_ID` | `prescription-s3-secret` | `key_id` | | `PRESCRIPTION_S3_SECRET_ACCESS_KEY` | `prescription-s3-secret` | `access_key` | | `PRESCRIPTION_S3_BUCKET` | `prescription-s3-secret` | `storage_bucket_name` | | `PRESCRIPTION_S3_ENDPOINT_URL` | `prescription-s3-secret` | `endpoint_url` | Дополнительно чарт монтирует конфиг uWSGI (`uwsgi-configmap` → `/opt/server/uwsgi.ini`, только сервис `api`), CA-сертификат PostgreSQL (`yc-ch-certificate` → `/root/.postgresql/ca.crt`) и внутренний CA Яндекса (`YandexInternalRootCA.crt`). ## Переменные в CI (`.gitlab-ci.yml`) Пайплайн подключает общие шаблоны из `generic/common-ci` (`common-security-scan.yaml`, `universal-pipeline.yaml`, ref `apps-business`). Основные переменные: `SERVICE_NAME=issues`, `DOCKERFILE_PATH=./compose/server/Dockerfile`. Окружение выбирается по ветке/тегу: | Условие | STAND | Namespace | CHART_VERSION | | --- | --- | --- | --- | | ветка `stage` | `stage` | `proc` | `0.0.1-stage` | | ветка `master` | `preprod` | `issues-preprod` | `0.0.1-preprod` | | тег (`CI_COMMIT_TAG`) | `production` | `issues-prod` | `0.0.1-prod` | `HELM_SET_ARGS` для каждого окружения проставляет образы четырёх сервисов (`api`, `celery`, `celery-beat`, `kafka-app`), `universal-chart.global.env` и метаданные коммита (`commitSha`, `gitlabUri`, `gitlabJobUrl`, `owner`). ## Замечания и потенциальные проблемы - В отличие от FastAPI-сервисов, переменные не имеют единого префикса и читаются напрямую через `os.getenv`. Файл `.env` подхватывается автоматически (`load_dotenv()` в `base.py`). - `DEBUG` в `base.py` установлен в `True`; в `production.py` переопределяется на `False`. Для боевого окружения обязателен модуль `config.settings.production`. - `MAILGUN_API_KEY` имеет захардкоженный дефолт в коде — в реальных окружениях его нужно переопределять секретом. - Ряд переменных без дефолта (`DATABASE_*`, `KAFKA_*`, `YC_S3_*`, `SAREX_USERNAME`/`SAREX_PASSWORD`, `PRESCRIPTION_WF_*`) обязательны для полноценной работы соответствующих подсистем. - Переменные `SAREX_MAILER_URL`, `MAILGUN_HOST`, `SENTRY_KEY`, `API_ADDRESS` задаются в Helm, но не читаются кодом приложения напрямую. ## Минимальный набор для локального запуска Postgres, RabbitMQ, Redis и Kafka поднимаются локально; приложение — `python ./src/manage.py runserver --settings=config.settings.production`, консьюмер — `manage.py consume_kafka`. Минимально необходимо задать: - `DJANGO_ADMIN_SECRET_KEY` - `DATABASE_NAME`, `DATABASE_USER`, `DATABASE_PASSWORD`, `DATABASE_HOST`, `DATABASE_PORT` - `RABBITMQ_USERNAME`, `RABBITMQ_PASSWORD`, `RABBITMQ_HOSTNAME`, `RABBITMQ_VHOST`, `REDIS_HOST` - `KAFKA_HOST`, `KAFKA_USERNAME`, `KAFKA_PASSWORD`, `KAFKA_EAV_ASSETS_TOPIC`, `KAFKA_ISSUES_TOPIC` (для консьюмера) - `YC_S3_*` (для работы с файлами) и при необходимости `PRESCRIPTION_S3_*` - внешние URL: `SAREX_API`, `AERO_HOST`, `GATEWAY_URL`, `DOCUMENTATIONS_URL`, `WORKFLOWS_URL`, `RESOURCES_API_HOST`, `EAV_HOST`, `INSPECTION_HOST`, `REVIEW_HOST` - почта: `ENABLE_MAILGUN` + `MAILGUN_*` **или** `SMTP_HOST`/`SMTP_PORT` - `USE_OTEL=False` для локальной разработки Готовые значения-примеры приведены в `.env.example`.