# Feature Flags Dinámicos

**Versión:** 1.0.0
**Origen:** projects/gamilit
**Estado:** Producción
**Última actualización:** 2025-12-08

---

## Descripción

Sistema de feature flags para activación gradual de funcionalidades:
- Activar/desactivar features sin redespliegue
- Rollout gradual por porcentaje de usuarios
- Target por usuarios específicos o roles
- Condiciones personalizadas via JSONB
- Período de validez (starts_at/ends_at)
- Multi-tenant opcional

---

## Características

| Característica | Descripción |
|----------------|-------------|
| Toggle dinámico | On/off sin redespliegue |
| Rollout gradual | 0-100% con hash consistente |
| Target users | Early access para usuarios específicos |
| Target roles | Habilitar por rol (admin, user, etc.) |
| Condiciones | Reglas personalizadas vía JSONB |
| Período | Fecha inicio/fin automático |
| Multi-tenant | Flags globales o por tenant |
| Auditoría | Tracking de quién creó/modificó |

---

## Stack Tecnológico

```yaml
backend:
  framework: NestJS
  orm: TypeORM
  database: PostgreSQL

algoritmos:
  - SHA256 hash para rollout consistente
  - Determinístico por userId + featureKey
```

---

## Dependencias NPM

```json
{
  "typeorm": "^0.3.x",
  "@nestjs/typeorm": "^10.x"
}
```

**Nota:** No requiere librerías externas de feature flags (LaunchDarkly, Unleash, etc.)

---

## Tablas Requeridas

| Tabla | Propósito |
|-------|-----------|
| system_configuration.feature_flags | Configuración de flags |

---

## Estructura del Módulo

```
feature-flags/
├── entities/
│   └── feature-flag.entity.ts
├── services/
│   └── feature-flags.service.ts
├── controllers/
│   └── feature-flags.controller.ts
├── dto/
│   ├── create-feature-flag.dto.ts
│   ├── update-feature-flag.dto.ts
│   └── feature-flag-query.dto.ts
├── decorators/
│   └── feature-flag.decorator.ts     # @FeatureFlag('key')
└── guards/
    └── feature-flag.guard.ts
```

---

## Modelo de Datos

### FeatureFlag

```typescript
interface FeatureFlag {
  id: string;                          // UUID
  tenant_id?: string;                  // null = global
  feature_key: string;                 // "new_checkout" (único)
  feature_name: string;                // "Nuevo Checkout v2"
  description?: string;
  is_enabled: boolean;                 // Toggle principal
  rollout_percentage: number;          // 0-100
  target_users?: string[];             // UUIDs con early access
  target_roles?: string[];             // ['admin', 'beta_tester']
  target_conditions: Record<string, any>;  // { min_level: 5 }
  starts_at?: Date;                    // Fecha inicio
  ends_at?: Date;                      // Fecha fin
  metadata: Record<string, any>;       // { category: 'checkout' }
  created_by?: string;
  updated_by?: string;
  created_at: Date;
  updated_at: Date;
}
```

---

## Flujo de Evaluación

```
isEnabled(key, userId, userRoles)?
        │
        ▼
1. Feature habilitada globalmente?
   └─► NO → return false
        │
        ▼
2. Usuario en target_users?
   └─► SÍ → return true (early access)
        │
        ▼
3. Usuario tiene target_role?
   └─► SÍ → return true
        │
        ▼
4. rollout_percentage == 100?
   └─► SÍ → return true
        │
        ▼
5. rollout_percentage == 0?
   └─► SÍ → return false
        │
        ▼
6. Hash(userId + key) < rollout_percentage?
   └─► SÍ → return true
   └─► NO → return false
```

---

## Uso Rápido

### 1. Verificar feature programáticamente

```typescript
import { FeatureFlagsService } from '@/modules/feature-flags/services';

// En un servicio
const result = await featureFlagsService.isEnabled(
  'new_checkout',    // feature key
  userId,            // opcional
  userRoles,         // opcional: ['admin', 'user']
);

if (result.enabled) {
  // Usar nueva funcionalidad
} else {
  // Usar funcionalidad legacy
}
```

### 2. Guard para proteger rutas

```typescript
// Proteger endpoint completo
@Get('beta-feature')
@UseGuards(JwtAuthGuard, FeatureFlagGuard)
@FeatureFlag('beta_feature')
async betaFeature() {
  return { message: 'Solo para usuarios con feature habilitada' };
}
```

### 3. Decorador para check inline

```typescript
@Get('dashboard')
async getDashboard(
  @CurrentUser() user: User,
  @CheckFeature('new_dashboard') hasNewDashboard: boolean,
) {
  if (hasNewDashboard) {
    return this.newDashboardService.getData(user.id);
  }
  return this.legacyDashboardService.getData(user.id);
}
```

### 4. En frontend (API call)

```typescript
// GET /api/feature-flags/check/new_checkout
const response = await api.get(`/feature-flags/check/${featureKey}`, {
  params: { userId },
});

if (response.data.enabled) {
  showNewCheckout();
} else {
  showLegacyCheckout();
}
```

---

## Rollout Gradual

El rollout usa un hash SHA256 del `userId + featureKey` para determinar si un usuario está en el porcentaje:

```typescript
// Algoritmo de hash consistente
private hashUserId(userId: string, featureKey: string): number {
  const hash = createHash('sha256')
    .update(`${userId}:${featureKey}`)
    .digest('hex');

  const hashInt = parseInt(hash.substring(0, 8), 16);
  return hashInt % 101; // 0-100
}

// Verificación
const userHash = hashUserId(userId, featureKey);
const isInRollout = userHash < rollout_percentage;
```

**Beneficios:**
- Mismo usuario siempre obtiene mismo resultado
- Distribución uniforme entre usuarios
- Diferente distribución por feature (gracias al featureKey)

---

## Estrategias de Rollout

### Canary Release

```typescript
// 1. Crear flag deshabilitada
await featureFlagsService.create({
  key: 'new_payment_gateway',
  name: 'Nuevo Gateway de Pagos',
  isEnabled: false,
  rolloutPercentage: 0,
});

// 2. Habilitar para equipo interno
await featureFlagsService.update('new_payment_gateway', {
  isEnabled: true,
  targetUsers: ['dev-team-uuid-1', 'dev-team-uuid-2'],
});

// 3. Expandir a 5% de usuarios
await featureFlagsService.updateRollout('new_payment_gateway', 5);

// 4. Si todo OK, expandir gradualmente
await featureFlagsService.updateRollout('new_payment_gateway', 25);
await featureFlagsService.updateRollout('new_payment_gateway', 50);
await featureFlagsService.updateRollout('new_payment_gateway', 100);
```

### Beta por Roles

```typescript
await featureFlagsService.create({
  key: 'advanced_analytics',
  name: 'Analytics Avanzados',
  isEnabled: true,
  rolloutPercentage: 0,  // No rollout general
  targetRoles: ['admin', 'premium_user'],
});
```

### Feature Temporal

```typescript
await featureFlagsService.create({
  key: 'black_friday_banner',
  name: 'Banner Black Friday',
  isEnabled: true,
  rolloutPercentage: 100,
  startsAt: new Date('2025-11-25'),
  endsAt: new Date('2025-11-30'),
});
```

---

## Variables de Entorno

```env
# Feature flags
FEATURE_FLAGS_CACHE_TTL=300  # Cache de 5 minutos
FEATURE_FLAGS_DEFAULT_ENABLED=false
```

---

## Endpoints Principales

| Método | Ruta | Descripción |
|--------|------|-------------|
| GET | /admin/feature-flags | Listar todas las flags |
| GET | /admin/feature-flags/:key | Obtener flag por key |
| POST | /admin/feature-flags | Crear nueva flag |
| PUT | /admin/feature-flags/:key | Actualizar flag |
| DELETE | /admin/feature-flags/:key | Eliminar flag |
| POST | /admin/feature-flags/:key/enable | Habilitar flag |
| POST | /admin/feature-flags/:key/disable | Deshabilitar flag |
| PUT | /admin/feature-flags/:key/rollout | Actualizar porcentaje |
| POST | /feature-flags/:key/check | Verificar si está habilitada |

---

## Casos de Uso Comunes

| Caso | Configuración |
|------|---------------|
| A/B Testing | Rollout 50%, metadata con grupo |
| Beta cerrada | targetUsers con UUIDs específicos |
| Kill switch | is_enabled = false cuando hay problemas |
| Feature por plan | targetRoles: ['premium', 'enterprise'] |
| Lanzamiento programado | starts_at + ends_at |
| Migración gradual | Rollout 10% → 25% → 50% → 100% |

---

## Adaptaciones Necesarias

1. **Roles**: Ajustar enum de roles según tu sistema
2. **Cache**: Implementar cache si hay muchas verificaciones
3. **Multi-tenant**: Decidir si flags son globales o por tenant
4. **UI Admin**: Crear interfaz para gestionar flags
5. **Métricas**: Integrar con sistema de analytics

---

## Referencias

- [Feature Flags Best Practices](https://martinfowler.com/articles/feature-toggles.html)
- [Gradual Rollout Strategies](https://docs.launchdarkly.com/home/targeting-flags)

---

**Mantenido por:** Sistema NEXUS
**Proyecto origen:** Gamilit Platform
