База данных
GM-Relay v1.7.0 использует PostgreSQL. Изменения схемы управляются DbUp-миграциями, встроенными в GmRelay.Bot как embedded resources.
Миграции
Текущие миграции:
V001__initial_schema.sql— базовые таблицы игроков, групп, сессий и участников.V002__add_session_batch.sql— полеsessions.batch_idдля пачек сессий.V003__add_thread_id.sql— полеsessions.thread_idдля Telegram forum topics.V004__add_reschedule_proposals.sql— таблицы предложений переноса и голосов.V005__add_batch_message_id.sql— полеsessions.batch_message_idдля редактирования исходного сообщения расписания.V006__add_session_capacity_waitlist.sql— лимит местsessions.max_players, статус участникаsession_participants.registration_status, время постановки в очередьsession_participants.created_atи индексы для waitlist.V007__add_session_notification_mode.sql— режим уведомленийsessions.notification_mode, отметка обработки T-1h remindersessions.one_hour_reminder_processed_atи индекс для одночасовых напоминаний.V008__add_group_managers.sql— таблицаgroup_managersдля ролейOwnerиCoGm; миграция переносит текущих GM изgame_groups.gm_telegram_idв owner-записи.V009__add_multi_option_reschedule_votes.sql— дедлайн и выбранный вариант вreschedule_proposals, таблицыreschedule_optionsиreschedule_option_votesдля голосования по нескольким слотам.
Основные таблицы
players
Известные Telegram-пользователи, которые взаимодействовали с ботом.
Важные поля:
telegram_id— уникальный Telegram ID пользователя.display_name— актуальное отображаемое имя из Telegram.telegram_username— username пользователя, если он есть.
game_groups
Telegram-группы, где организуются игры.
Важные поля:
telegram_chat_id— уникальный Telegram chat ID.name— актуальное название Telegram-чата.gm_telegram_id— Telegram ID первого owner для совместимости с ранними версиями и миграциями; новая проверка доступа идёт черезgroup_managers.
group_managers
Таблица управляющих группой. Она поддерживает несколько пользователей с правами управления одной Telegram-группой.
Важные поля:
group_idиplayer_id— уникальная пара группы и пользователя.role—OwnerилиCoGm.added_by_player_id— кто назначил co-GM; для owner-записей из миграции может бытьNULL.created_at— время назначения роли.
Индексы:
ix_group_managers_group_roleускоряет выбор управляющих группы и проверку owner.ix_group_managers_playerускоряет список групп, доступных пользователю в Web Dashboard.
game_group_members
Таблица связи группы и игроков. Она остаётся базовой схемой для группового membership; права управления вынесены в group_managers.
sessions
Отдельные игровые сессии.
Важные поля:
batch_id— объединяет несколько сессий, созданных одной командой/newsession.group_id— Telegram-группа, которой принадлежит сессия.title— название игры.join_link— ссылка для подключения.scheduled_at— дата и время в UTC.status—Planned,ConfirmationSent,ConfirmedилиCancelled.max_players— необязательный лимит основного состава;NULLозначает запись без лимита.confirmation_message_id— ID Telegram-сообщения RSVP-подтверждения.link_message_id— ID Telegram-сообщения со ссылкой перед игрой.thread_id— ID Telegram forum topic, если тема была создана.batch_message_id— ID исходного Telegram-сообщения с расписанием пачки.notification_mode—GroupAndDirectдля групповых сообщений с DM-дублированием илиGroupOnlyтолько для группы.one_hour_reminder_processed_at— когда бот обработал персональное напоминание примерно за 1 час до игры.
Bulk-операции Web не требуют новых таблиц: общий title/link обновляется по batch_id, перенос пересчитывает scheduled_at существующих строк, а clone создаёт новый batch_id и новые строки sessions без копирования session_participants.
Для активных статусов есть partial index ix_sessions_pending по scheduled_at.
Для T-1h напоминаний есть partial index ix_sessions_one_hour_reminders по scheduled_at.
session_participants
Участники сессий, их RSVP-состояние и положение в основном составе или очереди.
Важные поля:
session_idиplayer_id— уникальная пара сессии и игрока.is_gm— признак, что участник является GM.registration_status—Activeдля основного состава илиWaitlistedдля листа ожидания.rsvp_status—Pending,ConfirmedилиDeclined.responded_at— время RSVP-ответа.created_at— время записи; используется для порядка листа ожидания.
Индексы:
ix_session_participants_session_registration_statusускоряет подсчёт основного состава и waitlist.ix_session_participants_waitlist_orderускоряет выбор первого игрока из очереди.
Таблицы переноса сессий
reschedule_proposals
Активные предложения переноса.
Статусы:
AwaitingTime— GM нажал перенос, бот ждёт новое время.Voting— идёт голосование активных участников.Approved— перенос принят.Rejected— перенос отклонён.
Важные поля:
voting_deadline_at— дедлайн голосования по вариантам.selected_option_id— победивший вариант после финализации, если перенос принят.
reschedule_options
Варианты нового времени для активного предложения переноса. Для одного предложения хранится 2-3 строки с display_order и proposed_at.
reschedule_option_votes
Голоса активных участников по вариантам переноса. Уникальная пара proposal_id + player_id не даёт одному участнику проголосовать несколько раз; повторный голос обновляет option_id и время voted_at.
reschedule_votes
Старая таблица голосов yes/no из версии одиночного переноса. Новые голосования используют reschedule_option_votes.
Модель статусов
Статусы сессии:
Planned -> ConfirmationSent -> Confirmed
Planned -> Cancelled
ConfirmationSent -> Cancelled
Confirmed -> ConfirmationSent, если активный участник отказался после подтверждения
Статусы участия в составе:
Active
Waitlisted -> Active, когда GM повышает игрока из листа ожидания
Active -> удаление строки, когда игрок самостоятельно снимает запись
Waitlisted -> удаление строки, когда игрок выходит из листа ожидания
RSVP-статусы:
Pending -> Confirmed
Pending -> Declined
Confirmed -> Declined
Declined -> Confirmed
Работа со временем
Пользовательский ввод и вывод работают в московском времени UTC+3. В базе scheduled_at хранится в UTC. MoscowTime.TryParseMoscow преобразует поддерживаемые локальные форматы в UTC перед сохранением.