forked from syntaxbullet/aurorabot
docs: add guild settings system documentation
Document guild settings architecture, service layer, admin commands, API endpoints, and migration strategy from file-based config.
This commit is contained in:
184
docs/guild-settings.md
Normal file
184
docs/guild-settings.md
Normal file
@@ -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 <key> [value]` | Update a setting |
|
||||
| `/settings reset <key>` | Reset a setting to default |
|
||||
| `/settings colors <action> [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 |
|
||||
Reference in New Issue
Block a user