From ae6a068197bf2e8a5e0a785193bbd27850845d54 Mon Sep 17 00:00:00 2001 From: syntaxbullet Date: Thu, 12 Feb 2026 15:10:58 +0100 Subject: [PATCH] docs: add guild settings system documentation Document guild settings architecture, service layer, admin commands, API endpoints, and migration strategy from file-based config. --- docs/guild-settings.md | 184 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 docs/guild-settings.md diff --git a/docs/guild-settings.md b/docs/guild-settings.md new file mode 100644 index 0000000..661470e --- /dev/null +++ b/docs/guild-settings.md @@ -0,0 +1,184 @@ +# 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` + +## 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 |