# 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 |
