Dashboard¶
Flaggy includes a beautiful, easy-to-use web dashboard for managing your feature flags. The dashboard provides a complete UI for creating, updating, and monitoring flags without writing any code.
Overview¶
The Flaggy dashboard offers:
- Clean, modern web interface
- Real-time flag management
- User authentication with secure password hashing
- User management interface
- No external dependencies (embedded UI)
- Customizable route prefix
- Optional authorization filters
- RESTful API for programmatic access
Quick Start¶
Installation¶
The dashboard is included in the core Flaggy package:
dotnet add package Flaggy
Basic Setup¶
using Flaggy.Extensions;
using Flaggy.Providers;
using Flaggy.UI.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Add Flaggy with a provider
builder.Services.AddFlaggy(new InMemoryFeatureFlagProvider());
var app = builder.Build();
// Enable the dashboard
app.UseFlaggyUI();
app.Run();
Navigate to https://localhost:5001/flaggy to access the dashboard.
Configuration¶
Custom Route Prefix¶
Change the dashboard URL:
app.UseFlaggyUI(options =>
{
options.RoutePrefix = "/admin/flags";
});
Access at: https://localhost:5001/admin/flags
Disable Authentication¶
For development or internal tools:
app.UseFlaggyUI(options =>
{
options.EnableAuthentication = false;
});
Warning: Only disable authentication in trusted environments.
Custom Authorization¶
Add custom authorization logic:
app.UseFlaggyUI(options =>
{
options.RoutePrefix = "/admin/flags";
options.RequireAuthorization = true;
options.AuthorizationFilter = context =>
{
// Custom authorization logic
return context.User.IsInRole("Admin") || context.User.IsInRole("FlagManager");
};
});
Complete Configuration Example¶
using Flaggy.Extensions;
using Flaggy.UI.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Configure Flaggy with MySQL
builder.Services.AddFlaggy(options =>
{
options.UseMySQL(
connectionString: builder.Configuration.GetConnectionString("FlaggyDb"
);
})
);
var app = builder.Build();
// Configure dashboard
app.UseFlaggyUI(options =>
{
options.RoutePrefix = "/admin/feature-flags";
options.EnableAuthentication = true;
options.RequireAuthorization = true;
options.AuthorizationFilter = context =>
{
// Allow admins and developers
return context.User.IsInRole("Admin") ||
context.User.IsInRole("Developer");
};
});
app.Run();
Dashboard Features¶
Flag Management¶
The main dashboard provides a comprehensive flag management interface:
View All Flags¶
- List all feature flags
- See enabled/disabled status at a glance
- View flag values and descriptions
- Filter and search flags
- Sort by name, status, or update time
Create New Flag¶
Create a new flag with: - Key: Unique identifier (e.g., "new-dashboard", "beta-features") - Enabled: Toggle on/off - Value: Optional typed value (string, int, double, etc.) - description: Human-readable description
Example:
Key: premium-features
Enabled: ✓ Yes
Value: tier-1,tier-2,tier-3
description: Premium features for paid users
Update Existing Flag¶
Modify flags in real-time: - Toggle enabled/disabled status - Update values - Change descriptions - See last updated timestamp
Delete Flag¶
Remove flags that are no longer needed with confirmation dialog.
User Management¶
The dashboard includes a full user management interface (accessible via /flaggy/users):
View All Users¶
- List all dashboard users
- See usernames and email addresses
- View creation dates
- Manage user access
Create New User¶
Add users with: - username: Unique username - Password: Securely hashed with BCrypt - email: Optional email address
Update User¶
- Change password
- Update email address
- Modify user details
Delete User¶
Remove users with confirmation.
Authentication¶
The dashboard uses secure cookie-based authentication:
- BCrypt password hashing (work factor 12)
- Secure session cookies
- Auto-logout on session expiration
- Database-backed user storage
Default credentials (if no users exist): - username: admin - Password: admin
Important: Change default credentials immediately in production!
API Endpoints¶
The dashboard exposes RESTful API endpoints for programmatic access.
Authentication Endpoints¶
Login¶
POST /flaggy/api/auth/login
Content-Type: application/json
{
"username": "admin",
"password": "admin"
}
Response: Sets authentication cookie.
Logout¶
POST /flaggy/api/auth/logout
Response: Clears authentication cookie.
Flag Endpoints¶
Get All Flags¶
GET /flaggy/api/flags
Response:
[
{
"key": "new-feature",
"isEnabled": true,
"value": "v2",
"description": "New feature flag",
"createdAt": "2025-01-15T10:30:00Z",
"updatedAt": "2025-01-15T12:45:00Z"
}
]
Get Single Flag¶
GET /flaggy/api/flags/{key}
Response:
{
"key": "new-feature",
"isEnabled": true,
"value": "v2",
"description": "New feature flag",
"createdAt": "2025-01-15T10:30:00Z",
"updatedAt": "2025-01-15T12:45:00Z"
}
Create Flag¶
POST /flaggy/api/flags
Content-Type: application/json
{
"key": "new-feature",
"isEnabled": true,
"value": "beta",
"description": "New feature in beta"
}
Update Flag¶
PUT /flaggy/api/flags/{key}
Content-Type: application/json
{
"key": "new-feature",
"isEnabled": false,
"value": "v1",
"description": "Updated description"
}
Delete Flag¶
DELETE /flaggy/api/flags/{key}
User Endpoints¶
Get All Users¶
GET /flaggy/api/users
Response:
[
{
"username": "admin",
"email": "admin@example.com",
"createdAt": "2025-01-01T10:00:00Z"
}
]
Create User¶
POST /flaggy/api/users
Content-Type: application/json
{
"username": "developer",
"password": "secure-password",
"email": "dev@example.com"
}
Update User¶
PUT /flaggy/api/users/{username}
Content-Type: application/json
{
"username": "developer",
"password": "new-password",
"email": "developer@example.com"
}
Delete User¶
DELETE /flaggy/api/users/{username}
Usage Examples¶
Example 1: Development Setup¶
Simple setup for local development:
using Flaggy.Extensions;
using Flaggy.Providers;
using Flaggy.UI.Extensions;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddFlaggy(new InMemoryFeatureFlagProvider());
var app = builder.Build();
// Simple dashboard at /flaggy
app.UseFlaggyUI();
app.Run();
Example 2: Production Setup with MySQL¶
Production setup with MySQL and custom route:
using Flaggy.Extensions;
using Flaggy.UI.Extensions;
var builder = WebApplication.CreateBuilder(args);
// MySQL provider
builder.Services.AddFlaggy(options =>
{
options.UseMySQL(
connectionString: builder.Configuration.GetConnectionString("FlaggyDb"
);
}),
cacheExpiration: TimeSpan.FromMinutes(10)
);
var app = builder.Build();
// Dashboard at custom route
app.UseFlaggyUI(options =>
{
options.RoutePrefix = "/internal/feature-flags";
options.EnableAuthentication = true;
});
app.Run();
Example 3: Multi-Tenant with Authorization¶
Multi-tenant setup with role-based authorization:
using Flaggy.Extensions;
using Flaggy.UI.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Add authentication
builder.Services.AddAuthentication(/* your auth config */);
builder.Services.AddAuthorization();
// PostgreSQL provider
builder.Services.AddFlaggy(options =>
{
options.UsePostgreSQL(
connectionString: builder.Configuration.GetConnectionString("FlaggyDb"
);
})
);
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
// Dashboard with custom authorization
app.UseFlaggyUI(options =>
{
options.RoutePrefix = "/admin/flags";
options.RequireAuthorization = true;
options.AuthorizationFilter = context =>
{
// Check user role and tenant
var tenantId = context.User.FindFirst("TenantId")?.Value;
return context.User.IsInRole("Admin") && tenantId == "tenant-123";
};
});
app.Run();
Example 4: API-Only Mode¶
Use API endpoints without the UI:
using Flaggy.Extensions;
using Flaggy.Providers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddFlaggy(new InMemoryFeatureFlagProvider());
var app = builder.Build();
// Custom API endpoints (no dashboard UI)
app.MapGet("/api/flags", async (IFeatureFlagService flagService) =>
{
var flags = await flagService.GetAllFlagsAsync();
return Results.Ok(flags);
});
app.MapPost("/api/flags", async (FeatureFlag flag, IFeatureFlagService flagService) =>
{
var created = await flagService.CreateFlagAsync(flag);
return created ? Results.Created($"/api/flags/{flag.Key}", flag) : Results.BadRequest();
});
app.Run();
Security Best Practices¶
1. Change Default Credentials¶
Always create a new admin user and remove defaults:
// After first login, create a new admin user through the UI
// Then delete the default admin user
2. Use Strong Passwords¶
Flaggy uses BCrypt with work factor 12 for secure password hashing:
// Passwords are automatically hashed
// Minimum recommended: 12 characters, mixed case, numbers, symbols
3. Enable HTTPS¶
Always use HTTPS in production:
var builder = WebApplication.CreateBuilder(args);
// Force HTTPS
builder.Services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
options.HttpsPort = 443;
});
var app = builder.Build();
app.UseHttpsRedirection();
4. Restrict Dashboard Access¶
Use custom authorization filters:
app.UseFlaggyUI(options =>
{
options.AuthorizationFilter = context =>
{
// Restrict to specific IP range
var remoteIp = context.Connection.RemoteIpAddress?.ToString();
return remoteIp?.StartsWith("10.0.") ?? false;
};
});
5. Use Environment Variables¶
Store sensitive configuration in environment variables:
// appsettings.json
{
"ConnectionStrings": {
"FlaggyDb": "${FLAGGY_DB_CONNECTION}"
}
}
// Set environment variable
// export FLAGGY_DB_CONNECTION="Server=...;Password=...;"
Troubleshooting¶
Dashboard Not Loading¶
Problem: Dashboard returns 404 or blank page.
Solution: Ensure UseFlaggyUI() is called after Build():
var app = builder.Build();
// This must come after Build()
app.UseFlaggyUI();
app.Run();
Authentication Loop¶
Problem: Login page redirects indefinitely.
Solution: Check cookie settings and HTTPS configuration:
// Enable cookie support
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession();
var app = builder.Build();
app.UseSession();
app.UseFlaggyUI();
Cannot Create Users¶
Problem: User creation fails silently.
Solution: Verify database provider supports user management:
// Ensure user table exists (auto-migration enabled)
builder.Services.AddFlaggy(options =>
{
options.UseMySQL(
connectionString: connectionString,
autoMigrate: true // Creates user table
);
});
Custom Route Not Working¶
Problem: Dashboard not accessible at custom route.
Solution: Check for routing conflicts:
// Dashboard route must be unique
app.UseFlaggyUI(options =>
{
options.RoutePrefix = "/admin/flags"; // Ensure no conflicts
});
// Check routing order
app.MapControllers(); // Application routes
app.UseFlaggyUI(); // Dashboard routes
Best Practices¶
1. Use Custom Route in Production¶
// Don't use default /flaggy in production
app.UseFlaggyUI(options =>
{
options.RoutePrefix = "/internal/admin/feature-management";
});
2. Enable Authentication¶
// Always enable authentication in production
app.UseFlaggyUI(options =>
{
options.EnableAuthentication = true;
});
3. Combine with Custom Authorization¶
// Add additional security layers
app.UseFlaggyUI(options =>
{
options.EnableAuthentication = true;
options.RequireAuthorization = true;
options.AuthorizationFilter = context =>
{
// Multiple checks
return context.User.Identity?.IsAuthenticated == true &&
context.User.IsInRole("Admin") &&
IsAllowedIpAddress(context.Connection.RemoteIpAddress);
};
});
4. Monitor Dashboard Access¶
// Log dashboard access
app.Use(async (context, next) =>
{
if (context.Request.Path.StartsWithSegments("/flaggy"))
{
var logger = context.RequestServices.GetRequiredService<ILogger<Program>>();
logger.LogInformation(
"Dashboard access: {User} from {IP}",
context.User.Identity?.Name ?? "Anonymous",
context.Connection.RemoteIpAddress
);
}
await next();
});
app.UseFlaggyUI();
5. Regular Security Audits¶
- Review user accounts regularly
- Remove unused users
- Update passwords periodically
- Monitor login attempts
- Check authorization rules
Performance Considerations¶
1. Caching¶
The dashboard benefits from caching:
// Use Redis for better dashboard performance
builder.Services.AddFlaggy(
provider: new InMemoryFeatureFlagProvider(),
cachingProvider: CachingProvider.Redis,
redisConnectionString: "localhost:6379"
);
2. Connection Pooling¶
Enable connection pooling for database providers:
builder.Services.AddFlaggy(options =>
{
options.UseMySQL(
connectionString: "Server=localhost;Database=myapp;User=root;Password=pass;Pooling=true;MinimumPoolSize=5;MaximumPoolSize=20;"
);
});
3. Load Testing¶
Test dashboard under load:
# Using Apache Bench
ab -n 1000 -c 10 https://localhost:5001/flaggy/
# Using wrk
wrk -t4 -c100 -d30s https://localhost:5001/flaggy/
Related Topics¶
- User Management - Managing dashboard users
- Programmatic API - Managing flags without the UI
- Caching - Optimizing dashboard performance
- Providers - Configuring storage backends