## 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>
397 lines
13 KiB
Markdown
397 lines
13 KiB
Markdown
---
|
|
id: EPIC-MCH-032
|
|
type: Epic
|
|
title: "MCH-032: Feature Flags por Plan"
|
|
code: MCH-032
|
|
status: Planificado
|
|
phase: 7
|
|
priority: P1
|
|
created_at: 2026-01-10
|
|
updated_at: 2026-01-10
|
|
simco_version: "4.0.1"
|
|
dependencies:
|
|
blocks: []
|
|
depends_on: ["MCH-029", "MCH-018"]
|
|
---
|
|
|
|
# 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
|
|
|
|
1. Definir flags globales con valores por defecto
|
|
2. Asociar flags a planes de suscripcion
|
|
3. Permitir overrides por tenant para beta testing
|
|
4. Evaluar flags en tiempo real con cache
|
|
5. 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
|
|
|
|
```sql
|
|
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
|
|
|
|
```typescript
|
|
@UseGuards(FeatureFlagGuard)
|
|
@FeatureFlag('ai_assistant')
|
|
@Get('ai/suggestions')
|
|
async getAISuggestions() {
|
|
// Solo accesible si flag habilitado
|
|
}
|
|
```
|
|
|
|
### Uso en Frontend
|
|
|
|
```tsx
|
|
function Dashboard() {
|
|
const hasAI = useFeatureFlag('ai_assistant');
|
|
|
|
return (
|
|
<div>
|
|
{hasAI && <AIAssistantWidget />}
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
## ADRs Relacionados
|
|
|
|
- [ADR-0005: Feature Flags Strategy](../97-adr/ADR-0005-feature-flags.md)
|
|
|
|
---
|
|
|
|
## 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:
|
|
|
|
```typescript
|
|
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)
|
|
|
|
```typescript
|
|
{
|
|
"rules": [
|
|
{
|
|
"condition": "plan",
|
|
"operator": "in",
|
|
"values": ["pro", "enterprise"],
|
|
"enabled": true
|
|
},
|
|
{
|
|
"condition": "country",
|
|
"operator": "equals",
|
|
"values": ["MX"],
|
|
"enabled": true
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Caching con Redis
|
|
|
|
```typescript
|
|
// 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.md`
|
|
> Version: 1.0.0
|
|
|
|
---
|
|
|
|
**Ultima actualizacion:** 2026-01-13
|
|
**Autor:** Architecture Team
|