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

Документ описывает все переменные окружения и способы конфигурирования сервиса **pdm** (Go). Сервис деплоится в namespace `documentations` как деплоймент `pdm` (образ `pdmv2`). Это шлюз/агрегатор поверх Postgres и множества внутренних сервисов Sarex (документации, ресурсы, ремарки, вложения, состояния, подписки, EAV, инспекции, релизы, BIM, трансмитталы и др.).

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

Сервис настраивается **только через переменные окружения**. Разбор выполняется в `config/config.go` (функция `NewConfig`) через библиотеку [`cleanenv`](https://github.com/ilyakaznacheev/cleanenv) — вызовом `cleanenv.ReadEnv(cfg)`.

Особенности разбора:

- **Плоские имена переменных без общего префикса** — каждое поле помечено тегом `env:"..."` (напр. `POSTGRES_ADDRESS`, `RESOURCES_URL`). Вложенности/делимитера, как в pydantic-settings, здесь нет.
- **Обязательность** задаётся тегом `env-required:"true"` — при отсутствии такой переменной приложение не стартует (`config error`). В таблицах ниже дефолт `—` означает обязательное поле.
- **Значения по умолчанию** задаются тегом `env-default:"..."`.
- `cleanenv.ReadEnv` читает **только переменные окружения процесса** — конфиг-файла (yaml/toml) и авто-загрузки `.env` нет. Единственный файловый источник — JSON сервисного аккаунта S3 (`S3_SERVICE_ACCOUNT`).

Отдельно от env читается JSON-файл доступа к S3 — путь берётся из `S3_SERVICE_ACCOUNT`, разбор в `pkg/s3` (`NewFromConfigFile`). Формат файла (`.example.s3config.json`):

```json
{ "endpoint": "", "access_key_id": "", "secret_access_key": "", "use_ssl": true }
```

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

| Способ запуска | Откуда берутся переменные |
| --- | --- |
| Локально (бинарник) | Переменные окружения процесса. `make config` копирует `.example.env` → `.env` и `.example.s3config.json` → `.s3config.json` (только если файлов ещё нет), но приложение **не загружает `.env` автоматически** — его нужно экспортировать самому. В репозитории для этого есть `.envrc` (`use flake` + `dotenv`) под direnv |
| Локально (live-reload) | `make run-dev` → `air` (`.air.toml`), пересборка `./cmd/httpserver/main.go` |
| Kubernetes (Helm) | `.helm/values.yaml`: блок `services.api.envs` (обычные значения, ключ `_default` и переопределения по окружениям `stage`/`preprod`/`production`) и `services.api.secretEnvs` (значения из k8s-секретов через `secretKeyRef`). Используется зонтичный `universal-chart` |
| CI/CD (GitLab) | `.gitlab-ci.yml`: переменные пайплайна в `workflow.rules` (по ветке/тегу), общие шаблоны из `generic/common-ci` |

Точки входа (`cmd/`):

| Команда | Точка входа | Назначение |
| --- | --- | --- |
| `make run` / `make build` | `cmd/httpserver/main.go` | HTTP API (Fiber). Читает конфиг и вызывает `internal/app/http.New(cfg).Run()` |
| — | `cmd/example/main.go`, `cmd/test/main.go` | Вспомогательные утилиты (не участвуют в деплое) |

Порядок инициализации в `internal/app/http/httpserver.go` (`App.Run`): трейсер (при `TRACER_USE=true`) → подключение к Postgres → инициализация HTTP-клиентов внешних сервисов → репозитории/usecase/сервисы → опциональный Valkey → сборка Fiber-приложения (`internal/controller/http/v1.Setup`) → `app.Listen(":8080")`.

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

Все переменные читаются `config/config.go`. Дефолт `—` означает, что значение обязательно (`env-required:"true"`) и его отсутствие приводит к ошибке старта.

### App / Log

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `APP_NAME` | string | — | Имя приложения |
| `APP_VERSION` | string | — | Версия приложения |
| `LOG_LEVEL` | string | — | Уровень логирования (`pkg/logging`, напр. `DEBUG`/`INFO`) |

### Postgres (`POSTGRES`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `POSTGRES_ADDRESS` | string | — | Хост PostgreSQL |
| `POSTGRES_DB` | string | — | Имя базы данных |
| `POSTGRES_USER` | string | — | Пользователь БД |
| `POSTGRES_PASSWORD` | string | — | Пароль пользователя БД |
| `POSTGRES_PORT` | string | — | Порт PostgreSQL |
| `POSTGRES_POOL_SIZE` | int32 | — | Размер пула соединений (pgxpool) |
| `ENABLE_OBSERVABILITY` | bool | `false` | Инструментирование пула Postgres трейсингом (`otelpgx`) |

> DSN собирается в `Config.GetPostgresConnectionUrl()` как `postgres://user:password@address:port/db` — **без параметра `sslmode`**. Отдельный флаг `ENABLE_SSL` из Helm кодом не читается (см. «Замечания»).

### HTTP (`HTTP`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `HTTP_PORT` | string | — | Порт HTTP. **Обязателен по тегу, но фактически не используется** — сервер слушает `:8080` (хардкод в `httpserver.go`) |
| `PUBLIC_KEY` | string (PEM) | `""` | Публичный ключ (PKIX) для проверки JWT. Формально необязателен, но при пустом/некорректном значении приложение падает (`panic` в `v1.Setup`) |
| `HTTP_BODY_LIMIT` | int | `268435456` (256 MB) | Максимальный размер тела запроса, байт |
| `HTTP_READ_BUFFER_SIZE` | int | `98304` (96 KB) | Размер буфера чтения запроса, байт |

### Auth и хосты внешних сервисов

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `DJANGO_BASIC_AUTH` | string | — | Basic-токен для авторизации в бэкенде Sarex/Django (клиенты `targets`, `users`) |
| `DJANGO_HOST` | string | — | Базовый URL Django/бэкенда. Используется сразу двумя секциями — `USERS.UserHost` и `SA.SAHost` (accounts/companies/django-клиенты) |
| `NOTES_URL` | string | — | Сервис заметок (`notes`) |
| `FLOWS_URL` | string | — | Сервис процессов (`flows`) |
| `RESOURCES_URL` | string | — | Сервис ресурсов/IAM (`resources`) |
| `REMARKS_URL` | string | — | Сервис замечаний (`remarks`) |
| `ATTACHMENTS_URL` | string | — | Сервис вложений (`attachments`) |
| `STATES_URL` | string | — | Сервис состояний/рабочих областей (`workspaces`) |
| `SUBSCRIPTIONS_URL` | string | — | Сервис подписок (`subscriptions`) |
| `EAV_URL` | string | — | Сервис атрибутов EAV |
| `INSPECTIONS_URL` | string | — | Сервис инспекций |
| `SYSTEM_LOG_URL` | string | — | Сервис системного лога |
| `TARGET_URL` | string | — | Сервис таргетов |
| `DOCUMENTATION_URL` | string | — | Сервис документаций (documentation-api-v2) |
| `BIM_V2_HOST` | string | — | BIM core API v2 |
| `NOTES_URL` | string | — | (см. выше) |
| `DRAWINGS_INTERNAL_URL` | string | — | Внутренний URL сервиса чертежей |
| `RELEASES_URL` | string | — | URL GitLab для получения релизов |
| `RELEASES_TOKEN` | string | — | Токен доступа к GitLab (`RELEASES_URL`) |

### Ресурсы и фильтр разрешений (`RESOURCES`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `ENABLE_PERMISSIONS_FILTER` | bool | `false` | Включить фильтрацию по разрешениям на уровне сервиса документов |
| `PERMISSIONS_FILTER_COMPANIES` | string (JSON-массив) | `[133, 256, 247, 219, 248, 194, 242, 260, 252, 255, 239, 125, 116, 92, 311, 170]` | Список ID компаний, к которым применяется фильтр. Парсится `json.Unmarshal` в `[]uint64` |

### Thumbnails (`ATTACHMENTS`, `STATES`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `WIDTH_THUMB_ATTACHMENTS` | int | `100` | Ширина превью вложений |
| `HEIGHT_THUMB_ATTACHMENTS` | int | `100` | Высота превью вложений |
| `WIDTH_THUMB_STATES` | int | `100` | Ширина превью состояний |
| `HEIGHT_THUMB_STATES` | int | `100` | Высота превью состояний |

### Subscriptions / System log — доп. поля

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `USE_SUBSCRIPTIONS` | bool | `true` | Включить интеграцию с подписками в сервисе документов |
| `API_HOST_PREFIX` | string | `""` | Префикс хоста API (напр. `/gateway`), используется сервисом системного лога |

### S3 (`S3`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `S3_SERVICE_ACCOUNT` | string | — | Путь к JSON-файлу с доступом к S3 (`endpoint`, `access_key_id`, `secret_access_key`, `use_ssl`). Разбирается в `pkg/s3` |

### Transmittals (`Transmittals`)

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `TRANSMITTALS_ENABLE` | bool | `true` | Включить клиент трансмитталов; при `false` используется stub-реализация |
| `TRANSMITTALS_BASE_URL` | string | — | Базовый URL сервиса трансмитталов. Обязателен даже при `TRANSMITTALS_ENABLE=false` |

### Observability / Tracer

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `OBSERVABILITY_COLLECTOR_ENDPOINT` | string | `""` | Эндпоинт OTLP-коллектора (метрики/наблюдаемость) |
| `TRACER_USE` | bool | `false` | Включить трейсинг OpenTelemetry (`golang-fiber-otel-tools`) |
| `TRACER_HOST` | string | `localhost:4317` | Адрес OTLP-коллектора трейсов |
| `TRACER_USE_INSECURE` | bool | `true` | Небезопасное (без TLS) подключение к коллектору |
| `SERVICE_NAME` | string | `Pdm` | Имя сервиса в трейсах |
| `TRACER_LOGGER_NAME` | string | `tracer_logger` | Имя логгера OTel |

### Valkey (`VALKEY`) — кэш пользователей

Подключение опционально: если `VALKEY_ADDR` пуст — клиент не создаётся (кэш пользователей отключён). Ошибки подключения/пинга не фатальны (лог `Warn`).

| Переменная | Тип | Значение по умолчанию | Назначение |
| --- | --- | --- | --- |
| `VALKEY_ADDR` | string | `""` | Адрес Valkey (при пустом — кэш выключен) |
| `VALKEY_LOGIN` | string | `""` | Логин |
| `VALKEY_HOST` | string | `""` | Хост |
| `VALKEY_PASSWORD` | string | `""` | Пароль |
| `VALKEY_DB` | int | `0` | Номер БД |
| `VALKEY_SSL` | bool | `false` | Использовать TLS |
| `VALKEY_SSL_CA_CERTS` | string | `""` | Путь к CA-сертификату для TLS |

## Переменные инфраструктуры и сборки

Не читаются кодом приложения (`config/config.go`), но участвуют в сборке/деплое:

| Переменная | Где используется | Назначение |
| --- | --- | --- |
| `GITLAB_CREDENTIALS` | `Dockerfile` (build-arg), `.gitlab-ci.yml` (`BUILD_ARGS`) | Учётные данные для доступа к приватным Go-модулям `gitlab.sarex.io` при сборке |
| `SERVICE_NAME` (CI) | `.gitlab-ci.yml` | `pdmv2` — имя сервиса в пайплайне (не путать с `SERVICE_NAME` трейсера) |
| `DOCKERFILE_PATH`, `CI_TRIGGER_SOURCE` | `.gitlab-ci.yml` | Путь к Dockerfile, источник триггера |
| `ENABLE_LINTER`, `ENABLE_BUILD_CHART`, `ENABLE_BUILD_IMAGE`, `ENABLE_STATE_UPDATE`, `ENABLE_DEPLOY` | `.gitlab-ci.yml` | Флаги стадий пайплайна |
| `STAND`, `NAMESPACE`, `RELEASE_NAME`, `CHART_NAME`, `CHART_VERSION`, `K8S_HUSTLER_BRANCH`, `HELM_SET_ARGS`, `IMAGE_NAME` | `.gitlab-ci.yml` | Параметры окружения/деплоя Helm |

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

Обычные значения задаются в `services.api.envs` (ключ `_default` + переопределения по `stage`/`preprod`/`production`) и содержат переменные приложения, описанные выше, различаясь адресами БД/сервисов, `LOG_LEVEL`, доменами и т.п.

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

| Переменная | Секрет (`secretName`, prod/по умолчанию) | Ключ (`secretKey`) |
| --- | --- | --- |
| `POSTGRES_DB` | `documentations-postgresql-secret` (preprod: `ya-pg-secret`) | `database` |
| `POSTGRES_PORT` | `documentations-postgresql-secret` | `port` |
| `POSTGRES_ADDRESS` | `documentations-postgresql-secret` | `host` |
| `POSTGRES_USER` | `documentations-postgresql-secret` | `username` |
| `POSTGRES_PASSWORD` | `documentations-postgresql-secret` | `password` |
| `YC-PG-CERTIFICATE` | `documentations-postgresql-secret` (preprod: `yc-pg-certificate`) | `ca.crt` |
| `DJANGO_BASIC_AUTH` | `django-auth` | `key` |
| `PUBLIC_KEY` | `public-key` | `key` |
| `RELEASES_TOKEN` | `releases-token` | `key` |
| `VALKEY_ADDR` | `valkey-secret` | `url` |
| `VALKEY_LOGIN` | `valkey-secret` | `login` |
| `VALKEY_PASSWORD` | `valkey-secret` | `password` |
| `VALKEY_HOST` | `valkey-secret` | `host` |
| `VALKEY_PORT` | `valkey-secret` | `port` |
| `VALKEY_CA_CERTS` | `valkey-secret` | `cert` |

Помимо env, чарт монтирует секрет `documentations-yc-s3` как том в `/etc/sarex/yc-s3-storage` (readOnly). Именно на файл `/etc/sarex/yc-s3-storage/yc-s3-service-account.json` указывает `S3_SERVICE_ACCOUNT` в prod-конфигурации.

Прочие значения чарта (не переменные приложения): `deployment.*` (имя `pdm-api`, реплики `stage=3`/`preprod=2`/`production=8`, ресурсы `cpu=1`, `memory=2Gi`), `image.name` (`cr.yandex/.../pdm_v2`), `service.*` (порт `8080`), `imagePullSecrets` (`dockerhub`), `probes.*` (startup/liveness/readiness по `/internal/healthz/*` на порту `8080`).

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

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

| Условие | STAND | Namespace | `universal-chart.global.env` |
| --- | --- | --- | --- |
| ветка `stage` | `stage` | `documentations` | `stage` |
| ветка `master` | `preprod` | `documentations-preprod` | `preprod` |
| тег (`CI_COMMIT_TAG`) | `prod` | `documentations-prod` | `production` |
| merge request | — | — | сборка образа отключена (`ENABLE_BUILD_IMAGE=false`) |

Общие переменные: `SERVICE_NAME=pdmv2`, `RELEASE_NAME=pdmv2`, `CHART_NAME=pdmv2`, `CHART_VERSION=0.0.1-<env>`, `DOCKERFILE_PATH=Dockerfile`.

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

- **`HTTP_PORT` фактически игнорируется.** Поле обязательно (`env-required`), но сервер жёстко слушает `:8080` (`app.Listen(":8080")` в `httpserver.go`). Реальный порт задаётся только этим хардкодом; в Helm `HTTP_PORT` и `service.port` совпадают со `8080`, поэтому расхождение незаметно.
- **`PUBLIC_KEY` де-факто обязателен.** По тегам он необязателен (`env:"PUBLIC_KEY"`), но `v1.Setup` при пустом/битом PEM вызывает `panic` (`failed to parse PEM block...`). Для локального запуска нужен валидный публичный ключ.
- **SSL к Postgres в коде не настраивается.** DSN формируется без `sslmode` (`GetPostgresConnectionUrl`). Helm-переменные `ENABLE_SSL` и секрет `YC-PG-CERTIFICATE` кодом **не читаются** — подключение к БД идёт без TLS-параметров на уровне DSN.
- **Множество Helm-переменных не читается приложением.** В `services.api.envs`/`secretEnvs` присутствуют переменные, отсутствующие в `config/config.go`, — вероятно, унаследованы от `documentation-api`: `API_ADDRESS`, `API_ADDRESS_FILE`, `ENABLE_SSL`, `ENABLE_S3`, `FILE_URL_EXTERNAL`, `WORKFLOW_URL`, `WORKSPACE_URL`, `BIM_API_URL`, `BIM_API_V2_URL`, `BIM_API_URL_EXTERNAL`, `WORKSPACE_BUNDLE_VERSION`, `WORKFLOW_IMAGES_VERSION`/`WORKFLOWS_IMAGES_VERSION`, `NAMESPACE`, `DJANGO_ORIGINATOR`, `USE_EXPERIMENTAL`, `READ_WRITE_TIMEOUT_FILE_STREAM`, `CACHE_DEFAULT_EXPIRATION`, `CACHE_CLEANUP_INTERVAL`, `USE_CACHE_IN_FILE_STREAMER`, `SENTRY_DSN`, `SENTRY_DEBUG`, `ENVIRONMENT`, `YC-PG-CERTIFICATE`. Они не влияют на работу pdm.
- **Несовпадение имён Valkey.** Код ждёт `VALKEY_SSL_CA_CERTS` (`config.go`), а Helm-секрет прокидывает `VALKEY_CA_CERTS`; также Helm задаёт `VALKEY_PORT`, который код не читает (адрес берётся целиком из `VALKEY_ADDR`). В результате CA-сертификат и порт из секрета до приложения не доходят.
- **Секции `USERS`/`SA` используют один и тот же env `DJANGO_HOST`.** Оба поля (`UserHost`, `SAHost`) читают одну переменную.
- **`config.env` в репозитории содержит реальные учётные данные** (пароль Postgres, `DJANGO_BASIC_AUTH`, токены) — это конфигурация для отладки, не шаблон. Для примеров использовать `.example.env`; `config.env` не должен попадать в окружения и подлежит ротации секретов.
- **`ENABLE_SQL_QUERY` из `config.env` кодом не читается** — в `config/config.go` такого поля нет.
- **`cleanenv.ReadEnv` не загружает `.env` автоматически.** `make config` лишь создаёт файлы-шаблоны (`.env`, `.s3config.json`) при их отсутствии; переменные нужно экспортировать вручную (например, через `direnv`/`.envrc`).
- **v0-роутер (echo) не подключён.** В `cmd/httpserver/main.go` используется только `internal/controller/http/v1.Setup` (Fiber). Пакет `internal/controller/http/v0` (на `labstack/echo`) в рантайме не задействован.

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

Приложение поднимается через `make run` (или `make run-dev` с `air`). Минимально необходимо задать (обязательные поля `config/config.go`):

- `APP_NAME`, `APP_VERSION`, `LOG_LEVEL`;
- `POSTGRES_ADDRESS`, `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_PORT`, `POSTGRES_POOL_SIZE`;
- `HTTP_PORT` (любой — фактически используется `:8080`), а также **валидный** `PUBLIC_KEY` (иначе `panic`);
- `DJANGO_BASIC_AUTH`, `DJANGO_HOST`;
- хосты внешних сервисов: `NOTES_URL`, `FLOWS_URL`, `RESOURCES_URL`, `REMARKS_URL`, `ATTACHMENTS_URL`, `STATES_URL`, `SUBSCRIPTIONS_URL`, `EAV_URL`, `INSPECTIONS_URL`, `SYSTEM_LOG_URL`, `TARGET_URL`, `DOCUMENTATION_URL`, `BIM_V2_HOST`, `DRAWINGS_INTERNAL_URL`;
- `RELEASES_URL`, `RELEASES_TOKEN`;
- `S3_SERVICE_ACCOUNT` (путь к `.s3config.json`) и заполненный сам JSON-файл;
- `TRANSMITTALS_BASE_URL` (обязателен даже при выключенных трансмитталах).

Необязательные (есть дефолты): `ENABLE_OBSERVABILITY`, `HTTP_BODY_LIMIT`, `HTTP_READ_BUFFER_SIZE`, `ENABLE_PERMISSIONS_FILTER`, `PERMISSIONS_FILTER_COMPANIES`, `USE_SUBSCRIPTIONS`, `WIDTH_THUMB_*`/`HEIGHT_THUMB_*`, `API_HOST_PREFIX`, `TRANSMITTALS_ENABLE`, `TRACER_*`, `SERVICE_NAME`, `VALKEY_*`, `OBSERVABILITY_COLLECTOR_ENDPOINT`.

Готовые значения-примеры приведены в `pdm.env.example` (на основе `.example.env` репозитория).
