-
released this
2026-06-04 15:50:32 +03:00 | 36 commits to main since this release🧩 Wizard для создания игры
/newsessionв Telegram-боте больше не принимает текстовый шаблон — теперь это интерактивный пошаговый сценарий с inline-кнопками. Поддерживает и одиночные игры, и пулы (несколько связанных слотов под однимbatch_id).Что нового для пользователей
/newsessionоткрывает wizard: тип → одиночная или пул- Внутри: inline-кнопки везде, где есть выбор (тип, формат, видимость, waitlist, подтверждение)
- Свободный текст там, где кнопок мало: название, описание, дата/время, комментарии
- Back / Reset / Cancel на любом шаге
- Черновик сохраняется в
wizard_drafts(TTL 24 ч) — бот можно перезапустить, и/newsessionподхватит черновик через «Continue» - Одиночная игра и пул — один и тот же wizard: пул = type=pool + цикл добавления слотов (общие system/duration задаются на уровне пула)
- Предпросмотр перед финальным созданием
- Ошибки валидации возвращают на конкретный шаг, а не сбрасывают весь процесс
Архитектура
wizard_drafts(V031): JSONB payload + 24 ч TTL, чиститсяWizardDraftCleanupServiceраз в минутуGameCreationWizard— чистый state machine без I/O: читает/пишетWizardPayloadиз JSONB, делегирует Telegram-вызовы вITelegramWizardMessenger(AOT-safe, подменяется в тестах)WizardSteprenderer — pure-функцииpayload → (text, InlineKeyboardMarkup)для всех 17 шагов (12 single + 5 pool)IWizardDraftRepository— извлечён из sealedWizardDraftRepository, чтобы wizard тестировался hand-rolled fakes- Пул = один вызов shared
CreateSessionHandlerс NScheduledTimes. Shared handler сам создаёт N сессий с однимbatch_id - Router-level takeover: пока есть активный черновик, любое обновление в
(chat, thread, owner)уходит в wizard, минуя обычные handlers
Тесты
- 66 wizard-юнит-тестов — state-machine переходы, pool-slot lifecycle, валидация, рендер, cancel/back
- 8 handler/router тестов — submit-валидация, missing fields, cleanup-tick, router delegation, stale-command reset
- 2 Testcontainers-плейсхолдера (skipped локально, выполняются в CI на реальной Postgres)
- Полный прогон: 564 passed, 2 skipped, 0 failed
dotnet format --verify-no-changescleandotnet list package --vulnerable --include-transitivecleandotnet build— 0 warnings
Известное ограничение
Wizard сохраняет
VisibilityиClubIdв payload, но sharedCreateSessionCommandвGmRelay.Sharedпока их не принимает. Сессии, созданные через wizard, по умолчанию ведут себя как не-витринные. Это отдельная задача — когда shared handler научится showcase-видимости, в wizard ничего менять не придётся.Что вышло из скоупа
- Визуальные mock-апы из brainstorm-сессии (не требуются для корректности wizard'а)
- Шаг с загрузкой фото в
/newsession— оставлено, чтобы не ломать AOT-публикацию и не добавлять хрупкую Telegram download зависимость
Closes #111.
Downloads
-
released this
2026-06-03 22:43:09 +03:00 | 55 commits to main since this release🔧 Patch v3.7.1 — Hotfix: каталог игр возвращал 500
В v3.7.0 на странице
/showcaseпадал 500: Dapper.AOT не мог материализоватьShowcaseSessionRow— в SELECT не хватало колонокPublicationMode/IsMembersOnly, добавленных в DTO.🧩 Что вошло в релиз
src/GmRelay.Web/Services/SessionService.cs— в SELECT-ыGetShowcaseSessionsAsyncиGetShowcaseSessionAsyncдобавленыs.publication_mode AS PublicationModeи(s.publication_mode = 'ClubOnly') AS IsMembersOnly. КонструкторыShowcaseSessionDtoтеперь пробрасывают значения из row.- Версия синхронизирована:
Directory.Build.props,NavMenu.razor,compose.yaml(3 image refs),deploy.yml,CampaignTemplatesNavigationTests→ 3.7.1.
🗡 Что это даёт
/showcaseснова рендерится: витрина игр со всеми фильтрами (когда/места/система/тип/формат).- Заодно в DTO через SQL корректно приходят
PublicationModeиIsMembersOnly— раньше они захардкожились в"Catalog"/false, что скрывало настоящее значение режима публикации. - Никаких изменений в миграциях или API: это чистый bugfix.
📦 Версия и деплой
Downloads
-
released this
2026-06-03 11:58:07 +03:00 | 57 commits to main since this release🛠 Release v3.7.0 — Приватные клубные витрины
Issue #110: GM теперь может публиковать сессии только в клубной витрине, не показывая их в общем каталоге. Доступ к таким играм — только для одобренных участников клуба.
🧩 Что вошло в релиз
Data model (миграция V030)
- Новая таблица
club_membershipsсо статусами Pending/Active/Rejected/Left, частичный уникальный индексux_club_memberships_one_active. sessions.publication_mode(None/Catalog/ClubOnly/Both) вместоis_public, CHECK-ограничение и пересозданные partial-индексы.portfolio_games.publication_mode(defaultBoth) для совместимости с Portfolio-фичей.
Domain
GmRelay.Shared.Domain.PublicationModeс методамиToDatabaseValue,FromDatabaseValue,IsVisibleInCatalog,IsVisibleToClubMembers.
Сервисы
ISessionStoreрасширен 12 методами для membership/showcase.AuthorizedMembershipService(новый) — подача заявки, одобрение/отклонение GM-ом с проверкой прав.SessionService— SQL с учётом членства (EXISTSнаclub_membershipsсо статусом Active).AuthorizedSessionService—SetSessionPublic*переименованы вSetSessionPublicationMode*.
UI
MyClubMemberships.razor(/profile/memberships) — Active/Pending/History + кнопки покинуть/отозвать.ClubApplications.razor(/group/{GroupId}/applications) — owner/co-GM, approve/reject.PublicClub.razor— публичная и members-only секции, CTA «Подать заявку» и «Войти как участник».PublicMasterProfile.razor— member-aware видимость клубных сессий.EditSession.razorиGroupDetails.razor— булев toggle заменён на 4-state<select>.GroupDetails.razor— карточка «Заявки участников (N)» со ссылкой на/applications.NavMenu.razor— ссылка «Мои клубы» →/profile/memberships, версия v3.7.0.PublicLayout.razor— ссылка «Клубы» →/showcase.
Тесты (493 всего, все проходят)
- Новые файлы:
PublicationModeTests,ClubMembershipsTests,ClubShowcaseSourceTests,AuthorizedMembershipServiceTests. - Обновлены:
PublicClubPagesTests,AuthorizedSessionServiceTests,AuthorizedPortfolioServiceTests,CampaignTemplatesNavigationTests.
Версионирование
Directory.Build.props,compose.yaml,.gitea/workflows/deploy.yml,NavMenu.razor— синхронизированы на 3.7.0.
🗡 Что это даёт
- Клубы получают приватную витрину: игры видны только одобренным участникам, а не всему каталогу.
- GM сами управляют составом клуба: заявка (Pending) → одобрение (Active) или отказ (Rejected).
- Никаких сюрпризов в общем
/showcase— ClubOnly-игры туда не попадают. - Управление режимом публикации — в Web-дашборде (тот же UX, что и раньше, но с 4 опциями вместо 2).
📦 Версия и деплой
Downloads
- Новая таблица
-
released this
2026-06-02 18:38:48 +03:00 | 60 commits to main since this release🛠 Feature 3.6.0 — Портфолио прошедших игр
Добавлено публичное портфолио завершённых приключений на витрине мастера: мастера могут оформлять проведённые игры с обложкой, описанием, составом ГМов и модерируемыми отзывами игроков. Публичная страница
/portfolio/{slug}дополняет каталог будущих игр из/showcase(3.4.0) и публичные профили мастеров (3.5.0).🧩 Что вошло в релиз
src/GmRelay.Bot/Migrations/V029__add_completed_game_portfolios_and_reviews.sql— таблицыportfolio_games,portfolio_game_sessions,portfolio_game_masters,portfolio_game_reviews+ statement-level триггеры + deferred constraint triggervalidate_public_portfolio_game_required_links, атомарно проверяющий обязательные связи опубликованной игрыsrc/GmRelay.Web/Services/Portfolio/PortfolioContracts.cs— sanitized public DTOs (PublicPortfolioCard,PublicPortfolioGame,PublicPortfolioMaster,PublicPortfolioReview) без приватных UUID / storage keys / platform info; protected DTOs для редактора и модерацииsrc/GmRelay.Web/Services/Portfolio/IPortfolioStore.cs— 16 методов: 3 публичных чтения, 11 protected CRUD, 2 метода модерации отзывовsrc/GmRelay.Web/Services/Portfolio/PortfolioValidation.cs— slug regex + trim/collapse, title/description/format/review body нормализацияsrc/GmRelay.Web/Services/Portfolio/Covers/LocalPortfolioCoverStorage.cs— JPEG/PNG/WebP signature validation (не только content-type), 5 MB cap,SafeKeyPatternот path traversal, temp-file cleanup на ошибкеsrc/GmRelay.Web/Services/Portfolio/PortfolioService.cs— публичные чтения мастер/клуб/detail, protected CRUD с advisory lockpg_advisory_xact_lock(20260530, 108), friendly error mapping наUniqueViolation(slug), publish-валидация (slug + description + cover + ≥1 past session + ≥1 master) передis_public = truesrc/GmRelay.Web/Services/Portfolio/AuthorizedPortfolioService.cs— все 9 management-методов подIsGroupManagerAsync; cross-club →SessionAccessDeniedException; review submission требуетpublicationConsent = true; cover replace: new → DB → old с cleanup новой обложки на ошибке; delete: row first, cover secondsrc/GmRelay.Web/Components/Pages/PortfolioEditor.razor—/portfolio/manage/{PortfolioGameId:guid}(Authorize) с cover upload, draft/publish, delete, модерация отзывовsrc/GmRelay.Web/Components/Pages/GroupCompletedSessions.razor—/group/{GroupId:guid}/completedсо списком прошедших сессий иДобавить в портфолиоquick actionsrc/GmRelay.Web/Components/Portfolio/PortfolioCardGrid.razor— переиспользуемая сетка карточек для публичных страницsrc/GmRelay.Web/Components/Pages/PublicPortfolio.razor—/portfolio/{slug}(PublicLayout, без[Authorize]) с обложкой, описанием, составом ГМов, одобренными отзывами, формой отзыва с consent-чекбоксомsrc/GmRelay.Web/Components/Pages/PublicMasterProfile.razor,PublicClub.razor— portfolio card grid под существующим upcoming-session контентомsrc/GmRelay.Web/Components/Pages/GroupDetails.razor,SessionHistory.razor— секцияПроведённые приключенияс badges и quick actionsrc/GmRelay.Web/Services/Portfolio/PortfolioCoverStorageExtensions.cs+Program.cs— регистрацияIPortfolioCoverStorageиAuthorizedPortfolioServiceв DIcompose.yaml— Docker volumeportfolio_coversдля Bot и Web сервисов.env.example— добавленPORTFOLIO_COVERS_VOLUME_NAME=gmrelay_portfolio_coversREADME.md— новая секция "📚 Портфолио завершённых приключений" + portfolio bullets в Web Dashboarddocs/c4-system-context.md— обновлены System Context и Container диаграммы, новая Level 3 Component диаграмма для портфолио с границейIPortfolioCoverStorage(future S3 replacement)- Тесты:
PortfolioContractsTests,PortfolioValidationTests,LocalPortfolioCoverStorageTests,PortfolioCoverRuntimeWiringTests,PortfolioServiceSourceTests(включая regression assertion на неизменённыйinterval '4 hours'для showcase),AuthorizedPortfolioServiceTests,PortfolioPagesTests(Tasks 6+7) - Синхронизированы версии:
Directory.Build.props,NavMenu.razor,compose.yaml(3 образа),deploy.yml,README.md→ 3.6.0
🗡 Что это даёт
- Мастера могут публиковать проведённые приключения с обложкой, описанием, системой, форматом, составом ГМов
- Публичная страница
/portfolio/{slug}показывает карточку с обложкой, описанием, составом и одобренными отзывами — без раскрытия приватных идентификаторов - Публичные профили мастеров
/gm/{slug}и публичные страницы клубов/club/{slug}получают секциюЗавершённые приключенияс карточками - Игроки, участвовавшие в сессии (non-GM, Active), могут оставить модерируемый отзыв — без consent-чекбокса отзыв не сохраняется
- Мастер/co-GM модерируют отзывы (Approve/Reject/Hide) перед публикацией
- Cross-club изоляция: ни одна управляющая операция не доступна менеджеру чужого клуба
- Обложки хранятся в persistent volume
portfolio_covers(envPORTFOLIO_COVERS_VOLUME_NAME); будущая замена на S3 — черезIPortfolioCoverStorageбез изменений вPortfolioService
📦 Версия и деплой
Downloads
-
released this
2026-05-29 09:53:41 +03:00 | 94 commits to main since this release🔧 Patch 3.5.1 — Исправление публичных страниц игр
Исправлен HTTP 500 на
/showcase, публичных страницах клубов/club/{slug}и публичных страницах сессий/s/{id}после релиза 3.5.0.🧩 Что вошло в релиз
src/GmRelay.Web/Services/SessionService.cs— публичные запросы профилей мастеров теперь сортируют owner manager по существующей колонкеgroup_managers.created_atвместо несуществующейgm.added_attests/GmRelay.Bot.Tests/Web/MasterProfilesTests.cs— добавлен regression test на соответствие публичных запросов реальной схемеgroup_managers- Синхронизированы версии:
Directory.Build.props,NavMenu.razor,compose.yaml,deploy.yml,README.md→ 3.5.1
🗡 Что это даёт
- Каталог игр
/showcaseснова открывается - Публичные страницы клубов и сессий снова рендерятся без 500
- Новая проверка не даст снова сослаться на несуществующую колонку
added_at
📦 Версия и деплой
- версия обновлена до 3.5.1
- Docker-образы используют тег
3.5.1 - PR #114 интегрирован в
mainчерез merge commit394bd19b95bc4148cd349da0116089a1e6c1656e - Gitea Actions run #280 (PR checks) — success
- Gitea Actions run #281 (deploy) — success
- Продовая проверка после деплоя:
/showcase,/club/kulaki,/s/c7336ee7-84f3-4b34-9d07-9bf82460bb97— HTTP 200
Downloads
-
released this
2026-05-29 00:35:40 +03:00 | 96 commits to main since this release🛠 Feature 3.5.0 — Публичные профили мастеров
Добавлены публичные профили мастеров
/gm/{slug}с управлением публикацией из/profile. Публичные страницы игр и клубов теперь могут вести на профиль мастера без раскрытия технических идентификаторов.🧩 Что вошло в релиз
src/GmRelay.Bot/Migrations/V028__add_master_profiles.sql— новая таблицаmaster_profilesс публичным slug, флагом публикации, именем и описаниемsrc/GmRelay.Web/Components/Pages/Profile.razor— управление публикацией профиля мастера из личного профиляsrc/GmRelay.Web/Components/Pages/PublicMasterProfile.razor— публичная страница/gm/{slug}с клубами и опубликованными играми мастераsrc/GmRelay.Web/Services/SessionService.cs— privacy-filtered запросы публичного профиля, связи с опубликованными клубами и играми, поддержка owner/co-GM ассоциацийsrc/GmRelay.Web/Components/Pages/PublicClub.razor,PublicSession.razor,Showcase.razor— ссылки на опубликованные профили мастеровtests/GmRelay.Bot.Tests/Web/MasterProfilesTests.cs— source-level проверки миграции, публичных контрактов, отсутствия приватных идентификаторов и поддержки co-GMREADME.md,docs/c4-system-context.md— документация обновлена под публичные профили мастеров- Синхронизированы версии:
Directory.Build.props,NavMenu.razor,compose.yaml,deploy.yml,README.md→ 3.5.0
🗡 Что это даёт
- Мастера могут публиковать отдельную публичную визитку с коротким адресом
- Игроки могут перейти от опубликованной игры или клуба к профилю мастера
- Публичный профиль не отдаёт Telegram/Discord ID, external user id, linked identities или avatar URL с платформенными идентификаторами
- Публичные игры co-GM тоже попадают в профиль соответствующего мастера
📦 Версия и деплой
Downloads
-
released this
2026-05-28 18:13:55 +03:00 | 98 commits to main since this release🛠 Feature 3.4.0 — Каталог игр и витрина ваншотов
Реализован публичный каталог опубликованных игр
/showcaseи обновлённая карточка сессии/s/{id}с поддержкой прямой записи.🧩 Что вошло в релиз
src/GmRelay.Bot/Migrations/V027__add_showcase_fields.sql— добавлены поляis_one_shot,system,description,cover_image_url,duration_minutes,format,allow_direct_registrationв таблицуsessions+ partial index для каталогаsrc/GmRelay.Shared/Domain/GameSystem.cs— enum с 21 TTRPG-системой +Other, методыToDisplayName()иTryParseFuzzy()src/GmRelay.Shared/Features/Showcase/ShowcaseSessionDto.cs,ShowcaseFilter.cs— DTO для каталога и фильтровsrc/GmRelay.Web/Components/Pages/Showcase.razor— страница/showcaseс фильтрами по дате, системе, наличию мест и формату, пагинацией и карточкамиsrc/GmRelay.Web/Components/Pages/PublicSession.razor— обновлённая публичная карточка с обложкой, бейджами, описанием, длительностью и поддержкой?register=1для прямой записиsrc/GmRelay.Web/Services/SessionService.cs—GetShowcaseSessionsAsyncс динамическим SQL иLATERALjoin;RegisterFromShowcaseAsyncсFOR UPDATEиON CONFLICTsrc/GmRelay.Shared/Features/Sessions/CreateSession/CreateSessionCommand.cs— новые поля при создании сессииsrc/GmRelay.Shared/Features/Sessions/CreateSession/CreateSessionHandler.cs— сохранение новых полей +cover_image_urltests/GmRelay.Bot.Tests/Domain/GameSystemTests.cs— тесты для fuzzy matchingtests/GmRelay.Bot.Tests/Features/Sessions/CreateSession/SessionCapacityRulesTests.cs— boundary тесты для waitlist- Синхронизированы версии:
Directory.Build.props,NavMenu.razor,compose.yaml,deploy.yml,README.md→ 3.4.0
🗡 Что это даёт
- Пользователи могут находить опубликованные игры через
/showcaseбез доступа к приватному dashboard - ГМы могут публиковать игры с детальным описанием, системой, форматом и обложкой
- Включена прямая запись на игры (
allow_direct_registration) с соблюдением лимитов мест и waitlist - Owner/co-GM контролируют, что попадает в витрину через флаги публикации
📦 Версия и деплой
Downloads
-
released this
2026-05-28 12:51:26 +03:00 | 118 commits to main since this release🛠 Minor 3.3.0 — Публичные страницы клубов
Добавлены read-only публичные страницы клубов и отдельных сессий. Owner и co-GM управляют публикацией из Web Dashboard, а закрытые группы и приватные сессии остаются недоступны публично.
🧩 Что вошло в релиз
src/GmRelay.Bot/Migrations/V026__add_public_club_pages.sql— поля публикации клубов и сессий, уникальный slug и индекс публичного расписанияsrc/GmRelay.Web/Services/SessionService.cs— privacy-filtered запросы для публичных страниц без состава игроков и join-ссылокsrc/GmRelay.Web/Components/Pages/PublicClub.razorиPublicSession.razor— публичные маршруты/club/{slug}и/s/{sessionId}src/GmRelay.Web/Components/Pages/GroupDetails.razor— настройки публикации клуба, batch и отдельных сессийREADME.md,docs/c4-system-context.md— документация обновлена под публичные страницы- Синхронизированы версии:
Directory.Build.props,NavMenu.razor,compose.yaml,deploy.yml→ 3.3.0
🗡 Что это даёт
- Клубы могут делиться открытым расписанием без раскрытия личных данных игроков
- Приватные сессии не доступны по публичным URL и получают noindex-страницы
- Share-friendly ссылки работают для клуба и опубликованных сессий
📦 Версия и деплой
Downloads
-
released this
2026-05-27 16:11:45 +03:00 | 121 commits to main since this release🛠 Minor 3.2.0 — Завершение platform-neutral архитектуры
Все оставшиеся Telegram handlers перенесены в
GmRelay.Sharedс platform-neutral контрактами. Discord Bot получил parity для reschedule voting.🧩 Что вошло в релиз
src/GmRelay.Shared/Features/Sessions/*— извлечены 6 shared handlers: CreateSession, ListSessions, DeleteSession, ExportCalendar, HandleRescheduleTimeInput, HandleRescheduleVotesrc/GmRelay.Bot/Infrastructure/Telegram/TelegramPlatformMessenger.cs— новые методыSendScheduleAsync,UpdateScheduleAsync,CreateThreadAsync,DeleteThreadAsync,UpdateGroupMessageAsyncsrc/GmRelay.DiscordBot/Features/Sessions/DiscordRescheduleVoteHandler.cs— делегирует в sharedHandleRescheduleVoteHandlersrc/GmRelay.Bot/Program.cs— hotfix: добавлены недостающие DI-регистрации для sharedDeleteSessionHandlerиListSessionsHandler- Синхронизированы версии:
Directory.Build.props,NavMenu.razor,compose.yaml,deploy.yml→ 3.2.0
🗡 Что это даёт
- Новая платформа добавляется adapter-ом, без переписывания core flow
- Telegram и Discord routers используют единые command contracts
- Core handlers тестируются без Telegram SDK
📦 Версия и деплой
Downloads
-
released this
2026-05-27 14:18:40 +03:00 | 125 commits to main since this release🔧 Patch 3.1.1 — Telegram topics для batch из шаблонов
Исправлено создание batch из шаблона через Web UI: в Telegram forum-группах новая пачка игр теперь получает отдельный topic так же, как batch, созданный через
/newsession.🧩 Что вошло в релиз
src/GmRelay.Web/Services/SessionService.cs— Web-путь создания batch из шаблона проверяет Telegram-чат, создаёт forum topic, сохраняетthread_id/topic_created_by_botв новыхsessionsи отправляет расписание в созданный topic.tests/GmRelay.Bot.Tests/Infrastructure/Telegram/TelegramTopicIntegrationSmokeTests.cs— добавлен regression test на создание и сохранение Telegram topic для template batches.tests/GmRelay.Bot.Tests/Discord/DiscordProjectStructureTests.cs— синхронизированы release assertions под3.1.1.- Синхронизированы версии:
Directory.Build.props,NavMenu.razor,compose.yaml,deploy.yml→ 3.1.1.
🗡 Что это даёт
- Batch, созданный из Web-шаблона, больше не публикуется в общий чат forum-группы.
- Дальнейшие групповые уведомления и удаление пустого bot-owned topic работают по сохранённому
thread_id. - Поведение Web UI стало согласовано с
/newsessionв Telegram.
📦 Версия и деплой
Downloads