# Конфигурация проекта 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`.
