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

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

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

Сервис настраивается **только через переменные окружения**. Разбор выполняется в `src/app/config.py` через библиотеку [`pydantic`](https://docs.pydantic.dev/) (`pydantic.BaseSettings`, pydantic v1).

Конфигурация разбита на несколько классов настроек, каждый со своим префиксом (`Config.env_prefix`):

- `PostgresSettings` — префикс `PG_`;
- `DjangoSettings` — префикс `DJANGO_`;
- `Documentations` — префикс `DOCUMENTATIONS_`;
- `WorkflowSettings` — префикс `WORKFLOW_`;
- `AttachmentSettings` — префикс `ATTACHMENT_`;
- `LoggerSettings` — префикс `LOG_`;
- корневой `Settings` — **без префикса** (поля читаются по имени в верхнем регистре, напр. `BASE_HOST`, `FAAS_SERVICE`).

Каждый вложенный класс настроек инстанцируется отдельно и читает свои переменные из окружения по своему префиксу. Отдельного конфиг-файла (yaml/toml) у приложения нет.

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

| Способ запуска | Откуда берутся переменные |
| --- | --- |
| Локально (uvicorn/gunicorn) | Переменные окружения процесса. Приложение **не загружает `.env` автоматически** (в `config.py` нет `env_file`/`python-dotenv`) — переменные нужно экспортировать самому |
| Локально (контейнеры) | `docker-compose.yml`: блок `environment` для сервиса `notes` (`PG_HOST`, `PG_DB`, `PG_LOGIN`, `PG_PASSWORD`, `DJANGO_USE`, `TIMEOUT`) |
| Kubernetes (Helm) | `.helm/values.yaml`: блоки `envs` (обычные значения) и `secretEnvs` (значения из k8s-секретов) чарта `universal-chart` |
| CI/CD (GitLab) | `.gitlab-ci.yml`: переменные пайплайна (`workflow.rules`) — выбор окружения по ветке/тегу |

Порядок запуска в контейнере (`entrypoint.sh`): сначала выполняются миграции (`alembic upgrade head`), затем стартует gunicorn с воркерами `uvicorn.workers.UvicornWorker` на `0.0.0.0:8000` с таймаутом `$TIMEOUT`.

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

Дефолт `—` означает, что явного значения по умолчанию нет (пустая строка/обязательно задать для реального окружения).

### App / корневой `Settings` (без префикса)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `BASE_HOST` | string | `https://lk.sarex.io` | Внешний базовый URL сервиса |
| `API_PREFIX` | string | `/api/v1` | Префикс публичного API |
| `DEBUG` | bool | `False` | Режим отладки. Также влияет на `PostgresSettings` (см. ниже) и включает `ProfilingSqlQueryMiddleware` |
| `FAAS_SERVICE` | string | `https://stage-api.sarex.io/lambdas` | URL сервиса лямбд/FaaS |
| `WORKSPACE_URL` | string | `https://stage-api.sarex.io/workspaces/api/v1` | URL сервиса рабочих областей (для `SYNC_RESOURCE_ID`) |
| `RESOURCE_URL` | string | `https://stage-api.sarex.io/resources/api/v1` | URL сервиса ресурсов (для `SYNC_RESOURCE_ID`) |
| `SYNC_RESOURCE_ID` | bool | `False` | При `True` `resource_id` заметки вычисляется по workspace → target → resource |
| `REGISTRY` | string | `cr.yandex/crp3ccidau046kdj8g9q/` | Реестр образов (используется вспомогательно) |
| `ENABLE_ND` | bool | `False` | Подключить роутер `nd_service` (`/api/v1/nd/*`) |

### ND-сервис (без префикса)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `ND_JWT_ENABLE` | bool | `False` | Включить проверку JWT (`JWTBearer`) на части эндпоинтов НД |
| `ND_JWT_SECRET` | string | `""` | Секрет для подписи/проверки JWT |
| `ND_JWT_ALGORITHM` | string | `HS256` | Алгоритм JWT |
| `ND_ACCESS_TOKEN_EXPIRE_DAYS` | int | `30` | Срок жизни токена НД (дни) |

### Database (`PG_*`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `PG_LOGIN` | string | `""` | Пользователь PostgreSQL |
| `PG_PASSWORD` | string | `""` | Пароль пользователя |
| `PG_DB` | string | `""` | Имя базы данных |
| `PG_HOST` | string | `""` | Хост PostgreSQL |
| `PG_PORT` | string | `5432` | Порт PostgreSQL |
| `PG_SSL_MODE` | string | `disable` | Поле `ssl_mode` настроек (см. замечание ниже — фактически подключение всегда `verify-full`) |
| `DEBUG` | bool | `False` | Через `Field(env='DEBUG')`. При `True` хост БД принудительно `localhost:6432` (pgbouncer) |

> Итоговый DSN собирается в `PostgresSettings.url` как `postgresql://<login>:<password>@<host>:<port>/<db>`.

### Django / sarex-backend (`DJANGO_*`)

Клиент к основному backend (Django). Используется middleware `DjangoUserMiddleware` для аутентификации пользователя (запрос `/client/settings/`).

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `DJANGO_USE` | bool | `True` | При `False` аутентификация через Django отключается, используется тестовый пользователь (`is_admin=True`) |
| `DJANGO_HOST` | string | `http://localhost:8000` | Базовый хост Django (к нему добавляется `/api`) |
| `DJANGO_TIMEOUT` | int | `10` | Таймаут HTTP-клиента (сек) |
| `DJANGO_TOKEN` | string | `token` | Токен для служебных (sync) запросов |

### Documentations (`DOCUMENTATIONS_*`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `DOCUMENTATIONS_HOST` | string | `https://stage-api.sarex.io/documentations/api/v1` | URL сервиса документации |

### Workflows (`WORKFLOW_*`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `WORKFLOW_HOST` | string | `https://stage-api.sarex.io/workflows/api/v1` | URL сервиса обработки процессов |
| `WORKFLOW_TAG` | string | `dev` | Тег/канал workflow (`dev`/`stable`) |
| `WORKFLOW_TIMEOUT` | int | `30` | Таймаут HTTP-клиента (сек) |

### Attachments (`ATTACHMENT_*`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `ATTACHMENT_HOST` | string | `http://attachments-service.attachments-stage.svc.cluster.local:80/api/v1` | URL сервиса вложений |
| `ATTACHMENT_TIMEOUT` | int | `30` | Таймаут HTTP-клиента (сек) |

### Logger (`LOG_*`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `LOG_LEVEL` | string | `INFO` | Уровень логирования (`DEBUG`/`INFO`/…); при неизвестном значении используется `INFO` |
| `LOG_FORMAT` | string | `[%(asctime)s] [%(levelname)s] [%(filename)s]: %(message)s` | Формат сообщений лога |

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

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

| Переменная | Где используется | Назначение |
| --- | --- | --- |
| `TIMEOUT` | `docker-compose.yml`, `.helm/values.yaml`, `entrypoint.sh` | Таймаут воркеров gunicorn (`--timeout`) |
| `POSTGRES_USER` / `POSTGRES_PASSWORD` / `POSTGRES_DB` | `docker-compose.yml` (сервис `database`) | Параметры локального контейнера Postgres |
| `PGADMIN_DEFAULT_EMAIL` / `PGADMIN_DEFAULT_PASSWORD` | `docker-compose.yml` (сервис `pgadmin`) | Учётные данные pgAdmin для локальной разработки |
| `NPM_NEXUS_TOKEN` | (для фронтенда) | Токен приватного npm-реестра — здесь не используется |

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

Чарт — `universal-chart` (зависимость в `.helm/Chart.yaml`). Обычные значения задаются в блоке `services.main.envs` и различаются по окружениям (`_default`/`stage`/`preprod`/`production`):

| Переменная | `_default` (stage) | `preprod` | `production` |
| --- | --- | --- | --- |
| `PG_SSL_MODE` | `verify-full` | — | — |
| `PG_PORT` | `6432` | — | — |
| `DJANGO_HOST` | `https://stage.sarex.io` | `https://lk.preprod.sarex.io` | `https://lk.sarex.io` |
| `BASE_HOST` | `https://stage-api.sarex.io/notes` | `https://api.preprod.sarex.io/notes` | `https://api.sarex.io/notes` |
| `TIMEOUT` | `120` | — | — |
| `FAAS_SERVICE` | `https://stage-api.sarex.io/lambdas` | `https://api.preprod.sarex.io/lambdas` | `https://api.sarex.io/lambdas` |
| `WORKSPACE_URL` | `https://stage-api.sarex.io/workspaces/api/v1` | `https://api.preprod.sarex.io/workspaces/api/v1` | `https://api.sarex.io/workspaces/api/v1` |
| `WORKFLOW_HOST` | `https://stage-api.sarex.io/workflows/api/v1` | `https://api.preprod.sarex.io/workflows/api/v1` | `https://api.sarex.io/workflows/api/v1` |
| `WORKFLOW_TAG` | `dev` | `stable` | `stable` |
| `RESOURCE_URL` | `https://stage-api.sarex.io/resources/api/v1` | `https://api.preprod.sarex.io/resources/api/v1` | `https://api.sarex.io/resources/api/v1` |
| `SYNC_RESOURCE_ID` | `0` | — | — |
| `ENABLE_ND` | `1` | `0` | `0` |
| `ATTACHMENT_HOST` | `…attachments-stage…` | `…attachments-preprod…` | `…attachments-prod…` |

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

| Переменная | Секрет (`secretName`, stage) | Ключ (`secretKey`) |
| --- | --- | --- |
| `PG_DB` | `notes-postgresql-secret` | `database` |
| `PG_LOGIN` | `notes-postgresql-secret` | `username` |
| `PG_PASSWORD` | `notes-postgresql-secret` | `password` |
| `PG_HOST` | `notes-postgresql-secret` | `host` |
| `DJANGO_TOKEN` | `django-secret` | `token` |

Прочие значения чарта (не переменные приложения): `deployment.*` (имя, порт `8000`, реплики, ресурсы, probes отключены), `image.*`, `service.*` (`notes-backend-service`, в production — `backend-service`), `imagePullSecrets` (`dockerhub`), `ingress.enabled: false`.

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

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

| Условие | STAND | NAMESPACE | CHART_VERSION |
| --- | --- | --- | --- |
| ветка `stage` | `stage` | `aero` | `0.0.1-stage` |
| ветка `master` | `preprod` | `notes-preprod` | `0.0.1-preprod` |
| тег (`CI_COMMIT_TAG`) | `production` | `notes-prod` | `0.0.1-prod` |

Ключевые переменные: `SERVICE_NAME=notes-backend`, `DOCKERFILE_PATH`, `RELEASE_NAME`, `CHART_NAME`, `HELM_SET_ARGS` (проброс образа/окружения в `universal-chart`). Джобы `linter` (flake8), `typechecker` (mypy), `rest-api` (docker-compose + newman/postman) выполняются на MR/ветках/тегах.

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

- **SSL к БД всегда `verify-full`.** Поле `PG_SSL_MODE` (по умолчанию `disable`) в код подключения не попадает: и `PostgresSettings.create_session`, и `DBSessionMiddleware` жёстко передают `connect_args={'sslmode': "verify-full"}`. CA-сертификат монтируется из образа: `Dockerfile` копирует `yandex_pg.pem` → `/root/.postgresql/root.crt`.
- **`DEBUG` — общая переменная.** Она читается и корневым `Settings.debug`, и `PostgresSettings.debug` (`Field(env='DEBUG')`). При `DEBUG=true` хост БД принудительно становится `localhost:6432`, а также включается `ProfilingSqlQueryMiddleware`.
- **Приложение не загружает `.env` автоматически** — переменные нужно экспортировать в окружение (или задавать через `--env`/compose/helm).
- **Аутентификация.** При `DJANGO_USE=true` каждый публичный запрос (кроме путей с `/nd`) проверяется через Django `/client/settings/` по заголовку `Authorization` (опционально `Identity` для Zitadel). При `DJANGO_USE=false` подставляется тестовый администратор — использовать только локально.
- **Роутер НД включается флагом `ENABLE_ND`.** На stage он включён (`1`), на preprod/production выключен (`0`).
- Значение `SYNC_RESOURCE_ID` требует доступности `WORKSPACE_URL` и `RESOURCE_URL`; клиент к ним создаётся с `verify=False`.

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

Postgres и pgAdmin поднимаются через `docker-compose up -d database pgadmin`. Минимально необходимо задать:

- `PG_LOGIN`, `PG_PASSWORD`, `PG_DB`, `PG_HOST`, `PG_PORT`
- `DJANGO_USE=false` (чтобы не требовать реальный Django-токен)
- при `ENABLE_ND=true` — `ND_JWT_*` при необходимости проверки токена

Остальные значения имеют рабочие дефолты (см. `.env.example`).
