Files
GmRelayBot/docs/c4-system-context.md
Toutsu 39132be4e8
PR Checks / test-and-build (pull_request) Successful in 6m6s
feat(discord): enable session join leave buttons
Move neutral join/leave handlers into GmRelay.Shared so Telegram and Discord share capacity, waitlist, duplicate-click, and schedule-update behavior.

Add Discord component routing for join_session and leave_session buttons with deferred ephemeral replies and serialized schedule message updates.

Bump version to 2.5.0 and update Discord docs.

Refs #29
2026-05-19 14:13:48 +03:00

5.6 KiB

GM-Relay - C4 Model

Level 1: System Context

C4Context
    title GM-Relay System Context

    Person(gm, "Game Master", "Creates sessions and manages schedules")
    Person(player, "Player", "Joins, leaves, confirms, and receives reminders")

    System(gmrelay, "GM-Relay", "Telegram bot, Discord worker, web dashboard, and shared scheduling logic")

    System_Ext(telegram, "Telegram Bot API", "Commands, inline keyboards, callback queries, Mini App entry points")
    System_Ext(discord, "Discord Gateway and REST API", "Slash commands, button interactions, message edits, ephemeral replies")
    SystemDb_Ext(postgres, "PostgreSQL", "Sessions, players, participants, groups, platform identities")

    Rel(gm, telegram, "Creates and manages sessions")
    Rel(gm, discord, "Uses /newsession and /listsessions")
    Rel(player, telegram, "Uses inline buttons")
    Rel(player, discord, "Uses Join/Leave buttons")
    Rel(telegram, gmrelay, "Updates via long polling")
    Rel(discord, gmrelay, "Gateway events and component interactions")
    Rel(gmrelay, telegram, "SendMessage, EditMessage, AnswerCallbackQuery")
    Rel(gmrelay, discord, "Send/edit schedule messages and ephemeral interaction replies")
    Rel(gmrelay, postgres, "SQL via Npgsql and Dapper")

Level 2: Container

C4Container
    title GM-Relay Containers

    Person(gm, "Game Master")
    Person(player, "Player")

    System_Boundary(runtime, "Docker Compose / Aspire runtime") {
        Container(bot, "GmRelay.Bot", "Worker Service, .NET 10 AOT", "Telegram long polling, commands, callback routing, reminders")
        Container(discordBot, "GmRelay.DiscordBot", "Worker Service, .NET 10", "NetCord Gateway, slash commands, Join/Leave button interactions")
        Container(web, "GmRelay.Web", "Blazor Server", "Dashboard, Mini App pages, editing and stats")
        Container(shared, "GmRelay.Shared", ".NET library", "Shared domain models, rendering, and platform-neutral join/leave handlers")
        ContainerDb(db, "PostgreSQL", "Database", "sessions, players, session_participants, game_groups, platform identities")
    }

    System_Ext(telegram, "Telegram Bot API")
    System_Ext(discord, "Discord Gateway and REST API")

    Rel(gm, telegram, "Commands")
    Rel(gm, discord, "Slash commands")
    Rel(player, telegram, "Callback queries")
    Rel(player, discord, "Button interactions")
    Rel(telegram, bot, "GetUpdates")
    Rel(discord, discordBot, "Gateway events")
    Rel(bot, telegram, "Bot API calls")
    Rel(discordBot, discord, "REST send/edit/reply calls")
    Rel(bot, shared, "Uses shared renderers and join/leave handlers")
    Rel(discordBot, shared, "Uses shared renderers and join/leave handlers")
    Rel(web, shared, "Uses shared domain and rendering models")
    Rel(bot, db, "Npgsql + Dapper.AOT")
    Rel(discordBot, db, "Npgsql + Dapper")
    Rel(web, db, "Npgsql + Dapper")

Level 3: Component - Session Interactions

C4Component
    title Platform-Neutral Session Interactions

    Container_Boundary(shared, "GmRelay.Shared") {
        Component(join, "JoinSessionHandler", "Feature handler", "Adds players as Active or Waitlisted with session row locking")
        Component(leave, "LeaveSessionHandler", "Feature handler", "Removes players and promotes the first waitlisted player when capacity allows")
        Component(updateLock, "ScheduleMessageUpdateLock", "In-memory keyed lock", "Serializes DB changes and schedule message edits per platform message")
        Component(renderer, "SessionBatchViewBuilder", "Renderer model builder", "Builds platform-neutral schedule views and actions")
    }

    Container_Boundary(discordBot, "GmRelay.DiscordBot") {
        Component(discordModule, "DiscordSessionInteractionModule", "NetCord component module", "Maps join_session/leave_session buttons to neutral commands")
        Component(discordMessenger, "DiscordPlatformMessenger", "IPlatformMessenger", "Edits Discord schedule messages and stores interaction replies")
    }

    Container_Boundary(bot, "GmRelay.Bot") {
        Component(updateRouter, "UpdateRouter", "Telegram adapter", "Maps callback queries to neutral commands")
        Component(telegramMessenger, "TelegramPlatformMessenger", "IPlatformMessenger", "Edits Telegram schedule messages and answers callback queries")
    }

    ContainerDb(db, "PostgreSQL")
    System_Ext(telegram, "Telegram Bot API")
    System_Ext(discord, "Discord Gateway and REST API")

    Rel(discord, discordModule, "Button interaction")
    Rel(discordModule, join, "JoinSessionCommand")
    Rel(discordModule, leave, "LeaveSessionCommand")
    Rel(discordModule, discord, "Deferred ephemeral reply, then modify response")
    Rel(updateRouter, join, "JoinSessionCommand")
    Rel(updateRouter, leave, "LeaveSessionCommand")
    Rel(join, updateLock, "Acquire by PlatformMessageRef")
    Rel(leave, updateLock, "Acquire by PlatformMessageRef")
    Rel(join, db, "SELECT FOR UPDATE, INSERT participant")
    Rel(leave, db, "SELECT FOR UPDATE, DELETE/promote participant")
    Rel(join, renderer, "Build updated schedule view")
    Rel(leave, renderer, "Build updated schedule view")
    Rel(join, discordMessenger, "Update Discord schedule when command is Discord")
    Rel(leave, discordMessenger, "Update Discord schedule when command is Discord")
    Rel(join, telegramMessenger, "Update Telegram schedule when command is Telegram")
    Rel(leave, telegramMessenger, "Update Telegram schedule when command is Telegram")
    Rel(discordMessenger, discord, "ModifyMessage + ephemeral text")
    Rel(telegramMessenger, telegram, "EditMessage + AnswerCallbackQuery")