Переменные окружения
Справочник переменных окружения всех частей монорепозитория «Оптимы». Значения секретов здесь не приводятся: в production они задаются per-окружение в Coolify, в репозитории лежат только заглушки для локальной разработки и CI.
Бэкенд (backend/)
Источник истины — zod-схема backend/src/core/config/env.schema.ts. Пример —
backend/.env.example (локально скопируйте его в backend/.env). Приложение валидирует
env при старте: если обязательная переменная отсутствует или некорректна, процесс падает
до приёма трафика со списком нарушений.
В production дополнительно действует проверка «боевой пригодности» секретов
(backend/src/core/crypto/secret-strength.ts, ADR-0044):
активный ключ шифрования, JWT_ACCESS_SECRET и JWT_REFRESH_SECRET не должны совпадать с
заглушками из репозитория, содержать маркеры вроде change-me или иметь низкую энтропию,
а JWT-секреты не должны совпадать между собой. Иначе контейнер не стартует.
Приложение и инфраструктура
| Переменная | Обязательна | По умолчанию | Назначение |
|---|---|---|---|
NODE_ENV | нет | development | development / test / production. Влияет на Swagger, Bull Board, /metrics, CORS, проверку секретов. В Docker-образе задан production |
PORT | нет | 3000 | порт HTTP-сервера |
LOG_LEVEL | нет | по NODE_ENV: production — log, test — warn, иначе debug | минимальный уровень структурных JSON-логов: error / warn / log / debug / verbose |
DATABASE_URL | да | — | строка подключения PostgreSQL postgres://user:pass@host:port/db. Нужен PostgreSQL с расширением pgvector |
REDIS_URL | да | — | строка подключения Redis redis://[user:pass@]host:port[/db] |
QUEUE_PREFIX | нет | optima | префикс ключей BullMQ; изолирует окружения, если они делят один Redis |
GIT_SHA | нет | — | SHA коммита для ответа GET /version. Сейчас ни Dockerfile, ни CI его не передают |
TRUST_PROXY_HOPS | нет | 1 | число доверенных прокси для X-Forwarded-For (Coolify/Traefik). 0 — прямое подключение |
CORS_ORIGINS | нет | — | production: разрешённые origin'ы через запятую. Без переменной CORS-заголовки не выдаются. В dev/test CORS открыт |
Аутентификация и шифрование
| Переменная | Обязательна | По умолчанию | Назначение |
|---|---|---|---|
JWT_ACCESS_SECRET | да | — | секрет подписи access-токенов, не короче 16 символов |
JWT_REFRESH_SECRET | да | — | не короче 16 символов. Устарела: refresh-токены opaque и этим секретом не подписываются, переменная оставлена для совместимости. Её ротация не завершает сессии |
JWT_ACCESS_TTL | нет | 15m | срок жизни access-токена (формат ms: 15m, 1h) |
JWT_REFRESH_TTL | нет | 30d | срок жизни refresh-токена |
ENCRYPTION_KEYS | да | — | key-ring AES-256-GCM для секретов at-rest (API-ключи кабинетов WB): kid:hex64[,kid:hex64…], ключ — openssl rand -hex 32 (ADR-0005) |
ENCRYPTION_ACTIVE_KID | да | — | kid из ENCRYPTION_KEYS, которым шифруются новые записи |
AUTH_MAX_FAILED_ATTEMPTS | нет | 10 | неудачных входов до временной блокировки учётной записи |
AUTH_LOCKOUT_MS | нет | 900000 (15 мин) | длительность блокировки |
Порядок ротации ключа шифрования описан в backend/README.md (раздел «Ротация ключа
шифрования»).
Служебные интерфейсы (production)
В dev/test эти интерфейсы открыты. В production каждый подключается только при наличии обеих переменных пары и закрывается HTTP Basic; без них интерфейс отключён.
| Переменные | Что защищают |
|---|---|
SWAGGER_USER, SWAGGER_PASSWORD | Swagger UI /api/docs |
QUEUE_BOARD_USER, QUEUE_BOARD_PASSWORD | Bull Board /admin/queues |
METRICS_USER, METRICS_PASSWORD | Prometheus /metrics |
Входящий rate limiting
Подробнее — Обзор API, раздел «Входящий rate limiting».
| Переменная | По умолчанию | Назначение |
|---|---|---|
THROTTLE_DEFAULT_LIMIT | 300 | общий лимит запросов с IP за окно |
THROTTLE_DEFAULT_TTL_MS | 60000 | окно общего лимита |
THROTTLE_AUTH_LIMIT | 5 | попыток register/login с IP за окно |
THROTTLE_AUTH_TTL_MS | 900000 | окно auth-лимита (15 мин) |
THROTTLE_REFRESH_LIMIT | 60 | запросов POST /auth/refresh с IP за окно |
THROTTLE_REFRESH_TTL_MS | 60000 | окно refresh-лимита |
THROTTLE_LLM_LIMIT | 30 | вызовов эндпоинтов с LLM с IP за окно |
THROTTLE_LLM_TTL_MS | 3600000 | окно LLM-лимита (1 ч) |
THROTTLE_REFRESH_* читаются напрямую из process.env декоратором
(backend/src/core/security/throttle.decorators.ts) и в zod-схему не входят: некорректное
значение не уронит старт, а молча заменится значением по умолчанию.
Интеграция с Wildberries
Подробнее — Интеграция с WB API.
| Переменная | По умолчанию | Назначение |
|---|---|---|
WB_API_USE_SANDBOX | false | использовать sandbox-домены WB (только с токеном «Тестовый контур»). Для категорий без sandbox — явная ошибка |
WB_API_TIMEOUT_MS | 10000 | таймаут одного запроса к WB |
WB_API_RETRY_ATTEMPTS | 3 | максимум попыток HTTP-запроса, включая первую (1–10) |
WB_API_RETRY_BASE_MS | 500 | база экспоненциального backoff для 5xx и сетевых сбоев |
WB_API_RATE_LIMIT_MAX_WAIT_MS | 30000 | нижняя граница потолка ожидания лимита; эффективный потолок — max(значение, N × окно эндпоинта + 5 с) |
DIGITIZATION_INCREMENT_INTERVAL_MS | 30 мин (константа модуля) | интервал яруса «инкремент» синхронизации фидов оцифровки |
RNP_SYNC_INTERVAL_MS | — | устаревший синоним предыдущей переменной; читается, если новая не задана |
SYNC_QUEUE_CONCURRENCY | 5 (константа) | сколько кабинетов один процесс синхронизирует параллельно в каждой sync-очереди (ADR-0040) |
ИИ-провайдер (LLM)
Все переменные необязательны: без них приложение стартует, а вызов ИИ вернёт
LLM_UNAVAILABLE (ADR-0014).
| Переменная | По умолчанию | Назначение |
|---|---|---|
LLM_PROVIDER | openai-compatible | тип адаптера; других значений пока нет |
LLM_BASE_URL | — | базовый URL OpenAI-совместимого API |
LLM_API_KEY | — | ключ провайдера (секрет; для локальных эндпоинтов может быть пустым) |
LLM_MODEL | — | модель чата |
LLM_EMBEDDINGS_MODEL | — | модель эмбеддингов (нужна RAG) |
LLM_TIMEOUT_MS | 30000 | таймаут одного вызова |
LLM_RETRY_ATTEMPTS | 3 | максимум попыток (повтор на 429/5xx/сети) |
LLM_RETRY_BASE_MS | 500 | база backoff |
LLM_MAX_RETRY_AFTER_MS | 30000 | верхний предел ожидания по Retry-After |
LLM_MAX_TOKENS | 1024 | потолок max_tokens на вызов, если сервис не задал свой |
Ресурсные предохранители
| Переменная | По умолчанию | Назначение |
|---|---|---|
REPORT_MAX_PERIOD_DAYS | 366 | максимальная длина периода в отчётах; длиннее — 400 |
DB_STATEMENT_TIMEOUT_MS | 30000 | statement_timeout PostgreSQL; 0 — без лимита. Срабатывание — 503 с Retry-After |
DB_MAX_PARALLEL_WORKERS_PER_GATHER | 0 | max_parallel_workers_per_gather для соединений приложения; -1 — не задавать. В .env.example отсутствует |
Веб-приложение (frontend/)
Next.js; переменные NEXT_PUBLIC_* встраиваются в сборку, поэтому для образа задаются
build-аргументом. Пример — frontend/.env.example, код — frontend/src/env.ts.
| Переменная | По умолчанию в коде | Пример для локалки | Назначение |
|---|---|---|---|
NEXT_PUBLIC_API_URL | http://localhost:3000 | http://localhost:3000 | базовый URL API. В Docker-образе по умолчанию https://api.optimawb.ru |
NEXT_PUBLIC_LANDING_URL | https://optimawb.ru | http://localhost:3002 | адрес лендинга для ссылок из приложения |
Лендинг (landing/)
Vite; переменные встраиваются в сборку (build-аргументы образа). Пример — landing/.env.example.
| Переменная | По умолчанию в коде | В образе | Назначение |
|---|---|---|---|
VITE_APP_ORIGIN | http://localhost:3001 | https://app.optimawb.ru | адрес веб-приложения (кнопки входа и регистрации) |
VITE_DOCS_URL | https://docs.optimawb.ru | https://docs.optimawb.ru | адрес портала документации |
Портал документации (docs-site/)
| Переменная | По умолчанию | Назначение |
|---|---|---|
OPTIMA_SWAGGER_URL | https://api.optimawb.ru/api/docs | ссылка на Swagger UI в верхней навигации. В Coolify задаётся per-окружение с отметкой Build Variable и пробрасывается в сборку через ARG в docs-site/Dockerfile |
Локальный docker-compose.yml
| Переменная | По умолчанию | Назначение |
|---|---|---|
REDIS_PASSWORD | optima-local | пароль Redis (--requirepass); подставляется и в REDIS_URL контейнера backend |
NODE_ENV | development | режим контейнера backend (образ собран с production, compose его переопределяет) |
JWT_ACCESS_SECRET, JWT_REFRESH_SECRET, ENCRYPTION_KEYS, ENCRYPTION_ACTIVE_KID | локальные заглушки | можно переопределить из окружения хоста |
DATABASE_URL и REDIS_URL контейнера backend заданы в compose жёстко и указывают на
сервисы postgres и redis внутри compose-сети.
Переменные CI
Workflow backend-ci задаёт для проверок собственные значения (DATABASE_URL, REDIS_URL
без пароля, NODE_ENV=test, CI-заглушки JWT и ключа шифрования). Они имеют приоритет над
.env.example, который подгружают e2e-тесты. Секреты GitHub для деплоя перечислены на
странице CI/CD и деплой.