97 lines
14 KiB
Markdown
97 lines
14 KiB
Markdown
# Активный контекст
|
||
|
||
## Текущее состояние
|
||
|
||
Собран полный вертикальный production-пайплайн скрима: закрытие регистрации → versioned балансировка → ручная правка и подтверждение составов 1/2/2 → капитаны → drag-and-drop редактор произвольного графа матчей → атомарный старт готовых Bo3 → жеребьёвка → баны карт → баны героев → результаты и динамическое разрешение Winner/Loser-переходов. Состояние события, roster draft, bracket draft и серии сохраняется в PostgreSQL с optimistic locking, аудитом и глобальной SSE-синхронизацией.
|
||
|
||
Admin UI содержит пошаговый workflow и roster editor с same-role swap, резервом и запуском. Live, spectator и bracket используют реальные API-команды и realtime refresh; участник турнира автоматически открывает собственный матч, остальные попадают в spectator mode, а актуальная сетка и соседние параллельные матчи доступны прямо над серией. Demo fixtures остались только локальным showcase.
|
||
На странице события после выбора баланса публично показываются сохранённые составы команд. В live-control участник получает короткий звуковой сигнал, когда после действия соперника сервер передаёт ход его команде; первая загрузка страницы звук не запускает.
|
||
Добавлены профили всех игроков с уникальным nickname, необязательным BattleTag, текущими рангами, статистикой завершённых Bo3/карт и историей последних матчей. Имена в составах и списках ведут в профиль; player-facing UI больше не использует Discord username.
|
||
Admin-only Community settings хранит Discord invite URL. FAQ объясняет Discord-процесс, работу бота и показывает настроенную ссылку; Moderator не может её изменять.
|
||
Добавлена роль Moderator: она имеет все операционные права Admin, но управление списком модераторов доступно только Admin. До состояния Live workflow можно откатить на один этап назад.
|
||
Добавлен Discord-анонс нового микса: после успешного создания Event backend через Bot REST API публикует локализованный embed и кнопку регистрации. При создании staff может оставить включённой галочку уведомления `@everyone` или отправить тихий анонс без пинга. Ошибка Discord логируется, но не отменяет создание события; без bot token и channel ID интеграция отключена.
|
||
Добавлен PostgreSQL-backed Discord role worker. После подтверждения составов он создаёт и выдаёт роли по актуальным Team.Name, Captain и slot Tank/Damage/Support, учитывает live-переименование и аварийную замену, а при завершении/отмене/удалении/откате удаляет временные роли. Повтор jobs идемпотентен; guest и отсутствующие в guild игроки сохраняются как предупреждения и не блокируют микс.
|
||
При любом RSVP тот же worker создаёт event-specific роли «Зарегистрирован», «Идёт», «Возможно», «Не идёт», выдаёт общую роль ответа и ровно один текущий статус, обновляет названия при rename Event и снимает назначения после удаления RSVP. Registration close роли не удаляет; общий event teardown очищает их вместе с team/captain roles.
|
||
В Discord member list отдельными hoisted-группами отображаются роли команд и общая роль регистрации. Team-группы располагаются выше registered-группы; Captain, slot и конкретный RSVP-статус остаются негруппирующими служебными ролями.
|
||
Если связанный пользователь зарегистрировался до вступления на Discord-сервер, job повторяет назначение раз в пять минут и автоматически применяет все актуальные роли после его появления в guild.
|
||
Добавлен глобальный full reconcile при старте и каждые пять минут: он сравнивает фактические guild roles/members с полным active desired state, пересоздаёт удалённые managed roles, добавляет недостающие и снимает лишние managed assignments, не затрагивая посторонние роли сервера. Для пагинированного member inventory включается Server Members Intent; Gateway listener не используется.
|
||
|
||
## Подтверждённые требования
|
||
|
||
- сообщество из 20+ игроков;
|
||
- backend на Go с Clean Architecture;
|
||
- современный frontend на фреймворке;
|
||
- Discord OAuth и самостоятельное заполнение игроком рейтингов Tank, Damage и Support;
|
||
- выбор игроком предпочитаемых ролей, до трёх желаемых союзников и до трёх avoid-игроков;
|
||
- переключение всего интерфейса между RU и EN;
|
||
- календарь запланированных миксов со статусами Going / Maybe / NotGoing;
|
||
- административная панель управления событиями, игроками и регистрациями;
|
||
- Admin может отменить событие с сохранением его в календаре или полностью удалить событие и связанные данные;
|
||
- возможность Admin отметить участие за другого игрока;
|
||
- автоматическая балансировка полных команд 1 Tank / 2 Damage / 2 Support;
|
||
- резерв для участников, не вошедших в полные команды;
|
||
- назначение Admin капитана каждой сформированной команды;
|
||
- жеребьёвка на сайте;
|
||
- последовательные баны карт и героев;
|
||
- серии Bo3;
|
||
- фиксация исхода каждой карты, счёта серии и итогового победителя;
|
||
- актуальная турнирная сетка с параллельными матчами, умным live-входом и переключением spectator/control;
|
||
- production-развёртывание единым Docker Compose resource в Coolify;
|
||
- PostgreSQL в том же Compose-стеке с persistent volume;
|
||
- мобильный и десктопный интерфейс.
|
||
- карточки отменённых событий отображаются красными, завершённых — зелёными, активных — розовыми с меткой LIVE.
|
||
- новый микс автоматически анонсируется в настроенном Discord-канале со ссылкой на регистрацию; `@everyone` можно отключить при создании.
|
||
- подтверждённые составы автоматически проецируются в управляемые Discord-роли и очищаются по завершении их жизненного цикла.
|
||
- явные RSVP автоматически проецируются в локализованные event-specific Discord-роли ответа и статуса.
|
||
- игроки используют уникальные nickname, могут указать BattleTag и открывать профили друг друга со статистикой и историей матчей;
|
||
- Discord invite для FAQ настраивается только Admin.
|
||
|
||
## Исходный регламент
|
||
|
||
- основной Bo3: Control → Hybrid/Escort → Control;
|
||
- альтернативный Bo3: Control → Push → Escort;
|
||
- первая карта определяется банами: первый бан задаёт жеребьёвка, затем команды банят по очереди до одной оставшейся;
|
||
- вторую и последующие карты напрямую выбирает команда, проигравшая предыдущую карту;
|
||
- после ничьей следующую карту выбирает команда, проигравшая начальный жребий;
|
||
- тайбрейкер Control не повторяет уже сыгранную Control-карту;
|
||
- перед каждой картой команды делают по два бана героев в порядке A → B → A → B;
|
||
- два бана одной команды должны относиться к разным ролям;
|
||
- команда не повторяет собственный бан героя в пределах серии;
|
||
- повторить героя, которого ранее банил соперник, разрешено;
|
||
- первой героев банит команда, проигравшая начальный жребий.
|
||
|
||
## Предлагаемый стек
|
||
|
||
- backend: Go, PostgreSQL, REST, SSE;
|
||
- frontend: React, TypeScript, Vite, TanStack Query/Router, Tailwind CSS, shadcn/ui;
|
||
- контракт: OpenAPI;
|
||
- локальная инфраструктура: Docker Compose;
|
||
- production: Coolify + Docker Compose без пользовательских сетей.
|
||
|
||
## Принятые решения для MVP
|
||
|
||
- игрок входит через Discord;
|
||
- игрок самостоятельно указывает Overwatch-ранг от Bronze 5 до Champion 1 для каждой роли;
|
||
- балансировщик автоматически назначает роли и собирает команды 1/2/2;
|
||
- предпочтения ролей, союзников и avoid-списки учитываются как мягкие штрафы после требований баланса;
|
||
- участники сверх полного состава остаются в резерве;
|
||
- сетка редактируется как последовательный граф Team / Winner / Loser; последний матч определяет общего победителя;
|
||
- игрок отмечается на микс через календарь;
|
||
- Admin может изменить RSVP за игрока, а действие сохраняет автора;
|
||
- капитан назначается отдельно для каждой команды и должен входить в её состав;
|
||
- Admin закрывает регистрацию и фиксирует список участников перед балансировкой;
|
||
- до подтверждения составов Admin может менять игроков одной роли местами и заменять игрока резервным;
|
||
- подтверждённые составы и капитаны являются обязательным условием запуска скрима;
|
||
- запуск скрима создаёт серверную серию и переводит событие в последовательный конечный автомат жеребьёвки, банов и результатов;
|
||
- после запуска обычное редактирование составов блокируется; аварийная замена выполняется Admin отдельно и фиксируется в аудите;
|
||
- исход карты задаётся как победа одной из команд или ничья;
|
||
- сервер автоматически пересчитывает счёт Bo3 и победителя серии;
|
||
- frontend, API и PostgreSQL разворачиваются одним Compose-стеком;
|
||
- Coolify управляет сетью и публичным маршрутом, PostgreSQL хранит данные в named volume.
|
||
|
||
## Ближайший следующий шаг
|
||
|
||
Проверить миграции `006_event_workflow.sql` и `011`–`014` Discord migrations с реальной PostgreSQL (`TEST_DATABASE_URL`), затем на staging проверить RSVP transitions, member-list grouping, global reconcile, rename/emergency substitution и cleanup Discord-ролей перед первым production-миксом.
|
||
|
||
Публичная вкладка FAQ описывает регистрацию, балансировку, полномочия капитанов, выбор карт, баны героев и подсчёт Bo3.
|