Skip to content

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

  1. Key Naming:
  2. Use kebab-case: new-feature not newFeature
  3. Be descriptive: payment-gateway-fallback not pgf
  4. Use prefixes for related flags: auth-*, payment-*

  5. Value Storage:

  6. Keep values concise (usually < 255 characters)
  7. Use structured formats for complex values (CSV, JSON)
  8. Document expected format in Description

  9. Description:

  10. Include purpose and context
  11. Mention related flags if dependent
  12. Note rollout strategy or phases

  13. 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

  1. Password Storage:
  2. Always hash passwords with industry-standard algorithms
  3. Never use plain-text passwords
  4. Use strong hashing functions (bcrypt, Argon2, PBKDF2)

  5. Username:

  6. Enforce uniqueness
  7. Consider supporting email as username
  8. Implement length and character restrictions

  9. Email:

  10. Validate email format
  11. Consider email verification
  12. Optional but recommended