Toutsu 7a2965b43f
Deploy Telegram Bot / build-and-push (push) Successful in 6m39s
Deploy Telegram Bot / scan-images (push) Successful in 3m26s
Deploy Telegram Bot / deploy (push) Successful in 29s
fix(bot): add missing DI registrations for shared DeleteSessionHandler and ListSessionsHandler
PR #106 extracted DeleteSessionHandler and ListSessionsHandler to GmRelay.Shared,
but forgot to register the shared implementations in Program.cs. This caused
an InvalidOperationException at startup on Native AOT builds because the Bot
wrappers could not resolve their shared dependencies.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 15:58:51 +03:00
2026-04-13 13:52:49 +03:00
2026-05-12 16:25:17 +03:00

🎲 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_токен_здесь

# Discord OAuth (для Web Dashboard)
DISCORD_CLIENT_ID=ваш_discord_client_id_здесь
DISCORD_CLIENT_SECRET=ваш_discord_client_secret_здесь
DISCORD_REDIRECT_URI=https://your-domain.example/auth/discord/callback

# Имя бота без @ (для 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. Первоначальная настройка

  1. Напишите боту /start.
  2. Создайте группу через /newgroup.
  3. Откройте Mini App или Web Dashboard для расширенного управления.
  4. Для Discord пригласите application bot на сервер с правами bot и applications.commands. Скопируйте DISCORD_BOT_TOKEN в .env; DISCORD_CLIENT_ID, DISCORD_CLIENT_SECRET и DISCORD_REDIRECT_URI нужны только для входа в Web Dashboard через Discord.
  5. Перезапустите Docker Compose (docker compose up -d), а затем в Discord создайте сессию через /newsession или опубликуйте расписание через /listsessions; игроки записываются и выходят кнопками в опубликованном сообщении.

💾 Backup и восстановление

Проект включает автоматический ежедневный backup PostgreSQL через сервис db-backup в Docker Compose.

Как это работает

  • Каждый день в 03:00 выполняется pg_dump базы gmrelay_db.
  • Дампы сжимаются (gzip) и сохраняются в volume pgbackups (/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-сообщества.

S
Description
No description provided
Readme MIT 10 MiB
Languages
C# 80.8%
HTML 13.9%
CSS 3.6%
PLpgSQL 1%
Dockerfile 0.2%
Other 0.5%