Flaggy Models Reference¶
Overview¶
Flaggy provides domain models for managing feature flags and users. These models serve as the core data structures throughout the framework.
Namespace: Flaggy.Models
FeatureFlag Model¶
The FeatureFlag class represents a single feature flag with its configuration and metadata.
Properties¶
Key¶
public required string Key { get; set; }
Type: string (required)
Description: The unique identifier for the feature flag. Used as the primary lookup key.
Constraints: - Must be unique across the system - Typically lowercase with hyphens (kebab-case) - Case-sensitive
Example:
var flag = new FeatureFlag
{
Key = "new-checkout-flow"
};
Naming Best Practices:
- Use descriptive names: new-dashboard instead of nd
- Use kebab-case: dark-mode-enabled instead of DarkModeEnabled
- Group related flags: payment-stripe, payment-paypal
- Include phase if applicable: beta-feature-v2
IsEnabled¶
public bool IsEnabled { get; set; }
Type: bool
Description: Indicates whether the feature flag is currently enabled.
Default: false
Example:
var flag = new FeatureFlag
{
Key = "new-checkout-flow",
IsEnabled = true // Feature is active
};
// Usage in application
if (flag.IsEnabled)
{
return GetNewCheckoutFlow();
}
Use Cases: - Simple feature toggles - Enabling/disabling features gradually - Quick on/off switches
Value¶
public string? Value { get; set; }
Type: string? (nullable)
Description: An optional string value associated with the flag. Useful for storing configuration values, versions, or provider selections.
Default: null
Example:
// Provider selection
var flag = new FeatureFlag
{
Key = "payment-gateway",
IsEnabled = true,
Value = "stripe"
};
// Version selection
var flag = new FeatureFlag
{
Key = "api-version",
IsEnabled = true,
Value = "v2"
};
// Comma-separated options
var flag = new FeatureFlag
{
Key = "enabled-payment-methods",
IsEnabled = true,
Value = "credit-card,paypal,apple-pay"
};
Use Cases: - Selecting between implementations - Storing configuration values - Versioning features - Storing comma-separated lists
Description¶
public string? Description { get; set; }
Type: string? (nullable)
Description: A human-readable description of the feature flag's purpose and behavior.
Default: null
Example:
var flag = new FeatureFlag
{
Key = "new-checkout-flow",
IsEnabled = false,
Description = "Enable new checkout flow with one-click payment and save cards functionality"
};
var flag2 = new FeatureFlag
{
Key = "maintenance-mode",
IsEnabled = false,
Description = "Enable maintenance mode to temporarily disable access to the application"
};
Best Practices: - Be descriptive about the feature's purpose - Include rollout strategy if relevant - Mention dependencies on other flags - Note the business rationale
CreatedAt¶
public DateTime? CreatedAt { get; set; }
Type: DateTime? (nullable)
Description: Timestamp when the flag was created. Set automatically by the provider.
Default: null (set by provider on creation)
Example:
var flag = await flagService.GetFlagAsync("feature-key");
if (flag?.CreatedAt.HasValue == true)
{
Console.WriteLine($"Flag created on: {flag.CreatedAt:yyyy-MM-dd HH:mm:ss}");
}
Use Cases: - Auditing flag lifecycle - Determining feature age - Generating reports
UpdatedAt¶
public DateTime? UpdatedAt { get; set; }
Type: DateTime? (nullable)
Description: Timestamp when the flag was last updated. Set automatically by the provider.
Default: null (set by provider on updates)
Example:
var flag = await flagService.GetFlagAsync("feature-key");
if (flag?.UpdatedAt.HasValue == true)
{
Console.WriteLine($"Last modified: {flag.UpdatedAt:yyyy-MM-dd HH:mm:ss}");
// Check if recently modified
if (DateTime.UtcNow - flag.UpdatedAt.Value < TimeSpan.FromMinutes(5))
{
Console.WriteLine("Flag was recently updated");
}
}
Use Cases: - Tracking modification history - Detecting recent changes - Audit trails
FeatureFlag Usage Examples¶
Basic Flag Creation¶
var flag = new FeatureFlag
{
Key = "dark-mode",
IsEnabled = true,
Description = "Enable dark mode for user interface"
};
await flagService.CreateFlagAsync(flag);
Flag with Configuration Value¶
var flag = new FeatureFlag
{
Key = "notification-provider",
IsEnabled = true,
Value = "sendgrid", // Configuration value
Description = "Email notification provider"
};
await flagService.CreateFlagAsync(flag);
// Later, retrieve and use the value
var provider = await flagService.GetValueAsync("notification-provider");
Feature Rollout Flag¶
var flag = new FeatureFlag
{
Key = "beta-dashboard",
IsEnabled = false, // Start disabled
Value = "5%", // Can track rollout percentage in Value
Description = "Beta dashboard - Rolling out to 5% of users"
};
await flagService.CreateFlagAsync(flag);
Complete Example with All Properties¶
var flag = new FeatureFlag
{
Key = "new-payment-flow",
IsEnabled = false,
Value = "stripe,v3",
Description = "New payment flow with Stripe v3 integration - Phase 2 rollout",
CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow
};
await flagService.CreateFlagAsync(flag);
// Retrieve and inspect
var retrievedFlag = await flagService.GetFlagAsync("new-payment-flow");
Console.WriteLine($"Created: {retrievedFlag?.CreatedAt}");
Console.WriteLine($"Updated: {retrievedFlag?.UpdatedAt}");
User Model¶
The User class represents authentication users in the Flaggy system (used for admin access and user management).
Properties¶
Username¶
public required string Username { get; set; }
Type: string (required)
Description: The unique username for authentication.
Constraints: - Must be unique - Required field - Typically 3-50 characters
Example:
var user = new User
{
Username = "admin@example.com"
};
PasswordHash¶
public required string PasswordHash { get; set; }
Type: string (required)
Description: The hashed password. Never store plain-text passwords.
Important: Always use proper password hashing (bcrypt, PBKDF2, etc.)
Example:
// Example using bcrypt (library dependency required)
var passwordHash = BCrypt.Net.BCrypt.HashPassword("user-password");
var user = new User
{
Username = "admin@example.com",
PasswordHash = passwordHash
};
Security Notes: - Never log or display password hashes - Use industry-standard hashing algorithms - Include salt in the hash - Set appropriate work factor/iterations
Email¶
public string? Email { get; set; }
Type: string? (nullable)
Description: The user's email address.
Default: null
Example:
var user = new User
{
Username = "admin",
PasswordHash = hashedPassword,
Email = "admin@example.com"
};
Use Cases: - Contact information - Password reset - Account notifications
CreatedAt¶
public DateTime? CreatedAt { get; set; }
Type: DateTime? (nullable)
Description: Timestamp when the user account was created.
Default: null (set by provider on creation)
Example:
var user = await userProvider.GetUserAsync("admin");
if (user?.CreatedAt.HasValue == true)
{
Console.WriteLine($"Account created: {user.CreatedAt:yyyy-MM-dd}");
}
UpdatedAt¶
public DateTime? UpdatedAt { get; set; }
Type: DateTime? (nullable)
Description: Timestamp when the user account was last updated.
Default: null (set by provider on updates)
Example:
var user = await userProvider.GetUserAsync("admin");
if (user?.UpdatedAt.HasValue == true)
{
Console.WriteLine($"Last modified: {user.UpdatedAt:yyyy-MM-dd}");
}
User Usage Examples¶
Creating a User¶
using System.Security.Cryptography;
// Hash password securely
var hashedPassword = BCrypt.Net.BCrypt.HashPassword("SecurePassword123");
var user = new User
{
Username = "john_admin",
PasswordHash = hashedPassword,
Email = "john@example.com"
};
await userProvider.CreateUserAsync(user);
Validating User Credentials¶
var user = await userProvider.GetUserAsync(username);
if (user != null && BCrypt.Net.BCrypt.Verify(providedPassword, user.PasswordHash))
{
Console.WriteLine("Authentication successful");
return user;
}
Updating User Email¶
var user = await userProvider.GetUserAsync("john_admin");
if (user != null)
{
user.Email = "john.new@example.com";
await userProvider.UpdateUserAsync(user);
}
Model Guidelines¶
FeatureFlag Best Practices¶
- Key Naming:
- Use kebab-case:
new-featurenotnewFeature - Be descriptive:
payment-gateway-fallbacknotpgf -
Use prefixes for related flags:
auth-*,payment-* -
Value Storage:
- Keep values concise (usually < 255 characters)
- Use structured formats for complex values (CSV, JSON)
-
Document expected format in Description
-
Description:
- Include purpose and context
- Mention related flags if dependent
-
Note rollout strategy or phases
-
Usage Pattern:
// Good: Complete flag definition var flag = new FeatureFlag { Key = "stripe-v3-integration", IsEnabled = true, Value = "production", Description = "Enable Stripe v3 API integration for payments" }; // Avoid: Vague naming and description var flag = new FeatureFlag { Key = "feature1", IsEnabled = true, Description = "Something" };
User Best Practices¶
- Password Storage:
- Always hash passwords with industry-standard algorithms
- Never use plain-text passwords
-
Use strong hashing functions (bcrypt, Argon2, PBKDF2)
-
Username:
- Enforce uniqueness
- Consider supporting email as username
-
Implement length and character restrictions
-
Email:
- Validate email format
- Consider email verification
- Optional but recommended
Related Documentation¶
- Service: IFeatureFlagService Interface
- Provider: IFeatureFlagProvider Interface
- Extensions: Extension Methods