# Конфигурация проекта documentations-api Документ описывает все переменные окружения и способы конфигурирования сервиса документаций (`documentation-api`). Репозиторий собирает **два бинарника/образа**, разворачиваемых в неймспейсе `documentations`: | Бинарник | Точка входа | Образ | Deployment | Назначение | | --- | --- | --- | --- | --- | | **API** | `cmd/api` | `documentations` (`cr.yandex/.../documentations-api`) | `documentations-api` | Основной REST-API: диски, документы, бандлы, права, воркспейсы, штампы, публичные ссылки и т. д. | | **Filestream** | `cmd/filestreamer` | `documentations-api-files` (`.../documentations-filestream`) | `documentations-filestream` | Потоковая отдача/приём файлов из S3 (скачивание документов и бандлов, догрузка частей, gzip/range). | Оба бинарника используют **одну и ту же структуру конфигурации** (`config.Config`) — различия только в том, какие поля реально задействуются (см. раздел «Различия api и filestream»). ## Способы конфигурирования Сервис настраивается **только через переменные окружения**. Разбор выполняется в `config/config.go` через библиотеку [`github.com/kelseyhightower/envconfig`](https://github.com/kelseyhightower/envconfig) (функция `config.FromEnv()` → `envconfig.Process("", &cfg)`). Особенности разбора: - **Префикса нет** (в `envconfig.Process` передаётся пустая строка) — имена переменных плоские, задаются тегом `envconfig:"..."` у каждого поля структуры `Config`; - **Вложенности нет** — двойных подчёркиваний/секций, как в pydantic, здесь не используется; - **Значения по умолчанию** задаются тегом `default:"..."` прямо в структуре (например `USE_BIM_INSERTER default:"true"`). Поля без `default` и без значения в окружении получают нулевое значение типа (`""`, `0`, `false`, `nil`) — то есть формально **обязательных полей с ошибкой старта у envconfig нет**; отсутствующая переменная просто становится «пустой», а несостоятельность конфигурации всплывает позже в рантайме (например, невозможность подключиться к БД/S3); - **Отдельного конфиг-файла (yaml/toml) у приложения нет.** Приложение **не загружает `.env` автоматически** — переменные должны быть в окружении процесса (в контейнере их проставляет Helm, локально — вручную или через `docker-compose --env-file`); - Единственный внешний файл конфигурации — `WORKFLOWS_CONFIG_FILEPATH` (JSON с параметрами запуска задач обработки, см. `.example.tasks_execution_config.json`), читается `workflow.NewTasksExecutionConfigFromFilepath` при старте api. Источники переменных по способам запуска: | Способ запуска | Откуда берутся переменные | | --- | --- | | Локально (бинарник) | Переменные окружения процесса. Готовый шаблон — `.docker/.env` | | Локально (контейнеры) | `.docker/docker-compose.yml` + `make docker`: значения из `.docker/.env` и `.docker/.docker.env` | | Kubernetes (Helm) | `.helm/values.yaml` (universal-chart): блоки `services.api.envs`/`secretEnvs` и `services.filestream.envs`/`secretEnvs` | | CI/CD (GitLab) | `.gitlab-ci.yml`: `workflow.rules` (окружение по ветке/тегу) и `HELM_SET_ARGS` | Способы запуска процессов: | Команда | Точка входа | Назначение | | --- | --- | --- | | `api` (`make api` / `make run-api-dev`) | `cmd/api` | Основной REST-API | | `filestreamer` (`make file_api` / `make run-filestreamer-dev`) | `cmd/filestreamer` | Файловый стример | | `migrations migrate` | `cmd/migrations` | Прогон миграций БД | | `delete_expired_public_links` | `cmd/scripts/delete_expired_public_links` | CronJob удаления просроченных публичных ссылок | | `refresh_latest_bundle_filters_view` | `cmd/scripts/refresh_latest_bundle_filters_view` | CronJob обновления материализованного представления | | `cleanup_failed_s32d_sessions` | `cmd/scripts/cleanup_failed_s32d_sessions` | CronJob очистки зависших s3d→ifc сессий | Порядок запуска в контейнере: сначала миграции, затем сервер. - `entrypoint.sh` (api): `migrations migrate` → `api`; - `file_entrypoint.sh` (filestream): `migrations migrate` → `filestreamer`. Для локальной разработки предусмотрен hot-reload через `air`: `.air.toml` (api, `./tmp/api`) и `.air.filestreamer.toml` (filestream, `./tmp/filestreamer`). Окружение сборки описано в `flake.nix` (Go 1.22 + `air`), образы собираются с Go 1.24 (`.docker/api.dockerfile`, `.docker/api-filestream.dockerfile`). ## HTTP-фреймворк, порты, health - Роутер — `gorilla/mux`, обёрнутый в `rest.NewCustomRouter` (`gitlab.sarex.io/platform/gotools/rest`). Ответы оборачиваются в JSON (`rest.JSONResponse`), включена gzip-компрессия (`gorilla/handlers.CompressHandler`). - Пробы `liveness`/`readiness` в Helm ходят на `GET /ping` (эндпоинт предоставляется кастомным роутером `rest`, в коде маршрутов репозитория не объявлен). - Порт api — из `API_ADDRESS`, порт filestream — из `API_ADDRESS_FILE` (в k8s оба слушают `0.0.0.0:8080`). - Таймауты: у api `Read/WriteTimeout = 30m` (жёстко в коде), у filestream `Read/WriteTimeout = READ_WRITE_TIMEOUT_FILE_STREAM` (по умолчанию окружения — `6h`). - Оба сервиса регистрируют `net/http/pprof` (`/debug/pprof/...`). ## Аутентификация и авторизация Разбор описан в `cmd/api/bootstrap.go`, `cmd/filestreamer/main.go`, `pkg/midleware/auth.go`, `pkg/midleware/signature.go`. Цепочка middleware для `/api/v1/*`: `sentry` → `JSONResponse` → `reqid` → `logging` → (**только filestream**: `SignatureMiddleware`) → `auth.JWTToCtx` → `JWTUserExtractorFromCtx` → `DjangoToCtx` → `NewAuthMiddleware`/`NewAuthMiddlewareWithZitadel` → `DeleteJWTFromQueryMiddleware` → `sentry.AddUser`. - **JWT**: токен из заголовка `Authorization: Bearer ...` проверяется по RSA-публичному ключу (`PUBLIC_KEY`, формат PEM/PKIX). Из claims извлекаются `company_ids` и `service_accounts`. - **Zitadel** (опционально, `USE_ZITADEL=1`): дополнительная проверка токена через Zitadel и разбор метаданных пользователя (`urn:zitadel:iam:user:metadata`, base64-поля `company_ids`/`service_accounts`). - **Identity-заголовок**: при наличии `Identity` метаданные берутся из него. - **Публичные ссылки/временные загрузки**: пути `/api/v1/public/...`, `/api/v1/public_link_mrpas/...` и запросы с `download_type=temporary` проверяются по HMAC-секрету `DOCUMENT_PUBLIC_LINK_JWT_SECRET`. - **Подписанные ссылки (только filestream)**: при наличии query-параметра `signature` `SignatureMiddleware` убирает `Authorization` и проверяет подпись (`SIGNATURE_SECRET_KEY`) с `expires_at`; включается флагом `ENABLE_SIGNATURE_IN_URL` (при `true` обязателен рабочий Valkey — иначе api/filestream завершается с кодом 2). - Маршруты `/internal/v1/*` используют облегчённую цепочку (`auth.JWTToCtxIfPossible`) без обязательной проверки. ## Переменные приложения В столбце «Переменная» — точное имя (тег `envconfig`). Дефолт `—` означает, что тег `default` не задан (поле получает нулевое значение типа, если переменная не задана в окружении). ### PostgreSQL | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `POSTGRES_ADDRESS` | string | — | Хост PostgreSQL | | `POSTGRES_PORT` | string | — | Порт PostgreSQL | | `POSTGRES_USER` | string | — | Пользователь БД | | `POSTGRES_PASSWORD` | string | — | Пароль БД | | `POSTGRES_DB` | string | — | Имя базы данных | | `POSTGRES_POOL_SIZE` | int | — | Размер пула соединений (**только api**; filestreamer использует фиксированное значение 50) | | `ENABLE_SSL` | bool | — | TLS-подключение к БД; при `true` используется `YC-PG-CERTIFICATE` | | `YC-PG-CERTIFICATE` | string | — | PEM CA-сертификат PostgreSQL (имя с дефисами; в проде — из секрета `yc-pg-certificate`) | ### S3 | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `ENABLE_S3` | bool | — | Включить S3. В api при `false` сервис стартует без S3-клиента; в filestream S3 нужен всегда | | `S3_SERVICE_ACCOUNT` | string | — | Путь к JSON сервис-аккаунта S3 (монтируется как файл) | | `S3_SERVICE_ACCOUNT_STR` | string | — | Альтернатива: JSON сервис-аккаунта строкой | ### API-адреса | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `API_ADDRESS` | string | — | Адрес прослушивания основного API (`cmd/api`) | | `API_ADDRESS_FILE` | string | — | Адрес прослушивания файлового стримера (`cmd/filestreamer`) | ### Sarex backend (Django) и Zitadel | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `DJANGO_HOST` | string | — | Базовый URL Sarex backend (Django). Используется клиентами `django`, `users`, `sarex_backend`, `accounts` | | `DJANGO_BASIC_AUTH` | string | — | Basic-auth для системных вызовов Django | | `DJANGO_BASIC_AUTH_FOR_GET_USER` | string | — | Отдельный basic-auth для запросов пользователей | | `DJANGO_ORIGINATOR` | string | — | Идентификатор источника запросов | | `USE_ZITADEL` | bool | — | Включить проверку токенов через Zitadel | | `ZITADEL_DOMAIN` | string | — | Домен Zitadel (IdP) | | `ZITADEL_ACCOUNT` | string | — | Путь к JSON сервис-аккаунта Zitadel | ### Внешние сервисы (базовые URL) | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `FILE_URL_EXTERNAL` | string | — | Внешний URL файлового сервиса | | `DOCUMENTATION_URL` | string | — | URL самого сервиса документаций (для внутренних ссылок) | | `WORKFLOW_URL` | string | — | URL сервиса workflows (создание/чтение процессов обработки) | | `WORKSPACE_URL` | string | — | URL сервиса воркспейсов | | `WORKSPACE_V2_EXTERNAL_URL` | string | — | Внешний URL воркспейсов v2 | | `WORKSPACE_BUNDLE_VERSION` | string | — | Версия бандла воркспейса (`v1`) | | `MARKS_PROCESSING_URL` | string | — | URL сервиса штампов/маркировок (при HTTP-режиме) | | `BIM_API_URL` | string | — | URL BIM-API v1 | | `BIM_API_V2_URL` | string | — | URL BIM-API v2 (bim-core-api) | | `BIM_API_URL_EXTERNAL` | string | — | Внешний URL BIM-API | | `SYSTEM_LOG_URL` | string | — | URL сервиса системного лога | | `FLOWS_URL` | string | — | URL сервиса flows | | `AUTOMATION_URL` | string | — | URL сервиса автоматизаций | | `TRANSMITTALS_BASE_URL` | string (nullable) | `nil` | URL сервиса трансмитталов; клиент создаётся только если переменная задана | ### Публичные ссылки и JWT | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `PUBLIC_LINK_HOST` | string | — | Хост публичных ссылок на документы | | `PUBLIC_KEY` | string | — | RSA-публичный ключ (PEM/PKIX) для проверки JWT | | `DOCUMENT_PUBLIC_LINK_JWT_SECRET` | string | — | HMAC-секрет для JWT публичных ссылок и временных загрузок | | `DOCUMENT_PUBLIC_LINK_JWT_EXPIRATION_MINUTES` | uint8 | — | Время жизни JWT публичной ссылки (мин.) | | `PUBLIC_LINK_FOLDER_CONNECTOR_ENABLED` | bool | `true` | Коннектор публичных ссылок для папок | ### Подпись ссылок (signature-in-URL) | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `ENABLE_SIGNATURE_IN_URL` | bool | `false` | Проверять подпись в URL. При `true` требуется рабочий Valkey (иначе сервис завершается с кодом 2) | | `SIGNATURE_SECRET_KEY` | string | `""` | Секрет для подписи ссылок скачивания | | `SIGNATURE_IN_URL_EXPIRATION_SECONDS` | uint64 | `600` | Срок жизни подписи (сек.) | | `ENABLE_AUTH_JWT_IN_URL` | bool | `true` | Добавлять `auth_jwt` в URL | ### Valkey (Redis-совместимый) — кэши | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `VALKEY_ADDR` | string | `localhost:6380` | Адрес `host:port`. Пустая строка полностью отключает клиент Valkey | | `VALKEY_LOGIN` | string | `""` | Логин | | `VALKEY_HOST` | string | `""` | Хост (доп. поле) | | `VALKEY_PASSWORD` | string | `""` | Пароль | | `VALKEY_DB` | int | `0` | Номер БД Redis/Valkey | | `VALKEY_CACHE_TTL` | duration | `1h` | TTL кэша | | `VALKEY_SSL` | bool | `false` | TLS-подключение | | `VALKEY_SSL_CA_CERTS` | string | `""` | CA-сертификат для TLS | ### Файловый стример и in-memory кэш | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `READ_WRITE_TIMEOUT_FILE_STREAM` | duration | — | Read/Write-таймаут HTTP-сервера filestream (в окружении — `6h`) | | `USE_CACHE_IN_FILE_STREAMER` | bool | — | Включить in-memory кэш в filestream-хранилище | | `CACHE_DEFAULT_EXPIRATION` | duration | — | TTL записей кэша | | `CACHE_CLEANUP_INTERVAL` | duration | — | Интервал очистки кэша | ### BIM / обработка файлов | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `USE_BIMV1_FOR_BIMV2` | bool | — | Использовать BIM v1 для v2 | | `USE_BIM_INSERTER` | bool | `true` | Включить BIM-inserter | | `USE_LEGACY_BIM_FLOW` | bool | `false` | Старый flow BIM | | `LAST_MASTER_BIM` | uint64 | — | Граница master-BIM | | `LAST_SLAVE_1_BIM` | uint64 | — | Граница slave-1-BIM | | `LAST_SLAVE_2_BIM` | uint64 | — | Граница slave-2-BIM | | `CONVERT_DWG_TO_GEOJSON` | bool | `true` | Конвертация DWG→GeoJSON | | `CONVERT_DXF_TO_GEOJSON` | bool | `true` | Конвертация DXF→GeoJSON | | `IS_CONVERTED_PDF_UPLOADING_TO_S3` | bool | `true` | Загружать сконвертированный PDF в S3 | | `DELETE_S3D_AFTER_MESHOPT` | bool | `false` | Удалять s3d после mesh-оптимизации | | `WORKFLOW_IMAGES_VERSION` | string | — | Тег образов workflow | | `WORKFLOWS_IMAGES_VERSION` | string | — | Тег образов задач обработки (используется клиентом `workflow`) | | `CONTAINER_REGISTRY` | string | `cr.yandex/crp3ccidau046kdj8g9q` | Реестр контейнеров для образов задач | | `WORKFLOWS_CONFIG_FILEPATH` | string | `.example.tasks_execution_config.json` | Путь к JSON с ресурсами задач обработки | ### Штампы/маркировки (HTTP или RabbitMQ) | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `USE_MARKS_RABBITMQ` | bool | `0` | `0` — ходить в `MARKS_PROCESSING_URL` по HTTP; `1` — через RabbitMQ | | `MARKS_RABBITMQ_HOST` | string | `""` | Хост RabbitMQ | | `MARKS_RABBITMQ_PORT` | string | `""` | Порт RabbitMQ | | `MARKS_RABBITMQ_USER` | string | `""` | Пользователь (из секрета) | | `MARKS_RABBITMQ_PASSWORD` | string | `""` | Пароль (из секрета) | | `MARKS_RABBITMQ_API` | string | `""` | Vhost/имя очереди | ### Rate limit эндпоинта метаданных | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `METADATA_RATE_LIMIT_ENABLED` | bool | `true` | Включить rate-limit для `/documents/metadata` | | `METADATA_RATE_LIMIT_MAX_REQUESTS` | int | `10` | Макс. число запросов | ### Почта | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `ENABLE_MAILGUN` | bool | `true` | Флаг использования Mailgun | | `ENABLE_SMTP` | bool | `false` | Флаг использования SMTP | ### Наблюдаемость | Переменная | Тип | Значение по умолчанию | Назначение | | --- | --- | --- | --- | | `ENVIRONMENT` | string | — | Окружение (для Sentry/трейсинга) | | `SENTRY_DSN` | string | — | DSN Sentry | | `SENTRY_DEBUG` | bool | — | Отладка Sentry | | `NAMESPACE` | string | — | Неймспейс (для контекста запусков задач) | | `ENABLE_SQL_QUERY` | bool | — | Логировать SQL-запросы | | `TRACER_USE` | bool | `false` | Включить OpenTelemetry-трейсинг | | `TRACER_HOST` | string | `localhost:4317` | Адрес OTLP-коллектора | | `TRACER_USE_INSECURE` | bool | `true` | Подключение к коллектору без TLS | | `TRACER_LOGGER_NAME` | string | `tracer_logger` | Имя логгера трейсинга | | `SERVICE_NAME` | string | `documentations-api` | Имя сервиса в трейсах (используется api) | | `SERVICE_NAME_FILESTREAM` | string | `filestream-api` | Имя сервиса в трейсах (используется filestream) | ## Различия api и filestream Оба процесса читают одну и ту же структуру `config.Config`, но: | Аспект | api (`cmd/api`) | filestream (`cmd/filestreamer`) | | --- | --- | --- | | Слушает адрес из | `API_ADDRESS` | `API_ADDRESS_FILE` | | Пул соединений к БД | `POSTGRES_POOL_SIZE` | фиксировано `50` (+ `PoolTimeout=1m`), `POSTGRES_POOL_SIZE` игнорируется | | Read/Write-таймаут сервера | жёстко `30m` | `READ_WRITE_TIMEOUT_FILE_STREAM` | | S3 | опционален (`ENABLE_S3`) | обязателен (при отсутствии кредов процесс завершается) | | In-memory кэш хранилища | выключен | управляется `USE_CACHE_IN_FILE_STREAMER` / `CACHE_*` | | Имя сервиса в трейсах | `SERVICE_NAME` | `SERVICE_NAME_FILESTREAM` | | Signature-middleware на `/api/v1` | нет | есть (`SignatureMiddleware`) | | Набор маршрутов | полный REST CRUD (`cmd/api/routes_api.go`, `routes_internal.go`) | только потоковые скачивания/загрузки файлов (`cmd/filestreamer/routes_api.go`, `routes_internal.go`) | **Что делает filestream-бинарник.** Это отдельный HTTP-сервис для тяжёлой потоковой работы с файлами, вынесенный из основного API, чтобы не блокировать его долгими соединениями (отсюда таймаут в часы и увеличенный пул БД). Публичные маршруты (`/api/v1`): - `GET /documents/folders` — скачивание нескольких папок архивом (gzip); - `GET|HEAD|POST /bundles/...` — скачивание файлов бандла; при `?format=gz` отдаётся без повторного сжатия, иначе — `CompressHandler`; поддержаны HEAD (range) и внешний матчер `DownloadMatcherExternal`; - `GET|HEAD|POST /pages/...` — скачивание страниц (постранично); - `GET|HEAD /documents/...` — скачивание по документам; `POST /documents/...` — скачивание по списку bundle-id; - `POST /bundles_mrpas/...` и `GET /public_link_mrpas/...` — выгрузка MRPA (в т. ч. по публичной ссылке). Внутренние маршруты (`/internal/v1`): скачивание/загрузка бандлов между сервисами и `POST /upload_finish/bundles/...`. ## Переменные сборки и запуска (не читаются кодом приложения) | Переменная | Где используется | Назначение | | --- | --- | --- | | `APP_VERSION` | `Makefile`, dockerfiles | Версия, зашиваемая в бинарь (`-ldflags -X main.version`) | | `CI_COMMIT_SHORT_SHA` | dockerfiles | Тег версии образа files | | `GITLAB_CREDENTIALS` | dockerfiles (build-arg) | Доступ к приватным Go-модулям `gitlab.sarex.io` | | `API_VERSION` | `.docker/docker-compose.yml` | Тег локально запускаемого образа | | `POSTGRES_EXTERNAL_PORT` | `.docker/docker-compose.yml` | Внешний порт локального Postgres | | `KEY_JWT` / `JWT_KEY` | `.docker/.env`, docker-compose | JWT-ключ **только для интеграционных тестов**, кодом приложения не читается | ## Переменные из Helm-чарта (`.helm/values.yaml`) Чарт основан на `universal-chart` (зависимость из `Chart.yaml`) и описывает два сервиса — `services.api` и `services.filestream`. У каждого свои блоки `envs` (обычные значения, с разбивкой по окружениям `_default`/`stage`/`preprod`/`production`) и `secretEnvs` (значения из k8s-секретов). Наборы переменных у обоих сервисов практически идентичны. Значения из секретов (`secretEnvs`, монтируются как env через `secretKeyRef`): | Переменная | Секрет (`secretName`) | Ключ (`secretKey`) | | --- | --- | --- | | `SIGNATURE_SECRET_KEY` | `documentations-download-secret` | `secret` | | `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` | | `POSTGRES_USER` | `documentations-postgresql-secret` | `user` | | `POSTGRES_PORT` | `documentations-postgresql-secret` | `port` | | `POSTGRES_ADDRESS` | `documentations-postgresql-secret` | `host` | | `POSTGRES_DB` | `documentations-postgresql-secret` | `database` | | `POSTGRES_PASSWORD` | `documentations-postgresql-secret` | `password` | | `DJANGO_BASIC_AUTH` | `django-auth` | `key` | | `DJANGO_BASIC_AUTH_FOR_GET_USER` | `django-auth-get-user` | `key` | | `DOCUMENT_PUBLIC_LINK_JWT_SECRET` | `yc-jwt-secret` | `secret` | | `PUBLIC_KEY` | `public-key` | `key` | | `MARKS_RABBITMQ_USER` | `cde-rabbitmq-secret` (в api; prod — `marks-rabbit-secret`) / `marks-rabbit-secret` (в filestream) | `user` | | `MARKS_RABBITMQ_PASSWORD` | то же | `password` | | `YC-PG-CERTIFICATE` | `yc-pg-certificate` | `certificate` | Тома (`volumes`) монтируют секреты как файлы: `documentations-yc-s3` → `/etc/sarex/yc-s3-storage` (на него указывает `S3_SERVICE_ACCOUNT`), `zitadel-account` → `/etc/sarex/zitadel` (на него указывает `ZITADEL_ACCOUNT`). Файл `WORKFLOWS_CONFIG_FILEPATH` в проде — `/etc/app/tasks_execution_config.json`. Ingress включён только у `filestream` (`ingress.enabled: false` по умолчанию, path `/files/api/` → rewrite `/api/`); у api ingress-блока в values нет — сервис доступен через `documentations-api-svc`. Прочие значения чарта (не переменные приложения): `deployment.*` (реплики stage/preprod/prod = 1/3/6, ресурсы, revisionHistoryLimit), `probes` (`/ping`), `service.*`, `serviceAccount`, `imagePullSecrets: dockerhub`, `affinity` (podAntiAffinity у filestream), а также блок `cronjobs` (`delete_expired_public_links`, `refresh_latest_bundle_filters_view`, `refresh_string_path_materialized_view`). ## Переменные в CI (`.gitlab-ci.yml`) Пайплайн подключает общие шаблоны `generic/common-ci` (`common-security-scan.yaml`, `universal-pipeline.yaml`, ref `apps-business`). Окружение переключается по ветке/тегу через `workflow.rules`: | Условие | STAND | NAMESPACE | universal-chart env | | --- | --- | --- | --- | | ветка `stage` | `stage` | `documentations` | `stage` | | ветка `master` | `preprod` | `documentations-preprod` | `preprod` | | тег (`CI_COMMIT_TAG`) | `prod` | `documentations-prod` | `production` | | merge request | — | — | сборка образа отключена (`ENABLE_BUILD_IMAGE=false`) | Общие для всех окружений: `RELEASE_NAME=documentations`, `CHART_NAME=documentations`, `SERVICE_NAME: documentations`, `DOCKERFILE_PATH: .docker/api.dockerfile`, `IMAGE_PATH: api.deployment.image`. Через `HELM_SET_ARGS` проставляются образы: `services.api.image` (основной), `services.filestream.image` (`IMAGE_NAME_API_FILES`, dockerfile `.docker/api-filestream.dockerfile`), а также образы кронджоб `cronjobs.delete_expired_public_links`, `cronjobs.refresh_latest_bundle_filters_view`, `cronjobs.cleanup_failed_s32d_sessions`. Дополнительные образы собираются отдельными job-ами `build_files`, `build_public_link_autodeletion`, `build_refresh_latest_bundle_filters_view`, `build_cleanup_failed_s32d_sessions` (только на `stage`/`master`/тег). ## Замечания и потенциальные проблемы - **У envconfig нет «обязательных» полей.** Отсутствующая переменная без `default` становится нулевым значением, ошибка старта не выбрасывается. Некорректная конфигурация проявляется в рантайме (не удаётся подключиться к БД/S3, невалидный `PUBLIC_KEY` при первой проверке JWT и т. п.). - **`.env` не подхватывается автоматически** — приложение читает только окружение процесса. Локально удобнее запускать через `docker-compose --env-file` (`make docker`) или экспортировать `.docker/.env` вручную. - **`POSTGRES_POOL_SIZE` игнорируется в filestream** — там пул жёстко задан как `50`. В api берётся из переменной. - **`YC-PG-CERTIFICATE`** — имя с дефисами (не в стиле `SNAKE_CASE`), но envconfig читает его по точному тегу. Значение приходит из секрета и используется как содержимое PEM (`AppendCertsFromPEM`), а не как путь к файлу. - **Рассинхрон имён Valkey.** В Helm задаются `VALKEY_PORT` и `VALKEY_CA_CERTS`, но код читает `VALKEY_ADDR` (host:port одной строкой) и `VALKEY_SSL_CA_CERTS`. Переменные `VALKEY_PORT`/`VALKEY_CA_CERTS` приложением напрямую не читаются (адрес и CA берутся из `VALKEY_ADDR`/`VALKEY_SSL_CA_CERTS`). - **`HOST` и `DOCUMENTATION_EXTERNAL_URL` из Helm кодом не читаются** — в `config.Config` таких полей нет (для внутренних ссылок используется `DOCUMENTATION_URL`, `FILE_URL_EXTERNAL`, `PUBLIC_LINK_HOST`). - **`ENABLE_SIGNATURE_IN_URL=true` требует Valkey.** Если клиент Valkey не инициализировался, а флаг включён, оба процесса завершаются с кодом `2`. - **Флаги `ENABLE_MAILGUN`/`ENABLE_SMTP`** присутствуют в конфиге и Helm, но собственной отправкой почты сервис не занимается (в отличие от transmittal-api); это флаги для внешних интеграций. - **`TRANSMITTALS_BASE_URL` — nullable.** Клиент трансмитталов создаётся только если переменная задана; иначе связанные вызовы пропускаются. - **Штампы: HTTP vs RabbitMQ.** При `USE_MARKS_RABBITMQ=1` используется RPC-клиент через RabbitMQ (`MARKS_RABBITMQ_*`), при `0` — HTTP-клиент на `MARKS_PROCESSING_URL`. В values для prod-секретов имя `marks-rabbit-secret` отличается от stage/preprod (`cde-rabbitmq-secret`). ## Минимальный набор для локального запуска Ориентир — `.docker/.env` (+ `make docker` для запуска в контейнерах вместе с Postgres). Минимально нужно задать: - `API_ADDRESS`, `API_ADDRESS_FILE`; - `POSTGRES_ADDRESS`, `POSTGRES_PORT`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`, `POSTGRES_POOL_SIZE`, `ENABLE_SSL=0`; - `ENABLE_S3` (`0` для api без S3; для filestream — `1` и `S3_SERVICE_ACCOUNT`/`S3_SERVICE_ACCOUNT_STR`); - `DJANGO_HOST`, `DJANGO_ORIGINATOR`, `NAMESPACE`; - сервисные URL по необходимости: `WORKFLOW_URL`, `WORKSPACE_URL`, `SYSTEM_LOG_URL`, `FLOWS_URL`, `MARKS_PROCESSING_URL`; - для filestream: `READ_WRITE_TIMEOUT_FILE_STREAM`, `USE_CACHE_IN_FILE_STREAMER`, `CACHE_DEFAULT_EXPIRATION`, `CACHE_CLEANUP_INTERVAL`; - `ENABLE_SQL_QUERY=1` (для отладки), `TRACER_USE=false`; - `PUBLIC_KEY`/`DOCUMENT_PUBLIC_LINK_JWT_SECRET` — для реальной проверки JWT (локально можно оставить пустыми, но защищённые ручки будут отклонять токены). Готовый пример со всеми значениями приведён в `api.env.example` (рядом с этим документом) и в `.docker/.env` исходного репозитория.