workspace-v1/shared/catalog/feature-flags/README.md
rckrdmrd cb4c0681d3 feat(workspace): Add new projects and update architecture
New projects created:
- michangarrito (marketplace mobile)
- template-saas (SaaS template)
- clinica-dental (dental ERP)
- clinica-veterinaria (veterinary ERP)

Architecture updates:
- Move catalog from core/ to shared/
- Add MCP servers structure and templates
- Add git management scripts
- Update SUBREPOSITORIOS.md with 15 new repos
- Update .gitignore for new projects

Repository infrastructure:
- 4 main repositories
- 11 subrepositorios
- Gitea remotes configured

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 04:43:28 -06:00

8.5 KiB

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

backend:
  framework: NestJS
  orm: TypeORM
  database: PostgreSQL

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

Dependencias NPM

{
  "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

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

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

// 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

@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)

// 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:

// 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

// 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

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

Feature Temporal

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

# 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


Mantenido por: Sistema NEXUS Proyecto origen: Gamilit Platform