Skip to content

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/