Sistema NEXUS v3.4 migrado con: Estructura principal: - core/orchestration: Sistema SIMCO + CAPVED (27 directivas, 28 perfiles) - core/catalog: Catalogo de funcionalidades reutilizables - shared/knowledge-base: Base de conocimiento compartida - devtools/scripts: Herramientas de desarrollo - control-plane/registries: Control de servicios y CI/CD - orchestration/: Configuracion de orquestacion de agentes Proyectos incluidos (11): - gamilit (submodule -> GitHub) - trading-platform (OrbiquanTIA) - erp-suite con 5 verticales: - erp-core, construccion, vidrio-templado - mecanicas-diesel, retail, clinicas - betting-analytics - inmobiliaria-analytics - platform_marketing_content - pos-micro, erp-basico Configuracion: - .gitignore completo para Node.js/Python/Docker - gamilit como submodule (git@github.com:rckrdmrd/gamilit-workspace.git) - Sistema de puertos estandarizado (3005-3199) Generated with NEXUS v3.4 Migration System EPIC-010: Configuracion Git y Repositorios
361 lines
8.5 KiB
Markdown
361 lines
8.5 KiB
Markdown
# 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
|