iac/apps/documentations/api.CONFIGURATION.md

346 lines
33 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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