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