• v3.9.0 415c13bf00

    v3.9.0 — Discord-визард создания игр (issue #112)
    Deploy Telegram Bot / build-and-push (push) Successful in 6m52s
    Deploy Telegram Bot / scan-images (push) Successful in 2m32s
    Deploy Telegram Bot / deploy (push) Successful in 41s
    Stable

    Toutsu released this 2026-06-06 08:18:37 +03:00 | 27 commits to main since this release

    🎯 Discord-визард создания игр

    Платформо-нейтральный wizard (тот же движок, что в Telegram-боте с 3.8.0) теперь работает и в Discord-боте. /newsession-wizard открывает пошаговый сценарий с кнопками, выпадающими меню и модальными окнами, через которые мастер (GM) собирает одиночную игру или пул слотов. Single-source-of-truth стейт-машина GameCreationWizard живёт в GmRelay.Shared и используется обеими платформами.

    Что нового для пользователей

    • /newsession-wizard открывает Discord-wizard: тип в†’ одиночная или РїСѓР»
    • Внутри: native Discord components — buttons, StringSelectMenu, modals
    • РўРѕС‚ Р¶Рµ flow, что РІ Telegram: 11 шагов для single, 7 для pool (общие system/duration РЅР° СѓСЂРѕРІРЅРµ пула)
    • Owner / co-GM / admin проверка прав через DiscordPermissionChecker + group_managers РІ БД
    • Предпросмотр перед созданием
    • РљРЅРѕРїРєР° «Другое… вњЏпёЏВ» РЅР° шагах System / Duration / PoolSystemDuration открывает модалку для СЃРІРѕР±РѕРґРЅРѕРіРѕ РІРІРѕРґР°
    • PickClub-шаг использует реальный SQL Рє club_memberships СЃ фильтром РїРѕ роли Owner/CoGm (раньше возвращал пустой СЃРїРёСЃРѕРє)
    • 3-retry finalize СЃ retry/cancel кнопками РїСЂРё ошибке БД

    Архитектура

    Shared (платформо-нейтральное ядро)

    • GameCreationWizard — state machine без I/O, читает/пишет WizardPayload РёР· JSONB
    • IWizardMessenger — контракт мессенджера (edit/send/answer/getOwnerClubs). РћР±Рµ платформы реализуют
    • WizardInteraction — record взаимодействия (OwnerId, Text, CallbackPayload, PhotoFileId, PhotoUrl, InteractionId)
    • WizardAction / WizardKeyboard — модель РєРЅРѕРїРѕРє Рё СЂСЏРґРѕРІ
    • WizardPayloadJsonContext — AOT JSON source-gen
    • WizardStepViewBuilder — pure-функции payload в†’ (text, actions) (вместо Telegram-специфичного WizardStep рендерера)
    • WizardDraft — добавлено поле Platform; миграция V032 добавила platform TEXT NOT NULL DEFAULT 'Telegram'
    • Telegram-мессенджер (ITelegramWizardMessenger) адаптирован РїРѕРґ новый контракт, поведение РЅРµ поменялось

    Discord-адаптер

    • DiscordWizardCommand — /newsession-wizard slash-команда СЃ owner/co-GM проверкой
    • DiscordWizardStep — рендер 15 шагов РІ NetCord embed + buttons/StringSelectMenu/modals
    • DiscordWizardMessenger — реализация IWizardMessenger через NetCord REST (edit СЃ fallback РЅР° re-send РїСЂРё 401/403/404)
    • DiscordWizardSubmitter — 3-retry finalize: shared CreateSessionHandler в†’ edit embed В«вњ… Создано» или retry/cancel РєРЅРѕРїРєРё
    • DiscordWizardContextStore — in-memory РєСЌС€ (guildId, channelId, messageId, threadId?) РїРѕ draft.Id для восстановления после 15-РјРёРЅ interaction token
    • DiscordWizardInteractionModule — 3 NetCord ComponentInteractionModule<TContext> (button / StringMenu / modal) + shared WizardInteractionDispatcher
    • DiscordPermissionLookup — DB-хелпер group_managers для slash-команды

    Custom-id wire format (канонический, единый для renderer'а и dispatcher'а):

    • wizard:btn:choice:<step>:<value> — choice РєРЅРѕРїРєРё
    • wizard:btn:<action>:1 — control (back/cancel/skip/create/resume)
    • wizard:btn:modal:<step> — открыть модалку
    • wizard:select:<step> — StringSelectMenu
    • wizard:modal:<step> — модальный submit

    Тесты

    • 66 wizard-СЋРЅРёС‚-тестов — state-machine переходы, pool-slot lifecycle, валидация, рендер, cancel/back
    • 12 source-level structural smoke-тестов РЅР° Discord interaction module (NetCord registration, dispatcher shape, customId format)
    • 2 новых parser-roundtrip теста (Renderer_And_Dispatcher_Agree_On_Wire_Format, ControlButtons_Are_Parsed_As_Control_Not_Choice) — реальные behavioural тесты, РЅРµ string-grep
    • 8 handler/router тестов — submit-валидация, missing fields, cleanup-tick, router delegation, stale-command reset
    • Полный РїСЂРѕРіРѕРЅ: 583 passed, 2 skipped, 0 failed
    • dotnet format --verify-no-changes clean
    • dotnet list package --vulnerable --include-transitive clean
    • dotnet build — 0 warnings
    • AOT-safe: zero System.Reflection, zero dynamic, zero Activator.CreateInstance РІ Discord Рё Shared РєРѕРґРµ
    • SecretRedactor.RedactConnectionString РЅР° startup log

    Безопасность

    • Р’СЃРµ SQL-запросы параметризованы (@GuildId, @Platform, @ExternalUserId, @OwnerId)
    • DM-инвокации /newsession-wizard отклоняются (null-check РЅР° GuildId)
    • Context.User as GuildInteractionUser — null-check перед использованием
    • Internal ex.Message РѕС‚ Postgres РќР• утекает РІ Discord channel (C-3 фикс) — пользователь РІРёРґРёС‚ generic error, полный exception остался РІ server-side log

    Известные ограничения

    • Free-text модалы (SystemFreeText, DurationFreeText, PoolSystemDurationFreeText) маппятся РЅР° канонические шаги (System, Duration, PoolSystemDuration) хаком РІ диспетчере. Работает, РЅРѕ чистое решение — добавить отдельные free-text шаги РІ WizardStepNames
    • resume:continue — re-render текущего шага, РЅРµ настоящий resume (однако wizard РІСЃС‘ равно сохраняет state РІ БД, так что переживает перезапуск бота)
    • РћРґРёРЅ активный draft per owner per платформа (by design state machine'Р°)
    • DiscordProjectStructureTests.Version_ShouldBeSynchronizedForDiscordFeatureRelease — broken test РёР· 3.7.1, синхронизирован РІ этом релизе РїРѕРґ 3.9.0

    Что вышло из скоупа

    • Шаг СЃ загрузкой фото-обложки РІ Discord wizard (image upload) — РїРѕРєР° URL-only (как РІ Telegram-варианте)
    • Slack / Teams адаптеры — общий контракт IWizardMessenger готов, РЅРѕ платформенные реализации РЅРµ РІ СЃРєРѕСѓРїРµ
    • Backlog: cache для LoadManagerUserIdsAsync (I-1), exhaustiveness-проверка для switch (I-4), глобальная константа WizardEmbedColor (Nit)

    Closes #112.

    Downloads