docs: add feature flags system documentation
Document feature flag architecture, usage, admin commands, and best practices for beta testing features in production.
This commit is contained in:
168
docs/feature-flags.md
Normal file
168
docs/feature-flags.md
Normal file
@@ -0,0 +1,168 @@
|
||||
# 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 |
|
||||
Reference in New Issue
Block a user