Files
gridpilot.gg/docs/FEATURE_ARCHITECTURE.md
2026-01-07 16:20:19 +01:00

225 lines
6.4 KiB
Markdown

# Feature Architecture: Modes vs Feature Flags
## The Problem
Your current system has two overlapping concepts that conflict:
- **Feature Flags** (`features.config.ts`) - Controls individual features
- **App Modes** (`NEXT_PUBLIC_GRIDPILOT_MODE`) - Controls overall platform visibility
This creates confusion because:
1. Development shows only landing page but feature config says everything is enabled
2. It's unclear which system controls what
3. Teams don't know when to use mode vs feature flag
## The Solution: Clear Separation
### **Two-Tier System**
```
┌─────────────────────────────────────────┐
│ APP MODE (Tier 1) │
│ Controls WHAT the platform shows │
│ - pre-launch: Landing page only │
│ - alpha: Full platform access │
│ - beta: Production-ready features │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ FEATURE FLAGS (Tier 2) │
│ Controls WHICH features are enabled │
│ - Individual feature toggles │
│ - Rollout control │
│ - A/B testing │
└─────────────────────────────────────────┘
```
### **Mode = Platform Scope**
**App Mode defines what the entire platform can do:**
- **`pre-launch`**: "We're not ready yet"
- Shows: Landing page, Discord CTA, FAQ
- Hides: All navigation, dashboard, leagues, teams, races
- Purpose: Marketing/teaser phase
- **`alpha`**: "Early access for testers"
- Shows: Everything + alpha badges
- Purpose: Internal testing, early adopters
- All features enabled by default
- **`beta`**: "Public beta"
- Shows: Production features only
- Purpose: Gradual rollout to real users
- Features controlled individually
### **Feature Flags = Feature Control**
**Feature flags control individual features within a mode:**
```typescript
// In alpha mode, all features are ON by default
// But you can still disable specific ones for testing
{
"platform.dashboard": "enabled",
"platform.leagues": "enabled",
"platform.teams": "disabled", // Testing without teams
"sponsors.portal": "enabled",
"admin.dashboard": "enabled"
}
```
## Simple Mental Model
### **For Developers: "The Restaurant Analogy"**
```
APP MODE = Restaurant State
├── "Closed" (pre-launch) → Only show entrance/menu
├── "Soft Opening" (alpha) → Full menu, everything available
└── "Grand Opening" (beta) → Full menu, but some items may be 86'd
FEATURE FLAGS = Menu Items
├── Each dish can be: Available / 86'd / Coming Soon
├── Works within whatever restaurant state you're in
└── Lets you control individual items precisely
```
### **Decision Tree**
```
Question: "What should I use?"
├─ "Is the platform ready for ANY users?"
│ ├─ No → Use APP MODE = pre-launch
│ └─ Yes → Continue...
├─ "Are we in testing or production?"
│ ├─ Testing → Use APP MODE = alpha
│ └─ Production → Use APP MODE = beta
└─ "Do I need to control a specific feature?"
└─ Yes → Use FEATURE FLAGS (regardless of mode)
```
## Implementation Rules
### **Rule 1: Mode Controls Visibility**
```typescript
// ❌ WRONG: Using feature flags to hide entire platform
{
"platform": {
"dashboard": "disabled",
"leagues": "disabled",
"teams": "disabled"
}
}
// ✅ CORRECT: Use mode for platform-wide visibility
// NEXT_PUBLIC_GRIDPILOT_MODE=pre-launch
```
### **Rule 2: Feature Flags Control Granularity**
```typescript
// ✅ CORRECT: Feature flags for fine-grained control
{
"platform": {
"dashboard": "enabled",
"leagues": "enabled",
"teams": "enabled", // But specific team features...
"teams.create": "disabled", // ...can be toggled
"teams.delete": "coming_soon"
}
}
```
### **Rule 3: Alpha Mode = Auto-Enable**
```typescript
// In alpha mode, ALL features are enabled automatically
// Feature flags can only DISABLE, not enable
// This eliminates configuration complexity
// Feature flag service in alpha mode:
if (mode === 'alpha') {
return new FeatureFlagService([
'all', 'features', 'enabled', 'by', 'default'
]);
}
```
## Migration Path
### **Current State (Confusing)**
```
Development:
- Mode: pre-launch (default)
- Features: All enabled in config
- Result: Shows landing page only ❌
Why? Because mode overrides feature config
```
### **Target State (Clear)**
```
Development:
- Mode: alpha (explicit)
- Features: All auto-enabled
- Result: Full platform with alpha badges ✅
Production:
- Mode: beta
- Features: Controlled individually
- Result: Gradual rollout ✅
```
## Configuration Examples
### **Simple Mode Config**
```typescript
// apps/website/.env.development
NEXT_PUBLIC_GRIDPILOT_MODE=alpha
// apps/website/.env.production
NEXT_PUBLIC_GRIDPILOT_MODE=beta
```
### **Feature Flags (Only When Needed)**
```typescript
// Only override defaults when necessary
// apps/api/src/config/features.config.ts
{
production: {
platform: {
dashboard: 'enabled',
leagues: 'enabled',
teams: 'enabled',
races: 'enabled',
leaderboards: 'enabled'
},
sponsors: {
portal: 'enabled',
dashboard: 'enabled',
management: 'disabled' // Not ready yet
}
}
}
```
## Benefits
1. **No Confusion**: Clear separation of concerns
2. **Less Config**: Alpha mode needs zero feature config
3. **Easy Onboarding**: New devs just set mode=alpha
4. **Powerful Control**: Feature flags still available when needed
5. **Backward Compatible**: Existing code works with new concept
## Quick Reference
| Scenario | Mode | Feature Flags | Result |
|----------|------|---------------|--------|
| Local dev | `alpha` | None needed | Full platform |
| CI/CD tests | `alpha` | None needed | Full platform |
| Staging | `beta` | Some disabled | Controlled rollout |
| Production | `beta` | Gradual enable | Public launch |
| Marketing site | `pre-launch` | N/A | Landing page only |
This eliminates the contradiction and gives you clear power: **Mode for scope, flags for granularity.**