# GM-Relay - C4 Model

## Level 1: System Context

```mermaid
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 and RSVP 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, RSVP, reminder, and reschedule messages")
    Rel(gmrelay, postgres, "SQL via Npgsql and Dapper")
```

## Level 2: Container

```mermaid
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, "Discord Gateway Worker", "Внутри GmRelay.Bot", "NetCord Gateway, slash commands, scheduler notifications, button interactions, healthcheck :8082")
        Container(web, "GmRelay.Web", "Blazor Server", "Dashboard, Mini App pages, editing and stats")
        Container(shared, "GmRelay.Shared", ".NET library", "Shared domain models, rendering, scheduler, and platform-neutral 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, scheduler, and platform-neutral 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

```mermaid
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(rsvp, "HandleRsvpHandler", "Feature handler", "Updates RSVP state and emits platform-neutral RSVP outcomes")
        Component(scheduler, "SessionSchedulerService", "Background service", "Triggers confirmation, reminder, and join-link notifications per platform")
        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")
    }

    Component(healthCheck, "DiscordHealthCheckHostedService", ":8082", "Healthcheck для Docker Compose")

    Container_Boundary(discordBot, "GmRelay.DiscordBot") {
        Component(discordModule, "DiscordSessionInteractionModule", "NetCord component module", "Maps join_session/leave_session/rsvp buttons to neutral commands")
        Component(discordMessenger, "DiscordPlatformMessenger", "IPlatformMessenger", "Sends and edits Discord schedule, RSVP, reminder, join-link, and reschedule messages")
    }

    Container_Boundary(bot, "GmRelay.Bot") {
        Component(updateRouter, "UpdateRouter", "Telegram adapter", "Maps callback queries to neutral commands")
        Component(telegramMessenger, "TelegramPlatformMessenger", "IPlatformMessenger", "Sends and edits Telegram schedule, RSVP, reminder, join-link, and reschedule messages")
    }

    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, rsvp, "HandleRsvpCommand")
    Rel(discordModule, discord, "Deferred ephemeral reply, then modify response")
    Rel(updateRouter, join, "JoinSessionCommand")
    Rel(updateRouter, leave, "LeaveSessionCommand")
    Rel(updateRouter, rsvp, "HandleRsvpCommand")
    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(rsvp, db, "Update RSVP and load notification recipients")
    Rel(scheduler, db, "Load due session triggers")
    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(rsvp, discordMessenger, "Update Discord confirmation and outcomes")
    Rel(rsvp, telegramMessenger, "Update Telegram confirmation and outcomes")
    Rel(scheduler, discordMessenger, "Send Discord scheduler notifications")
    Rel(scheduler, telegramMessenger, "Send Telegram scheduler notifications")
    Rel(discordMessenger, discord, "REST send/edit/DM + ephemeral text")
    Rel(telegramMessenger, telegram, "SendMessage/EditMessage + AnswerCallbackQuery")
    Rel(healthCheck, discord, "HTTP /health")
```
