Клубы — контракт и оргконтекст
Клуб в коде — Organizer. Всё, что делает клуб, проходит проверку
OrganizersService.requireRole, поэтому раздел стоит читать вместе с
аутентификацией и ролями.
Оргконтекст на фронте
Заголовок раздела «Оргконтекст на фронте»Поверх обычной авторизации приложение организатора держит оргконтекст: хук
useOrg тянет членства из GET /organizers/mine.
- одно членство — выбирается автоматически;
- несколько — показывается экран
select-org, клуб можно сменить в любой момент.
Роль внутри клуба определяет и набор вкладок, и доступные действия. Вкладка «Клуб» существует только у владельца, у дилера «Турниры» называется «Назначения».
Контракт
Заголовок раздела «Контракт»| Метод и путь | Кто может |
|---|---|
GET /organizers/mine |
любой вошедший — свои членства |
GET/PATCH /organizers/{id} |
owner |
GET/POST /organizers/{id}/members |
owner |
DELETE /organizers/{id}/members/{memberId} |
owner |
GET/POST /organizers/{id}/dealer-invites |
owner |
POST /dealer-invites/claim |
приглашённый дилер |
POST /organizers/{id}/locations, GET/PATCH /locations/{id}, GET /locations |
owner; каталог залов публичный |
GET/POST /organizers/{id}/blind-templates |
owner |
POST /organizers/{id}/tournaments |
owner, td |
POST /tournaments/{id}/dealers, PATCH /tournaments/{id}/dealers/{dealerUserId} |
owner |
GET /me/dealer-assignments |
дилер — свои назначения |
GET /dealers, GET /dealers/{userId}, PATCH /dealers/me |
каталог публичный, правка своя |
Пути даны без префикса /api/v1. Заведение самого клуба — операция платформы:
POST /admin/organizers, право organizers.manage.
Приглашение дилера
Заголовок раздела «Приглашение дилера»DealerInvite — телефон плюс одноразовый код с TTL. Особенность, которая
удивляет: платформа этот код не доставляет. Клуб получает его в ответе и
показывает на экране, дальше передаёт человеку сам.
Код срабатывает только с того номера, на который выписан: claim сверяет
телефон вошедшего с телефоном приглашения.
Канал доставки одноразовых кодов у платформы есть — тот же, что для входа, — но приглашение через него не идёт. Это осознанное состояние, а не забытая ветка.
Залы и структуры блайндов
Заголовок раздела «Залы и структуры блайндов»Location — зал: имя, город из справочника, адрес, таймзона, координаты,
описание, фото. Каталог залов читается публично, правит владелец.
BlindTemplate — уровни в JSON, стартовый стек, lateRegLevel. Значение
organizerId = null означает платформенный шаблон, доступный всем клубам;
сид кладёт один такой — «Стандарт 20 мин».
lateRegLevel нигде не проверяется. Поле хранится и отдаётся, но ни одна
ветка кода на него не смотрит: walk-in доступен на любом уровне, пока турнир
running.
Назначение дилера на стол
Заголовок раздела «Назначение дилера на стол»POST /tournaments/{id}/dealers создаёт строку в tournament_dealers,
PATCH уточняет стол. Дилер читает свои назначения через
GET /me/dealer-assignments.
Живое рабочее место дилера не потребовало ни одной серверной строки: оно
собрано из уже существующего LiveState — clock с уровнями и tables с
местами. Стоит помнить при отладке: GET /tournaments/{id}/live отдаётся
без гарда, а сокет /live требует JWT на handshake, но роль при входе в
комнату не проверяет.
Что рядом
Заголовок раздела «Что рядом»- Клуб — залы, блайнды, настройки — то же словами продукта.
- Дилеры на турнире — что видит дилер.
- Live-цикл и реалтайм — состав
LiveState. - poker-organizer — как запустить приложение.