Synchronize version across all files: - Directory.Build.props → 3.0.1 - compose.yaml → gmrelay-bot/web/discord-bot:3.0.1 - deploy.yml → VERSION: 3.0.1 - NavMenu.razor → v3.0.1 - DiscordProjectStructureTests → 3.0.1 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
🎲 GM-Relay: TTRPG Session Scheduling Bot & Web Dashboard
GM-Relay — это комплексное решение для Мастеров Подземелий (ГМов), состоящее из высокопроизводительного Telegram-бота, Discord worker и удобного веб-интерфейса. Предназначено для автоматизации записи игроков на сессии, управления расписанием и проведения игр.
Проект разработан с упором на производительность, архитектуру Vertical Slice, Native AOT (для бота) и удобство развертывания с использованием .NET Aspire.
Текущая версия: v2.8.0.
✨ Key Features
🤖 Telegram Bot
- 📅 Создание расписаний (Batch Sessions): Создавайте сразу несколько игр одним сообщением изменения (на недельный месяц в перед).
- 🖼 Обложки расписаний: И batch-посту можно прикрепить фото к
/newsessionили указать строкуКартинка: https://...; бот отправит обложку перед сообщением записи. - ⚡ Быстрые повторы расписания: Для регулярной кампании можно указать одну дату, количество игр и интервал, а бот сам развернёт повторяющийся batch.
- ✋ Интерактивная запись и выход: Игроки записываются на конкретные даты и самостоятельно снимают запись нажатием одной кнопки.
- 👥 Лимит мест и лист ожидания: ГМ задаёт максимальный состав, бот не переполняет сессию, автоматически ведёт очередь ожидания и освобождённое место отдаёт первому ожидающему.
- 📁 Поддержка Форумов (Telegram Topics): Если
/newsessionзапущен в теме форума Telegram, расписание и групповые уведомления остаются в этой теме; при запуске из корня форума бот создает отдельную тему и сообщает о необходимости прав admin/Manage Topics, если их не хватает. - ❌ Управление сессиями: Owner и назначенные co-GM могут создавать, отменять, удалять и переносить игры из Telegram через
/listsessions; публичный пост записи показывает только кнопки игроков. - 🔄 Голосование за перенос: Быстрый поиск свободного места с через свободное недель и кнопками новых времени и дедлайном.
- 🔔 Уведомления: Игрок получают за 24 часа, напоминание за 1 час, ссылку перед игрой, отмены и переносы; групповые уведомления при этом остаются.
- 🕐 Режим уведомлений batch: Для каждой пачки можно выбрать
В группе и в личкуилиТолько в группе. - ⬆️ Управление очередью: Веб-интерфейс показывает заполненность, лист ожидания и позволяет ГМу поднять первого игрока из очереди.
- 🔄 Автоматическая синхронизация: Любые изменения в веб-интерфейсе мгновенно обновляют сообщения с расписанием в подключенных Telegram- и Discord-каналах.
Discord Bot
- Slash-команды
/newsessionи/listsessions: GM создаёт сессии и публикует актуальное расписание прямо в Discord-канале. - Кнопки Join/Leave с ephemeral-ответами: игроки нажимают Join/Leave в Discord-сообщении; бот отвечает ephemeral-сообщением и обновляет schedule message.
- RSVP (подтверждения) за 24ч до сессии: scheduler публикует запрос подтверждения в Discord-канале, игроки отвечают кнопками, а GM получает итоги RSVP.
- DM-напоминания за 1ч и ссылки перед игрой: one-hour reminders и join-link notifications отправляются в Discord DM при включённых личных уведомлениях; сбои DM логируются без публичного fallback.
- Reschedule voting (голосование за перенос): deadline-сервис обновляет Discord vote message и schedule message через
IPlatformMessenger. - Лимиты и waitlist: при заполненном составе игрок попадает в waitlist, а при выходе участника первый ожидающий автоматически продвигается в основной состав.
🌐 Web Dashboard (Blazor Server)
- 🔐 Авторизация через Telegram: Telegram Login Widget с HMAC-SHA256 валидацией.
- 📱 Telegram Mini App Dashboard: Мобильная панель открывается из Telegram, проверяет
initDataна сервере, учитывает safe-area телефона и верхнюю панель Telegram. - ✏️ Редактирование: Детальное изменение дат, названий и статусов сессий.
- 🤝 Co-GM и делегирование: Owner назначает помощников по Telegram ID; co-GM управляет расписанием, но не может назначать других co-GM.
- 📋 Шаблоны кампаний: Вкладка
Шаблоныотдельно от страницы группы: сохранение типовых параметров и запуск нового batch из шаблона. - 📦 Bulk-операции для Batch Sessions:
- обновить общий
title/linkу всей пачки; - перенести пачку на фиксированный шаг в днях;
- клонировать batch на следующую неделю или месяц.
- обновить общий
- ⬆️ Управление очередью: Заполненность, лист ожидания и ручное повышение игрока из очереди.
- 📜 История изменений сессий: Страница
/session/{id}/historyпоказывает аудит-лог всех значимых изменений (время, ссылка, название, участники, статус) с указанием акторов и дат. - 📊 Статистика посещаемости: Страница
/group/{id}/statsпоказывает долю присутствия, количество пропусков и среднюю явку по каждому игроку группы. - 🔄 Автосинхронизация: Изменения в вебе мгновенно перерисовывают platform message расписания через
IPlatformMessenger.
🛠 Технологический стек
| Компонент | Технология |
|---|---|
| Язык | C# 14 (.NET 10) |
| Архитектура | Vertical Slice + общая библиотека GmRelay.Shared |
| Боты | Telegram.Bot (Native AOT), NetCord Gateway (Discord worker внутри GmRelay.Bot) |
| Веб | Blazor Server |
| Оркестрация | .NET Aspire (GmRelay.AppHost) |
| БД | PostgreSQL |
| ORM | Dapper + Dapper.AOT (source generators) |
| Миграции | DbUp |
| Развёртывание | Docker Compose, Multi-arch (AMD64/ARM64) |
Note
При использовании Dapper в режиме Native AOT все SQL-запросы используют строго типизированные DTO; динамические типы (
dynamic) не поддерживаются.
🚀 Быстрый старт (Docker Compose)
Требования: Docker и Docker Compose.
1. Настройка окружения
cp .env.example .env
Ключевые переменные .env:
# Токен от @BotFather (используется ботом и как секретный ключ веб-авторизации)
TELEGRAM_BOT_TOKEN=ваш_токен_здесь
# Токен Discord application bot
DISCORD_BOT_TOKEN=ваш_discord_токен_здесь
# Client ID Discord application (используется для slash-команд)
DISCORD_BOT_CLIENT_ID=ваш_discord_client_id_здесь
# Имя бота без @ (для Telegram Login Widget)
TELEGRAM_BOT_USERNAME=ваше_имя_бота_здесь
# HTTPS URL Mini App, например https://your-domain.example/miniapp
TELEGRAM_MINI_APP_URL=https://your-domain.example/miniapp
POSTGRES_PASSWORD=ваш_надежный_пароль
GMRELAY_WEB_PORT=8080
Настройка в @BotFather:
- Команда
/setdomainдля работы виджета авторизации на вашем домене. - Для Mini App настройте домен Web Dashboard и menu button на URL из
TELEGRAM_MINI_APP_URL. - Начиная с v1.9.3 дополнительных действий для фикса входа не требуется: fallback выполняется внутри активного Telegram WebView по тому же HTTPS-адресу
/miniapp.
2. Запуск
docker compose up -d
Автоматически выполняется:
- создание Docker-сети и volume PostgreSQL;
- подъём PostgreSQL (
db:5432); - запуск бота с плавной миграцией (DbUp);
- запуск Discord Gateway worker на NetCord (healthcheck на
:8082); - запуск веб-приложения с подключением к БД и Telegram API.
3. Первоначальная настройка
- Напишите боту
/start. - Создайте группу через
/newgroup. - Откройте Mini App или Web Dashboard для расширенного управления.
- Для Discord пригласите application bot на сервер с правами
botиapplications.commands. СкопируйтеDISCORD_BOT_TOKENиDISCORD_BOT_CLIENT_IDв.env. - Перезапустите Docker Compose (
docker compose up -d), а затем в Discord создайте сессию через/newsessionили опубликуйте расписание через/listsessions; игроки записываются и выходят кнопками в опубликованном сообщении.
💾 Backup и восстановление
Проект включает автоматический ежедневный backup PostgreSQL через сервис db-backup в Docker Compose.
Как это работает
- Каждый день в 03:00 выполняется
pg_dumpбазыgmrelay_db. - Дампы сжимаются (
gzip) и сохраняются в volumepgbackups(/backups). - Формат имени:
gmrelay_db_YYYYMMDD_HHMMSS.sql.gz. - Ротация: по умолчанию хранятся последние 7 дней (настраивается через
BACKUP_RETENTION_DAYS).
Проверка бэкапов
docker compose exec db-backup ls -la /backups
Ручное создание дампа
docker compose exec db-backup sh -c "pg_dump -h db -U gmrelay -d gmrelay_db | gzip > /backups/gmrelay_db_manual.sql.gz"
Восстановление из бэкапа
# Использовать последний автоматический бэкап
./scripts/restore.sh
# Или указать конкретный файл
./scripts/restore.sh backups/gmrelay_db_20260512_030000.sql.gz
Warning
Восстановление перезаписывает текущую базу данных. Убедитесь, что вы понимаете последствия, прежде чем запускать
restore.sh.
Переменные окружения (опциональные)
BACKUP_RETENTION_DAYS=7
BACKUP_VOLUME_NAME=game_pgbackups
🗂 Структура репозитория
├── src/
│ ├── GmRelay.AppHost/ # .NET Aspire orchestrator
│ ├── GmRelay.Bot/ # Telegram- и Discord-бот (Native AOT + NetCord Gateway worker)
│ ├── GmRelay.ServiceDefaults/ # Aspire service defaults
│ ├── GmRelay.Shared/ # Общие доменные модели
│ └── GmRelay.Web/ # Blazor Server dashboard
├── tests/
│ └── GmRelay.Bot.Tests/ # xUnit + NSubstitute
├── compose.yaml # Docker Compose (AMD64 + ARM64)
└── .env.example # Шаблон переменных окружения
👨💻 Для разработчиков
- Архитектура: проект следует Vertical Slice с явным DI. Подробности — в ADR-001 и ADR-002.
- Добавление обработчика: из-за Native AOT все DI-регистрации выполняются вручную в
src/GmRelay.Bot/Program.cs(assembly scanning не используется). - Миграции: SQL-скрипты добавляются как embedded resources в
src/GmRelay.Bot/Migrations/и применяются автоматически при старте бота через DbUp. - Тесты:
dotnet test tests/GmRelay.Bot.Tests/GmRelay.Bot.Tests.csproj --verbosity normal - Сборка:
dotnet build
📜 Лицензия
MIT License. См. LICENSE.
Построено с ❤️ для TTRPG-сообщества.