# Конфигурация проекта pm-backend Документ описывает все переменные окружения и способы конфигурирования сервиса. ## Способы конфигурирования Сервис — это Django-приложение (Django 5.1 + Django REST Framework), запускаемое как ASGI (`config.asgi_root:application`) через gunicorn с воркерами `uvicorn.workers.UvicornWorker`. Настройки читаются из переменных окружения через набор классов [`pydantic-settings`](https://docs.pydantic.dev/latest/concepts/pydantic_settings/), объявленных в `config/settings/base.py` и `config/settings/deps/*`. Особенности разбора: - **у каждой секции свой префикс** (`env_prefix`), напр. `SERVER_`, `DB_`, `S3_`, `CACHE_`, `CLICKHOUSE_`, `KAFKA_`, `CELERY_RABBITMQ_`, `CELERY_REDIS_`, `AUTH_`, `GATEWAY_`, `EAV_`, `DOCUMENTATION_`, `USERS_`, `RESOURCES_`, `TRACING_`, `SENTRY_`; - **вложенного делимитера нет** — каждая настройка задаётся плоской переменной вида ``, напр. `DB_HOST`, `CELERY_RABBITMQ_VHOST`; - **`extra='ignore'`** — все классы игнорируют посторонние переменные, поэтому один общий `.env` без ошибок разбирается всеми секциями; - **`env_file='.env'`** — в отличие от эталонного сервиса, здесь `.env` **загружается автоматически** каждым классом настроек (у `SentrySettings` — `.env.base` и `.env`). Значения из реального окружения процесса имеют приоритет над файлом. Отдельного конфиг-файла (yaml/toml) у приложения нет. `DJANGO_SETTINGS_MODULE` по умолчанию — `config.settings.base` (см. `manage.py`). Источники переменных по способам запуска: | Способ запуска | Откуда берутся переменные | | --- | --- | | Локально (manage.py / gunicorn) | Переменные окружения процесса + файл `.env` в корне репозитория (загружается pydantic-settings) | | Локально (docker-compose) | `docker-compose.yaml` поднимает зависимости (postgres, redis, rabbit, clickhouse, minio, pgadmin); переменные приложения задаются через окружение/`.env` | | Kubernetes (Helm) | `.helm/values.yaml`: блок `envs` (обычные значения) и `secretEnvs` (значения из k8s-секретов) для сервисов `api` и `celery`; чарт-зависимость `universal-chart` | | CI/CD (GitLab) | `.gitlab-ci.yml`: переменные пайплайна (`workflow.rules`) и job-ы `linter`/`typechecker`/`linter_src` | Способы запуска процессов: | Процесс | Точка входа | Назначение | | --- | --- | --- | | HTTP API | `docker/entrypoint.sh` → `gunicorn config.asgi_root:application` (uvicorn worker, порт 8000) | REST API | | Celery worker/beat | `celery -A config worker -B -Q pm …` (см. `.helm/values.yaml`, сервис `celery`) | Фоновые задачи и периодические (beat) | | `manage.py migrate` | `manage.py` | Миграции БД | | `manage.py clean_db` / `import_data` | `manage.py` | Служебные команды (см. `README.md`) | ## Переменные приложения Ниже перечислены все секции настроек с их префиксами. Дефолт `—` означает отсутствие значения по умолчанию в коде. ### Server (`SERVER_*`) Класс `ServerSettings` (`config/settings/base.py`). | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `SERVER_HOST` | string | `https://lk.sarex.io` | Внешний базовый URL (личный кабинет); из него формируется `SERVER_MEDIA_HOST` | | `SERVER_API_HOST` | string | `https://api.sarex.io` | Базовый URL API-шлюза (используется внешними клиентами по умолчанию) | | `SERVER_MEDIA_ROOT` | string | `sarex/media` | Каталог медиафайлов | | `SERVER_DEBUG` | bool | `False` | Django DEBUG. При `True` также включает `FAKE_CELERY` и обход аутентификации в `JWTAuthentication` | | `SERVER_ENABLE_SILK` | bool | `False` | Подключить профайлер django-silk (только при `DEBUG`) | | `SERVER_ALLOWED_HOSTS` | list[str] (JSON) | `["*"]` | Django `ALLOWED_HOSTS` | | `SERVER_SECRET_KEY` | string | `secret` | Django `SECRET_KEY` | | `SERVER_USE_OTEL` | bool | `False` | Включить OpenTelemetry-трейсинг и OTel-логгер (см. секцию `TRACING_*`) | | `SERVER_VERIFY_SSL` | bool | `True` | Проверять TLS-сертификаты при обращении к внешним сервисам | | `SERVER_LOG_LEVEL` | enum | `INFO` | `DEBUG`/`INFO`/`WARNING`/`CRITICAL`/`FATAL` | | `SERVER_ENABLE_SYNC_RESOURCES` | bool | `False` | Включить синхронизацию ресурсов | | `SERVER_DELETED_TASK_MAX_AGE_DAYS` | int | `30` | Срок хранения удалённых задач (дней) | | `SERVER_EXPIRED_TASK_NOTIFICATION_HOUR` | int | `9` | Час отправки уведомлений о просроченных задачах | | `SERVER_EXPIRED_TASK_NOTIFICATION_MAX_DAYS` | int | `7` | Горизонт уведомлений о просрочке (дней) | | `SERVER_SEND_UPDATED_PROJECTS_INFO_INTERVAL` | int | `5` | Интервал отправки информации об обновлённых проектах | ### Auth (`AUTH_*`) Класс `AUTHSettings` (`config/settings/deps/auth.py`). | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `AUTH_ALGORITHM` | string | `RS512` | Алгоритм проверки подписи JWT | | `AUTH_PUBLIC_KEY` | string | `''` | Публичный RSA-ключ для проверки JWT в режиме sarex-backend | | `AUTH_PUBLIC_TOKEN_URL` | string | `https://lk.sarex.io/api/token/public/` | URL получения публичного ключа/токена | Аутентификация DRF (`REST_FRAMEWORK.DEFAULT_AUTHENTICATION_CLASSES`) — по очереди `ZitadelJWTAuthentication`, затем `JWTAuthentication`; доступ по умолчанию `IsAuthenticated`. Zitadel-режим требует одновременно заголовки `Authorization` и `Identity`. ### Database (`DB_*`) Класс `DBSettings` (`config/settings/deps/db.py`). PostgreSQL. | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `DB_ENGINE` | string | `django.db.backends.postgresql` | Движок Django ORM | | `DB_HOST` | string | `localhost` | Хост PostgreSQL | | `DB_PORT` | int | `5432` | Порт PostgreSQL | | `DB_DATABASE` | string | `sarex_db` | Имя базы данных | | `DB_USERNAME` | string | `sarex` | Пользователь БД | | `DB_PASSWORD` | string | `sarex` | Пароль пользователя БД | ### S3 (`S3_*`) Класс `S3Settings` (`config/settings/deps/s3.py`). Хранилище через django-storages (boto3), по умолчанию Yandex Object Storage. | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `S3_HOST` | string | `https://storage.yandexcloud.net` | Endpoint S3 | | `S3_LOGIN` | string | `''` | Access key | | `S3_PASSWORD` | string | `''` | Secret key | | `S3_BUCKET` | string | `sarex-media-storage` | Бакет по умолчанию | | `S3_VERIFY` | bool | `True` | Проверять TLS-сертификат | ### Cache (`CACHE_*`) Класс `CacheSettings` (`config/settings/deps/cache.py`). Redis-кеш, включается отдельно. | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `CACHE_ENABLE` | bool | `False` | Включить кеш (иначе `CACHE_CLIENT=None`) | | `CACHE_EXPIRATION` | int | `300` | TTL записей (сек) | | `CACHE_HOST` | string | `localhost` | Хост Redis | | `CACHE_PORT` | int | `6379` | Порт Redis | | `CACHE_PASSWORD` | string \| null | `None` | Пароль | | `CACHE_SSL` | bool | `False` | Подключение по TLS | | `CACHE_SSL_CA_CERTS` | string \| null | `None` | Путь к CA-сертификату | | `CACHE_QUEUE` | string | `default` | Имя очереди кеша | ### ClickHouse (`CLICKHOUSE_*`) Класс `ClickHouseSettings` (`config/settings/deps/click_house.py`). Хранилище значений, включается отдельно. | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `CLICKHOUSE_ENABLE` | bool | `False` | Включить ClickHouse | | `CLICKHOUSE_HOST` | string | `rc1d-…​.mdb.yandexcloud.net` | Хост | | `CLICKHOUSE_PORT` | int | `9000` | Порт | | `CLICKHOUSE_USER` | string | `''` | Пользователь | | `CLICKHOUSE_PASSWORD` | string | `''` | Пароль | | `CLICKHOUSE_DATABASE` | string | `values_db` | База данных | | `CLICKHOUSE_TABLE` | string | `values` | Таблица | | `CLICKHOUSE_SECURE` | bool | `False` | Защищённое подключение | | `CLICKHOUSE_VERIFY` | bool | `False` | Проверять сертификат | | `CLICKHOUSE_CERT` | string | `''` | Путь к CA-сертификату | ### Kafka (`KAFKA_*`) Класс `KafkaSettings` (`config/settings/deps/kafka.py`). Продюсер сообщений, включается отдельно. | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `KAFKA_ENABLE` | bool | `False` | Включить продюсер (иначе `get_producer()` вернёт `None`) | | `KAFKA_BOOTSTRAP_SERVERS` | list[str] (JSON) | `["localhost:9092"]` | Список брокеров | | `KAFKA_SECURITY_PROTOCOL` | string | `''` | Протокол безопасности | | `KAFKA_SASL_MECHANISM` | string | `''` | SASL-механизм | | `KAFKA_SASL_PLAIN_USERNAME` | string | `user` | SASL-логин | | `KAFKA_SASL_PLAIN_PASSWORD` | string | `password` | SASL-пароль | | `KAFKA_SSL_CAFILE` | string | `''` | Путь к CA-сертификату | | `KAFKA_TOPICS` | dict (JSON) | `{}` | Карта топиков, напр. `{"planning": "message-hub-stage"}` | ### Celery — RabbitMQ (`CELERY_RABBITMQ_*`) Класс `CeleryRabbitMQ` (`config/settings/deps/celery.py`). Брокер задач; из полей собирается `BROKER_URL` (`amqp://…?heartbeat=30`). | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `CELERY_RABBITMQ_HOST` | string | `localhost` | Хост | | `CELERY_RABBITMQ_PORT` | int | `5672` | Порт | | `CELERY_RABBITMQ_USER` | string | `rabbit` | Пользователь | | `CELERY_RABBITMQ_PASSWORD` | string | `rabbit` | Пароль | | `CELERY_RABBITMQ_VHOST` | string | `api` | Виртуальный хост (в `.env`/helm — `pm`) | ### Celery — Redis (`CELERY_REDIS_*`) Класс `CeleryRedis` (`config/settings/deps/celery.py`). Result backend; при `SSL=true` используется `rediss://` и `ssl_cert_reqs`. | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `CELERY_REDIS_HOST` | string | `redis` | Хост | | `CELERY_REDIS_PORT` | int | `6379` | Порт | | `CELERY_REDIS_DATABASE` | int | `0` | Номер БД Redis | | `CELERY_REDIS_PASSWORD` | string \| null | `None` | Пароль (используется при SSL) | | `CELERY_REDIS_SSL` | bool | `False` | Подключение по TLS (`rediss://`) | | `CELERY_REDIS_SSL_CA_CERTS` | string \| null | `None` | Путь к CA-сертификату | | `CELERY_REDIS_SSL_CERT_REQS` | string \| null | `required` | Требования к сертификату | ### HTTP-клиенты внешних сервисов Общий базовый класс `BaseApiServiceMixin` (`config/settings/base.py`): поля `host` (по умолчанию `SERVER_API_HOST`), `api_prefix`, `internal_host`, `internal_prefix`, `timeout` (`10`), `enable` (`True`). Наследники задают собственные префиксы и дефолтные значения prefix. | Секция / префикс | Класс | Назначение | Особенности | | --- | --- | --- | --- | | `GATEWAY_*` | `GateWaySetttings` | API-шлюз | `api_prefix=/gateway/api/v1` | | `EAV_*` | `EAVSettings` | Сервис атрибутов (EAV) | `api_prefix=/eav/api/v0`, доп. `EAV_API_PREFIX_V1=/eav/api/v1` | | `DOCUMENTATION_*` | `DocumentationSettings` | Сервис документаций | `api_prefix=/documentations/api/v1` | | `USERS_*` | `UsersSettings` | Сервис пользователей (core) | `host=SERVER_HOST`, `api_prefix=/api/core`, `internal_host=http://localhost:8001`, `internal_prefix=/internal` | | `RESOURCES_*` | `ResourceSettings` | Сервис ресурсов (IAM) | `internal_host=http://localhost:8001`, `internal_prefix=/api/v1` | Для каждого клиента доступны переменные `HOST`, `API_PREFIX`, `INTERNAL_HOST`, `INTERNAL_PREFIX`, `TIMEOUT`, `ENABLE` (плюс `EAV_API_PREFIX_V1`). ### Tracing / OpenTelemetry (`TRACING_*`) Класс `TracingConfig` (`config/settings/base.py`). Применяется только при `SERVER_USE_OTEL=true`. | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `TRACING_SERVICE_NAME` | string | `pm-backend.pm-pord` | Имя сервиса в трейсах | | `TRACING_ENDPOINT` | string | `localhost:4317` | Адрес OTLP-коллектора | | `TRACING_INSECURE` | bool | `False` | Небезопасное (без TLS) подключение | | `TRACING_ENVIRONMENT` | string | `prod` | Окружение (атрибут трейса) | | `TRACING_MODULE` | string | `planning` | Модуль (атрибут трейса) | | `TRACING_TEAM` | string | `team_planning` | Команда (атрибут трейса) | | `TRACING_COMPONENT` | string | `backend` | Компонент (атрибут трейса) | ### Sentry (`SENTRY_*`) Класс `SentrySettings` (`config/settings/deps/sentry.py`). Читает `.env.base` и `.env`. Инициализируется при `SENTRY_USE=true`. | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `SENTRY_USE` | bool | `True` | Включить Sentry | | `SENTRY_HOST` | string | `''` | DSN Sentry | | `SENTRY_ENVIRONMENT` | string | `''` | Окружение | | `SENTRY_TRACES_SAMPLE_RATE` | float | `1.0` | Доля трейсов | | `SENTRY_PROFILES_SAMPLE_RATE` | float | `0.1` | Доля профилей | ## Переменные инфраструктуры, сборки и деплоя Не читаются кодом приложения напрямую, но участвуют в запуске/сборке/деплое. | Переменная | Где используется | Назначение | | --- | --- | --- | | `GUNICORN_WORKERS` | `docker/entrypoint.sh` | Число воркеров gunicorn (по умолчанию `4`) | | `TIMEOUT` | `docker/entrypoint.sh` | Таймаут воркера gunicorn (по умолчанию `60`) | | `NEXUS_USERNAME`, `NEXUS_PASSWORD` | `docker/Dockerfile` (build-arg), `.gitlab-ci.yml` | Доступ к приватному индексу пакетов Nexus | | `SETTINGS_BASE_HOST` | `.helm/values.yaml` (env) | Базовый хост окружения (`stage`/`preprod`/`lk`) | Порядок запуска контейнера (`docker/entrypoint.sh`): миграции закомментированы, сразу стартует gunicorn с ASGI-приложением `config.asgi_root:application`. ## Переменные из Helm-чарта (`.helm/values.yaml`) Чарт зависит от `universal-chart` (`oci://cr.yandex/crp3ccidau046kdj8g9q/charts`). Значения задаются для двух сервисов — `api` и `celery` — с ключами по окружениям `_default`/`stage`/`preprod`/`production`. Обычные значения (блок `envs`) включают: `USERS_INTERNAL_HOST`, `CELERY_REDIS_HOST`, `RESOURCES_INTERNAL_HOST`, `EAV_HOST`, `EAV_API_PREFIX`, `EAV_API_PREFIX_V1`, `TRACING_ENDPOINT`, `TRACING_INSECURE`, `SERVER_ENABLE_SYNC_RESOURCES`, `SERVER_DELETED_TASK_MAX_AGE_DAYS`, `SERVER_EXPIRED_TASK_NOTIFICATION_HOUR`, `SETTINGS_BASE_HOST` (различаются адресами сервисов по окружениям). Значения из секретов (блок `secretEnvs`, монтируются как env через `secretKeyRef`): | Секрет (`secretName`) | Переменные | | --- | --- | | `ya-pg-secret-pm` | `DB_USERNAME`, `DB_PASSWORD`, `DB_DATABASE`, `DB_HOST`, `DB_PORT` | | `ya-s3-secret-pm` | `S3_HOST`, `S3_LOGIN`, `S3_PASSWORD`, `S3_BUCKET` | | `cache-secret-pm` | `CACHE_HOST`, `CACHE_PORT`, `CACHE_PASSWORD`, `CACHE_SSL`, `CACHE_SSL_CA_CERTS`, `CACHE_ENABLE` | | `clickhouse-secret-pm` | `CLICKHOUSE_HOST`, `CLICKHOUSE_PORT`, `CLICKHOUSE_USER`, `CLICKHOUSE_PASSWORD`, `CLICKHOUSE_DATABASE`, `CLICKHOUSE_TABLE`, `CLICKHOUSE_SECURE`, `CLICKHOUSE_VERIFY`, `CLICKHOUSE_CERT`, `CLICKHOUSE_ENABLE` | | `ya-kafka-secret-pm` | `KAFKA_ENABLE`, `KAFKA_BOOTSTRAP_SERVERS`, `KAFKA_SECURITY_PROTOCOL`, `KAFKA_SASL_MECHANISM`, `KAFKA_SASL_PLAIN_USERNAME`, `KAFKA_SASL_PLAIN_PASSWORD`, `KAFKA_SSL_CAFILE`, `KAFKA_TOPICS` | | `rabbit-secret-pm` | `CELERY_RABBITMQ_HOST`, `CELERY_RABBITMQ_PORT`, `CELERY_RABBITMQ_USER`, `CELERY_RABBITMQ_PASSWORD`, `CELERY_RABBITMQ_VHOST` | | `server-secret-pm` | `AUTH_PUBLIC_TOKEN_URL`, `SERVER_HOST`, `SERVER_API_HOST`, `SERVER_DEBUG`, `SERVER_ALLOWED_HOSTS`, `SERVER_VERIFY_SSL`, `SERVER_LOG_LEVEL` | Дополнительно чарт монтирует CA-сертификат ClickHouse (configMap `ch-cert`, ключ `CA.pem`) как файл `/root/clickhouse/RootCA.crt` и `tmp-volume` в `/tmp`. Прочие значения чарта (не переменные приложения): `deployment.*` (имя, реплики, ресурсы, probes на `/api/health/`), `image.*`, `service.*`, `affinity`, `owner`. ## Переменные в CI (`.gitlab-ci.yml`) Пайплайн подключает общие шаблоны из `generic/common-ci` (`common-security-scan.yaml`, `universal-pipeline.yaml@apps-business`) и переключает окружение по ветке/тегу через `workflow.rules`: | Условие | STAND | NAMESPACE | CHART_VERSION | | --- | --- | --- | --- | | ветка `stage` | `stage` | `planning` | `0.0.1-stage` | | ветка `master` | `preprod` | `pm-preprod` | `0.0.1-preprod` | | тег (`CI_COMMIT_TAG`) | `production` | `pm-prod` | `0.0.1-prod` | | merge request | — | — | сборка образа отключена (`ENABLE_BUILD_IMAGE=false`) | Ключевые переменные пайплайна: `SERVICE_NAME=pm-backend`, `DOCKERFILE_PATH=docker/Dockerfile`, `RELEASE_NAME`, `CHART_NAME`, `K8S_HUSTLER_BRANCH`, `IMAGE_NAME`, `HELM_SET_ARGS` (`--set universal-chart.services.{api,celery}.image.name…` и метаданные коммита). Джобы стадии `test`: `linter` (flake8 по `sarex`), `typechecker` (mypy по `src`), `linter_src` (ruff check/format по `src`). ## Замечания и потенциальные проблемы - При `SERVER_DEBUG=true` `JWTAuthentication` возвращает анонимного пользователя и **аутентификация обходится** — использовать только локально. - Все секции читают `.env` автоматически (`env_file='.env'`), поэтому один общий `.env` в корне достаточен для локального запуска. `SentrySettings` дополнительно читает `.env.base`. - Sentry инициализируется по умолчанию (`SENTRY_USE=true`), но при пустом `SENTRY_HOST` DSN не задан — задайте `SENTRY_USE=false` локально, чтобы отключить. - `CELERY_RABBITMQ_VHOST` в коде по умолчанию `api`, тогда как в `.env.example`/helm используется `pm` — для корректной работы очереди значение должно совпадать с брокером. - Переменные `CACHE_PASSWORD`/`CACHE_SSL_CA_CERTS`/`CELERY_REDIS_PASSWORD` допускают `None`; в `.env` для «пустого» значения используйте `None` или закомментируйте строку. - Список-переменные (`SERVER_ALLOWED_HOSTS`, `KAFKA_BOOTSTRAP_SERVERS`) и dict (`KAFKA_TOPICS`) задаются в формате JSON. ## Минимальный набор для локального запуска Зависимости (postgres, redis, rabbit, clickhouse, minio) поднимаются через `docker-compose up`. Минимально необходимо задать: - `DB_HOST`, `DB_PORT`, `DB_DATABASE`, `DB_USERNAME`, `DB_PASSWORD` - `S3_HOST`, `S3_BUCKET`, `S3_LOGIN`, `S3_PASSWORD`, `S3_VERIFY` - `CELERY_RABBITMQ_*` (host/port/user/password/vhost) и `CELERY_REDIS_HOST`/`CELERY_REDIS_PORT` - `SERVER_DEBUG=true` (локально), `SERVER_ALLOWED_HOSTS`, `SERVER_LOG_LEVEL` - `AUTH_PUBLIC_KEY` (можно пустой при `SERVER_DEBUG=true`) - адреса внешних сервисов при необходимости: `USERS_INTERNAL_HOST`, `RESOURCES_INTERNAL_HOST`, `EAV_HOST` - `SENTRY_USE=false`, `SERVER_USE_OTEL=false` — чтобы не подключать Sentry/OTel локально - опциональные подсистемы по флагам: `CACHE_ENABLE`, `CLICKHOUSE_ENABLE`, `KAFKA_ENABLE` (`0` по умолчанию) Готовые значения-примеры приведены в `.env.example`.