## Documentation - Align MCH-029 to MCH-032 with template-saas modules (SAAS-008 to SAAS-015) - Create MCH-034 (Analytics) and MCH-035 (Reports) from SAAS-016/017 - Update PLAN-DESARROLLO.md with Phase 7 and 8 - Update _MAP.md indexes (35 total epics) ## Database (5 new schemas, 14 tables) - Add storage schema: buckets, files, signed_urls - Add webhooks schema: endpoints, deliveries - Add audit schema: logs, retention_policies - Add features schema: flags, tenant_flags (14 seeds) - Add analytics schema: metrics, events, reports, report_schedules - Add auth.oauth_connections for MCH-030 - Add timestamptz_to_date() IMMUTABLE function - Update EXPECTED_SCHEMAS in recreate-database.sh ## Analysis Reports - ANALISIS-INTEGRACION-TEMPLATE-SAAS-2026-01-13.md - VALIDACION-COHERENCIA-2026-01-13.md - GAP-ANALYSIS-BD-2026-01-13.md - REPORTE-EJECUCION-2026-01-13.md Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
13 KiB
| id | type | title | code | status | phase | priority | created_at | updated_at | simco_version | dependencies | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| EPIC-MCH-032 | Epic | MCH-032: Feature Flags por Plan | MCH-032 | Planificado | 7 | P1 | 2026-01-10 | 2026-01-10 | 4.0.1 |
|
MCH-032: Feature Flags por Plan
Metadata
- Codigo: MCH-032
- Fase: 7 - Expansion
- Prioridad: P1
- Estado: Planificado
- Story Points: 5
- Sprint Objetivo: Sprint 8
Descripcion
Implementar sistema de feature flags que permite habilitar/deshabilitar funcionalidades por plan de suscripcion, tenant o usuario individual. Permite diferenciacion de ofertas, beta testing controlado y rollouts graduales.
Objetivos
- Definir flags globales con valores por defecto
- Asociar flags a planes de suscripcion
- Permitir overrides por tenant para beta testing
- Evaluar flags en tiempo real con cache
- SDK para frontend (React hook)
Alcance
Incluido
- Feature flags por plan (Basic, Pro, Enterprise)
- Overrides por tenant y usuario
- Expiracion de overrides
- Cache en Redis
- Guard de NestJS para backend
- Hook useFeatureFlag para React
Excluido
- A/B testing (futuro)
- Percentage rollouts
- Feature usage analytics
Arquitectura
┌─────────────────────────────────────┐
│ MCH-032: Feature Flags │
└─────────────────────────────────────┘
│
┌─────────────────────────────┼─────────────────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Flags │ │ Plans │ │ Overrides │
│ (global) │ │ (MCH-018) │ │ (por tenant) │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
└──────────────────────────┼──────────────────────────┘
▼
┌─────────────────────────────────────┐
│ FeatureFlagEvaluator │
│ (Redis cache + fallback DB) │
└─────────────────────────────────────┘
│
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│FeatureFlagGuard│ │useFeatureFlag│ │ Admin UI │
│ (Backend) │ │ (React) │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
Entregables
| Entregable | Estado | Sprint | Ubicacion |
|---|---|---|---|
| Schema feature_flags (DDL) | Planificado | 8 | database/schemas/13-feature-flags.sql |
| FeatureFlagService | Planificado | 8 | apps/backend/src/modules/feature-flags/ |
| FeatureFlagEvaluator | Planificado | 8 | apps/backend/src/modules/feature-flags/ |
| FeatureFlagGuard | Planificado | 8 | apps/backend/src/common/guards/ |
| useFeatureFlag hook | Planificado | 8 | apps/web/src/hooks/ |
| Admin UI | Planificado | 8 | apps/web/src/pages/admin/feature-flags/ |
Dependencias
Depende de
- MCH-029 (Redis para cache de evaluaciones)
- MCH-018 (Plans para asociar flags)
Bloquea a
- Ninguna
Historias de Usuario
MCH-US-109: Feature Flags por Plan
Como administrador del sistema Quiero habilitar/deshabilitar features segun el plan del tenant Para diferenciar la oferta entre planes
Story Points: 3
Criterios de Aceptacion:
- [CA-109-1] Definicion de flags globales con key, descripcion, valor por defecto
- [CA-109-2] Asociacion de flags a planes (Basic: false, Pro: true, Enterprise: true)
- [CA-109-3] Evaluacion en tiempo real (latencia <10ms con cache)
- [CA-109-4] Cache en Redis con invalidacion al cambiar flag
- [CA-109-5] Hook useFeatureFlag(key) retorna boolean
Tareas:
| ID | Tarea | Tipo | SP |
|---|---|---|---|
| MCH-TT-109-01 | DDL schema feature_flags | DDL | 0.25 |
| MCH-TT-109-02 | FeatureFlagService (CRUD de flags) | Backend | 0.5 |
| MCH-TT-109-03 | FeatureFlagEvaluator con cache Redis | Backend | 0.5 |
| MCH-TT-109-04 | FeatureFlagGuard para proteger endpoints | Backend | 0.25 |
| MCH-TT-109-05 | FeatureFlagsController (API) | Backend | 0.25 |
| MCH-TT-109-06 | Hook useFeatureFlag en frontend | Frontend | 0.5 |
| MCH-TT-109-07 | Tests | Test | 0.5 |
| MCH-TT-109-08 | Documentacion | Docs | 0.25 |
MCH-US-110: Overrides por Tenant
Como administrador del sistema Quiero habilitar features especificos para ciertos tenants Para dar acceso beta o promociones especiales
Story Points: 2
Criterios de Aceptacion:
- [CA-110-1] Override por tenant_id habilita feature aunque plan no lo incluya
- [CA-110-2] Override por user_id para usuarios especificos
- [CA-110-3] Expiracion configurable del override (fecha/hora)
- [CA-110-4] UI de administracion para gestionar overrides
Tareas:
| ID | Tarea | Tipo | SP |
|---|---|---|---|
| MCH-TT-110-01 | DDL tabla flag_overrides | DDL | 0.25 |
| MCH-TT-110-02 | Logica de override en evaluador | Backend | 0.5 |
| MCH-TT-110-03 | UI para superadmin | Frontend | 0.5 |
| MCH-TT-110-04 | Tests | Test | 0.25 |
| MCH-TT-110-05 | Documentacion de uso | Docs | 0.5 |
Resumen de Story Points
| Historia | SP | Sprint |
|---|---|---|
| MCH-US-109: Feature Flags por Plan | 3 | 8 |
| MCH-US-110: Overrides por Tenant | 2 | 8 |
| TOTAL | 5 | 8 |
Criterios de Aceptacion de Epica
- Flags evaluados correctamente por plan
- Cache Redis funcional (<10ms latencia)
- Overrides aplicandose correctamente
- UI de administracion funcional
- Hook React integrado
- Cobertura de tests >80%
Notas Tecnicas
Schema feature_flags
CREATE SCHEMA IF NOT EXISTS feature_flags;
CREATE TABLE feature_flags.flags (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
key VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
default_value BOOLEAN DEFAULT false,
type VARCHAR(20) DEFAULT 'boolean', -- boolean, string, number
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE TABLE feature_flags.plan_flags (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
flag_id UUID REFERENCES feature_flags.flags(id),
plan_id UUID REFERENCES billing.plans(id),
value BOOLEAN NOT NULL,
UNIQUE(flag_id, plan_id)
);
CREATE TABLE feature_flags.flag_overrides (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
flag_id UUID REFERENCES feature_flags.flags(id),
tenant_id UUID,
user_id UUID,
value BOOLEAN NOT NULL,
expires_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
CHECK (tenant_id IS NOT NULL OR user_id IS NOT NULL)
);
Ejemplo de Flags Iniciales
| Flag Key | Descripcion | Basic | Pro | Enterprise |
|---|---|---|---|---|
| ai_assistant | Asistente IA en chat | false | true | true |
| advanced_reports | Reportes avanzados | false | true | true |
| api_access | Acceso a API publica | false | false | true |
| white_label | Sin branding MiChangarrito | false | false | true |
| multi_location | Multiples ubicaciones | false | true | true |
Uso en Backend
@UseGuards(FeatureFlagGuard)
@FeatureFlag('ai_assistant')
@Get('ai/suggestions')
async getAISuggestions() {
// Solo accesible si flag habilitado
}
Uso en Frontend
function Dashboard() {
const hasAI = useFeatureFlag('ai_assistant');
return (
<div>
{hasAI && <AIAssistantWidget />}
</div>
);
}
ADRs Relacionados
Especificaciones Tecnicas Detalladas (Ref: SAAS-009)
Esta seccion documenta las especificaciones del modulo de feature flags segun template-saas para garantizar alineacion arquitectonica.
Estructura de Tabla feature_flags
| Campo | Tipo | Descripcion |
|---|---|---|
| id | UUID | Identificador unico |
| key | VARCHAR (unique) | Clave del flag |
| name | VARCHAR | Nombre descriptivo |
| description | TEXT | Descripcion del flag |
| type | VARCHAR | Tipo: boolean/string/number/json |
| default_value | JSONB | Valor por defecto |
| is_enabled | BOOLEAN | Si el flag esta activo |
| rollout_percentage | INTEGER | Porcentaje de rollout (0-100) |
| targeting_rules | JSONB | Reglas de targeting avanzado |
| created_at | TIMESTAMP | Fecha de creacion |
| updated_at | TIMESTAMP | Fecha de actualizacion |
Tablas de Overrides
tenant_feature_overrides
| Campo | Tipo | Descripcion |
|---|---|---|
| id | UUID | Identificador unico |
| tenant_id | UUID | Tenant afectado |
| feature_key | VARCHAR | Clave del flag |
| value | JSONB | Valor override |
| enabled | BOOLEAN | Estado del override |
| expires_at | TIMESTAMP | Fecha de expiracion |
user_feature_overrides
| Campo | Tipo | Descripcion |
|---|---|---|
| id | UUID | Identificador unico |
| user_id | UUID | Usuario afectado |
| feature_key | VARCHAR | Clave del flag |
| value | JSONB | Valor override |
| enabled | BOOLEAN | Estado del override |
| expires_at | TIMESTAMP | Fecha de expiracion |
Endpoints API del Modulo
| Metodo | Endpoint | Descripcion |
|---|---|---|
| GET | /features | Listar todos los flags |
| GET | /features/:key | Obtener flag especifico |
| POST | /features | Crear nuevo flag |
| PUT | /features/:key | Actualizar flag |
| DELETE | /features/:key | Eliminar flag |
| GET | /features/evaluate | Evaluar todos los flags para contexto actual |
| POST | /features/:key/override/tenant | Crear override para tenant |
| POST | /features/:key/override/user | Crear override para usuario |
| DELETE | /features/:key/override/tenant | Eliminar override de tenant |
Tipos de Flags Soportados
| Tipo | Descripcion | Ejemplo |
|---|---|---|
| boolean | Verdadero/Falso | true |
| string | Texto | 'dark' |
| number | Numerico | 10 |
| json | Objeto JSON | {"limit": 100} |
Flags Predefinidos de Referencia
| 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 de archivo en MB |
| theme | string | 'light' | Tema por defecto |
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
El rollout por porcentaje es deterministico, es decir, el mismo usuario siempre obtendra el 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 (Reglas Avanzadas)
{
"rules": [
{
"condition": "plan",
"operator": "in",
"values": ["pro", "enterprise"],
"enabled": true
},
{
"condition": "country",
"operator": "equals",
"values": ["MX"],
"enabled": true
}
]
}
Caching con Redis
// Cache key format
const cacheKey = `features:${tenantId}:${userId}`;
// TTL: 5 minutos
await redis.setex(cacheKey, 300, JSON.stringify(flags));
Referencia
Documentacion fuente:
/projects/template-saas/docs/01-modulos/SAAS-009-feature-flags.mdVersion: 1.0.0
Ultima actualizacion: 2026-01-13 Autor: Architecture Team