# Guild Settings System The guild settings system enables per-guild configuration stored in the database, eliminating environment-specific config files and enabling runtime updates without redeployment. ## Overview Guild settings allow you to: - Store per-guild configuration in the database - Update settings at runtime without code changes - Support multiple guilds with different configurations - Maintain backward compatibility with file-based config ## Architecture ### Database Schema **`guild_settings` table:** | Column | Type | Description | |--------|------|-------------| | `guild_id` | bigint | Primary key (Discord guild ID) | | `student_role_id` | bigint | Student role ID | | `visitor_role_id` | bigint | Visitor role ID | | `color_role_ids` | jsonb | Array of color role IDs | | `welcome_channel_id` | bigint | Welcome message channel | | `welcome_message` | text | Custom welcome message | | `feedback_channel_id` | bigint | Feedback channel | | `terminal_channel_id` | bigint | Terminal channel | | `terminal_message_id` | bigint | Terminal message ID | | `moderation_log_channel_id` | bigint | Moderation log channel | | `moderation_dm_on_warn` | jsonb | DM user on warn | | `moderation_auto_timeout_threshold` | jsonb | Auto timeout after N warnings | | `feature_overrides` | jsonb | Feature flag overrides | | `created_at` | timestamp | Creation time | | `updated_at` | timestamp | Last update time | ### Service Layer The `guildSettingsService` (`shared/modules/guild-settings/guild-settings.service.ts`) provides: ```typescript // Get settings for a guild (returns null if not configured) await guildSettingsService.getSettings(guildId); // Create or update settings await guildSettingsService.upsertSettings({ guildId: "123456789", studentRoleId: "987654321", visitorRoleId: "111222333", }); // Update a single setting await guildSettingsService.updateSetting(guildId, "welcomeChannel", "456789123"); // Delete all settings for a guild await guildSettingsService.deleteSettings(guildId); // Color role helpers await guildSettingsService.addColorRole(guildId, roleId); await guildSettingsService.removeColorRole(guildId, roleId); ``` ## Usage ### Getting Guild Configuration Use `getGuildConfig()` instead of direct `config` imports for guild-specific settings: ```typescript import { getGuildConfig } from "@shared/lib/config"; // In a command or interaction const guildConfig = await getGuildConfig(interaction.guildId); // Access settings const studentRole = guildConfig.studentRole; const welcomeChannel = guildConfig.welcomeChannelId; ``` ### Fallback Behavior `getGuildConfig()` returns settings in this order: 1. **Database settings** (if guild is configured in DB) 2. **File config fallback** (during migration period) This ensures backward compatibility while migrating from file-based config. ### Cache Invalidation Settings are cached for 60 seconds. After updating settings, invalidate the cache: ```typescript import { invalidateGuildConfigCache } from "@shared/lib/config"; await guildSettingsService.upsertSettings({ guildId, ...settings }); invalidateGuildConfigCache(guildId); ``` ## Admin Commands The `/settings` command (Administrator only) provides full management: ### Subcommands | Command | Description | |---------|-------------| | `/settings show` | Display current guild settings | | `/settings set [value]` | Update a setting | | `/settings reset ` | Reset a setting to default | | `/settings colors [role]` | Manage color roles | ### Settable Keys | Key | Type | Description | |-----|------|-------------| | `studentRole` | Role | Role for enrolled students | | `visitorRole` | Role | Role for visitors | | `welcomeChannel` | Channel | Channel for welcome messages | | `welcomeMessage` | Text | Custom welcome message | | `feedbackChannel` | Channel | Channel for feedback | | `terminalChannel` | Channel | Terminal channel | | `terminalMessage` | Text | Terminal message ID | | `moderationLogChannel` | Channel | Moderation log channel | | `moderationDmOnWarn` | Boolean | DM users on warn | | `moderationAutoTimeoutThreshold` | Number | Auto timeout threshold | ## API Endpoints | Method | Endpoint | Description | |--------|----------|-------------| | GET | `/api/guilds/:guildId/settings` | Get guild settings | | PUT | `/api/guilds/:guildId/settings` | Create/replace settings | | PATCH | `/api/guilds/:guildId/settings` | Partial update | | DELETE | `/api/guilds/:guildId/settings` | Delete settings | ## Migration To migrate existing config.json settings to the database: ```bash bun run db:migrate-config ``` This will: 1. Read values from `config.json` 2. Create a database record for `DISCORD_GUILD_ID` 3. Store all guild-specific settings ## Migration Strategy for Code Update code references incrementally: ```typescript // Before import { config } from "@shared/lib/config"; const role = config.studentRole; // After import { getGuildConfig } from "@shared/lib/config"; const guildConfig = await getGuildConfig(guildId); const role = guildConfig.studentRole; ``` ### Files to Update Files using guild-specific config that should be updated: - `bot/events/guildMemberAdd.ts` - `bot/modules/user/enrollment.interaction.ts` - `bot/modules/feedback/feedback.interaction.ts` - `bot/commands/feedback/feedback.ts` - `bot/commands/inventory/use.ts` - `bot/commands/admin/create_color.ts` - `shared/modules/moderation/moderation.service.ts` - `shared/modules/terminal/terminal.service.ts` ## Files Updated to Use Database Config All code has been migrated to use `getGuildConfig()`: - `bot/events/guildMemberAdd.ts` - Role assignment on join - `bot/modules/user/enrollment.interaction.ts` - Enrollment flow - `bot/modules/feedback/feedback.interaction.ts` - Feedback submission - `bot/commands/feedback/feedback.ts` - Feedback command - `bot/commands/inventory/use.ts` - Color role handling - `bot/commands/admin/create_color.ts` - Color role creation - `bot/commands/admin/warn.ts` - Warning with DM and auto-timeout - `shared/modules/moderation/moderation.service.ts` - Accepts config param - `shared/modules/terminal/terminal.service.ts` - Terminal location persistence - `shared/modules/economy/lootdrop.service.ts` - Terminal updates ## Implementation Files | File | Purpose | |------|---------| | `shared/db/schema/guild-settings.ts` | Database schema | | `shared/modules/guild-settings/guild-settings.service.ts` | Service layer | | `shared/lib/config.ts` | Config loader with getGuildConfig() | | `bot/commands/admin/settings.ts` | Admin command | | `web/src/routes/guild-settings.routes.ts` | API routes | | `shared/scripts/migrate-config-to-db.ts` | Migration script |