Bot Control
Overview
The Connections group of the settings window shows bot control in the Chat bot section of the Twitch, YouTube and Kick areas. Discord server status and connection actions appear in the Discord area. The Overview lists bots and servers that need attention.
Chat Bot Control
Per-platform bot management in the platform's area of the settings window (/dashboard/settings/channel/connections/{platform}):
- Status: in chat, paused, offline, disconnected or waiting for a channel.
- Pause / resume:
toggleBotForPlatformupdateschannel_connections.bot_enabled. - Re-enter chat:
rejoinBotsends abot_joinaction via Redis pub/sub to trigger an immediate channel rejoin. This does not renew OAuth. - Reconnect bot: a disconnected own bot repeats its OAuth grant on the same platform tab.
Database
channel_connections.bot_enabled (BOOLEAN, default true) - when false, bots ignore this channel during sync.
API
| Type | Endpoint | Permission |
|---|---|---|
| GraphQL Query | botStatus | bot-connections:read |
| GraphQL Mutation | toggleBotForPlatform(platform, enabled) | bot-connections:create |
| GraphQL Mutation | rejoinBot(platform) | bot-connections:create |
| REST | GET /v1/bot-status | bot-connections:read |
| REST | POST /v1/bot-toggle | bot-connections:create |
| REST | POST /v1/bot-rejoin | bot-connections:create |
| System Query | botChannels(platform) | System key with bots:internal |
Bot Worker Actions
All chat bots listen for Redis pub/sub actions on lumio:bot:action:{platform}:{account_id}:
bot_join/bot_sync- Refresh the Discord guild map immediately; other bot workers apply their own sync behaviorbot_leave- Immediately remove account's channels from in-memory map + clear Redis cacheguild_leave(Discord only,data.guild_id) - Published when an account disconnects a Discord server. The bot re-syncs its guild map and leaves the server unless it is mapped again (reconnect or takeover); without a fresh map it stays
Discord Server Mapping
Discord guilds are mapped to Lumio accounts via discord_guild_connections table.
Tables
discord_guild_connections- guild_id → account_id mapping (UNIQUE on guild_id)discord_guild_settings- per-guild JSONB settingsdiscord_guild_channel_mappings- feature → Discord channel routing (live_notification, event_feed, chat_mirror, etc.)
Server connection
The Discord area (/dashboard/settings/channel/connections/discord) shows each server's status. Add server and Reconnect start authorizeBot(platform: "discord") through /api/connections/bot/discord/authorize. Discord returns to /api/connections/oauth/discord/callback; the unified exchange redeems the code and takes the server ID from Discord's token response. After verification it links the server to the account, returns to the Discord area and notifies the running bot to refresh its guild map. A Discord user token is revoked after that one-time check and is never stored. The equivalent REST authorize endpoint is GET /v1/bot-connections/discord/authorize; the old /v1/discord-guilds/exchange route is not part of this flow.
The server's status is Connected, Bot removed, or Permissions missing. Removal on Discord marks the connection while preserving its settings; reconnecting clears the mark. Disconnect removes the mapping and its server settings, and the bot leaves the server.
Redis Cache
| Key | Content | TTL |
|---|---|---|
lumio:discord_guild:{guild_id} | account_id | 1h |
lumio:discord_guild:{guild_id}:channels | JSON array of the channels the bot can view (VIEW_CHANNEL) | 1h |
lumio:discord_guild:{guild_id}:roles | JSON array of roles | 1h |
lumio:discord_guild:{guild_id}:features | JSON array of feature mappings | 1h |
lumio:discord_channel_guild:{channel_id} | guild_id (reverse lookup) | 1h |
Feature-Channel Mappings
The catalogue is the DISCORD_FEATURES const in apps/api/src/graphql/discord_guilds.rs - adding one is a code change, not a database migration. setDiscordGuildFeature rejects any key not in the list:
| Feature Key | Description |
|---|---|
live_notification | Stream live alerts |
event_feed | Follows, subs, donations |
chat_mirror | Platform chat → Discord |
announcement | Announcements |
moderation_log | Ban/timeout logs |
clip_feed | New clips |
API
| Type | Endpoint | Permission |
|---|---|---|
| GraphQL Query | discordGuildConnections | bot-connections:read |
| GraphQL Mutation | authorizeBot(platform: "discord") | bot-connections:create, interactive session and feature:bots |
| GraphQL Mutation | disconnectDiscordGuild(guildId) | bot-connections:delete |
| GraphQL Query | discordGuildChannels(guildId) | bot-connections:read |
| GraphQL Query | discordGuildRoles(guildId) | bot-connections:read |
| GraphQL Query | discordGuildFeatures(guildId) | bot-connections:read |
| GraphQL Mutation | setDiscordGuildFeature(...) | bot-connections:create |
| System Query | discordBotGuilds | System key with bots:internal |
| System Mutation | updateDiscordGuildInfo(...) | System key with bots:internal |
| System Mutation | removeDiscordGuildByBot(guildId: String!) | System key with bots:internal |
| REST | GET /v1/bot-connections/discord/authorize | bot-connections:create, interactive session and feature:bots |
| REST | GET /v1/discord-guilds, DELETE /v1/discord-guilds/{guild_id} | bot-connections:read / bot-connections:delete |
Admin
Admin permissions: bot-control:read/edit, discord-guilds:read/delete (enforced via require_admin_permission).
/admin/bot-control- View/toggle bots per account. REST:GET /v1/admin/bot-control/statuses,PUT /v1/admin/bot-control/{account_id}/{platform}./admin/discord-guilds- View all guild-to-account mappings, delete connections. REST:GET /v1/admin/discord-guilds,DELETE /v1/admin/discord-guilds/{guild_id}.
Feature Gating
The Bot Control surface (bot_connections resolvers/routes - bot status, toggle,
rejoin, authorize, delete) is gated on the feature:bots flag on both protocols
(GraphQL FeatureGuard, REST require_feature). With feature:bots disabled the
API rejects the call directly; the webapp route gate is UX only. See
Bot Connections › Feature Flags for the
full endpoint list.
Security
- Guild ownership verified before channel/role queries
- Channel ownership verified in Discord bot actions (post_message)
- GuildDelete with
unavailable=trueonly cleans cache, preserves DB - Admin middleware on API routes
- Snowflake validation on all Discord IDs
- UUID validation on action listener account_id
Key Files
| Path | Description |
|---|---|
apps/api/src/graphql/bot_connections.rs | GraphQL queries and mutations for bot status/toggle/rejoin |
apps/api/src/graphql/discord_guilds.rs | GraphQL for Discord guild management |
apps/api/src/db/discord_guilds.rs | Database operations for Discord guilds |
apps/discord-bot/src/handlers/events.rs | Discord bot gateway event handling |
extensions/system/ | System extension manifests and handlers for built-in bot modules |
See Also
- Bot Connections - Custom bot identity OAuth flow
- Bot Commands - Dynamic command system for all bots
- Bot Modules - Chat moderation modules
- Provider Management - Feature flag controls