From 0f03da0a60d31dece386b9dbea44e1f814921066 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Thu, 7 May 2026 12:30:11 +0000 Subject: [PATCH] docs(#15): bump version to 1.10.2 and add session history feature to README --- README.md | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 135 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3d4eb87..955faa4 100644 --- a/README.md +++ b/README.md @@ -1 +1,135 @@ -IyDwn46yIEdNLVJlbGF5OiBUVFJQRyBTZXNzaW9uIFNjaGVkdWxpbmcgQm90ICYgV2ViIERhc2hib2FyZAoKKipHTS1SZWxheSoqIOKAlCDRjdGC0L4g0LrQvtC80L/Qu9C10LrRgdC90L7QtSDRgNC10YjQtdC90LjQtSDQtNC70Y8g0JzQsNGB0YLQtdGA0L7QsiDQn9C+0LTQt9C10LzQtdC70LjQuSAo0JPQnNC+0LIpLCDRgdC+0YHRgtC+0Y/RidC10LUg0LjQtyDQstGL0YHQvtC60L7Qv9GA0L7QuNC30LLQvtC00LjRgtC10LvRjNC90L7Qs9C+IFRlbGVncmFtLdCx0L7RgtCwINC4INGD0LTQvtCx0L3QvtCz0L4g0LLQtdCxLdC40L3RgtC10YDRhNC10LnRgdCwLiDQn9GA0LXQtNC90LDQt9C90LDRh9C10L3QviDQtNC70Y8g0LDQstGC0L7QvNCw0YLQuNC30LDRhtC40Lgg0LfQsNC/0LjRgdC4INC40LPRgNC+0LrQvtCyINC90LAg0YHQtdGB0YHQuNC4LCDRg9C/0YDQsNCy0LvRtdC90LjRjyDRgNCw0YHQv9C40YHQsNC90LjQtdC8INC4INC/0YDQvtCy0LXQtNC10L3QuNGPINC40LPRgC4KCtCf0YDQvtC10LrRgiDRgNCw0LfRgNCw0LHQvtGC0LDQvSDRgSDRg9C/0L7RgNC+0Lwg0L3QsCDQv9GA0L7QuNC30LLQvtC00LjRgtC10LvRjNC90L7RgdGC0YwsINCw0YDRhdC40YLQtdC60YLRg9GA0YMgVmVydGljYWwgU2xpY2UsIE5hdGl2ZSBBT1QgKNC00LvRjyDQsdC+0YLQsCkg0Lgg0YPQtNC+0LHRgdGC0LLQviDRgNCw0LfQstC10YDRgtGL0LLQsNC90LjRjyDRgSDQuNGB0L/QvtC70YzQt9C+0LLQsNC90LjQtdC8IC5ORVQgQXNwaXJlLgoKKirQotC10LrRg9GJ0LDRjyDQstC10YDRgdC40Y86KiogYHYxLjEwLjFgLgoKLS0tCgojIyDwn5qAIEtleSBGZWF0dXJlcwoKIyMjIPCfkokoIFRlbGVncmFtIEJvdAotICoq8J+ThSDQodC+0LfQtNCw0L3QuNC1INGA0LDRgdC/0LjRgdCw0L3QuNC5IChCYXRjaCBTZXNzaW9ucykqKjog0KHQvtC30LTQsNCy0LDQudGC0LUg0YHQgNCw0LfRgyDQvdC10YHQutC+0LvRjNC60L4g0LjQs9GAINC+0LTQvdC40LzQtdC90LjRjyDQuNC30LzQtdC90LXQvdC40Y8gKNC90LAg0L3QtdC00LXQu9GM0L3Ri9C8INC80LXQsdGP0YYg0LIg0L/QtdGA0LXQtCkuCi0gKirwn5a8INCe0LHQu9C+0LbQutC4INGA0LDRgdC/0LjRgdCw0L3QuNC5Kio6INCYIGJhdGNoLdC/0L7RgdGC0YMg0LzQvtC20L3QviDQv9GA0LjQutGA0LXQv9C40YLRjCDRhNC+0YLQviDQuiBgL25ld3Nlc3Npb25gINC40LvQuCDRg9C60LDQt9Cw0YLRjCDRgdGC0YDQvtC60YMgYNCa0LDRgNGC0LjQvdC60LA6IGh0dHBzOi8vLi4uYDsg0LHQvtGCINC+0YLQv9GA0LDQstC40YIg0L7QsdC70L7QttC60YMg0L/QtdGA0LXQtCDRgdC+0L7QsdGJ0LXQvdC40LXQvCDQt9Cw0L/QuNGB0LguCi0gKirimqEg0JHRi9GB0YLRgNGL0LUg0L/QvtCy0YLQvtGA0Ysg0YDQsNGB0L/QuNGB0LDQvdC40Y8qKjog0JTQu9GPINGA0LXQs9GD0LvRj9GA0L3QvtC5INC60LDQvNC/0LDQvdC40Lgg0LzQvtC20L3QviDRg9C60LDQt9Cw0YLRjCDQvtC00L3RgyDQtNCw0YLRgywg0LrQvtC70LjRh9C10YHRgtCy0L4g0LjQs9GAINC4INC40L3RgtC10YDQstCw0LssINCwINCx0L7RgiDRgdCw0Lwg0YDQsNC30LLQtdGA0L3RkdGCINC/0L7QstGC0L7RgNGP0Y7RidC40LnRgdGPIGJhdGNoLgotICoq4pyLINCY0L3RgtC10YDQsNC60YLQuNCy0L3QsNGPINC30LDQv9C40YHRjCDQuCDQstGL0YXQvtC0Kio6INCY0LPRgNC+0LrQuCDQt9Cw0L/QuNGB0YvQstCw0Y7RgtGB0Y8g0L3QsCDQutC+0L3QutGA0LXRgtC90YvQtSDQtNCw0YLRiyDQuCDRgdCw0LzQvtGB0YLQvtGP0YLQtdC70YzQvdC+INGB0L3QuNC80LDRjtGCINC30LDQv9C40YHRjCDQvdCw0LbQsNGC0LjQtdC8INC+0LTQvdC+0Lkg0LrQvdC+0L/QutC4LgotICoq8J+RpSDQm9C40LzQuNGCINC80LXRgdGCINC4INC70LjRgdGCINC+0LbQuNC00LDQvdC40Y8qKjog0JPQnCDQt9Cw0LTQsNGR0YIg0LzQsNC60YHQuNC80LDQu9GM0L3Ri9C5INGB0L7RgdGC0LDQsiwg0LHQvtGCINC90LUg0L/QtdGA0LXQv9C+0LvQvdGP0LXRgiDRgdC10YHRgdC40Y4sINCw0LLRgtC+0LzQsNGC0LjRh9C10YHQutC4INCy0LXQtNGR0YIg0L7Rh9C10YDQtdC00Ywg0L7QttC40LTQsNC90LjRjyDQuCDQvtGB0LLQvtCx0L7QttC00ZHQvdC90L7QtSDQvNC10YHRgtC+INC+0YLQtNCw0ZHRgiDQv9C10YDQstC+0LzRgyDQvtC20LjQtNCw0Y7RidC10LzRgy4KLSAqKvCfk4Eg0J/QvtC00LTQtdGA0LbQutCwINCk0L7RgNGD0LzQvtCyIChUZWxlZ3JhbSBUb3BpY3MpKio6INCR0L7RgiDQsNCy0YLQvtC80LDRgtC40YfQtdGB0LrQuCDRgdC+0LfQtNCw0LXRgiDRgtC10LzRgyDQstC+INCy0LvQvtC20LXQvdC90YvRhSDRh9Cw0YLQsNGFIFRlbGVncmFtINC/0L7QtCDQutCw0LbQtNGD0Y4g0L3QvtCy0YPRjiDQv9Cw0YfQutGDINC40LPRgC4KLSAqKuKdjCDQo9C/0YDQsNCy0LvQtdC90LjQtSDRgdC10YHRgdC40Y/QvNC4Kio6IE93bmVyINC4INC90LDQt9C90LDRh9C10L3QvdGL0LUgY28tR00g0LzQvtCz0YPRgiDRgdC+0LfQtNCw0LLQsNGC0YwsINC+0YLQvNC10L3Rj9GC0YwsINGD0LTQsNC70Y/RgtGMINC4INC/0LXRgNC10L3QvtGB0LjRgtGMINC40LPRgNGLINC40LcgVGVsZWdyYW0g0YfQtdGA0LXQtyBgL2xpc3RzZXNzaW9uc2A7INC/0YPQsdC70LjRh9C90YvQuSDQv9C+0YHRgiDQt9Cw0L/QuNGB0Lgg0L/QvtC60LDQt9GL0LLQsNC10YIg0YLQvtC70YzQutC+INC60L3QvtC/0LrQuCDQuNCz0YDQvtC60L7Qsi4KLSAqKvCflIQg0JPQvtC70L7RgdC+0LLQsNC90LjQtSDQt9CwINC/0LXRgNC10L3QvtGBKio6INCR0YvRgdGC0YDRi9C5INC/0L7QtNC20LXQvdC90L7Qs9C+INC80LXRgdGC0L4g0YEg0YfQtdGA0LXQtyDRgdCy0L7QsdC+0LTQvdC+0LUg0L3QtdC00LXQu9GMINC4INC60L3QvtC/0LrQsNC80Lgg0L3QvtCy0YvRhSDQstGA0LXQvNC10L3QuCDQuCDQtNC10LTQu9Cw0LnQvdC+0Lw6CiAgYGBgdGV4dAogIDI1LjA0LjIwMjYgMTk6MzAKICAyNi4wNC4yMDI2IDE4OjAwCiAg0JTQtdC00LvQsNC50L06IDI1LjA0LjIwMjYgMTI6MDAKICBgYGAKICANCi0gKirwn5SUINCQ0LLQtdC00L7QvNC70LXQvdC40Y8qKjog0JjQs9GA0L7QuiDQv9C+0LvRg9GH0LDRjtGCINCTLCDQt9CwIDI0INGH0LDRgdCwLCDQvdCw0L/QvtC80LjQvdCw0L3QuNC1INC30LAgMSDRh9Cw0YEsINGB0YHRi9C70LrRgyDQv9C10YDQtdC0INC40LPRgNC+0LksINC+0YLQvNC10L3RiyDQuCDQv9C10YDQtdC90L7RgdGLOyDQs9GA0YPQv9C/0L7QstGL0LUg0YPQstC10LTQvtC80LvQtdC90LjRjyDQv9GA0Lgg0Y3RgtC+0Lwg0L7RgdGC0LDRjtGC0YHRjy4KLSAqKifwn5WjINCg0LXQttC40Lwg0YPQstC10LTQvtC80LvQtdC90LjQuSBiYXRjaCoqOiDQlNC70Y8g0LrQsNC20LTQvtC5INC/0LDRh9C60Lgg0LzQvtC20L3QviDQstGL0LHRgNCw0YLRjCBg0JIg0LPRgNGD0L/Qv9C1INC4INCyINC70LjRh9C60YNgINC40LvQuCBg0KLQvtC70YzQutC+INCyINCz0YDRg9C/0L/QtWAuCi0gKirirIbvuo/igJAg0KPQv9GA0LDQstC70LXQvdC40LUg0L7Rh9C10YDQtdC00YzRjioqOiDQktC10LEt0LjQvdGC0LXRgNGE0LXQudGBINC/0L7QutCw0LfRi9Cy0LDQtdGCINC30LDQv9C+0LvQvdC10L3QvdC+0YHRgtGMLCDQu9C40YHRgiDQvtC20LjQtNCw0L3QuNGPINC4INC/0L7Qt9Cy0L7Qu9GP0LXRgiDQk9Cc0YMg0L/QvtC00L3Rj9GC0Ywg0L/QtdGA0LLQvtCz0L4g0LjQs9GA0L7QurQsINC40Lcg0L7Rh9C10YDQtdC00LguCi0gKirwn5SEINCQ0LLRgtC+0LzQsNGC0LjRh9C10YHQutCw0Y8g0YHQuNC90YXRgNC+0L3QuNC30LDRhtC40Y8qKjog0JvRjtCx0YvQtSDQuNC30LzQtdC90LXQvdC40Y8g0LIg0LLQtdCxLdC40L3RgtC10YDRhNC10LnRgdC1INC80LPQvdC+0LLQtdC90L3QviDQvtCx0L3QvtCy0LvRj9GO0YIg0YHQvtC+0LHRidC10L3QuNGPINGBINGA0LDRgdC/0LjRgdCw0L3QuNC10Lwg0LIgVGVsZWdyYW0t0YfQsNGC0LDRhSDQuNCz0YDQvtC60L7Qsi4KCiMjIyDwn5qAIHdlYiBERFNoYm9hcmQgKEJsYXpvciBTZXJ2ZXIpCi0gKirwn5CUINCR0YPQstGC0L7RgNC40LfQsNGG0LjRjyDRh9C10YDQtdCcgVGVsZWdyYW0qKjog0JHR0LXQt9C+0L/QsNGB0L3Ri9C5INCy0YXQvtC00LTRgSDRgSDQuNGB0L/QvtC70YzQt9C+0LLQsNC90LjQtdC8IFRlbGVncmFtIExvZ2luIFdpZGdldCAoSE1BQy1TSEEyNTYg0LLQsNC70LjQtNCw0YbQuNC4KS4KLSAqKvCfk7EgVGVsZWdyYW0gTWluaSBBcHAgRGFzaGJvYXJkKio6INCR0L7QsdC40LvRjNC90LDRjyDQstC10YDRgdC40Y8gZGFzaGJvYXJkINC+0YLQutGA0YvQstCw0LXRgtGB0Y8g0L/RgNGP0LzQviDQuNC3IFRlbGVncmFtLCDQv9GA0L7QstC10YDQvtC00LjRgtC10YLRgdGPINCy0YHQtdC4INGC0L7QutC10L3QvtC8INCx0L7RgtCwLiDQndCw0LbQsNC90LjRgtC1IFRlbGVncmFtIExvZ2luIFdpZGdldCDQsNCy0YLQvtGA0LjQt9GD0LXRgtGB0Y8g0L/QvtC70YzQt9C+0LLQsNGC0LXQu9GMINCyINGC0LXQutGD0YnQtdCz0L4gV2ViVmlldywg0LAgZGFzaGJvYXJkINC+0YLQutGA0L7QtdGC0YHRjyDQsdC10Lcg0YDRg9GH0L3QvtCz0L4g0LfQsNC60YDRi9GC0LjRjyDQuCDQv9C+0LLRgtC+0YDQvdC+0LPQviDQvdCw0L/QvtC80LjQvdCw0L3QuNC10LwuCi0gKirwn5OdINCo0LDQsdC70L7QvdGLINC60LDQvNC/0LDQvdC40LkqKjogT3duZXIg0LggY28tR00g0YPQv9GA0LDQstC70Y/RjtGCINGC0LjQv9C+0LLRi9C80Lgg0L/QsNGA0LDQvNC10YLRgNCw0LzQuCDQutCw0LzQv9Cw0L3QuNC5INCyINC+0YLQtNC10LvRjNC90L7QuSDQstC60LvQsNC00LrQtSDQoNGw0LHQtdC70L7QvdGLYCwg0LAg0L3QsCDRgdGC0YDQsNC90LjRhtC1INCz0YDRg9C/0L/RiyDQt9Cw0L/Rg9GB0LrQsNGO0YIg0L3QvtCy0YvQuSDQv9C+0LLRgtC+0YDRj9GO0YnQuNC50YHRjyBiYXRjaCDQuNC3INCy0YvQsdGA0LDQvdC90L7Qs9C+INGI0LDQsdC70L7QvdCwLgotICoq8J+TnSDQmNC90YLQtdGA0LLQsNC70L7QvCBidWxrLdC+0L/QtdGA0LDRhtC40LggYmF0Y2ggc2Vzc2lvbnMqKjog0JPQnCDQvNC+0LbQtdGCINC+0LHQvdC+0LLQuNGC0Ywg0L7QsdGJ0LjQuSB0aXRsZS9saW5rLCDQv9C10YDQtdC90LXQsdGC0Lgg0LLRgdGOINC/0LDRh9C60YMg0L3QsCDRhNC40LrRgdC40YDQvtCy0LDQvdC90YvQuSDRiNCw0LMg0Lgg0LrQu9C+0L3QuNGA0L7QstCw0YLRjCBiYXRjaCDQvdCwINGB0LvQtdC00YPRjtGJ0YPRjiDQvdC10LTQtdC70Y4g0LjQu9C4INC80LXRgdGP0YYuCi0gKirwn5WjINCY0L3RgtC10YDQstCw0Lcg0YPQstC10LTQvtC80LvQtdC90LjQuSBiYXRjaCoqOiDQlNC70Y8g0LrQsNC20LTQvtC5INC/0LDRh9C60Lgg0LzQvtC20L3QviDQstGL0LHRgNCw0YLRjCBg0JIg0LPRgNGD0L/Qv9C1INC4INCyINC70LjRh9C60YNgINC40LvQuCBg0KLQvtC70YzQutC+INCyINCz0YDRg9C/0L/QtSDQt9Cw0L/Rg9GB0LrQsNGC0Ywg0YjQsNCx0LvQvtC90YsgV2ViIERhc2hib2FyZC4KLSAqKvCflIwgc3RhdGlzdGljcyBvZiBhdHRlbmRhbmNlIGluIGdyb3Vwcw== \ No newline at end of file +# 🎲 GM-Relay: TTRPG Session Scheduling Bot & Web Dashboard + +**GM-Relay** — это комплексное решение для Мастеров Подземелий (ГМов), состоящее из высокопроизводительного Telegram-бота и удобного веб-интерфейса. Предназначено для автоматизации записи игроков на сессии, управления расписанием и проведения игр. + +Проект разработан с упором на производительность, архитектуру Vertical Slice, Native AOT (для бота) и удобство развертывания с использованием .NET Aspire. + +**Текущая версия:** `v1.10.2`. + +--- + +## ✨ Key Features + +### 🤖 Telegram Bot +- **📅 Создание расписаний (Batch Sessions)**: Создавайте сразу несколько игр одним сообщением изменения (на недельный месяц в перед). +- **🖼 Обложки расписаний**: И batch-посту можно прикрепить фото к `/newsession` или указать строку `Картинка: https://...`; бот отправит обложку перед сообщением записи. +- **⚡ Быстрые повторы расписания**: Для регулярной кампании можно указать одну дату, количество игр и интервал, а бот сам развернёт повторяющийся batch. +- **✋ Интерактивная запись и выход**: Игроки записываются на конкретные даты и самостоятельно снимают запись нажатием одной кнопки. +- **👥 Лимит мест и лист ожидания**: ГМ задаёт максимальный состав, бот не переполняет сессию, автоматически ведёт очередь ожидания и освобождённое место отдаёт первому ожидающему. +- **📁 Поддержка Форумов (Telegram Topics)**: Бот автоматически создает тему во вложенных чатах Telegram под каждую новую пачку игр. +- **❌ Управление сессиями**: Owner и назначенные co-GM могут создавать, отменять, удалять и переносить игры из Telegram через `/listsessions`; публичный пост записи показывает только кнопки игроков. +- **🔄 Голосование за перенос**: Быстрый поиск свободного места с через свободное недель и кнопками новых времени и дедлайном. +- **🔔 Уведомления**: Игрок получают за 24 часа, напоминание за 1 час, ссылку перед игрой, отмены и переносы; групповые уведомления при этом остаются. +- **🕐 Режим уведомлений batch**: Для каждой пачки можно выбрать `В группе и в личку` или `Только в группе`. +- **⬆️ Управление очередью**: Веб-интерфейс показывает заполненность, лист ожидания и позволяет ГМу поднять первого игрока из очереди. +- **🔄 Автоматическая синхронизация**: Любые изменения в веб-интерфейсе мгновенно обновляют сообщения с расписанием в Telegram-чатах игроков. + +### 🌐 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` показывает долю присутствия, количество пропусков и среднюю явку по каждому игроку группы. +- **🔄 Автосинхронизация**: Изменения в вебе мгновенно перерисовывают Telegram-сообщения расписания. + +--- + +## 🛠 Технологический стек + +| Компонент | Технология | +|---|---| +| Язык | C# 14 (.NET 10) | +| Архитектура | Vertical Slice + общая библиотека `GmRelay.Shared` | +| Бот | Telegram.Bot, **Native AOT** | +| Веб | 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. Настройка окружения +```bash +cp .env.example .env +``` + +**Ключевые переменные `.env`:** +```env +# Токен от @BotFather (используется ботом и как секретный ключ веб-авторизации) +TELEGRAM_BOT_TOKEN=ваш_токен_здесь + +# Имя бота без @ (для 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. Запуск +```bash +docker compose up -d +``` + +**Автоматически выполняется:** +- создание Docker-сети и volume PostgreSQL; +- подъём PostgreSQL (`db:5432`); +- запуск бота с плавной миграцией (DbUp); +- запуск веб-приложения с подключением к БД и Telegram API. + +### 3. Первоначальная настройка +1. Напишите боту `/start`. +2. Создайте группу через `/newgroup`. +3. Откройте Mini App или Web Dashboard для расширенного управления. + +--- + +## 🗂 Структура репозитория + +``` +├── src/ +│ ├── GmRelay.AppHost/ # .NET Aspire orchestrator +│ ├── GmRelay.Bot/ # Telegram-бот (Native AOT) +│ ├── GmRelay.Migrator/ # DbUp-миграции +│ ├── GmRelay.ServiceDefaults/ # Aspire service defaults +│ ├── GmRelay.Shared/ # Общие доменные модели +│ ├── GmRelay.Web/ # Blazor Server dashboard +│ └── GmRelay.Worker/ # Background workers +├── tests/ +│ └── GmRelay.Bot.Tests/ # xUnit + NSubstitute +├── compose.yaml # Docker Compose (AMD64 + ARM64) +└── .env.example # Шаблон переменных окружения +``` + +--- + +## 📜 Лицензия + +MIT License. См. [LICENSE](./LICENSE). + +--- + +*Построено с ❤️ для TTRPG-сообщества.*