Feature Flags Reference - Audit Trail Platform (ATP)¶
Deploy fearlessly, toggle safely — ATP uses Microsoft.FeatureManagement + Azure App Configuration to enable runtime feature control, progressive rollouts, A/B testing, and instant kill switches without redeployment.
📋 Documentation Generation Plan¶
This document will be generated in 12 cycles. Current progress:
| Cycle | Topics | Estimated Lines | Status |
|---|---|---|---|
| Cycle 1 | Feature Flag Philosophy & Architecture (1-2) | ~3,000 | ⏳ Not Started |
| Cycle 2 | Microsoft.FeatureManagement Fundamentals (3-4) | ~3,500 | ⏳ Not Started |
| Cycle 3 | Feature Flag Configuration (5-6) | ~3,500 | ⏳ Not Started |
| Cycle 4 | Built-In Feature Filters (7-8) | ~3,500 | ⏳ Not Started |
| Cycle 5 | Custom Feature Filters (9-10) | ~3,000 | ⏳ Not Started |
| Cycle 6 | Azure App Configuration Integration (11-12) | ~4,000 | ⏳ Not Started |
| Cycle 7 | Feature Flags in Code (13-14) | ~3,500 | ⏳ Not Started |
| Cycle 8 | Progressive Rollout & A/B Testing (15-16) | ~3,500 | ⏳ Not Started |
| Cycle 9 | Multi-Tenant & Edition-Based Flags (17-18) | ~3,000 | ⏳ Not Started |
| Cycle 10 | Testing Feature Flags (19-20) | ~2,500 | ⏳ Not Started |
| Cycle 11 | Operational Best Practices (21-22) | ~3,000 | ⏳ Not Started |
| Cycle 12 | Troubleshooting & Monitoring (23-24) | ~2,500 | ⏳ Not Started |
Total Estimated Lines: ~39,000
Purpose & Scope¶
This document provides the complete feature flag reference for the Audit Trail Platform (ATP), covering runtime feature toggling using Microsoft.FeatureManagement library, Azure App Configuration for centralized management, progressive rollout strategies, A/B testing patterns, multi-tenant targeting, and operational best practices.
Why Feature Flags for ATP? - Zero-Downtime Releases: Deploy code with features disabled, enable them when ready - Progressive Rollout: Gradually expose features to subsets of tenants/users - Kill Switches: Instantly disable problematic features without redeployment - A/B Testing: Test feature variants for performance and user acceptance - Compliance Testing: Enable audit-sensitive features only in validated environments - Multi-Tenant Control: Enable features per tenant, edition, or subscription level - Canary Deployments: Test new code paths with a small percentage of traffic
Feature Flag Use Cases in ATP - New Export Formats: Enable enhanced eDiscovery export formats for specific tenants - Advanced Search: Activate full-text search with PII masking for enterprise edition - Integrity Verification: Enable Merkle tree verification for high-assurance customers - Classification Models: Switch between PII detection algorithms (rule-based vs. ML) - Retention Policies: Activate tiered storage and archival for specific editions - Webhook Enhancements: Enable webhook batching, compression, or signature verification - Performance Optimizations: Test new caching strategies or query optimizations - Beta Features: Grant early access to select customers for feedback
Detailed Cycle Plan¶
CYCLE 1: Feature Flag Philosophy & Architecture (~3,000 lines)¶
Topic 1: ATP Feature Flag Philosophy¶
What will be covered: - Why Feature Flags? - Decouple deployment from release - Enable/disable features at runtime - No redeployment required to change behavior - Reduce risk of new features (instant rollback) - Enable progressive delivery and continuous deployment - Support A/B testing and experimentation
- Feature Flag vs. Configuration
- Feature Flags: Enable/disable entire code paths (boolean decisions)
- Configuration: Tune behavior of existing features (values, settings)
- Feature flags are temporary (removed after full rollout)
-
Configuration is permanent (operational tuning)
-
Feature Flag Lifecycle
1. Development: Feature flag created, code paths added 2. Testing: Feature tested in dev/test with flag ON 3. Staging: Feature validated with flag ON 4. Production (10%): Progressive rollout begins 5. Production (50%): Expand rollout if stable 6. Production (100%): Full rollout, feature default ON 7. Cleanup: Remove feature flag, code path becomes default -
ATP Feature Flag Principles
- Short-Lived: Remove flags after full rollout (technical debt prevention)
- Boolean-Only: Flags are on/off, not multi-valued (simplicity)
- Default-Off: New features default to disabled (safe by default)
- Centralized: All flags in Azure App Configuration (single source of truth)
- Auditable: Flag changes tracked in App Configuration history
- Testable: Flags easily overridden in tests
- Monitored: Flag evaluation tracked in telemetry
Code Examples: - Feature flag lifecycle diagram - Feature flag vs. configuration comparison - ATP flag naming conventions
Diagrams: - Feature flag lifecycle - Deployment vs. release timeline - Flag decision tree
Deliverables: - Feature flag philosophy document - Lifecycle management guide - Naming conventions
Topic 2: Feature Flag Architecture¶
What will be covered: - ATP Feature Flag Stack
┌─────────────────────────────────────────┐
│ Application Code (IFeatureManager) │
├─────────────────────────────────────────┤
│ Microsoft.FeatureManagement Library │
├─────────────────────────────────────────┤
│ Feature Filters (Percentage, Time, │
│ Targeting, Custom) │
├─────────────────────────────────────────┤
│ Configuration Providers │
│ - appsettings.json (local dev) │
│ - Azure App Configuration (prod) │
├─────────────────────────────────────────┤
│ Azure App Configuration Service │
│ (Centralized flag management + UI) │
└─────────────────────────────────────────┘
- Feature Flag Components
- IFeatureManager: Evaluate if flag is enabled
- IFeatureManagerSnapshot: Cached evaluation per request (consistency)
- IFeatureFilter: Custom logic for conditional enablement
- ITargetingContextAccessor: Provide user/tenant context for targeting
-
FeatureGate: Attribute to gate ASP.NET Core actions/controllers
-
Configuration Sources
- Development: appsettings.Development.json (local testing)
- Staging/Production: Azure App Configuration (centralized, dynamic)
-
Testing: In-memory configuration (test overrides)
-
Feature Flag Scope
- Global: Applies to all requests/tenants
- Per-Tenant: Enabled for specific tenants (targeting filter)
- Per-Edition: Enabled based on subscription edition (Enterprise, Pro, Free)
- Per-Environment: Different flag states per environment (dev/staging/prod)
Code Examples: - Feature flag architecture diagram - IFeatureManager registration - Configuration source precedence
Diagrams: - ATP feature flag architecture - Component interaction flow - Configuration source hierarchy
Deliverables: - Architecture overview - Component reference - Configuration strategy
CYCLE 2: Microsoft.FeatureManagement Fundamentals (~3,500 lines)¶
Topic 3: Microsoft.FeatureManagement Library¶
What will be covered:
- Library Overview
- Microsoft-maintained open-source library
- NuGet packages:
- Microsoft.FeatureManagement (core)
- Microsoft.FeatureManagement.AspNetCore (MVC/API support)
- GitHub: https://github.com/microsoft/FeatureManagement-Dotnet
-
Core Interfaces
// Check if feature enabled public interface IFeatureManager { Task<bool> IsEnabledAsync(string feature); Task<bool> IsEnabledAsync<TContext>(string feature, TContext context); IAsyncEnumerable<string> GetFeatureNamesAsync(); } // Cached per-request evaluation (consistency within request) public interface IFeatureManagerSnapshot : IFeatureManager { // Same interface, but evaluations cached per HTTP request } // Custom feature filter logic public interface IFeatureFilter { Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context); } // Provide user/tenant context for targeting public interface ITargetingContextAccessor { Task<TargetingContext> GetContextAsync(); } -
Registration
-
ATP Extension Method
// In FeatureFlagsExtensions.cs internal static IServiceCollection AddAuditFeatureManagement( this IServiceCollection services) { services.AddFeatureManagement() .AddFeatureFilter<PercentageFilter>() .AddFeatureFilter<TimeWindowFilter>() .AddFeatureFilter<TargetingFilter>() .AddFeatureFilter<TenantFeatureFilter>() .AddFeatureFilter<EditionFeatureFilter>(); // Add ATP-specific targeting context services.AddScoped<ITargetingContextAccessor, AuditTargetingContextAccessor>(); return services; }
Code Examples: - IFeatureManager interface usage - IFeatureManagerSnapshot for request consistency - Feature management registration - ATP-specific extensions
Diagrams: - Microsoft.FeatureManagement architecture - Interface hierarchy - Registration flow
Deliverables: - Library reference guide - Interface documentation - Registration patterns
Topic 4: Basic Feature Flag Usage¶
What will be covered: - Simple Boolean Flag
public class ExportService
{
private readonly IFeatureManager _featureManager;
public ExportService(IFeatureManager featureManager)
{
_featureManager = featureManager;
}
public async Task<ExportPackage> CreateExportAsync(ExportRequest request)
{
if (await _featureManager.IsEnabledAsync("EnableEnhancedExportFormat"))
{
return await CreateEnhancedExportAsync(request);
}
else
{
return await CreateLegacyExportAsync(request);
}
}
}
-
FeatureGate Attribute (ASP.NET Core)
[ApiController] [Route("api/[controller]")] public class AdvancedSearchController : ControllerBase { [HttpGet] [FeatureGate("EnableAdvancedSearch")] public async Task<IActionResult> Search([FromQuery] SearchQuery query) { // Only accessible if EnableAdvancedSearch is enabled var results = await _searchService.AdvancedSearchAsync(query); return Ok(results); } } -
Disabling Actions
-
Feature-Aware Views (Razor)
Code Examples: - IFeatureManager usage patterns (all scenarios) - FeatureGate attribute usage - DisabledFeatures attribute - Razor feature tag helper
Diagrams: - Feature flag evaluation flow - FeatureGate middleware
Deliverables: - Usage patterns guide - FeatureGate reference - Razor integration
CYCLE 3: Feature Flag Configuration (~3,500 lines)¶
Topic 5: Feature Flag Configuration Structure¶
What will be covered: - appsettings.json Feature Flags Section
{
"FeatureManagement": {
// Simple boolean flags
"EnableEnhancedExportFormat": true,
"EnableAdvancedSearch": false,
// Filter-based flags (conditional enablement)
"EnableIntegrityVerification": {
"EnabledFor": [
{
"Name": "Percentage",
"Parameters": {
"Value": 50
}
}
]
},
"EnableBetaFeatures": {
"EnabledFor": [
{
"Name": "TimeWindow",
"Parameters": {
"Start": "2025-11-01T00:00:00Z",
"End": "2025-12-31T23:59:59Z"
}
}
]
},
"EnableEnterpriseFeatures": {
"EnabledFor": [
{
"Name": "Edition",
"Parameters": {
"AllowedEditions": ["Enterprise"]
}
}
]
}
}
}
- Configuration Structure
- Section Name: Always
"FeatureManagement" - Boolean Flags:
"FlagName": true/false - Filter-Based Flags:
"FlagName": { "EnabledFor": [...] } -
Multiple Filters: AND logic (all must pass)
-
Environment-Specific Overrides
// appsettings.Development.json { "FeatureManagement": { "EnableBetaFeatures": true, // Always enabled in dev "EnableEnterpriseFeatures": true // Test enterprise features } } // appsettings.Production.json { "FeatureManagement": { "EnableBetaFeatures": false, // Disabled in production "EnableEnterpriseFeatures": { "EnabledFor": [ { "Name": "Edition", "Parameters": { "AllowedEditions": ["Enterprise"] } } ] } } }
Code Examples: - Complete appsettings.json FeatureManagement section - Environment-specific overrides - Filter configuration examples
Diagrams: - FeatureManagement section structure - Environment override hierarchy
Deliverables: - Configuration reference - ATP feature flags catalog - Environment override patterns
Topic 6: ATP Feature Flags Catalog¶
What will be covered: - ATP Feature Flags Registry
// ATP Feature Flag Names (constants)
public static class AuditFeatureFlags
{
// Export Features
public const string EnableEnhancedExportFormat = "EnableEnhancedExportFormat";
public const string EnableExportCompression = "EnableExportCompression";
public const string EnableExportEncryption = "EnableExportEncryption";
// Search Features
public const string EnableAdvancedSearch = "EnableAdvancedSearch";
public const string EnableFullTextSearch = "EnableFullTextSearch";
public const string EnableSemanticSearch = "EnableSemanticSearch";
// Integrity Features
public const string EnableIntegrityVerification = "EnableIntegrityVerification";
public const string EnableMerkleTreeVerification = "EnableMerkleTreeVerification";
public const string EnableTimestampAnchoring = "EnableTimestampAnchoring";
// Classification Features
public const string EnableMLClassification = "EnableMLClassification";
public const string EnableAdvancedPIIDetection = "EnableAdvancedPIIDetection";
// Storage Features
public const string EnableTieredStorage = "EnableTieredStorage";
public const string EnableArchivalToBlob = "EnableArchivalToBlob";
// Webhook Features
public const string EnableWebhookBatching = "EnableWebhookBatching";
public const string EnableWebhookCompression = "EnableWebhookCompression";
public const string EnableWebhookSignatureV2 = "EnableWebhookSignatureV2";
// Performance Features
public const string EnableRedisSecondLevelCache = "EnableRedisSecondLevelCache";
public const string EnableQueryOptimization = "EnableQueryOptimization";
public const string EnableBatchIngestion = "EnableBatchIngestion";
// Beta Features
public const string EnableBetaFeatures = "EnableBetaFeatures";
public const string EnableExperimentalFeatures = "EnableExperimentalFeatures";
// Edition Features
public const string EnableEnterpriseFeatures = "EnableEnterpriseFeatures";
public const string EnableProFeatures = "EnableProFeatures";
}
- Feature Flag Metadata
Code Examples: - Complete ATP feature flags constants - Feature flag metadata class - Feature flag documentation generator
Diagrams: - ATP feature flags map (by domain)
Deliverables: - ATP feature flags catalog (complete) - Constants class - Metadata tracking
CYCLE 4: Built-In Feature Filters (~3,500 lines)¶
Topic 7: PercentageFilter & TimeWindowFilter¶
What will be covered: - PercentageFilter
{
"FeatureManagement": {
"EnableQueryOptimization": {
"EnabledFor": [
{
"Name": "Percentage",
"Parameters": {
"Value": 25
}
}
]
}
}
}
- Behavior: Enables feature for 25% of evaluations
- Use Case: Gradual rollout, canary testing
- Consistency: Non-deterministic unless context provided
-
Progressive Rollout: 10% → 25% → 50% → 100%
-
TimeWindowFilter
-
Behavior: Enables feature during UTC time window
- Use Case: Scheduled releases, time-limited features, trials
-
Timezone: Always UTC (convert local times to UTC)
-
Combining Filters (AND logic)
-
Behavior: Enabled only if time window is active AND 50% evaluation passes
- Use Case: Time-limited gradual rollout
Code Examples: - PercentageFilter configuration and usage - TimeWindowFilter configuration - Combined filter examples - Progressive rollout timeline
Diagrams: - PercentageFilter evaluation flow - TimeWindowFilter timeline - Combined filter logic (AND)
Deliverables: - PercentageFilter guide - TimeWindowFilter guide - Progressive rollout strategy
Topic 8: TargetingFilter¶
What will be covered: - TargetingFilter Configuration
{
"FeatureManagement": {
"EnableBetaFeatures": {
"EnabledFor": [
{
"Name": "Targeting",
"Parameters": {
"Audience": {
"Users": [
"tenant:acme-corp",
"user:john@example.com"
],
"Groups": [
"beta-testers",
"early-access"
],
"DefaultRolloutPercentage": 0,
"Exclusion": {
"Users": [
"tenant:problematic-tenant"
]
}
}
}
}
]
}
}
}
-
Targeting Context
public class AuditTargetingContextAccessor : ITargetingContextAccessor { private readonly IHttpContextAccessor _httpContextAccessor; private readonly ITenantResolver _tenantResolver; public async Task<TargetingContext> GetContextAsync() { var httpContext = _httpContextAccessor.HttpContext; var tenantId = await _tenantResolver.GetTenantIdAsync(httpContext); var userId = httpContext.User.FindFirst(ClaimTypes.NameIdentifier)?.Value; var userEmail = httpContext.User.FindFirst(ClaimTypes.Email)?.Value; var groups = new List<string>(); // Add tenant as group if (!string.IsNullOrEmpty(tenantId)) { groups.Add($"tenant:{tenantId}"); } // Add edition as group var edition = await _tenantResolver.GetEditionAsync(tenantId); if (!string.IsNullOrEmpty(edition)) { groups.Add($"edition:{edition}"); } return new TargetingContext { UserId = userEmail ?? userId, Groups = groups }; } } -
Targeting Strategies
- User-Based: Enable for specific user emails
- Tenant-Based: Enable for specific tenants
- Edition-Based: Enable for specific editions (via groups)
- Percentage Fallback: Enable for N% of non-targeted users
Code Examples: - TargetingFilter configuration (all patterns) - ITargetingContextAccessor implementation - Per-tenant targeting - Per-edition targeting
Diagrams: - TargetingFilter evaluation flow - Targeting context resolution
Deliverables: - TargetingFilter guide - Targeting context implementation - Targeting strategies
CYCLE 5: Custom Feature Filters (~3,000 lines)¶
Topic 9: Custom Feature Filter Implementation¶
What will be covered: - IFeatureFilter Interface
public interface IFeatureFilter
{
Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context);
}
// Evaluation context
public class FeatureFilterEvaluationContext
{
public string FeatureName { get; }
public IConfiguration Parameters { get; }
}
-
EditionFeatureFilter (ATP Custom Filter)
[FilterAlias("Edition")] public class EditionFeatureFilter : IFeatureFilter { private readonly ITenantResolver _tenantResolver; public EditionFeatureFilter(ITenantResolver tenantResolver) { _tenantResolver = tenantResolver; } public async Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context) { // Get allowed editions from configuration var allowedEditions = context.Parameters .GetSection("AllowedEditions") .Get<string[]>() ?? Array.Empty<string>(); // Get current tenant's edition var currentEdition = await _tenantResolver.GetCurrentEditionAsync(); // Check if current edition is allowed return allowedEditions.Contains(currentEdition, StringComparer.OrdinalIgnoreCase); } } // Usage in appsettings.json { "FeatureManagement": { "EnableEnterpriseFeatures": { "EnabledFor": [ { "Name": "Edition", "Parameters": { "AllowedEditions": ["Enterprise"] } } ] } } } -
TenantFeatureFilter (Per-Tenant Control)
[FilterAlias("Tenant")] public class TenantFeatureFilter : IFeatureFilter { private readonly ITenantResolver _tenantResolver; public async Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context) { // Get allowed tenants from configuration var allowedTenants = context.Parameters .GetSection("AllowedTenants") .Get<string[]>() ?? Array.Empty<string>(); // Get current tenant ID var currentTenantId = await _tenantResolver.GetCurrentTenantIdAsync(); // Check if current tenant is allowed return allowedTenants.Contains(currentTenantId, StringComparer.OrdinalIgnoreCase); } } // Usage { "FeatureManagement": { "EnableBetaExportFormat": { "EnabledFor": [ { "Name": "Tenant", "Parameters": { "AllowedTenants": ["acme-corp", "contoso", "fabrikam"] } } ] } } } -
EnvironmentFeatureFilter
[FilterAlias("Environment")] public class EnvironmentFeatureFilter : IFeatureFilter { private readonly IHostEnvironment _environment; public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context) { var allowedEnvironments = context.Parameters .GetSection("AllowedEnvironments") .Get<string[]>() ?? Array.Empty<string>(); return Task.FromResult( allowedEnvironments.Contains( _environment.EnvironmentName, StringComparer.OrdinalIgnoreCase)); } }
Code Examples: - Complete custom filter implementations (all ATP filters) - Filter registration and configuration - Custom filter testing
Diagrams: - Custom filter evaluation flow - Filter registration pipeline
Deliverables: - Custom filter library (all ATP filters) - Filter implementation guide - Registration patterns
Topic 10: Contextual Feature Filters¶
What will be covered:
- IContextualFeatureFilter
public interface IContextualFeatureFilter<TContext>
{
Task<bool> EvaluateAsync(
FeatureFilterEvaluationContext featureContext,
TContext appContext);
}
-
Example: RequestContextFeatureFilter
[FilterAlias("RequestContext")] public class RequestContextFeatureFilter : IContextualFeatureFilter<HttpContext> { public Task<bool> EvaluateAsync( FeatureFilterEvaluationContext featureContext, HttpContext appContext) { // Enable feature only for specific request headers var requiredHeader = featureContext.Parameters["RequiredHeader"]; var requiredValue = featureContext.Parameters["RequiredValue"]; if (appContext.Request.Headers.TryGetValue(requiredHeader, out var headerValue)) { return Task.FromResult(headerValue == requiredValue); } return Task.FromResult(false); } } -
Providing Context
Code Examples: - Contextual filter implementations - Context provision patterns - Request-specific feature flags
Diagrams: - Contextual filter flow - Context resolution
Deliverables: - Contextual filter guide - ATP contextual filters - Usage patterns
CYCLE 6: Azure App Configuration Integration (~4,000 lines)¶
Topic 11: Azure App Configuration for Feature Flags¶
What will be covered: - Why Azure App Configuration for Flags? - Centralized flag management (all services, all environments) - UI for non-technical users (PMs, QA, operations) - Dynamic updates without redeployment - Version history and rollback - Label-based environment separation - Import/export capabilities - Role-based access control (RBAC)
-
Integration Setup
configurationBuilder.AddAzureAppConfiguration(options => { options.Connect(new Uri("https://appconfig-atp-prod.azconfig.io")) .ConfigureKeyVault(kv => kv.SetCredential(new DefaultAzureCredential())); // Load feature flags options.UseFeatureFlags(featureFlags => { featureFlags.Select("ConnectSoft.Audit:*", LabelFilter.Null); featureFlags.SetRefreshInterval(TimeSpan.FromMinutes(5)); featureFlags.CacheExpirationInterval = TimeSpan.FromMinutes(5); }); }); // Add feature management services services.AddFeatureManagement() .AddFeatureFilter<PercentageFilter>() .AddFeatureFilter<TimeWindowFilter>() .AddFeatureFilter<TargetingFilter>() .AddFeatureFilter<EditionFeatureFilter>() .AddFeatureFilter<TenantFeatureFilter>(); // Add middleware to refresh feature flags app.UseAzureAppConfiguration(); -
Feature Flag Naming in App Configuration
-
Label-Based Environments
- Label = environment name (dev, test, staging, prod)
- Same feature flag, different states per environment
- Application selects label based on ASPNETCORE_ENVIRONMENT
Code Examples: - Complete Azure App Configuration setup - Feature flag loading configuration - Label-based environment separation - Dynamic refresh setup
Diagrams: - Azure App Configuration architecture for feature flags - Feature flag refresh flow - Label-based environment model
Deliverables: - App Configuration integration guide - Feature flag naming standards - Environment label strategy
Topic 12: Managing Flags in Azure Portal¶
What will be covered: - Azure Portal Feature Flags UI - Create/edit/delete feature flags - Toggle flags on/off instantly - Configure filters (percentage, time window, targeting) - View flag history - Rollback to previous version
- Creating Feature Flag in Portal
- Navigate to Azure App Configuration resource
- Select "Feature manager" blade
- Click "+ Create" to add new flag
-
Provide:
- Key:
ConnectSoft.Audit:EnableNewFeature - Label:
prod(environment) - State: Enabled/Disabled
- Description: What this flag controls
- Filters: Add percentage, time window, or targeting
- Key:
-
Targeting Configuration in Portal
- Users: Add email addresses or IDs
- Groups: Add group names (e.g., "beta-testers", "tenant:acme")
- Default percentage: Fallback for non-targeted users
-
Exclusions: Explicitly exclude users/groups
-
Feature Flag Versioning
- Every change creates a new version
- View history: See who changed what and when
- Rollback: Restore previous version instantly
- Export: Download as JSON for backup/disaster recovery
Code Examples: - Azure CLI commands for flag management - ARM/Bicep templates for flag provisioning - REST API for programmatic flag updates
Diagrams: - Azure Portal feature flags UI (screenshots) - Feature flag change workflow - Versioning and rollback flow
Deliverables: - Portal management guide - CLI command reference - IaC templates for flags
CYCLE 7: Feature Flags in Code (~3,500 lines)¶
Topic 13: IFeatureManager Usage Patterns¶
What will be covered: - Basic Conditional Logic
public class ExportService
{
private readonly IFeatureManager _featureManager;
public async Task<ExportPackage> CreateExportAsync(ExportRequest request)
{
if (await _featureManager.IsEnabledAsync(AuditFeatureFlags.EnableEnhancedExportFormat))
{
return await CreateEnhancedExportAsync(request);
}
else
{
return await CreateLegacyExportAsync(request);
}
}
}
-
Early Return Pattern
-
Fallback Pattern
public async Task<SearchResults> SearchAsync(SearchQuery query) { if (await _featureManager.IsEnabledAsync(AuditFeatureFlags.EnableAdvancedSearch)) { try { return await _advancedSearchService.SearchAsync(query); } catch (Exception ex) { _logger.LogError(ex, "Advanced search failed, falling back to basic search"); return await _basicSearchService.SearchAsync(query); } } else { return await _basicSearchService.SearchAsync(query); } } -
Strategy Pattern with Feature Flags
public class ClassificationService { private readonly IFeatureManager _featureManager; private readonly IRuleBasedClassifier _ruleBasedClassifier; private readonly IMLClassifier _mlClassifier; public async Task<Classification> ClassifyAsync(AuditEvent auditEvent) { IClassifier classifier = await _featureManager.IsEnabledAsync( AuditFeatureFlags.EnableMLClassification) ? _mlClassifier : _ruleBasedClassifier; return await classifier.ClassifyAsync(auditEvent); } } -
Feature Flag Caching (IFeatureManagerSnapshot)
public class RequestProcessor { private readonly IFeatureManagerSnapshot _featureManager; public async Task ProcessAsync() { // Evaluate feature flag once at start of request var useNewLogic = await _featureManager.IsEnabledAsync("EnableNewLogic"); // Use same result throughout request (consistent behavior) await Step1Async(useNewLogic); await Step2Async(useNewLogic); await Step3Async(useNewLogic); } }
Code Examples: - Complete IFeatureManager usage patterns (all scenarios) - Fallback and error handling - Strategy pattern with flags - IFeatureManagerSnapshot for consistency
Diagrams: - Feature flag decision trees - Fallback pattern flow - Strategy pattern with flags
Deliverables: - Usage patterns catalog - Code templates - Best practices guide
Topic 14: FeatureGate Attribute & Middleware¶
What will be covered: - FeatureGate Attribute
[ApiController]
[Route("api/[controller]")]
public class AdvancedSearchController : ControllerBase
{
[HttpGet]
[FeatureGate(AuditFeatureFlags.EnableAdvancedSearch)]
public async Task<IActionResult> Search([FromQuery] SearchQuery query)
{
// Only accessible if EnableAdvancedSearch is enabled
var results = await _searchService.SearchAsync(query);
return Ok(results);
}
}
- FeatureGate Returns 404 (default)
- If feature disabled, returns
404 Not Found -
Hides feature from discovery
-
Custom Behavior
services.AddFeatureManagement() .UseDisabledFeaturesHandler(new CustomDisabledFeatureHandler()); public class CustomDisabledFeatureHandler : IDisabledFeaturesHandler { public Task HandleDisabledFeature(IEnumerable<string> features, ActionExecutingContext context) { // Return 403 Forbidden instead of 404 context.Result = new StatusCodeResult((int)HttpStatusCode.Forbidden); return Task.CompletedTask; } } -
DisabledFeatures Attribute
-
Multiple Feature Gates (AND logic)
Code Examples: - FeatureGate attribute usage (all scenarios) - Custom disabled features handler - DisabledFeatures attribute - Multiple feature gate logic
Diagrams: - FeatureGate middleware flow - Feature gate decision tree
Deliverables: - FeatureGate reference - Custom handler guide - Middleware integration
CYCLE 8: Progressive Rollout & A/B Testing (~3,500 lines)¶
Topic 15: Progressive Rollout Strategy¶
What will be covered: - Progressive Rollout Phases
Phase 1: Development (100%)
- Feature flag: ON in dev/test environments
- Goal: Internal validation
- Duration: 1-2 weeks
Phase 2: Canary (10%)
- Feature flag: 10% in production (PercentageFilter)
- Goal: Detect critical issues with small blast radius
- Duration: 2-3 days
- Metrics: Error rate, latency, resource usage
Phase 3: Expanded (50%)
- Feature flag: 50% in production
- Goal: Validate performance at scale
- Duration: 1 week
- Metrics: Same as canary + user feedback
Phase 4: Full Rollout (100%)
- Feature flag: 100% in production
- Goal: Complete migration to new feature
- Duration: 1 week
- Metrics: Confirm stability
Phase 5: Cleanup
- Remove feature flag from code
- Delete flag from App Configuration
- New code path becomes default
-
Rollout Configuration
// Week 1: Canary (10%) { "FeatureManagement": { "EnableQueryOptimization": { "EnabledFor": [ { "Name": "Percentage", "Parameters": { "Value": 10 } } ] } } } // Week 2: Expand (50%) { "FeatureManagement": { "EnableQueryOptimization": { "EnabledFor": [ { "Name": "Percentage", "Parameters": { "Value": 50 } } ] } } } // Week 3: Full rollout (100%) { "FeatureManagement": { "EnableQueryOptimization": true } } // Week 4: Cleanup (remove flag from code) -
Rollout Monitoring
- Error rate comparison (flag ON vs. OFF)
- Latency comparison (P50, P95, P99)
- Resource usage (CPU, memory, database queries)
- User feedback (support tickets, NPS scores)
- Rollback trigger: Error rate increase > 10%
Code Examples: - Progressive rollout timeline - Monitoring query examples (Application Insights) - Rollback procedure - Rollout checklist
Diagrams: - Progressive rollout timeline - Monitoring dashboard (feature flag impact) - Rollback decision tree
Deliverables: - Progressive rollout playbook - Monitoring guide - Rollback procedures
Topic 16: A/B Testing with Feature Flags¶
What will be covered: - A/B Testing Setup
public class ExportService
{
private readonly IFeatureManager _featureManager;
private readonly ITelemetryClient _telemetry;
public async Task<ExportPackage> CreateExportAsync(ExportRequest request)
{
var useVariantB = await _featureManager.IsEnabledAsync("ExportFormatVariantB");
// Track variant assignment
_telemetry.TrackEvent("ExportFormatVariant", new Dictionary<string, string>
{
["Variant"] = useVariantB ? "B" : "A",
["TenantId"] = request.TenantId,
["ExportType"] = request.ExportType
});
var result = useVariantB
? await CreateExportVariantBAsync(request)
: await CreateExportVariantAAsync(request);
// Track variant outcome
_telemetry.TrackMetric("ExportDuration", result.DurationMs, new Dictionary<string, string>
{
["Variant"] = useVariantB ? "B" : "A"
});
return result;
}
}
-
50/50 A/B Test Configuration
-
Analysis Queries (Application Insights)
// Compare variants performance customEvents | where name == "ExportFormatVariant" | extend Variant = tostring(customDimensions.Variant) | join kind=inner ( customMetrics | where name == "ExportDuration" | extend Variant = tostring(customDimensions.Variant) ) on Variant | summarize Count = count(), AvgDuration = avg(value), P50Duration = percentile(value, 50), P95Duration = percentile(value, 95) by Variant | order by Variant
Code Examples: - A/B test implementation patterns - Telemetry tracking - Analysis queries (Application Insights, Kusto) - Statistical significance testing
Diagrams: - A/B test architecture - Variant assignment flow - Analysis dashboard
Deliverables: - A/B testing guide - Telemetry patterns - Analysis query library
CYCLE 9: Multi-Tenant & Edition-Based Flags (~3,000 lines)¶
Topic 17: Per-Tenant Feature Flags¶
What will be covered: - Tenant Targeting Filter
{
"FeatureManagement": {
"EnableBetaExportFormat": {
"EnabledFor": [
{
"Name": "Tenant",
"Parameters": {
"AllowedTenants": ["acme-corp", "contoso", "fabrikam"]
}
}
]
}
}
}
-
Per-Tenant Overrides (Database or App Configuration)
// Store tenant-specific overrides in database public class TenantFeatureOverride { public string TenantId { get; set; } public string FeatureName { get; set; } public bool Enabled { get; set; } public DateTime? ExpiresAt { get; set; } } // Custom feature filter with database lookups public class TenantFeatureOverrideFilter : IFeatureFilter { private readonly ITenantFeatureOverrideRepository _repository; private readonly ITenantResolver _tenantResolver; public async Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context) { var tenantId = await _tenantResolver.GetCurrentTenantIdAsync(); var featureName = context.FeatureName; var override = await _repository.GetOverrideAsync(tenantId, featureName); if (override != null) { // Check if override expired if (override.ExpiresAt.HasValue && override.ExpiresAt.Value < DateTime.UtcNow) { return false; // Expired, fall back to default } return override.Enabled; } return false; // No override, fall back to default } } -
Tenant Feature Management API
[ApiController] [Route("api/admin/tenant-features")] [Authorize(Roles = "Administrator")] public class TenantFeatureManagementController : ControllerBase { [HttpPost("{tenantId}/features/{featureName}/enable")] public async Task<IActionResult> EnableFeature(string tenantId, string featureName) { await _tenantFeatureService.EnableFeatureAsync(tenantId, featureName); return Ok(); } [HttpPost("{tenantId}/features/{featureName}/disable")] public async Task<IActionResult> DisableFeature(string tenantId, string featureName) { await _tenantFeatureService.DisableFeatureAsync(tenantId, featureName); return Ok(); } }
Code Examples: - Per-tenant targeting configuration - Tenant override database model - Tenant feature management API - Feature flag resolution with overrides
Diagrams: - Tenant feature flag resolution flow - Override precedence - Admin management UI
Deliverables: - Per-tenant feature flag guide - Override database schema - Management API
Topic 18: Edition-Based Feature Gating¶
What will be covered: - Edition Feature Matrix
Feature | Free | Pro | Enterprise
----------------------------------|------|-----|------------
BasicAuditIngestion | ✅ | ✅ | ✅
AdvancedSearch | ❌ | ✅ | ✅
IntegrityVerification | ❌ | ❌ | ✅
CustomRetentionPolicies | ❌ | ✅ | ✅
TieredStorage | ❌ | ❌ | ✅
UnlimitedExport | ❌ | ❌ | ✅
PremiumSupport | ❌ | ❌ | ✅
-
Edition Feature Filter
[FilterAlias("Edition")] public class EditionFeatureFilter : IFeatureFilter { private readonly ITenantResolver _tenantResolver; public async Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context) { var allowedEditions = context.Parameters .GetSection("AllowedEditions") .Get<string[]>() ?? Array.Empty<string>(); var currentEdition = await _tenantResolver.GetCurrentEditionAsync(); return allowedEditions.Contains(currentEdition, StringComparer.OrdinalIgnoreCase); } } -
Configuration
-
Feature Enforcement
[FeatureGate(AuditFeatureFlags.EnableAdvancedSearch)] public async Task<IActionResult> AdvancedSearch() { // Returns 404 if tenant is on Free edition } // Or with custom response public async Task<IActionResult> AdvancedSearch() { if (!await _featureManager.IsEnabledAsync(AuditFeatureFlags.EnableAdvancedSearch)) { return StatusCode(402, new { Error = "FeatureNotAvailable", Message = "Advanced Search is available on Pro and Enterprise plans.", UpgradeUrl = "https://audit.connectsoft.io/pricing" }); } // Feature enabled, proceed }
Code Examples: - Edition feature matrix (complete) - Edition filter implementation - Edition-based configuration - Feature enforcement patterns
Diagrams: - Edition feature matrix - Edition filter evaluation - Upgrade flow
Deliverables: - Edition feature guide - Edition filter implementation - Enforcement patterns
CYCLE 10: Testing Feature Flags (~2,500 lines)¶
Topic 19: Unit Testing with Feature Flags¶
What will be covered: - Mocking IFeatureManager
[TestClass]
public class ExportServiceTests
{
[TestMethod]
public async Task Should_UseEnhancedFormat_When_FlagEnabled()
{
// Arrange
var featureManagerMock = new Mock<IFeatureManager>();
featureManagerMock
.Setup(fm => fm.IsEnabledAsync(AuditFeatureFlags.EnableEnhancedExportFormat))
.ReturnsAsync(true);
var service = new ExportService(featureManagerMock.Object, ...);
// Act
var result = await service.CreateExportAsync(new ExportRequest());
// Assert
Assert.IsInstanceOfType(result, typeof(EnhancedExportPackage));
}
[TestMethod]
public async Task Should_UseLegacyFormat_When_FlagDisabled()
{
// Arrange
var featureManagerMock = new Mock<IFeatureManager>();
featureManagerMock
.Setup(fm => fm.IsEnabledAsync(AuditFeatureFlags.EnableEnhancedExportFormat))
.ReturnsAsync(false);
var service = new ExportService(featureManagerMock.Object, ...);
// Act
var result = await service.CreateExportAsync(new ExportRequest());
// Assert
Assert.IsInstanceOfType(result, typeof(LegacyExportPackage));
}
}
- In-Memory Configuration for Tests
[TestClass] public class FeatureFlagIntegrationTests { private IConfiguration CreateTestConfiguration(bool enableFeature) { var configData = new Dictionary<string, string> { ["FeatureManagement:EnableEnhancedExportFormat"] = enableFeature.ToString() }; return new ConfigurationBuilder() .AddInMemoryCollection(configData) .Build(); } [TestMethod] public async Task Should_LoadFeaturesFromConfiguration() { // Arrange var config = CreateTestConfiguration(enableFeature: true); var services = new ServiceCollection(); services.AddSingleton<IConfiguration>(config); services.AddFeatureManagement(); var provider = services.BuildServiceProvider(); var featureManager = provider.GetRequiredService<IFeatureManager>(); // Act var isEnabled = await featureManager.IsEnabledAsync("EnableEnhancedExportFormat"); // Assert Assert.IsTrue(isEnabled); } }
Code Examples: - IFeatureManager mocking (all scenarios) - In-memory configuration setup - Test helper classes - Integration test patterns
Diagrams: - Test configuration hierarchy - Mock setup patterns
Deliverables: - Testing guide - Test helper library - Integration test patterns
Topic 20: Feature Flag Testing Strategies¶
What will be covered: - Test Matrix Strategy
Test Scenario | Flag State | Expected Behavior
---------------------------|------------|-------------------
Enhanced Export (ON) | ON | Uses enhanced format
Enhanced Export (OFF) | OFF | Uses legacy format
Advanced Search (ON) | ON | Returns advanced results
Advanced Search (OFF) | OFF | Returns basic results
Combined (Both ON) | ON + ON | Uses both features
Combined (Mixed) | ON + OFF | Uses only enabled feature
Combined (Both OFF) | OFF + OFF | Uses legacy flow
-
Parameterized Tests
[DataTestMethod] [DataRow(true, typeof(EnhancedExportPackage))] [DataRow(false, typeof(LegacyExportPackage))] public async Task Should_UseCorrectFormat_BasedOnFlag( bool flagEnabled, Type expectedType) { // Arrange var featureManagerMock = new Mock<IFeatureManager>(); featureManagerMock .Setup(fm => fm.IsEnabledAsync(AuditFeatureFlags.EnableEnhancedExportFormat)) .ReturnsAsync(flagEnabled); var service = new ExportService(featureManagerMock.Object, ...); // Act var result = await service.CreateExportAsync(new ExportRequest()); // Assert Assert.IsInstanceOfType(result, expectedType); } -
Feature Flag Test Helpers
public static class FeatureFlagTestHelpers { public static IFeatureManager CreateFeatureManager(params (string name, bool enabled)[] flags) { var mock = new Mock<IFeatureManager>(); foreach (var (name, enabled) in flags) { mock.Setup(fm => fm.IsEnabledAsync(name)).ReturnsAsync(enabled); } return mock.Object; } } // Usage var featureManager = FeatureFlagTestHelpers.CreateFeatureManager( (AuditFeatureFlags.EnableAdvancedSearch, true), (AuditFeatureFlags.EnableIntegrityVerification, false));
Code Examples: - Test matrix implementation - Parameterized tests - Test helper utilities - Acceptance test patterns
Diagrams: - Test matrix coverage - Test automation flow
Deliverables: - Testing strategy document - Test helper library - Acceptance test templates
CYCLE 11: Operational Best Practices (~3,000 lines)¶
Topic 21: Feature Flag Best Practices¶
What will be covered: - Feature Flag Best Practices - ✅ Short-Lived: Remove flags after full rollout (technical debt prevention) - ✅ Boolean-Only: Flags are on/off, not multi-valued (simplicity) - ✅ Default-Off: New features default to disabled (safe by default) - ✅ Constants for Names: Use constants, not magic strings (refactoring-safe) - ✅ Consistent Naming: Prefix with "Enable" (e.g., "EnableAdvancedSearch") - ✅ Document Ownership: Each flag has owner and removal target date - ✅ Monitor Usage: Track flag evaluations in telemetry - ✅ Test Both Paths: Test feature ON and OFF - ✅ Gradual Rollout: Progressive rollout (10% → 50% → 100%) - ✅ Cleanup Regularly: Schedule flag cleanup sprints (quarterly)
- Anti-Patterns to Avoid
- ❌ Long-Lived Flags: Flags that live forever (technical debt)
- ❌ Magic Strings:
"EnableFeature"instead of constants - ❌ Multi-Valued Flags: Flags with multiple values (use configuration)
- ❌ No Monitoring: Not tracking flag evaluations
- ❌ No Testing: Only testing feature ON path
- ❌ No Documentation: No owner or removal plan
- ❌ Nested Flags: Flags depending on other flags (complexity)
-
❌ Default-On: New features default to enabled (risky)
-
Flag Lifecycle Management
public class FeatureFlagMetadata { public string Name { get; set; } public string Description { get; set; } public string Owner { get; set; } // Team or person public DateTime IntroducedDate { get; set; } public DateTime? RemovalTargetDate { get; set; } public FeatureFlagStatus Status { get; set; } // Active, Rollout, Cleanup public string[] RequiredEditions { get; set; } } public enum FeatureFlagStatus { Active, // In use, not yet fully rolled out FullyRolledOut, // 100% enabled, candidate for cleanup Deprecated, // Marked for removal Removed // Removed from code }
Code Examples: - Best practices checklist - Anti-pattern examples - Flag metadata tracking - Cleanup automation scripts
Diagrams: - Feature flag lifecycle (with cleanup) - Best practices vs. anti-patterns
Deliverables: - Best practices handbook - Anti-pattern catalog - Lifecycle tracking system
Topic 22: Feature Flag Monitoring & Observability¶
What will be covered: - Telemetry for Feature Flags
public class FeatureFlagTelemetryFilter : IFeatureFilter
{
private readonly IFeatureFilter _innerFilter;
private readonly ITelemetryClient _telemetry;
public async Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context)
{
var stopwatch = Stopwatch.StartNew();
var result = await _innerFilter.EvaluateAsync(context);
stopwatch.Stop();
_telemetry.TrackEvent("FeatureFlagEvaluated", new Dictionary<string, string>
{
["FeatureName"] = context.FeatureName,
["FilterName"] = context.Parameters["Name"],
["Result"] = result.ToString(),
["DurationMs"] = stopwatch.ElapsedMilliseconds.ToString()
});
return result;
}
}
-
Application Insights Queries
// Feature flag evaluations by flag customEvents | where name == "FeatureFlagEvaluated" | extend FeatureName = tostring(customDimensions.FeatureName) | extend Result = tostring(customDimensions.Result) | summarize Count = count(), EnabledCount = countif(Result == "True"), DisabledCount = countif(Result == "False") by FeatureName | extend EnabledPercentage = (EnabledCount * 100.0) / Count | order by Count desc // Feature flag evaluation latency customEvents | where name == "FeatureFlagEvaluated" | extend FeatureName = tostring(customDimensions.FeatureName) | extend DurationMs = todouble(customDimensions.DurationMs) | summarize P50 = percentile(DurationMs, 50), P95 = percentile(DurationMs, 95), P99 = percentile(DurationMs, 99) by FeatureName -
Monitoring Dashboards
- Feature flag evaluation rate
- Feature flag enabled/disabled ratio
- Feature flag evaluation latency
- Feature flag errors
- Rollout progress (% enabled over time)
Code Examples: - Telemetry integration (complete) - Application Insights queries - Dashboard creation (ARM templates) - Alerting rules
Diagrams: - Feature flag telemetry flow - Monitoring dashboard (example)
Deliverables: - Monitoring guide - Query library - Dashboard templates
CYCLE 12: Troubleshooting & Monitoring (~2,500 lines)¶
Topic 23: Troubleshooting Feature Flag Issues¶
What will be covered:
- Common Problems
- Problem: Feature flag not updating
- Cause: Azure App Configuration refresh interval not expired
- Solution: Wait for refresh interval (5 minutes) or restart application
- Debug: Check UseAzureAppConfiguration() middleware registered
-
Problem: Feature flag returns wrong value
- Cause: Stale cached value (IOptions
instead of IOptionsSnapshot ) - Solution: Use IFeatureManagerSnapshot for per-request consistency
- Debug: Log flag evaluation result and timestamp
- Cause: Stale cached value (IOptions
-
Problem: Targeting filter not working
- Cause: ITargetingContextAccessor not registered or returns null
- Solution: Register ITargetingContextAccessor in DI
- Debug: Log targeting context values
-
Problem: Custom filter not evaluating
- Cause: Filter not registered with AddFeatureFilter<>()
- Solution: Add filter to feature management registration
- Debug: Check DI container registration
-
Debugging Feature Flags
public class FeatureFlagDebugService { private readonly IFeatureManager _featureManager; public async Task LogAllFeatureFlags() { await foreach (var featureName in _featureManager.GetFeatureNamesAsync()) { var isEnabled = await _featureManager.IsEnabledAsync(featureName); _logger.LogInformation("Feature {FeatureName} = {IsEnabled}", featureName, isEnabled); } } } -
Enable Verbose Logging
Code Examples: - Debugging utilities (complete) - Verbose logging configuration - Troubleshooting scripts - Health check integration
Diagrams: - Troubleshooting decision tree - Debugging flow
Deliverables: - Troubleshooting guide - Common problems catalog - Debugging utilities
Topic 24: Feature Flag Cleanup¶
What will be covered: - When to Remove Feature Flags - Flag is enabled for 100% of users for 2+ weeks - No rollback concerns - Feature is stable and working as expected - Legacy code path no longer needed
- Cleanup Process
- Verify Full Rollout: Confirm flag is 100% enabled in production
- Remove Conditional Logic: Replace
if (feature enabled)with direct call - Delete Legacy Code Path: Remove else branch and old implementation
- Remove Flag Configuration: Delete from appsettings.json and App Configuration
- Remove Flag Constant: Delete from AuditFeatureFlags class
- Update Tests: Remove feature flag mocking, test only new path
-
Update Documentation: Remove flag from documentation
-
Cleanup Example
// BEFORE (with feature flag) public async Task<ExportPackage> CreateExportAsync(ExportRequest request) { if (await _featureManager.IsEnabledAsync(AuditFeatureFlags.EnableEnhancedExportFormat)) { return await CreateEnhancedExportAsync(request); } else { return await CreateLegacyExportAsync(request); } } // AFTER (cleanup) public async Task<ExportPackage> CreateExportAsync(ExportRequest request) { return await CreateEnhancedExportAsync(request); } -
Automated Cleanup Detection
// Script to find flags enabled 100% for > 2 weeks var flagsForCleanup = await _flagMetadataRepo .Where(f => f.Status == FeatureFlagStatus.FullyRolledOut) .Where(f => f.RolloutCompletedDate < DateTime.UtcNow.AddDays(-14)) .ToListAsync(); foreach (var flag in flagsForCleanup) { _logger.LogInformation("Flag {FlagName} ready for cleanup", flag.Name); }
Code Examples: - Cleanup process (step-by-step) - Before/after code examples - Automated cleanup detection - Cleanup checklist
Diagrams: - Cleanup workflow - Cleanup timeline
Deliverables: - Cleanup playbook - Automation scripts - Cleanup checklist
Summary of Deliverables¶
Across all 12 cycles, this documentation will provide:
- Philosophy & Architecture
- Feature flag philosophy and principles
- ATP feature flag architecture
-
Microsoft.FeatureManagement fundamentals
-
Configuration
- appsettings.json structure
- ATP feature flags catalog (complete)
-
Environment-specific overrides
-
Filters
- Built-in filters (Percentage, TimeWindow, Targeting)
- Custom ATP filters (Edition, Tenant, Environment)
-
Contextual filters
-
Azure App Configuration
- Integration setup and configuration
- Portal management guide
-
Dynamic refresh and versioning
-
Code Usage
- IFeatureManager patterns (all scenarios)
- FeatureGate attribute and middleware
-
Fallback and strategy patterns
-
Rollout Strategies
- Progressive rollout playbook
- A/B testing patterns
-
Monitoring and rollback procedures
-
Multi-Tenant Control
- Per-tenant feature flags
- Edition-based feature gating
-
Feature enforcement patterns
-
Testing
- Unit testing with mocks
- Integration testing with in-memory configuration
-
Test matrix and parameterized tests
-
Operations
- Best practices and anti-patterns
- Monitoring and observability
-
Telemetry integration
-
Troubleshooting & Cleanup
- Common problems and solutions
- Debugging utilities
- Cleanup playbook and automation
Related Documentation¶
- Configuration Reference: Feature flag configuration in appsettings.json and App Configuration
- Azure Pipelines: Feature flag deployment in CI/CD
- Environments: Environment-specific feature flag configuration
- Testing Strategy: Feature flag testing patterns
- Observability: Feature flag monitoring and telemetry
- A/B Testing Guide: A/B testing with feature flags (detailed)
- Progressive Rollout: Rollout strategies and procedures
This documentation plan covers complete feature flag management for ATP, from philosophy and implementation with Microsoft.FeatureManagement to Azure App Configuration integration, progressive rollouts, A/B testing, multi-tenant control, testing strategies, and operational best practices for safe, controlled feature deployment.