Skip to main content

Discord Integration

Guild overview displays real-time Discord activity when a guild has a linked Discord server.

Architecture

flowchart LR
B1[Browser] -->|"REST poll (30s)"| A1["GET /discord/:id/activity"]
A1 --> D1["Discord.js cache + API"]
B2[Browser] -->|SSE stream| A2["GET /discord/:id/voice-stream"]
A2 --> D2[Discord gateway events]

Text channels use 30-second REST polling to show recent messages. Voice channels use Server-Sent Events (SSE) for real-time member join/leave updates, with the initial REST fetch as a baseline.

API Endpoints

MethodPathPurpose
GET/discord/bot-inviteBot invite URL + required permissions list
GET/discord/:guildId/channelsList text and voice channels
GET/discord/:guildId/rolesList Discord roles
GET/discord/:guildId/activityChannel activity (messages + voice members)
SSE/discord/:guildId/voice-streamReal-time voice state events
PATCH/organizations/:id/settingsSave discordOverviewChannelIds

Activity Endpoint

Accepts optional channelIds query parameter (comma-separated) to filter which channels are returned. When omitted, all channels are returned.

Voice Stream (SSE)

Emits VoiceStateEvent objects when users join, leave, or move between voice channels:

interface VoiceStateEvent {
guildId: string;
channelId: string | null;
channelName: string | null;
channelType: 'voice' | 'stage';
userId: string;
displayName: string;
avatarUrl: string | null;
action: 'join' | 'leave' | 'move';
}

The backend listens to Discord gateway voiceStateUpdate events via an RxJS Subject and filters per-guild for each SSE connection. The Subject is completed on module destroy.

Frontend Hooks

useDiscordVoiceStream

Custom hook that subscribes to the SSE endpoint and merges real-time voice data with the REST baseline.

  • On first SSE event for a channel, seeds from REST data then applies live updates
  • Once SSE has tracked a channel, its member list becomes authoritative (replaces REST)
  • Resets patches when REST data refreshes (React "store previous props" pattern)
  • Cleans up EventSource on unmount or when server ID changes

Configurable Overview Channels

Guild admins can select which Discord channels appear on the overview tab via Settings > Integrations. Selected channel IDs are stored in guild.settings.discordOverviewChannelIds.

Event Announcements

When events are published, the bot posts a rich embed to the configured Discord channel with:

  • Event title, type, date, and description
  • Signup link back to the platform
  • Live roster that updates as users sign up (character name, class, spec)
  • Instance/difficulty metadata when applicable

Per-Event Discord Controls

The event form exposes a granular Discord section (only shown when the guild has a Discord server linked):

ToggleDefaultEffect
Enable Discord integrationonMaster switch — when off, no Discord actions fire for this event
Create Discord scheduled eventonCreates a native Discord Scheduled Event on publish
Send Discord announcementonPosts a rich embed to the announcement channel on publish

All three flags are stored in event.metadata (discordAnnounce, discordScheduledEvent). Absence of a flag is treated as true (defaults to guild behaviour). Setting a flag to false explicitly opts out.

Announcement Channel Override

When "Send Discord announcement" is on, an optional channel selector appears. Leaving it empty uses the guild default (guild.settings.discordAnnouncementChannelId). Selecting a channel stores it on event.discordChannelId and takes precedence over the guild default.

The announcement embed is a "living" message — it updates automatically when signups change.

Voice Channel Override

When "Create Discord scheduled event" is on, an optional voice channel selector appears. This overrides the guild-level discordVoiceChannelId setting for this specific event. If no voice channel is chosen (event-level or guild-level), the scheduled event is created as an External type instead.

Voice channel override is stored in event.metadata.discordVoiceChannelId.

Discord Scheduled Events

Events can optionally create native Discord Scheduled Events, linked to voice channels when configured. See Event Lifecycle for details on auto-start, delay, and completion.

Voice Attendance Tracking

The bot tracks voice channel joins/leaves during active events. This data feeds into the attendance confirmation workflow. See Event Lifecycle for the full flow.

Bot Permissions

Required Discord bot permissions:

  • Manage Roles
  • Manage Events
  • Send Messages
  • View Channels
  • Read Message History
  • Connect (voice)
  • View Voice Channel Members

When permissions change, the UI displays the updated requirements and prompts re-invitation.