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