Files
mixmaker/memory_bank/active_context.md
lemintare 6b189bfce4
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
CI / compose (push) Has been cancelled
Add global role synchronization for Discord with configurable interval
This commit introduces a new feature for global role synchronization in Discord, allowing for periodic reconciliation of managed roles. A new environment variable, `DISCORD_GLOBAL_SYNC_INTERVAL`, has been added to configure the synchronization interval, defaulting to 5 minutes. The `RoleWorker` has been updated to schedule global sync jobs, ensuring that missing managed roles are restored and extra assignments are removed without affecting unrelated server roles. Database schema changes support the new synchronization logic, and tests have been added to validate the functionality of the global reconciliation process.
2026-07-19 12:04:33 +03:00

12 KiB
Raw Blame History

Активный контекст

Текущее состояние

Собран полный вертикальный 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. Добавлена роль 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-роли ответа и статуса.

Исходный регламент

  • основной 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 и 011014 Discord migrations с реальной PostgreSQL (TEST_DATABASE_URL), затем на staging проверить RSVP transitions, member-list grouping, global reconcile, rename/emergency substitution и cleanup Discord-ролей перед первым production-миксом.

Публичная вкладка FAQ описывает регистрацию, балансировку, полномочия капитанов, выбор карт, баны героев и подсчёт Bo3.