Files
aurorabot/docs/feature-flags.md
syntaxbullet 1ff24b0f7f docs: add feature flags system documentation
Document feature flag architecture, usage, admin commands, and best practices for beta testing features in production.
2026-02-12 14:54:51 +01:00

169 lines
5.4 KiB
Markdown

# Feature Flag System
The feature flag system enables controlled beta testing of new features in production without requiring a separate test environment.
## Overview
Feature flags allow you to:
- Test new features with a limited audience before full rollout
- Enable/disable features without code changes or redeployment
- Control access per guild, user, or role
- Eliminate environment drift between test and production
## Architecture
### Database Schema
**`feature_flags` table:**
| Column | Type | Description |
|--------|------|-------------|
| `id` | serial | Primary key |
| `name` | varchar(100) | Unique flag identifier |
| `enabled` | boolean | Whether the flag is active |
| `description` | text | Human-readable description |
| `created_at` | timestamp | Creation time |
| `updated_at` | timestamp | Last update time |
**`feature_flag_access` table:**
| Column | Type | Description |
|--------|------|-------------|
| `id` | serial | Primary key |
| `flag_id` | integer | References feature_flags.id |
| `guild_id` | bigint | Guild whitelist (nullable) |
| `user_id` | bigint | User whitelist (nullable) |
| `role_id` | bigint | Role whitelist (nullable) |
| `created_at` | timestamp | Creation time |
### Service Layer
The `featureFlagsService` (`shared/modules/feature-flags/feature-flags.service.ts`) provides:
```typescript
// Check if a flag is globally enabled
await featureFlagsService.isFlagEnabled("trading_system");
// Check if a user has access to a flagged feature
await featureFlagsService.hasAccess("trading_system", {
guildId: "123456789",
userId: "987654321",
memberRoles: ["role1", "role2"]
});
// Create a new feature flag
await featureFlagsService.createFlag("new_feature", "Description");
// Enable/disable a flag
await featureFlagsService.setFlagEnabled("new_feature", true);
// Grant access to users/roles/guilds
await featureFlagsService.grantAccess("new_feature", { userId: "123" });
await featureFlagsService.grantAccess("new_feature", { roleId: "456" });
await featureFlagsService.grantAccess("new_feature", { guildId: "789" });
// List all flags or access records
await featureFlagsService.listFlags();
await featureFlagsService.listAccess("new_feature");
```
## Usage
### Marking a Command as Beta
Add `beta: true` to any command definition:
```typescript
export const newFeature = createCommand({
data: new SlashCommandBuilder()
.setName("newfeature")
.setDescription("A new experimental feature"),
beta: true, // Marks this command as a beta feature
execute: async (interaction) => {
// Implementation
},
});
```
By default, the command name is used as the feature flag name. To use a custom flag name:
```typescript
export const trade = createCommand({
data: new SlashCommandBuilder()
.setName("trade")
.setDescription("Trade items with another user"),
beta: true,
featureFlag: "trading_system", // Custom flag name
execute: async (interaction) => {
// Implementation
},
});
```
### Access Control Flow
When a user attempts to use a beta command:
1. **Check if flag exists and is enabled** - Returns false if flag doesn't exist or is disabled
2. **Check guild whitelist** - User's guild has access if `guild_id` matches
3. **Check user whitelist** - User has access if `user_id` matches
4. **Check role whitelist** - User has access if any of their roles match
If none of these conditions are met, the user sees:
> **Beta Feature**
> This feature is currently in beta testing and not available to all users. Stay tuned for the official release!
## Admin Commands
The `/featureflags` command (Administrator only) provides full management:
### Subcommands
| Command | Description |
|---------|-------------|
| `/featureflags list` | List all feature flags with status |
| `/featureflags create <name> [description]` | Create a new flag (disabled by default) |
| `/featureflags delete <name>` | Delete a flag and all access records |
| `/featureflags enable <name>` | Enable a flag globally |
| `/featureflags disable <name>` | Disable a flag globally |
| `/featureflags grant <name> [user\|role]` | Grant access to a user or role |
| `/featureflags revoke <id>` | Revoke access by record ID |
| `/featureflags access <name>` | List all access records for a flag |
### Example Workflow
```
1. Create the flag:
/featureflags create trading_system "Item trading between users"
2. Grant access to beta testers:
/featureflags grant trading_system user:@beta_tester
/featureflags grant trading_system role:@Beta Testers
3. Enable the flag:
/featureflags enable trading_system
4. View access list:
/featureflags access trading_system
5. When ready for full release:
- Remove beta: true from the command
- Delete the flag: /featureflags delete trading_system
```
## Best Practices
1. **Descriptive Names**: Use snake_case names that clearly describe the feature
2. **Document Flags**: Always add a description when creating flags
3. **Role-Based Access**: Prefer role-based access over user-based for easier management
4. **Clean Up**: Delete flags after features are fully released
5. **Testing**: Always test with a small group before wider rollout
## Implementation Files
| File | Purpose |
|------|---------|
| `shared/db/schema/feature-flags.ts` | Database schema |
| `shared/modules/feature-flags/feature-flags.service.ts` | Service layer |
| `shared/lib/types.ts` | Command interface with beta properties |
| `bot/lib/handlers/CommandHandler.ts` | Beta access check |
| `bot/commands/admin/featureflags.ts` | Admin command |