template-saas/docs/01-modulos/SAAS-009-feature-flags.md
rckrdmrd 4dafffa386 feat: Add superadmin metrics, onboarding and module documentation
- Add MetricsPage and useOnboarding hook
- Update superadmin controller and service
- Add module documentation (docs/01-modulos/)
- Add CONTEXT-MAP.yml and Sprint 5 execution report
- Update project status and task traces

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 05:40:26 -06:00

226 lines
5.1 KiB
Markdown

# SAAS-009: Feature Flags
## Metadata
- **Codigo:** SAAS-009
- **Modulo:** Feature Flags
- **Prioridad:** P2
- **Estado:** Pendiente
- **Fase:** 4 - Advanced
## Descripcion
Sistema de feature flags para control granular de funcionalidades: flags globales, por tenant, por usuario, con porcentaje de rollout y A/B testing basico.
## Objetivos
1. Flags globales (sistema)
2. Flags por tenant
3. Flags por usuario
4. Porcentaje de rollout
5. A/B testing basico
## Alcance
### Incluido
- Feature flags booleanos
- Flags con valores (string/number)
- Override por tenant
- Override por usuario
- Rollout gradual (%)
- UI de administracion
### Excluido
- A/B testing avanzado - usar servicio dedicado
- Analytics de experimentos
- Machine learning para targeting
## Modelo de Datos
### Tablas (schema: features)
**feature_flags**
- id, key (unique), name, description
- type (boolean/string/number/json)
- default_value, is_enabled
- rollout_percentage (0-100)
- targeting_rules (JSONB)
- created_at, updated_at
**tenant_feature_overrides**
- id, tenant_id, feature_key
- value, enabled
- expires_at
**user_feature_overrides**
- id, user_id, feature_key
- value, enabled
- expires_at
## Flags Predefinidos
| Key | Tipo | Default | Descripcion |
|-----|------|---------|-------------|
| new_dashboard | boolean | false | Nuevo dashboard beta |
| ai_assistant | boolean | false | Asistente IA |
| export_v2 | boolean | false | Nueva exportacion |
| max_file_size_mb | number | 10 | Limite archivo |
| theme | string | 'light' | Tema default |
## Endpoints API
| Metodo | Endpoint | Descripcion |
|--------|----------|-------------|
| GET | /features | Listar flags |
| GET | /features/:key | Obtener flag |
| POST | /features | Crear flag |
| PUT | /features/:key | Actualizar flag |
| DELETE | /features/:key | Eliminar flag |
| GET | /features/evaluate | Evaluar todos para usuario |
| POST | /features/:key/override/tenant | Override tenant |
| POST | /features/:key/override/user | Override usuario |
| DELETE | /features/:key/override/tenant | Quitar override |
## Implementacion
### Servicio
```typescript
interface FeatureFlagService {
isEnabled(key: string, context?: EvaluationContext): Promise<boolean>;
getValue<T>(key: string, context?: EvaluationContext): Promise<T>;
getAllFlags(context?: EvaluationContext): Promise<Record<string, any>>;
}
interface EvaluationContext {
tenantId?: string;
userId?: string;
attributes?: Record<string, any>;
}
```
### Guard
```typescript
@RequiresFeature('new_dashboard')
@Get('/dashboard/v2')
async getNewDashboard() {
// Solo si feature habilitada
}
```
### Condicional en Codigo
```typescript
if (await this.features.isEnabled('ai_assistant')) {
// Mostrar boton de IA
}
const maxSize = await this.features.getValue<number>('max_file_size_mb');
```
## Logica de Evaluacion
```
1. Usuario solicita feature
2. Buscar override de usuario
3. Si existe, usar ese valor
4. Si no, buscar override de tenant
5. Si existe, usar ese valor
6. Si no, evaluar rollout %
7. Si pasa rollout, usar default_value
8. Si no pasa, feature deshabilitada
```
### Rollout Deterministico
```typescript
// Mismo usuario siempre obtiene mismo resultado
function shouldEnableForUser(userId: string, percentage: number): boolean {
const hash = crypto.createHash('md5').update(userId).digest('hex');
const value = parseInt(hash.substring(0, 8), 16) % 100;
return value < percentage;
}
```
## Targeting Rules
```typescript
// Ejemplo de reglas avanzadas
{
"rules": [
{
"condition": "plan",
"operator": "in",
"values": ["pro", "enterprise"],
"enabled": true
},
{
"condition": "country",
"operator": "equals",
"values": ["MX"],
"enabled": true
}
]
}
```
## Frontend SDK
```typescript
// React hook
function useFeatureFlag(key: string): boolean {
const { flags } = useFeatureFlags();
return flags[key] ?? false;
}
// Componente
function Dashboard() {
const showNewDashboard = useFeatureFlag('new_dashboard');
return showNewDashboard ? <NewDashboard /> : <OldDashboard />;
}
```
## Entregables
| Entregable | Estado | Archivo |
|------------|--------|---------|
| features.module.ts | Pendiente | `modules/features/` |
| feature-flag.service.ts | Pendiente | `services/` |
| feature.guard.ts | Pendiente | `guards/` |
| DDL features schema | Pendiente | `ddl/schemas/features/` |
| Seeds flags default | Pendiente | `seeds/prod/features/` |
## Dependencias
### Depende de
- SAAS-001 (Auth)
- SAAS-002 (Tenants)
- SAAS-003 (Users)
### Bloquea a
- Rollouts graduales
- Experimentos de producto
## Criterios de Aceptacion
- [ ] Flags booleanos funcionan
- [ ] Override por tenant funciona
- [ ] Override por usuario funciona
- [ ] Rollout % es deterministico
- [ ] UI admin permite gestion
- [ ] Cache funciona correctamente
## Caching
```typescript
// Redis cache con invalidacion
const cacheKey = `features:${tenantId}:${userId}`;
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached);
const flags = await this.evaluateAllFlags(context);
await redis.setex(cacheKey, 300, JSON.stringify(flags)); // 5 min
return flags;
```
---
**Ultima actualizacion:** 2026-01-07