forked from syntaxbullet/aurorabot
200 lines
6.6 KiB
Markdown
200 lines
6.6 KiB
Markdown
# 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`
|
|
|
|
## 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 |
|