forked from syntaxbullet/aurorabot
Document feature flag architecture, usage, admin commands, and best practices for beta testing features in production.
5.4 KiB
5.4 KiB
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:
// 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:
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:
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:
- Check if flag exists and is enabled - Returns false if flag doesn't exist or is disabled
- Check guild whitelist - User's guild has access if
guild_idmatches - Check user whitelist - User has access if
user_idmatches - 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
- Descriptive Names: Use snake_case names that clearly describe the feature
- Document Flags: Always add a description when creating flags
- Role-Based Access: Prefer role-based access over user-based for easier management
- Clean Up: Delete flags after features are fully released
- 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 |