# День игры — контракт и фон

Источник: https://docs.novapoker.ru/dev/game-day/
Дорожка: разработка
Сверено с кодом: Mon Aug 24
Код: repos/poker-api/apps/server/src/registrations/registrations.service.ts, docs/superpowers/specs/2026-08-22-as-built-system-spec.md

---

День игры трогает три вещи: эндпоинты стойки регистрации, фоновые напоминания и
операцию старта, которая фиксирует состав.

## Эндпоинты стойки

| Метод и путь | Кто может |
|---|---|
| `POST /tournaments/{id}/check-in` | `owner`, `td` |
| `POST /tournaments/{id}/cancel-check-in` | `owner`, `td` |
| `POST /tournaments/{id}/walk-in` | `owner`, `td` |
| `GET /tournaments/{id}/registrations` | `owner`, `td` |

Чек-ин возможен только из статуса `registered` и только пока турнир в
`registration`. Полный контракт модуля — в статье
[Запись: контракт и переходы](https://docs.novapoker.ru/dev/registration.md).

## Walk-in

Принимает телефон и имя. Логика поиска человека:

1. телефон принадлежит существующему пользователю → запись привязывается к нему;
2. иначе заводится `GuestPlayer`, который клеймится при первом входе владельца
   телефона.

Операция **идемпотентна**: повтор и гонка возвращают ту же строку. Доступна
пока турнир `registration` **или** `running` — то есть это же и поздняя
дорегистрация. `capacity` намеренно не проверяется.

## Фоновые напоминания

pg-boss на том же PostgreSQL, без Redis; стартует по DI-токену `BOSS`, в тестах
подменён `FakeBoss`.

| Джоба | Расписание | Что делает |
|---|---|---|
| `tournament-reminders` | `*/5 * * * *` | пуш за 24 ч до старта и пуш в момент дедлайна отмены |
| `season-rollover` | `5 0 * * *` UTC | архивирует истёкший сезон, заводит текущий квартал |

**Окно поиска равно периоду запуска** — пять минут. Дедупликация идёт по журналу
`Notification`: ключ складывается из `kind`, `payload.tournamentId` и
`payload.window`, поэтому повторный тик или ручной перезапуск джобы не задваивает
напоминание. Гости без аккаунта пропускаются — им некуда слать.

Дедлайн отмены у каждого организатора свой: `organizer.cancelDeadlineHours`,
по умолчанию 3.

## Что делает старт турнира

Требует минимум двух записей в `checked_in`. В одной операции:

- рассадка — случайно и равномерно, `SEATS_PER_TABLE = 9`, разброс между столами
  не больше одного игрока;
- всем, кто остался в `registered`, ставится `no_show` и выдаётся страйк;
- запускается серверный таймер блайндов с первого уровня.

Отсюда важное следствие для отладки: **после старта состав уже зафиксирован**,
и «потерянный» игрок — это почти всегда несделанный чек-ин, а не сбой рассадки.

## Реалтайм

Живое состояние турнира отдаёт `GET /tournaments/{id}/live`, подписка — namespace
`/live` через socket.io. Гейт `/live` требует JWT на handshake: приложение
организатора передаёт `auth: { token }` при подключении. Молчащий сокет чаще
всего означает отсутствующий или протухший токен, а не потерянное соединение.

## Что рядом

- [День игры и чек-ин](https://docs.novapoker.ru/product/game-day.md) — те же правила словами продукта.
- [Запись: контракт и переходы](https://docs.novapoker.ru/dev/registration.md) — статусы и коды ошибок.
- [poker-api](https://docs.novapoker.ru/dev/poker-api.md) — как запустить сервис локально.
