# Окружения, стенды и деплой

Источник: https://docs.novapoker.ru/dev/environments/
Дорожка: разработка
Сверено с кодом: Mon Aug 24
Код: repos/poker-api/README.md, repos/poker-admin/Dockerfile, repos/poker-player/Dockerfile

---

## Переменные бэкенда

Полная таблица — в README `poker-api`; здесь то, без чего не поднимается или
ведёт себя неожиданно.

| Переменная | Зачем |
|---|---|
| `DATABASE_URL` | подключение к PostgreSQL |
| `JWT_SECRET` | подпись access-токенов; в production обязателен сильный, иначе старт падает |
| `PLATFORM_ADMIN_PHONES` | телефоны, получающие роль супер-админа при входе |
| `PORT` | порт HTTP и WS — они на одном |
| `OTP_CHANNELS` | порядок каналов доставки кода, по умолчанию `telegram,max,sms` |
| `CORS_ORIGINS` | **без него кросс-доменный доступ выключен** — самая частая причина «фронт не видит API» |
| `OTP_LOG_CODES` | печать кода в stdout, только для разработки |

Плюс секреты каналов доставки и настройки S3-хранилища. Значений здесь нет и быть
не может: сайт публичный.

## Локальный стенд

Четыре процесса. Конфигурация — в `.claude/launch.json` корневого репозитория.

| Что | Команда | Порт |
|---|---|---|
| PostgreSQL | `docker compose up -d` в `poker-api` | 5433 |
| API | `pnpm --filter server dev` | 3001 на стенде, 3000 по умолчанию |
| Игрок | `expo start --web --port 8090` | 8090 |
| Организатор | `expo start --web --port 8092` | 8092 |
| Админка | `vite dev --port 5199` | 5199 |

Две грабли, на которые наступают:

- **Сервер не читает `.env` из корня** — файл кладётся в `apps/server/`.
- **Коды OTP по умолчанию не видны.** Чтобы войти локально, нужны
  `OTP_CHANNELS=fake` и `OTP_LOG_CODES=1`, иначе код уходит в реальный канал.
  Хранится он только хешем, подсмотреть в базе нельзя.

PostgreSQL слушает **5433**, а не 5432 — чтобы не спорить с локальной базой.

## Стейджинг

| Адрес | Что |
|---|---|
| `novapoker.ru` | API с префиксом `/api/v1`, здоровье — `/api/v1/health`; в корне веб-сборка игрока |
| `admin.novapoker.ru` | админка |
| `docs.novapoker.ru` | эта документация |

Разделение сервисов на одном хосте делает Dokploy **по префиксу пути**: в карточке
домена задаётся поле Path, и Traefik предпочитает более длинное правило. Поэтому
`/api/v1` выигрывает у `/`.

## Деплой

У всех сервисов один паттерн: multi-stage `Dockerfile`, `nginx:alpine` в рантайме
для фронтов, Dokploy тянет образ и вешает домен с letsencrypt. Проверка живости —
`/healthz` у фронтов, `/api/v1/health` у API.

### Правило, которое стоит всех остальных

**Переменные, которые сборщик вшивает в бандл, задаются в Build Args, а не в Env.**

| Сервис | Переменная | Где задавать |
|---|---|---|
| `poker-admin` | `VITE_API_URL` | Build Args |
| `poker-player` | `EXPO_PUBLIC_API_URL`, `EXPO_PUBLIC_SHARE_BASE_URL` | Build Args |
| `poker-organizer` | `EXPO_PUBLIC_API_URL` | Build Args |

Vite и Metro подставляют значения прямо в бандл. Смена переменной окружения без
пересборки образа **не меняет ничего** — и выглядит это как «деплой не
применился».

Значение адреса API везде — голый origin, **без** `/api/v1`: префикс дописывает
HTTP-клиент.

Проверить, что реально вшито в живой бандл: скачать `/assets/index-*.js` через
`curl --compressed` и найти в нём `/api/v1` — рядом стоит функция базового адреса.

## Что рядом

- [Карточки сервисов](https://docs.novapoker.ru/dev/poker-api.md) — запуск и сборка каждого по отдельности.
- [Тесты и CI](https://docs.novapoker.ru/dev/testing.md) — что проверяется до деплоя.
