diff --git a/apps/backend/package.json b/apps/backend/package.json
index e15726103..c09ba4c63 100644
--- a/apps/backend/package.json
+++ b/apps/backend/package.json
@@ -24,32 +24,32 @@
"migration:revert": "npm run typeorm -- migration:revert -d src/database/data-source.ts"
},
"dependencies": {
- "@nestjs/common": "^10.3.0",
- "@nestjs/config": "^3.1.1",
- "@nestjs/core": "^10.3.0",
- "@nestjs/jwt": "^10.2.0",
- "@nestjs/passport": "^10.0.3",
- "@nestjs/platform-express": "^10.3.0",
- "@nestjs/swagger": "^7.2.0",
- "@nestjs/typeorm": "^10.0.1",
+ "@nestjs/common": "^11.1.0",
+ "@nestjs/config": "^3.3.0",
+ "@nestjs/core": "^11.1.0",
+ "@nestjs/jwt": "^11.0.1",
+ "@nestjs/passport": "^11.0.5",
+ "@nestjs/platform-express": "^11.1.0",
+ "@nestjs/swagger": "^8.1.0",
+ "@nestjs/typeorm": "^11.0.0",
"@react-native-community/netinfo": "^11.4.1",
"bcrypt": "^5.1.1",
"class-transformer": "^0.5.1",
- "class-validator": "^0.14.1",
- "helmet": "^7.1.0",
+ "class-validator": "^0.14.2",
+ "helmet": "^8.0.0",
"passport": "^0.7.0",
"passport-jwt": "^4.0.1",
- "pg": "^8.11.3",
- "reflect-metadata": "^0.2.1",
+ "pg": "^8.13.0",
+ "reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1",
"stripe": "^20.1.1",
- "typeorm": "^0.3.19",
- "uuid": "^9.0.1"
+ "typeorm": "^0.3.22",
+ "uuid": "^11.0.0"
},
"devDependencies": {
- "@nestjs/cli": "^10.3.0",
- "@nestjs/schematics": "^10.1.0",
- "@nestjs/testing": "^10.3.0",
+ "@nestjs/cli": "^11.0.0",
+ "@nestjs/schematics": "^11.0.0",
+ "@nestjs/testing": "^11.1.0",
"@types/bcrypt": "^5.0.2",
"@types/express": "^4.17.21",
"@types/jest": "^29.5.11",
diff --git a/docs/01-epicas/MCH-029-infraestructura-saas.md b/docs/01-epicas/MCH-029-infraestructura-saas.md
new file mode 100644
index 000000000..9c3bd7a7c
--- /dev/null
+++ b/docs/01-epicas/MCH-029-infraestructura-saas.md
@@ -0,0 +1,301 @@
+---
+id: EPIC-MCH-029
+type: Epic
+title: "MCH-029: Infraestructura SaaS Avanzada"
+code: MCH-029
+status: Planificado
+phase: 7
+priority: P0
+created_at: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+dependencies:
+ blocks: ["MCH-030", "MCH-032", "MCH-033"]
+ depends_on: []
+---
+
+# MCH-029: Infraestructura SaaS Avanzada
+
+## Metadata
+- **Codigo:** MCH-029
+- **Fase:** 7 - Expansion
+- **Prioridad:** P0 (Critica)
+- **Estado:** Planificado
+- **Story Points:** 24
+- **Sprint Objetivo:** Sprint 6-7
+
+## Descripcion
+
+Implementar infraestructura SaaS empresarial que incluye sistema de Email Multi-proveedor, Storage Abstracto en la nube, Redis como cache/queue, Webhooks Outbound con reintentos y Rate Limiting por plan. Esta epica es la base para las capacidades SaaS avanzadas.
+
+## Objetivos
+
+1. Establecer sistema de email multi-proveedor con fallback
+2. Implementar storage abstracto compatible con S3/R2/MinIO
+3. Configurar Redis para cache y colas
+4. Habilitar webhooks outbound con estrategia de reintentos
+5. Implementar rate limiting por plan de suscripcion
+
+## Alcance
+
+### Incluido
+- Email transaccional con SendGrid, SES y SMTP
+- Storage cloud con URLs firmadas
+- Redis cache con TTL configurable
+- BullMQ para procesamiento en background
+- Rate limiting con token bucket
+- Webhooks con firma HMAC-SHA256
+
+### Excluido
+- Push notifications (ver MCH-034)
+- Email marketing masivo
+- CDN para assets estaticos
+
+## Arquitectura
+
+```
+ ┌─────────────────────────────────────┐
+ │ MCH-029: Infraestructura │
+ └─────────────────────────────────────┘
+ │
+ ┌──────────────┬──────────────┼──────────────┬──────────────┐
+ ▼ ▼ ▼ ▼ ▼
+ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
+ │ Email │ │ Storage │ │ Redis │ │ Webhooks │ │ Rate │
+ │ Provider │ │ Provider │ │ Cache │ │ Outbound │ │ Limiting │
+ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘
+ │ │ │ │ │
+ ┌────┴────┐ ┌────┴────┐ │ ┌────┴────┐ │
+ │SendGrid │ │ S3 │ │ │ BullMQ │ │
+ │ SES │ │ R2 │ │ │ Queue │ │
+ │ SMTP │ │ MinIO │ │ │ │ │
+ └─────────┘ └─────────┘ │ └─────────┘ │
+ │ │
+ ┌─────┴────────────────────────────┘
+ │ Redis Server │
+ └──────────────────────────────────┘
+```
+
+## Entregables
+
+| Entregable | Estado | Sprint | Ubicacion |
+|------------|--------|--------|-----------|
+| Email module con multi-provider | Planificado | 6 | `apps/backend/src/modules/email/` |
+| Storage module abstracto | Planificado | 6 | `apps/backend/src/modules/storage/` |
+| Redis cache/queue config | Planificado | 6 | `apps/backend/src/modules/redis/` |
+| Webhooks module | Planificado | 7 | `apps/backend/src/modules/webhooks/` |
+| Rate limiting guard | Planificado | 7 | `apps/backend/src/common/guards/` |
+| DDL storage schema | Planificado | 6 | `database/schemas/12-storage.sql` |
+| DDL webhooks schema | Planificado | 7 | `database/schemas/15-webhooks.sql` |
+
+## Dependencias
+
+### Depende de
+- Ninguna (epica base de infraestructura)
+
+### Bloquea a
+- MCH-030 (Auth Social) - requiere email para verificacion
+- MCH-032 (Feature Flags) - requiere Redis para cache
+- MCH-033 (Onboarding) - requiere infraestructura completa
+
+---
+
+## Historias de Usuario
+
+### MCH-US-101: Email Multi-proveedor
+
+**Como** administrador del sistema
+**Quiero** enviar emails transaccionales via multiples proveedores
+**Para** garantizar entrega y tener fallback
+
+**Story Points:** 5
+
+**Criterios de Aceptacion:**
+- [CA-101-1] Soporta SendGrid como proveedor principal
+- [CA-101-2] Soporta AWS SES como fallback
+- [CA-101-3] Soporta SMTP generico como ultimo recurso
+- [CA-101-4] Templates reutilizables con variables Handlebars
+- [CA-101-5] Tracking de entrega (opens, clicks si proveedor soporta)
+- [CA-101-6] Rate limiting por tenant (max emails/hora)
+
+**Tareas:**
+| ID | Tarea | Tipo | SP |
+|----|-------|------|-----|
+| MCH-TT-101-01 | DDL tabla email_templates | DDL | 0.5 |
+| MCH-TT-101-02 | DDL tabla email_logs | DDL | 0.5 |
+| MCH-TT-101-03 | Servicio EmailProviderFactory | Backend | 0.5 |
+| MCH-TT-101-04 | Implementar SendGridProvider | Backend | 1 |
+| MCH-TT-101-05 | Implementar SESProvider | Backend | 1 |
+| MCH-TT-101-06 | Implementar SMTPProvider | Backend | 0.5 |
+| MCH-TT-101-07 | Controlador EmailController | Backend | 0.5 |
+| MCH-TT-101-08 | Tests unitarios | Test | 0.5 |
+| MCH-TT-101-09 | Documentacion INT-010 | Docs | 0 |
+
+---
+
+### MCH-US-102: Storage Abstracto
+
+**Como** usuario
+**Quiero** subir archivos (imagenes, facturas) a la nube
+**Para** tener respaldo seguro y acceso desde cualquier dispositivo
+
+**Story Points:** 8
+
+**Criterios de Aceptacion:**
+- [CA-102-1] Soporta AWS S3 como proveedor principal
+- [CA-102-2] Soporta Cloudflare R2 como alternativa economica
+- [CA-102-3] Soporta MinIO para desarrollo local
+- [CA-102-4] Limites de almacenamiento por plan (Basic: 1GB, Pro: 10GB, Enterprise: 100GB)
+- [CA-102-5] Organizacion de archivos en carpetas virtuales
+- [CA-102-6] URLs firmadas con expiracion configurable
+- [CA-102-7] Metadata de archivos (size, mime_type, upload_date)
+- [CA-102-8] Validacion de tipos MIME permitidos
+
+**Tareas:**
+| ID | Tarea | Tipo | SP |
+|----|-------|------|-----|
+| MCH-TT-102-01 | DDL schema storage (files, folders, usage) | DDL | 1 |
+| MCH-TT-102-02 | Servicio StorageProviderFactory | Backend | 0.5 |
+| MCH-TT-102-03 | Implementar S3Provider | Backend | 1.5 |
+| MCH-TT-102-04 | Implementar R2Provider | Backend | 1 |
+| MCH-TT-102-05 | Implementar MinIOProvider | Backend | 0.5 |
+| MCH-TT-102-06 | Controlador StorageController | Backend | 1 |
+| MCH-TT-102-07 | Middleware limite por plan | Backend | 0.5 |
+| MCH-TT-102-08 | Generacion URLs firmadas | Backend | 0.5 |
+| MCH-TT-102-09 | Tests unitarios e integracion | Test | 1 |
+| MCH-TT-102-10 | Documentacion INT-011 | Docs | 0.5 |
+
+---
+
+### MCH-US-103: Redis Cache y Queue
+
+**Como** sistema
+**Quiero** utilizar Redis como cache y queue
+**Para** mejorar rendimiento y procesar tareas en background
+
+**Story Points:** 3
+
+**Criterios de Aceptacion:**
+- [CA-103-1] Cache de sesiones JWT con TTL
+- [CA-103-2] Cache de configuracion de tenant
+- [CA-103-3] Queue para emails, webhooks, notificaciones via BullMQ
+- [CA-103-4] Health check endpoint de Redis
+- [CA-103-5] Metricas de uso (hits/misses, queue length)
+
+**Tareas:**
+| ID | Tarea | Tipo | SP |
+|----|-------|------|-----|
+| MCH-TT-103-01 | Configuracion Redis module | Backend | 0.5 |
+| MCH-TT-103-02 | Cache service con TTL | Backend | 0.5 |
+| MCH-TT-103-03 | BullMQ integration | Backend | 0.5 |
+| MCH-TT-103-04 | Queue processors base | Backend | 0.5 |
+| MCH-TT-103-05 | Health check endpoint | Backend | 0.25 |
+| MCH-TT-103-06 | Tests | Test | 0.5 |
+| MCH-TT-103-07 | Documentacion INT-013 | Docs | 0.25 |
+
+---
+
+### MCH-US-104: Webhooks Outbound
+
+**Como** administrador de tenant
+**Quiero** configurar webhooks para recibir notificaciones de eventos
+**Para** integrar con sistemas externos
+
+**Story Points:** 5
+
+**Criterios de Aceptacion:**
+- [CA-104-1] CRUD de endpoints webhook por tenant
+- [CA-104-2] Seleccion de eventos a suscribirse (order.created, payment.completed, etc)
+- [CA-104-3] Firma de payloads con HMAC-SHA256
+- [CA-104-4] Reintentos con exponential backoff (1s, 2s, 4s, 8s, 16s)
+- [CA-104-5] Logs de entregas con response status
+
+**Tareas:**
+| ID | Tarea | Tipo | SP |
+|----|-------|------|-----|
+| MCH-TT-104-01 | DDL schema webhooks (endpoints, deliveries) | DDL | 0.5 |
+| MCH-TT-104-02 | Servicio WebhookService | Backend | 1 |
+| MCH-TT-104-03 | Job processor con BullMQ | Backend | 1 |
+| MCH-TT-104-04 | Firma HMAC de payloads | Backend | 0.5 |
+| MCH-TT-104-05 | Controlador WebhooksController | Backend | 0.5 |
+| MCH-TT-104-06 | UI en portal admin | Frontend | 0.5 |
+| MCH-TT-104-07 | Tests | Test | 0.5 |
+| MCH-TT-104-08 | Documentacion INT-014 | Docs | 0.5 |
+
+---
+
+### MCH-US-112: Rate Limiting por Plan
+
+**Como** sistema
+**Quiero** limitar las solicitudes API segun el plan del tenant
+**Para** garantizar uso justo y proteger la infraestructura
+
+**Story Points:** 3
+
+**Criterios de Aceptacion:**
+- [CA-112-1] Limite de requests/minuto configurable por plan
+- [CA-112-2] Limite de requests/dia configurable por plan
+- [CA-112-3] Headers X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
+- [CA-112-4] Respuesta 429 Too Many Requests con Retry-After
+- [CA-112-5] Bypass para webhooks internos y health checks
+
+**Tareas:**
+| ID | Tarea | Tipo | SP |
+|----|-------|------|-----|
+| MCH-TT-112-01 | Implementar middleware RateLimitGuard | Backend | 0.5 |
+| MCH-TT-112-02 | Configuracion limites en plans | Backend | 0.5 |
+| MCH-TT-112-03 | Almacenamiento contadores en Redis | Backend | 0.5 |
+| MCH-TT-112-04 | Headers de respuesta | Backend | 0.25 |
+| MCH-TT-112-05 | Tests | Test | 0.5 |
+| MCH-TT-112-06 | Documentar en ADR-0009 | Docs | 0.25 |
+
+---
+
+## Resumen de Story Points
+
+| Historia | SP | Sprint |
+|----------|-----|--------|
+| MCH-US-101: Email Multi-proveedor | 5 | 6 |
+| MCH-US-102: Storage Abstracto | 8 | 6 |
+| MCH-US-103: Redis Cache y Queue | 3 | 6 |
+| MCH-US-104: Webhooks Outbound | 5 | 7 |
+| MCH-US-112: Rate Limiting | 3 | 7 |
+| **TOTAL** | **24** | 6-7 |
+
+---
+
+## Criterios de Aceptacion de Epica
+
+- [ ] Email enviado exitosamente con cada proveedor
+- [ ] Archivos subidos a S3 con URL firmada funcional
+- [ ] Redis cache reduce latencia en >50%
+- [ ] Webhook entregado con reintentos exitosos
+- [ ] Rate limiting bloquea requests excedentes
+- [ ] Cobertura de tests >80%
+- [ ] Documentacion de integraciones completa
+
+## Notas Tecnicas
+
+- **Redis:** Puerto 6379, DB 0 para cache, DB 1 para queues
+- **S3 Region:** us-east-1 (default)
+- **R2 Region:** auto
+- **Email Rate:** Max 1000/tenant/hora en plan Pro
+
+## Integraciones Relacionadas
+
+- [INT-010: Email Providers](../02-integraciones/INT-010-email-providers.md)
+- [INT-011: Storage Cloud](../02-integraciones/INT-011-storage-cloud.md)
+- [INT-013: Redis Cache](../02-integraciones/INT-013-redis-cache.md)
+- [INT-014: Webhooks Outbound](../02-integraciones/INT-014-webhooks-outbound.md)
+
+## ADRs Relacionados
+
+- [ADR-0006: Storage Abstraction](../97-adr/ADR-0006-storage-abstraction.md)
+- [ADR-0007: Webhook Retry Strategy](../97-adr/ADR-0007-webhook-retry-strategy.md)
+- [ADR-0009: Rate Limiting Strategy](../97-adr/ADR-0009-rate-limiting.md)
+- [ADR-0011: Email Multi-provider](../97-adr/ADR-0011-email-multi-provider.md)
+
+---
+
+**Ultima actualizacion:** 2026-01-10
+**Autor:** Architecture Team
diff --git a/docs/01-epicas/MCH-030-auth-social.md b/docs/01-epicas/MCH-030-auth-social.md
new file mode 100644
index 000000000..cdd05ed0c
--- /dev/null
+++ b/docs/01-epicas/MCH-030-auth-social.md
@@ -0,0 +1,221 @@
+---
+id: EPIC-MCH-030
+type: Epic
+title: "MCH-030: Auth Social (OAuth 2.0)"
+code: MCH-030
+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-030: Auth Social (OAuth 2.0)
+
+## Metadata
+- **Codigo:** MCH-030
+- **Fase:** 7 - Expansion
+- **Prioridad:** P1
+- **Estado:** Planificado
+- **Story Points:** 8
+- **Sprint Objetivo:** Sprint 8
+
+## Descripcion
+
+Agregar autenticacion social via OAuth 2.0 con Google y Apple Sign-In para simplificar el onboarding de usuarios. Permite registro e inicio de sesion con un clic, reduciendo friccion y aumentando conversion.
+
+## Objetivos
+
+1. Implementar Login con Google
+2. Implementar Sign in with Apple (requerido para iOS)
+3. Permitir vinculacion de cuentas sociales a cuenta existente
+4. Obtener perfil basico del usuario (nombre, email, foto)
+
+## Alcance
+
+### Incluido
+- OAuth 2.0 con Google
+- Sign in with Apple (web + iOS)
+- Vinculacion de multiples proveedores a una cuenta
+- Sync de foto de perfil
+
+### Excluido
+- Facebook Login (baja prioridad)
+- Microsoft/LinkedIn (B2B futuro)
+- Two-factor authentication (MCH-002 existente)
+
+## Arquitectura
+
+```
+ ┌─────────────────────────────────────┐
+ │ MCH-030: Auth Social │
+ └─────────────────────────────────────┘
+ │
+ ┌─────────────────┴─────────────────┐
+ ▼ ▼
+ ┌──────────┐ ┌──────────┐
+ │ Google │ │ Apple │
+ │ OAuth │ │ Sign-In │
+ └────┬─────┘ └────┬─────┘
+ │ │
+ ▼ ▼
+ ┌─────────────────────────────────────────┐
+ │ Passport.js Strategies │
+ └─────────────────────────────────────────┘
+ │
+ ▼
+ ┌─────────────────────────────────────────┐
+ │ oauth_accounts (tabla) │
+ │ user_id | provider | provider_id │
+ └─────────────────────────────────────────┘
+ │
+ ▼
+ ┌─────────────────────────────────────────┐
+ │ auth.users (existente) │
+ └─────────────────────────────────────────┘
+```
+
+## Entregables
+
+| Entregable | Estado | Sprint | Ubicacion |
+|------------|--------|--------|-----------|
+| Google OAuth Strategy | Planificado | 8 | `apps/backend/src/modules/auth/strategies/` |
+| Apple OAuth Strategy | Planificado | 8 | `apps/backend/src/modules/auth/strategies/` |
+| Tabla oauth_accounts | Planificado | 8 | `database/schemas/16-oauth.sql` |
+| Endpoints /auth/google, /auth/apple | Planificado | 8 | `apps/backend/src/modules/auth/` |
+| UI botones sociales web | Planificado | 8 | `apps/web/src/pages/auth/` |
+| Implementacion mobile | Planificado | 8 | `apps/mobile/src/screens/auth/` |
+
+## Dependencias
+
+### Depende de
+- MCH-029 (Email para verificacion de cuenta vinculada)
+
+### Bloquea a
+- Ninguna
+
+---
+
+## Historias de Usuario
+
+### MCH-US-105: Login con Google
+
+**Como** usuario nuevo
+**Quiero** registrarme/iniciar sesion con mi cuenta de Google
+**Para** no tener que recordar otra contrasena
+
+**Story Points:** 5
+
+**Criterios de Aceptacion:**
+- [CA-105-1] Boton "Continuar con Google" visible en login y registro
+- [CA-105-2] Registro automatico si no existe cuenta con ese email
+- [CA-105-3] Vinculacion automatica si ya existe cuenta con mismo email
+- [CA-105-4] Obtiene nombre y foto de perfil de Google
+- [CA-105-5] Funciona en web (popup) y mobile (Expo AuthSession)
+
+**Tareas:**
+| ID | Tarea | Tipo | SP |
+|----|-------|------|-----|
+| MCH-TT-105-01 | DDL tabla oauth_accounts | DDL | 0.5 |
+| MCH-TT-105-02 | Google OAuth strategy (Passport) | Backend | 1 |
+| MCH-TT-105-03 | Endpoint /auth/google | Backend | 0.5 |
+| MCH-TT-105-04 | Callback handler /auth/google/callback | Backend | 0.5 |
+| MCH-TT-105-05 | Servicio de vinculacion de cuentas | Backend | 0.5 |
+| MCH-TT-105-06 | UI boton Google en web | Frontend | 0.5 |
+| MCH-TT-105-07 | Implementacion mobile (Expo) | Frontend | 1 |
+| MCH-TT-105-08 | Tests unitarios e integracion | Test | 0.5 |
+| MCH-TT-105-09 | Documentacion en INT-012 | Docs | 0 |
+
+---
+
+### MCH-US-106: Login con Apple
+
+**Como** usuario de iOS
+**Quiero** iniciar sesion con Apple ID
+**Para** usar autenticacion nativa de mi dispositivo
+
+**Story Points:** 3
+
+**Criterios de Aceptacion:**
+- [CA-106-1] Sign in with Apple funcional en iOS nativo
+- [CA-106-2] Fallback web para Android y Desktop
+- [CA-106-3] Manejo correcto de email oculto (relay de Apple)
+- [CA-106-4] Registro automatico con nombre del usuario
+- [CA-106-5] Cumple requisitos App Store Review Guidelines
+
+**Tareas:**
+| ID | Tarea | Tipo | SP |
+|----|-------|------|-----|
+| MCH-TT-106-01 | Apple OAuth strategy | Backend | 0.5 |
+| MCH-TT-106-02 | Endpoint /auth/apple | Backend | 0.5 |
+| MCH-TT-106-03 | Manejo de private email relay | Backend | 0.5 |
+| MCH-TT-106-04 | Implementacion iOS nativa | Frontend | 0.5 |
+| MCH-TT-106-05 | Fallback web con apple-signin-api | Frontend | 0.5 |
+| MCH-TT-106-06 | Tests | Test | 0.25 |
+| MCH-TT-106-07 | Documentacion en INT-012 | Docs | 0.25 |
+
+---
+
+## Resumen de Story Points
+
+| Historia | SP | Sprint |
+|----------|-----|--------|
+| MCH-US-105: Login con Google | 5 | 8 |
+| MCH-US-106: Login con Apple | 3 | 8 |
+| **TOTAL** | **8** | 8 |
+
+---
+
+## Criterios de Aceptacion de Epica
+
+- [ ] Login con Google funcional en web y mobile
+- [ ] Sign in with Apple funcional en iOS
+- [ ] Cuentas vinculadas correctamente
+- [ ] No se crean duplicados de usuarios
+- [ ] Cobertura de tests >80%
+
+## Notas Tecnicas
+
+### Configuracion Google Cloud Console
+1. Crear proyecto en Google Cloud Console
+2. Habilitar Google+ API
+3. Crear OAuth 2.0 Client ID (Web Application)
+4. Configurar redirect URIs:
+ - `https://api.michangarrito.com/auth/google/callback`
+ - `http://localhost:3000/auth/google/callback` (dev)
+
+### Configuracion Apple Developer
+1. App ID con Sign in with Apple capability
+2. Service ID para web
+3. Key privada para validar tokens
+4. Configurar domains y redirect URLs
+
+### Variables de Entorno
+```env
+# Google OAuth
+GOOGLE_CLIENT_ID=xxx.apps.googleusercontent.com
+GOOGLE_CLIENT_SECRET=xxx
+
+# Apple Sign-In
+APPLE_CLIENT_ID=com.michangarrito.app
+APPLE_TEAM_ID=XXXXXXXXXX
+APPLE_KEY_ID=XXXXXXXXXX
+APPLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----..."
+```
+
+## Integraciones Relacionadas
+
+- [INT-012: OAuth Social](../02-integraciones/INT-012-oauth-social.md)
+
+## ADRs Relacionados
+
+- [ADR-0010: OAuth Social Strategy](../97-adr/ADR-0010-oauth-social.md)
+
+---
+
+**Ultima actualizacion:** 2026-01-10
+**Autor:** Architecture Team
diff --git a/docs/01-epicas/MCH-031-auditoria-empresarial.md b/docs/01-epicas/MCH-031-auditoria-empresarial.md
new file mode 100644
index 000000000..663a0f85f
--- /dev/null
+++ b/docs/01-epicas/MCH-031-auditoria-empresarial.md
@@ -0,0 +1,222 @@
+---
+id: EPIC-MCH-031
+type: Epic
+title: "MCH-031: Auditoria Empresarial"
+code: MCH-031
+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-031: Auditoria Empresarial
+
+## Metadata
+- **Codigo:** MCH-031
+- **Fase:** 7 - Expansion
+- **Prioridad:** P1
+- **Estado:** Planificado
+- **Story Points:** 5
+- **Sprint Objetivo:** Sprint 7
+
+## Descripcion
+
+Implementar sistema de auditoria completo con registro de todas las acciones CRUD, politica de retencion configurable y capacidad de exportacion para compliance. Permite trazabilidad completa de operaciones y deteccion de actividades sospechosas.
+
+## Objetivos
+
+1. Registrar todas las acciones de usuarios en el sistema
+2. Mantener historial de cambios con valores antes/despues
+3. Configurar politicas de retencion por tenant
+4. Exportar logs para auditorias externas
+5. Visualizar actividad en dashboard admin
+
+## Alcance
+
+### Incluido
+- Audit logs para CREATE, UPDATE, DELETE
+- Activity logs para acciones de usuario (login, logout, view)
+- Interceptor global NestJS
+- Politica de retencion (30, 90, 365 dias)
+- Exportacion CSV
+- Visor de logs en admin
+
+### Excluido
+- SIEM integration (futuro)
+- Real-time alerting (ver notificaciones)
+- Forensic analysis tools
+
+## Arquitectura
+
+```
+ ┌─────────────────────────────────────┐
+ │ MCH-031: Auditoria │
+ └─────────────────────────────────────┘
+ │
+ ┌───────────────────────┴───────────────────────┐
+ ▼ ▼
+ ┌─────────────────────┐ ┌─────────────────────┐
+ │ Audit Logs │ │ Activity Logs │
+ │ (data changes) │ │ (user actions) │
+ └──────────┬──────────┘ └──────────┬──────────┘
+ │ │
+ └──────────────────┬─────────────────────────┘
+ ▼
+ ┌─────────────────────────────────────────┐
+ │ AuditInterceptor │
+ │ (NestJS Global Interceptor) │
+ └─────────────────────────────────────────┘
+ │
+ ┌──────────────────┼──────────────────┐
+ ▼ ▼ ▼
+ ┌──────────┐ ┌──────────┐ ┌──────────┐
+ │ schema │ │ Retencion│ │ Export │
+ │ audit │ │ Policy │ │ CSV │
+ └──────────┘ └──────────┘ └──────────┘
+```
+
+## Entregables
+
+| Entregable | Estado | Sprint | Ubicacion |
+|------------|--------|--------|-----------|
+| Schema audit (DDL) | Planificado | 7 | `database/schemas/14-audit.sql` |
+| AuditInterceptor | Planificado | 7 | `apps/backend/src/common/interceptors/` |
+| AuditService | Planificado | 7 | `apps/backend/src/modules/audit/` |
+| AuditController | Planificado | 7 | `apps/backend/src/modules/audit/` |
+| Retention Job | Planificado | 7 | `apps/backend/src/jobs/` |
+| UI Visor logs | Planificado | 7 | `apps/web/src/pages/admin/audit/` |
+
+## Dependencias
+
+### Depende de
+- Ninguna (puede ejecutarse en paralelo con MCH-029)
+
+### Bloquea a
+- Ninguna
+
+---
+
+## Historias de Usuario
+
+### MCH-US-107: Registro de Acciones
+
+**Como** administrador
+**Quiero** ver un registro de todas las acciones realizadas en el sistema
+**Para** tener trazabilidad y detectar actividades sospechosas
+
+**Story Points:** 3
+
+**Criterios de Aceptacion:**
+- [CA-107-1] Registra CREATE, UPDATE, DELETE automaticamente
+- [CA-107-2] Incluye: usuario, timestamp, IP, user-agent
+- [CA-107-3] Guarda valor anterior y nuevo en cambios (old_value, new_value)
+- [CA-107-4] Filtrable por usuario, accion, entidad, rango de fechas
+- [CA-107-5] Exportable a CSV con columnas seleccionables
+
+**Tareas:**
+| ID | Tarea | Tipo | SP |
+|----|-------|------|-----|
+| MCH-TT-107-01 | DDL schema audit (audit_logs, activity_logs) | DDL | 0.5 |
+| MCH-TT-107-02 | AuditInterceptor global | Backend | 0.5 |
+| MCH-TT-107-03 | AuditService con metodos log/query | Backend | 0.5 |
+| MCH-TT-107-04 | AuditController (GET /audit/logs) | Backend | 0.25 |
+| MCH-TT-107-05 | UI visor de logs con filtros | Frontend | 0.5 |
+| MCH-TT-107-06 | Exportacion CSV | Backend | 0.25 |
+| MCH-TT-107-07 | Tests | Test | 0.25 |
+| MCH-TT-107-08 | Documentacion | Docs | 0.25 |
+
+---
+
+### MCH-US-108: Politica de Retencion
+
+**Como** administrador
+**Quiero** configurar cuanto tiempo se guardan los logs
+**Para** cumplir con politicas de retencion y optimizar almacenamiento
+
+**Story Points:** 2
+
+**Criterios de Aceptacion:**
+- [CA-108-1] Configuracion de dias de retencion: 30, 90, 180, 365
+- [CA-108-2] Job automatico de limpieza (cron diario)
+- [CA-108-3] Opcion de archivar a storage antes de eliminar
+- [CA-108-4] Notificacion por email antes de purga (7 dias antes)
+
+**Tareas:**
+| ID | Tarea | Tipo | SP |
+|----|-------|------|-----|
+| MCH-TT-108-01 | Configuracion de retencion en tenant_settings | Backend | 0.25 |
+| MCH-TT-108-02 | Job de limpieza con BullMQ (cron) | Backend | 0.5 |
+| MCH-TT-108-03 | Archivado opcional a storage (S3) | Backend | 0.5 |
+| MCH-TT-108-04 | Tests | Test | 0.25 |
+| MCH-TT-108-05 | Documentacion de politica de retencion | Docs | 0.5 |
+
+---
+
+## Resumen de Story Points
+
+| Historia | SP | Sprint |
+|----------|-----|--------|
+| MCH-US-107: Registro de Acciones | 3 | 7 |
+| MCH-US-108: Politica de Retencion | 2 | 7 |
+| **TOTAL** | **5** | 7 |
+
+---
+
+## Criterios de Aceptacion de Epica
+
+- [ ] Todas las acciones CRUD se registran automaticamente
+- [ ] Logs visibles en dashboard admin
+- [ ] Exportacion CSV funcional
+- [ ] Job de limpieza ejecutandose diariamente
+- [ ] Cobertura de tests >80%
+
+## Notas Tecnicas
+
+### Schema audit
+
+```sql
+CREATE SCHEMA IF NOT EXISTS audit;
+
+CREATE TABLE audit.audit_logs (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ tenant_id UUID NOT NULL,
+ user_id UUID,
+ action VARCHAR(20) NOT NULL, -- CREATE, UPDATE, DELETE
+ entity_type VARCHAR(100) NOT NULL, -- Product, Order, User
+ entity_id UUID NOT NULL,
+ old_value JSONB,
+ new_value JSONB,
+ ip_address INET,
+ user_agent TEXT,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
+);
+
+CREATE INDEX idx_audit_logs_tenant_date ON audit.audit_logs(tenant_id, created_at DESC);
+CREATE INDEX idx_audit_logs_entity ON audit.audit_logs(entity_type, entity_id);
+```
+
+### Configuracion de Retencion
+```typescript
+// En tenant_settings
+{
+ "audit": {
+ "retention_days": 90,
+ "archive_before_delete": true,
+ "notify_before_purge": true
+ }
+}
+```
+
+## ADRs Relacionados
+
+- [ADR-0008: Audit Log Retention](../97-adr/ADR-0008-audit-log-retention.md)
+
+---
+
+**Ultima actualizacion:** 2026-01-10
+**Autor:** Architecture Team
diff --git a/docs/01-epicas/MCH-032-feature-flags.md b/docs/01-epicas/MCH-032-feature-flags.md
new file mode 100644
index 000000000..c0daff598
--- /dev/null
+++ b/docs/01-epicas/MCH-032-feature-flags.md
@@ -0,0 +1,258 @@
+---
+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 (
+
+ );
+}
+```
+
+## ADRs Relacionados
+
+- [ADR-0005: Feature Flags Strategy](../97-adr/ADR-0005-feature-flags.md)
+
+---
+
+**Ultima actualizacion:** 2026-01-10
+**Autor:** Architecture Team
diff --git a/docs/01-epicas/MCH-033-onboarding-wizard.md b/docs/01-epicas/MCH-033-onboarding-wizard.md
new file mode 100644
index 000000000..2ec093bba
--- /dev/null
+++ b/docs/01-epicas/MCH-033-onboarding-wizard.md
@@ -0,0 +1,236 @@
+---
+id: EPIC-MCH-033
+type: Epic
+title: "MCH-033: Onboarding Wizard"
+code: MCH-033
+status: Planificado
+phase: 8
+priority: P2
+created_at: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+dependencies:
+ blocks: []
+ depends_on: ["MCH-029"]
+---
+
+# MCH-033: Onboarding Wizard
+
+## Metadata
+- **Codigo:** MCH-033
+- **Fase:** 8 - Mejoras UX
+- **Prioridad:** P2
+- **Estado:** Planificado
+- **Story Points:** 3
+- **Sprint Objetivo:** Sprint 9
+
+## Descripcion
+
+Crear asistente interactivo de configuracion inicial que guie al usuario en los primeros pasos de setup de su negocio. Reduce friccion, aumenta activacion y mejora la experiencia de primer uso.
+
+## Objetivos
+
+1. Guiar configuracion inicial de negocio
+2. Facilitar carga de primeros productos
+3. Configurar metodos de pago
+4. Invitar al equipo
+5. Mostrar tour interactivo de la app
+
+## Alcance
+
+### Incluido
+- Wizard de 5 pasos con progreso
+- Persistencia de progreso (continuar despues)
+- Skip opcional por paso
+- Productos sugeridos por giro de negocio
+- Animacion de celebracion al completar
+
+### Excluido
+- Migracion desde otros sistemas
+- Importacion masiva de productos (otra feature)
+- Video tutoriales (contenido futuro)
+
+## Arquitectura
+
+```
+ ┌─────────────────────────────────────┐
+ │ MCH-033: Onboarding Wizard │
+ └─────────────────────────────────────┘
+ │
+ ┌─────────────────────────────┼─────────────────────────────┐
+ ▼ ▼ ▼
+ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
+ │ Paso 1 │ │ Paso 2 │ │ Paso 3 │
+ │ Mi Negocio │ ───> │ Productos │ ───> │ Pagos │
+ └──────────────┘ └──────────────┘ └──────────────┘
+ │
+ ▼
+ ┌──────────────┐ ┌──────────────┐
+ │ Paso 5 │ <─── │ Paso 4 │
+ │ Completar │ │ Mi Equipo │
+ └──────────────┘ └──────────────┘
+
+ ┌─────────────────────────────────────┐
+ │ Onboarding Progress │
+ │ (tenant_settings.onboarding) │
+ └─────────────────────────────────────┘
+```
+
+## Entregables
+
+| Entregable | Estado | Sprint | Ubicacion |
+|------------|--------|--------|-----------|
+| OnboardingWizard component | Planificado | 9 | `apps/web/src/components/onboarding/` |
+| BusinessSetupStep | Planificado | 9 | `apps/web/src/components/onboarding/steps/` |
+| ProductsStep | Planificado | 9 | `apps/web/src/components/onboarding/steps/` |
+| PaymentsStep | Planificado | 9 | `apps/web/src/components/onboarding/steps/` |
+| TeamStep | Planificado | 9 | `apps/web/src/components/onboarding/steps/` |
+| CompletionStep | Planificado | 9 | `apps/web/src/components/onboarding/steps/` |
+
+## Dependencias
+
+### Depende de
+- MCH-029 (Infraestructura completa para guardar progreso)
+
+### Bloquea a
+- Ninguna
+
+---
+
+## Historias de Usuario
+
+### MCH-US-111: Wizard de Configuracion
+
+**Como** usuario nuevo
+**Quiero** una guia paso a paso para configurar mi negocio
+**Para** empezar a usar la app rapidamente
+
+**Story Points:** 3
+
+**Criterios de Aceptacion:**
+- [CA-111-1] Wizard de 5 pasos: Negocio, Productos, Pagos, Equipo, Completar
+- [CA-111-2] Progreso guardado en backend (puede cerrar y continuar)
+- [CA-111-3] Skip opcional por cada paso (excepto paso 1)
+- [CA-111-4] Productos iniciales sugeridos segun giro seleccionado
+- [CA-111-5] Animacion de confetti al completar
+
+**Tareas:**
+| ID | Tarea | Tipo | SP |
+|----|-------|------|-----|
+| MCH-TT-111-01 | OnboardingWizard container | Frontend | 0.25 |
+| MCH-TT-111-02 | Paso 1: Datos de negocio (nombre, giro, logo) | Frontend | 0.5 |
+| MCH-TT-111-03 | Paso 2: Productos iniciales (templates por giro) | Frontend | 0.5 |
+| MCH-TT-111-04 | Paso 3: Metodos de pago (conexion Stripe/MercadoPago) | Frontend | 0.5 |
+| MCH-TT-111-05 | Paso 4: Invitar equipo (emails de colaboradores) | Frontend | 0.25 |
+| MCH-TT-111-06 | Paso 5: Completar con confetti y tour | Frontend | 0.25 |
+| MCH-TT-111-07 | Persistencia de progreso en backend | Backend | 0.25 |
+| MCH-TT-111-08 | Tests | Test | 0.25 |
+| MCH-TT-111-09 | Documentacion | Docs | 0.25 |
+
+---
+
+## Resumen de Story Points
+
+| Historia | SP | Sprint |
+|----------|-----|--------|
+| MCH-US-111: Wizard de Configuracion | 3 | 9 |
+| **TOTAL** | **3** | 9 |
+
+---
+
+## Criterios de Aceptacion de Epica
+
+- [ ] Wizard visible para nuevos usuarios
+- [ ] Progreso persistido correctamente
+- [ ] Productos sugeridos por giro funcionando
+- [ ] Animacion de celebracion al completar
+- [ ] Tests de flujo completo
+
+## Notas Tecnicas
+
+### Persistencia de Progreso
+
+```typescript
+// tenant_settings.onboarding
+{
+ "current_step": 2,
+ "completed_steps": [1],
+ "skipped_steps": [],
+ "started_at": "2026-01-10T10:00:00Z",
+ "completed_at": null,
+ "data": {
+ "business_type": "abarrotes",
+ "products_count": 15
+ }
+}
+```
+
+### Giros y Productos Sugeridos
+
+| Giro | Productos Sugeridos |
+|------|---------------------|
+| Abarrotes | Refrescos, Galletas, Pan, Leche, Huevos |
+| Papeleria | Cuadernos, Lapices, Colores, Folders |
+| Ferreteria | Tornillos, Pintura, Brochas, Herramientas |
+| Farmacia | Medicamentos basicos, Vitaminas |
+| Comida | Tacos, Tortas, Aguas, Refrescos |
+
+### Componente OnboardingWizard
+
+```tsx
+function OnboardingWizard() {
+ const [step, setStep] = useState(1);
+ const [progress, saveProgress] = useOnboardingProgress();
+
+ const steps = [
+ { id: 1, name: 'Mi Negocio', component: BusinessSetupStep },
+ { id: 2, name: 'Productos', component: ProductsStep },
+ { id: 3, name: 'Pagos', component: PaymentsStep },
+ { id: 4, name: 'Mi Equipo', component: TeamStep },
+ { id: 5, name: 'Completar', component: CompletionStep },
+ ];
+
+ const CurrentStep = steps[step - 1].component;
+
+ return (
+
+
+
setStep(s => s + 1)}
+ onSkip={() => setStep(s => s + 1)}
+ saveProgress={saveProgress}
+ />
+
+ );
+}
+```
+
+### Animacion de Celebracion
+
+Usar libreria `canvas-confetti` para el efecto de confetti al completar:
+
+```tsx
+import confetti from 'canvas-confetti';
+
+function CompletionStep() {
+ useEffect(() => {
+ confetti({
+ particleCount: 100,
+ spread: 70,
+ origin: { y: 0.6 }
+ });
+ }, []);
+
+ return (
+
+
Tu negocio esta listo
+
+
+ );
+}
+```
+
+---
+
+**Ultima actualizacion:** 2026-01-10
+**Autor:** Architecture Team
diff --git a/docs/01-epicas/_MAP.md b/docs/01-epicas/_MAP.md
index 63a6e972f..1831b0adb 100644
--- a/docs/01-epicas/_MAP.md
+++ b/docs/01-epicas/_MAP.md
@@ -95,13 +95,23 @@
| MCH-024 | CoDi y SPEI | QR de cobro, CLABE virtual | P2 |
| MCH-025 | Widgets y Atajos | Android widgets, quick actions | P2 |
-### FASE 7: EXPANSIÓN (Futuro)
+### FASE 7: EXPANSIÓN
| ID | Épica | Descripción | Prioridad |
|----|-------|-------------|-----------|
| MCH-026 | Multi-idioma LATAM | i18n, localización | P3 |
| MCH-027 | Integración SAT | Facturación simplificada | P3 |
| MCH-028 | Marketplace Proveedores | Conexión con distribuidores | P3 |
+| MCH-029 | Infraestructura SaaS Avanzada | Email, Storage, Redis, Webhooks, Rate Limiting | P0 |
+| MCH-030 | Auth Social (OAuth 2.0) | Login con Google/Apple | P1 |
+| MCH-031 | Auditoria Empresarial | Audit logs, retencion, compliance | P1 |
+| MCH-032 | Feature Flags por Plan | Toggles por plan/tenant | P1 |
+
+### FASE 8: MEJORAS UX
+
+| ID | Épica | Descripción | Prioridad |
+|----|-------|-------------|-----------|
+| MCH-033 | Onboarding Wizard | Guia interactiva de setup | P2 |
## Índice de Archivos de Épicas
@@ -135,7 +145,12 @@ docs/01-epicas/
├── MCH-025-widgets-atajos.md
├── MCH-026-multi-idioma-latam.md
├── MCH-027-integracion-sat.md
-└── MCH-028-marketplace-proveedores.md
+├── MCH-028-marketplace-proveedores.md
+├── MCH-029-infraestructura-saas.md
+├── MCH-030-auth-social.md
+├── MCH-031-auditoria-empresarial.md
+├── MCH-032-feature-flags.md
+└── MCH-033-onboarding-wizard.md
```
## Dependencias entre Épicas
@@ -177,5 +192,6 @@ MCH-018 ─────┬─────► MCH-019 ─────► MCH-020
---
-**Versión**: 2.0.0
+**Versión**: 3.0.0
**Última actualización**: 2026-01-10
+**Total Épicas**: 33 (MCH-001 a MCH-033)
diff --git a/docs/02-devops/CICD-GUIDE.md b/docs/02-devops/CICD-GUIDE.md
new file mode 100644
index 000000000..966f4a2fb
--- /dev/null
+++ b/docs/02-devops/CICD-GUIDE.md
@@ -0,0 +1,81 @@
+# CI/CD Guide - MiChangarrito
+
+## Overview
+
+Este documento describe la configuracion de CI/CD para michangarrito.
+
+## Stack DevOps
+
+- **Container Runtime**: Docker
+- **Orchestration**: Docker Compose (desarrollo), Kubernetes (produccion)
+- **CI/CD**: GitHub Actions
+- **Registry**: Docker Hub / GitHub Container Registry
+- **Mobile**: Expo EAS Build
+
+## Pipelines
+
+### Build Pipeline
+
+```yaml
+# .github/workflows/build.yml
+name: Build
+on: [push, pull_request]
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ - run: npm ci
+ - run: npm run build
+ - run: npm test
+```
+
+### Mobile Build (Expo EAS)
+
+```yaml
+# .github/workflows/mobile.yml
+name: Mobile Build
+on:
+ push:
+ branches: [main]
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: expo/expo-github-action@v8
+ with:
+ eas-version: latest
+ token: ${{ secrets.EXPO_TOKEN }}
+ - run: eas build --platform all --non-interactive
+```
+
+## Environments
+
+| Environment | Branch | URL |
+|-------------|--------|-----|
+| Development | develop | localhost |
+| Staging | staging | TBD |
+| Production | main | TBD |
+
+## Apps
+
+| App | Tipo | Build |
+|-----|------|-------|
+| backend | NestJS | Docker |
+| web | React | Docker |
+| mobile | Expo | EAS Build |
+| mcp-server | TypeScript | Docker |
+| whatsapp-service | NestJS | Docker |
+
+## Docker Setup
+
+Ver [DOCKER-SETUP.md](./DOCKER-SETUP.md)
+
+---
+
+**Ultima actualizacion**: 2026-01-10
+**Estado**: Placeholder - Completar con detalles del proyecto
diff --git a/docs/02-devops/DOCKER-SETUP.md b/docs/02-devops/DOCKER-SETUP.md
new file mode 100644
index 000000000..6d1e0d5b3
--- /dev/null
+++ b/docs/02-devops/DOCKER-SETUP.md
@@ -0,0 +1,96 @@
+# Docker Setup - MiChangarrito
+
+## Overview
+
+Configuracion de Docker para desarrollo y produccion.
+
+## Servicios
+
+| Servicio | Puerto | Descripcion |
+|----------|--------|-------------|
+| backend | 3141 | API NestJS |
+| web | 3140 | Dashboard React |
+| mcp-server | 3142 | Gateway LLM |
+| whatsapp-service | 3143 | Bot WhatsApp |
+| postgres | 5432 | Base de datos |
+| redis | 6379 | Cache y queues |
+
+## Desarrollo Local
+
+```bash
+# Iniciar todos los servicios
+docker-compose up -d
+
+# Ver logs
+docker-compose logs -f backend
+
+# Detener
+docker-compose down
+```
+
+## docker-compose.yml
+
+```yaml
+version: '3.8'
+services:
+ backend:
+ build: ./apps/backend
+ ports:
+ - "3141:3141"
+ environment:
+ - NODE_ENV=development
+ - DATABASE_URL=postgresql://postgres:postgres@postgres:5432/michangarrito
+ depends_on:
+ - postgres
+ - redis
+
+ web:
+ build: ./apps/web
+ ports:
+ - "3140:3140"
+ depends_on:
+ - backend
+
+ mcp-server:
+ build: ./apps/mcp-server
+ ports:
+ - "3142:3142"
+ depends_on:
+ - backend
+
+ whatsapp-service:
+ build: ./apps/whatsapp-service
+ ports:
+ - "3143:3143"
+ environment:
+ - WHATSAPP_TOKEN=${WHATSAPP_TOKEN}
+ depends_on:
+ - backend
+ - redis
+
+ postgres:
+ image: postgres:16
+ environment:
+ - POSTGRES_DB=michangarrito
+ - POSTGRES_USER=postgres
+ - POSTGRES_PASSWORD=postgres
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+
+ redis:
+ image: redis:7-alpine
+ ports:
+ - "6379:6379"
+
+volumes:
+ postgres_data:
+```
+
+## Produccion
+
+TODO: Documentar configuracion de produccion con Kubernetes
+
+---
+
+**Ultima actualizacion**: 2026-01-10
+**Estado**: Placeholder - Completar con detalles del proyecto
diff --git a/docs/02-integraciones/INT-010-email-providers.md b/docs/02-integraciones/INT-010-email-providers.md
new file mode 100644
index 000000000..d413f16a3
--- /dev/null
+++ b/docs/02-integraciones/INT-010-email-providers.md
@@ -0,0 +1,308 @@
+---
+id: INT-010
+type: Integration
+title: "Email Multi-Provider"
+provider: "SendGrid/SES/SMTP"
+status: Planificado
+integration_type: "notifications"
+created_at: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+tags:
+ - email
+ - notifications
+ - transactional
+ - multi-provider
+---
+
+# INT-010: Email Multi-Provider
+
+## Metadata
+
+| Campo | Valor |
+|-------|-------|
+| **Codigo** | INT-010 |
+| **Proveedor** | SendGrid, AWS SES, SMTP |
+| **Tipo** | Notificaciones |
+| **Estado** | Planificado |
+| **Multi-tenant** | Si |
+| **Epic Relacionada** | MCH-029 |
+| **Owner** | Backend Team |
+
+---
+
+## 1. Descripcion
+
+Sistema de envio de emails transaccionales con soporte para multiples proveedores y fallback automatico. Incluye templates reutilizables, tracking de entrega y rate limiting por tenant.
+
+**Casos de uso principales:**
+- Emails de bienvenida y verificacion
+- Notificaciones de pedidos
+- Recordatorios de pago
+- Alertas de inventario bajo
+- Reportes programados
+
+---
+
+## 2. Credenciales Requeridas
+
+### Variables de Entorno
+
+| Variable | Descripcion | Tipo | Obligatorio |
+|----------|-------------|------|-------------|
+| `EMAIL_PROVIDER` | Proveedor principal (sendgrid/ses/smtp) | string | SI |
+| `SENDGRID_API_KEY` | API Key de SendGrid | string | SI (si usa SendGrid) |
+| `AWS_SES_REGION` | Region de AWS SES | string | SI (si usa SES) |
+| `AWS_SES_ACCESS_KEY` | Access Key para SES | string | SI (si usa SES) |
+| `AWS_SES_SECRET_KEY` | Secret Key para SES | string | SI (si usa SES) |
+| `SMTP_HOST` | Host del servidor SMTP | string | SI (si usa SMTP) |
+| `SMTP_PORT` | Puerto SMTP | number | SI (si usa SMTP) |
+| `SMTP_USER` | Usuario SMTP | string | SI (si usa SMTP) |
+| `SMTP_PASS` | Password SMTP | string | SI (si usa SMTP) |
+| `EMAIL_FROM_ADDRESS` | Email de remitente | string | SI |
+| `EMAIL_FROM_NAME` | Nombre de remitente | string | SI |
+
+### Ejemplo de .env
+
+```env
+# Email Configuration
+EMAIL_PROVIDER=sendgrid
+EMAIL_FROM_ADDRESS=noreply@michangarrito.com
+EMAIL_FROM_NAME=MiChangarrito
+
+# SendGrid
+SENDGRID_API_KEY=SG.xxxxxxxxxxxxxxxx
+
+# AWS SES (fallback)
+AWS_SES_REGION=us-east-1
+AWS_SES_ACCESS_KEY=AKIAXXXXXXXXXXXXXXXX
+AWS_SES_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+
+# SMTP (ultimo recurso)
+SMTP_HOST=smtp.mailtrap.io
+SMTP_PORT=587
+SMTP_USER=xxxxxxxx
+SMTP_PASS=xxxxxxxx
+```
+
+---
+
+## 3. Endpoints/SDK Utilizados
+
+### SendGrid
+
+| Operacion | Metodo | Endpoint | Descripcion |
+|-----------|--------|----------|-------------|
+| Enviar email | POST | `/v3/mail/send` | Envio simple o con template |
+| Templates | GET | `/v3/templates` | Listar templates |
+
+### AWS SES
+
+| Operacion | SDK Method | Descripcion |
+|-----------|------------|-------------|
+| Enviar email | `sendEmail()` | Via AWS SDK v3 |
+| Enviar raw | `sendRawEmail()` | Con attachments |
+
+### SMTP
+
+```typescript
+import * as nodemailer from 'nodemailer';
+
+const transporter = nodemailer.createTransport({
+ host: process.env.SMTP_HOST,
+ port: parseInt(process.env.SMTP_PORT),
+ auth: {
+ user: process.env.SMTP_USER,
+ pass: process.env.SMTP_PASS,
+ },
+});
+```
+
+---
+
+## 4. Rate Limits
+
+| Proveedor | Limite | Periodo | Plan SendGrid |
+|-----------|--------|---------|---------------|
+| SendGrid | 100 | por segundo | Pro |
+| SendGrid | 40,000 | por mes | Free |
+| AWS SES | 14 | por segundo | Default |
+| AWS SES | 50,000 | por dia | Verified |
+
+### Rate Limiting por Tenant
+
+| Plan MCH | Emails/hora | Emails/dia |
+|----------|-------------|------------|
+| Basic | 100 | 500 |
+| Pro | 1,000 | 10,000 |
+| Enterprise | Ilimitado | Ilimitado |
+
+---
+
+## 5. Manejo de Errores
+
+| Codigo | Descripcion | Accion | Retry |
+|--------|-------------|--------|-------|
+| 400 | Email invalido | Validar formato | NO |
+| 401 | API Key invalida | Verificar credencial | NO |
+| 429 | Rate limit | Esperar + retry | SI |
+| 500 | Error proveedor | Fallback a siguiente | SI |
+| 503 | Servicio no disponible | Fallback | SI |
+
+### Estrategia de Fallback
+
+```typescript
+const providers = ['sendgrid', 'ses', 'smtp'];
+
+async function sendWithFallback(email: EmailDto) {
+ for (const provider of providers) {
+ try {
+ return await this.send(provider, email);
+ } catch (error) {
+ this.logger.warn(`Provider ${provider} failed, trying next`);
+ continue;
+ }
+ }
+ throw new Error('All email providers failed');
+}
+```
+
+---
+
+## 6. Templates
+
+### Templates Disponibles
+
+| Template | Descripcion | Variables |
+|----------|-------------|-----------|
+| welcome | Bienvenida | `{name}` |
+| verify_email | Verificacion | `{name}, {link}` |
+| order_confirmation | Pedido confirmado | `{order_id}, {items}` |
+| payment_reminder | Recordatorio pago | `{amount}, {due_date}` |
+| low_inventory | Alerta inventario | `{product}, {quantity}` |
+
+### Formato de Template (Handlebars)
+
+```html
+Hola {{name}}
+Tu pedido #{{order_id}} ha sido confirmado.
+{{#each items}}
+ {{this.name}} x {{this.quantity}}
+{{/each}}
+```
+
+---
+
+## 7. Multi-tenant
+
+### Modelo de Credenciales
+
+- [x] **Global:** Credenciales compartidas por defecto
+- [x] **Por Tenant:** Tenant puede configurar sus propias credenciales
+- [x] **Branding:** From address personalizable por tenant (Enterprise)
+
+### Almacenamiento
+
+```sql
+CREATE TABLE messaging.tenant_email_config (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ tenant_id UUID REFERENCES auth.tenants(id) NOT NULL,
+ provider VARCHAR(20) NOT NULL, -- sendgrid, ses, smtp
+ from_address VARCHAR(255) NOT NULL,
+ from_name VARCHAR(100),
+ credentials JSONB NOT NULL, -- Encriptado
+ is_active BOOLEAN DEFAULT true,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ UNIQUE(tenant_id)
+);
+```
+
+---
+
+## 8. Tablas de BD
+
+### email_templates
+
+```sql
+CREATE TABLE messaging.email_templates (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ tenant_id UUID REFERENCES auth.tenants(id),
+ key VARCHAR(100) NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ subject VARCHAR(255) NOT NULL,
+ html_content TEXT NOT NULL,
+ text_content TEXT,
+ variables JSONB,
+ is_active BOOLEAN DEFAULT true,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ UNIQUE(tenant_id, key)
+);
+```
+
+### email_logs
+
+```sql
+CREATE TABLE messaging.email_logs (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ tenant_id UUID NOT NULL,
+ template_id UUID REFERENCES messaging.email_templates(id),
+ to_address VARCHAR(255) NOT NULL,
+ subject VARCHAR(255) NOT NULL,
+ provider VARCHAR(20) NOT NULL,
+ provider_message_id VARCHAR(255),
+ status VARCHAR(20) NOT NULL, -- sent, delivered, opened, clicked, bounced, failed
+ error_message TEXT,
+ sent_at TIMESTAMP WITH TIME ZONE,
+ delivered_at TIMESTAMP WITH TIME ZONE,
+ opened_at TIMESTAMP WITH TIME ZONE,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
+);
+```
+
+---
+
+## 9. Testing
+
+### Modo Sandbox
+
+| Ambiente | Proveedor | Comportamiento |
+|----------|-----------|----------------|
+| Development | Mailtrap | Emails atrapados, no enviados |
+| Staging | SendGrid Sandbox | Emails simulados |
+| Production | SendGrid/SES | Envio real |
+
+### Test de Conexion
+
+```bash
+# Test SendGrid
+curl -X POST "https://api.sendgrid.com/v3/mail/send" \
+ -H "Authorization: Bearer $SENDGRID_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{"personalizations":[{"to":[{"email":"test@example.com"}]}],"from":{"email":"noreply@michangarrito.com"},"subject":"Test","content":[{"type":"text/plain","value":"Test email"}]}'
+```
+
+---
+
+## 10. Monitoreo
+
+### Metricas
+
+| Metrica | Descripcion | Alerta |
+|---------|-------------|--------|
+| email_sent_total | Emails enviados | - |
+| email_failed_total | Emails fallidos | > 5% |
+| email_delivery_rate | Tasa de entrega | < 95% |
+| email_bounce_rate | Tasa de rebote | > 5% |
+
+---
+
+## 11. Referencias
+
+- [SendGrid API Docs](https://docs.sendgrid.com/api-reference)
+- [AWS SES Developer Guide](https://docs.aws.amazon.com/ses/)
+- [Nodemailer Docs](https://nodemailer.com/)
+
+---
+
+**Ultima actualizacion:** 2026-01-10
+**Autor:** Backend Team
diff --git a/docs/02-integraciones/INT-011-storage-cloud.md b/docs/02-integraciones/INT-011-storage-cloud.md
new file mode 100644
index 000000000..6cf51f659
--- /dev/null
+++ b/docs/02-integraciones/INT-011-storage-cloud.md
@@ -0,0 +1,328 @@
+---
+id: INT-011
+type: Integration
+title: "Storage Cloud"
+provider: "AWS S3/Cloudflare R2/MinIO"
+status: Planificado
+integration_type: "storage"
+created_at: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+tags:
+ - storage
+ - s3
+ - r2
+ - files
+ - multi-cloud
+---
+
+# INT-011: Storage Cloud
+
+## Metadata
+
+| Campo | Valor |
+|-------|-------|
+| **Codigo** | INT-011 |
+| **Proveedor** | AWS S3, Cloudflare R2, MinIO |
+| **Tipo** | Almacenamiento |
+| **Estado** | Planificado |
+| **Multi-tenant** | Si |
+| **Epic Relacionada** | MCH-029 |
+| **Owner** | Backend Team |
+
+---
+
+## 1. Descripcion
+
+Sistema de almacenamiento abstracto que soporta multiples proveedores cloud (S3, R2, MinIO). Permite subir archivos como imagenes de productos, facturas y documentos con URLs firmadas y control de acceso por tenant.
+
+**Casos de uso principales:**
+- Imagenes de productos
+- Fotos de perfil de usuario
+- Facturas y recibos PDF
+- Respaldos de datos
+- Assets de la tienda (logo, banner)
+
+---
+
+## 2. Credenciales Requeridas
+
+### Variables de Entorno
+
+| Variable | Descripcion | Tipo | Obligatorio |
+|----------|-------------|------|-------------|
+| `STORAGE_PROVIDER` | Proveedor (s3/r2/minio) | string | SI |
+| `S3_BUCKET` | Nombre del bucket | string | SI |
+| `S3_REGION` | Region AWS | string | SI (S3) |
+| `S3_ACCESS_KEY` | Access Key | string | SI |
+| `S3_SECRET_KEY` | Secret Key | string | SI |
+| `S3_ENDPOINT` | Endpoint custom (R2/MinIO) | string | NO |
+| `STORAGE_CDN_URL` | URL de CDN (opcional) | string | NO |
+
+### Ejemplo de .env
+
+```env
+# Storage Configuration
+STORAGE_PROVIDER=s3
+
+# AWS S3
+S3_BUCKET=michangarrito-uploads
+S3_REGION=us-east-1
+S3_ACCESS_KEY=AKIAXXXXXXXXXXXXXXXX
+S3_SECRET_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+
+# Cloudflare R2 (alternativa)
+# STORAGE_PROVIDER=r2
+# S3_ENDPOINT=https://xxx.r2.cloudflarestorage.com
+# S3_ACCESS_KEY=xxx
+# S3_SECRET_KEY=xxx
+
+# MinIO (desarrollo)
+# STORAGE_PROVIDER=minio
+# S3_ENDPOINT=http://localhost:9000
+# S3_ACCESS_KEY=minioadmin
+# S3_SECRET_KEY=minioadmin
+```
+
+---
+
+## 3. SDK Utilizado
+
+### AWS SDK v3
+
+```typescript
+import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
+import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
+
+const s3Client = new S3Client({
+ region: process.env.S3_REGION,
+ endpoint: process.env.S3_ENDPOINT,
+ credentials: {
+ accessKeyId: process.env.S3_ACCESS_KEY,
+ secretAccessKey: process.env.S3_SECRET_KEY,
+ },
+});
+```
+
+### Operaciones
+
+| Operacion | Comando SDK | Descripcion |
+|-----------|-------------|-------------|
+| Upload | PutObjectCommand | Subir archivo |
+| Download | GetObjectCommand | Descargar archivo |
+| Delete | DeleteObjectCommand | Eliminar archivo |
+| List | ListObjectsV2Command | Listar archivos |
+| Signed URL | getSignedUrl | URL temporal |
+
+---
+
+## 4. Limites por Plan
+
+| Plan | Almacenamiento | Archivos Max | Tamano Max/Archivo |
+|------|----------------|--------------|-------------------|
+| Basic | 1 GB | 500 | 5 MB |
+| Pro | 10 GB | 5,000 | 25 MB |
+| Enterprise | 100 GB | 50,000 | 100 MB |
+
+### MIME Types Permitidos
+
+```typescript
+const ALLOWED_MIME_TYPES = [
+ 'image/jpeg',
+ 'image/png',
+ 'image/webp',
+ 'image/gif',
+ 'application/pdf',
+ 'application/vnd.ms-excel',
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+];
+```
+
+---
+
+## 5. Manejo de Errores
+
+| Codigo | Descripcion | Accion | Retry |
+|--------|-------------|--------|-------|
+| 400 | Archivo invalido | Validar MIME/size | NO |
+| 403 | Sin permisos | Verificar policy | NO |
+| 404 | Archivo no existe | - | NO |
+| 413 | Archivo muy grande | Reducir tamano | NO |
+| 500 | Error de storage | Retry | SI |
+| 503 | Servicio no disponible | Retry con backoff | SI |
+
+---
+
+## 6. Estructura de Archivos
+
+### Path Convention
+
+```
+{bucket}/
+├── tenants/
+│ └── {tenant_id}/
+│ ├── products/
+│ │ └── {product_id}/
+│ │ ├── main.jpg
+│ │ └── thumb.jpg
+│ ├── invoices/
+│ │ └── {year}/{month}/
+│ │ └── INV-{id}.pdf
+│ ├── users/
+│ │ └── {user_id}/
+│ │ └── avatar.jpg
+│ └── assets/
+│ ├── logo.png
+│ └── banner.jpg
+└── public/
+ └── templates/
+```
+
+### Ejemplo de Path
+
+```
+tenants/550e8400-e29b-41d4-a716-446655440000/products/abc123/main.jpg
+```
+
+---
+
+## 7. URLs Firmadas
+
+### Generacion
+
+```typescript
+async function getSignedUploadUrl(
+ tenantId: string,
+ filename: string,
+ contentType: string,
+ expiresIn: number = 3600
+): Promise {
+ const key = `tenants/${tenantId}/uploads/${Date.now()}-${filename}`;
+
+ const command = new PutObjectCommand({
+ Bucket: process.env.S3_BUCKET,
+ Key: key,
+ ContentType: contentType,
+ });
+
+ return getSignedUrl(s3Client, command, { expiresIn });
+}
+```
+
+### Expiracion por Tipo
+
+| Tipo | Expiracion | Uso |
+|------|------------|-----|
+| Upload | 1 hora | Subida de archivos |
+| Download publico | 24 horas | Imagenes de productos |
+| Download privado | 15 minutos | Facturas, documentos |
+
+---
+
+## 8. Multi-tenant
+
+### Aislamiento
+
+- Cada tenant tiene su propio directorio
+- RLS en tabla `files` por `tenant_id`
+- Bucket policies restringen acceso
+
+### Almacenamiento de Metadata
+
+```sql
+CREATE SCHEMA IF NOT EXISTS storage;
+
+CREATE TABLE storage.files (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ tenant_id UUID NOT NULL,
+ folder_id UUID REFERENCES storage.folders(id),
+ name VARCHAR(255) NOT NULL,
+ original_name VARCHAR(255) NOT NULL,
+ path VARCHAR(1000) NOT NULL,
+ size_bytes BIGINT NOT NULL,
+ mime_type VARCHAR(100) NOT NULL,
+ provider VARCHAR(20) NOT NULL,
+ url TEXT,
+ is_public BOOLEAN DEFAULT false,
+ metadata JSONB,
+ created_by UUID,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ deleted_at TIMESTAMP WITH TIME ZONE
+);
+
+CREATE TABLE storage.folders (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ tenant_id UUID NOT NULL,
+ parent_id UUID REFERENCES storage.folders(id),
+ name VARCHAR(255) NOT NULL,
+ path VARCHAR(1000) NOT NULL,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
+);
+
+CREATE TABLE storage.storage_usage (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ tenant_id UUID UNIQUE NOT NULL,
+ bytes_used BIGINT DEFAULT 0,
+ files_count INTEGER DEFAULT 0,
+ last_calculated_at TIMESTAMP WITH TIME ZONE
+);
+```
+
+---
+
+## 9. Testing
+
+### MinIO para Desarrollo
+
+```yaml
+# docker-compose.yml
+services:
+ minio:
+ image: minio/minio:latest
+ ports:
+ - "9000:9000"
+ - "9001:9001"
+ environment:
+ MINIO_ROOT_USER: minioadmin
+ MINIO_ROOT_PASSWORD: minioadmin
+ command: server /data --console-address ":9001"
+ volumes:
+ - minio_data:/data
+```
+
+### Test de Conexion
+
+```bash
+# Listar buckets
+aws s3 ls --endpoint-url http://localhost:9000
+
+# Subir archivo
+aws s3 cp test.jpg s3://michangarrito-uploads/test/ --endpoint-url http://localhost:9000
+```
+
+---
+
+## 10. Monitoreo
+
+### Metricas
+
+| Metrica | Descripcion | Alerta |
+|---------|-------------|--------|
+| storage_bytes_total | Bytes usados | > 80% plan |
+| storage_uploads_total | Uploads exitosos | - |
+| storage_failures_total | Uploads fallidos | > 5% |
+| storage_signed_urls_total | URLs generadas | - |
+
+---
+
+## 11. Referencias
+
+- [AWS S3 Developer Guide](https://docs.aws.amazon.com/s3/)
+- [Cloudflare R2 Docs](https://developers.cloudflare.com/r2/)
+- [MinIO Docs](https://min.io/docs/minio/linux/index.html)
+- [ADR-0006: Storage Abstraction](../97-adr/ADR-0006-storage-abstraction.md)
+
+---
+
+**Ultima actualizacion:** 2026-01-10
+**Autor:** Backend Team
diff --git a/docs/02-integraciones/INT-012-oauth-social.md b/docs/02-integraciones/INT-012-oauth-social.md
new file mode 100644
index 000000000..bec78b0e5
--- /dev/null
+++ b/docs/02-integraciones/INT-012-oauth-social.md
@@ -0,0 +1,363 @@
+---
+id: INT-012
+type: Integration
+title: "OAuth Social"
+provider: "Google/Apple"
+status: Planificado
+integration_type: "auth"
+created_at: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+tags:
+ - oauth
+ - authentication
+ - google
+ - apple
+ - social-login
+---
+
+# INT-012: OAuth Social
+
+## Metadata
+
+| Campo | Valor |
+|-------|-------|
+| **Codigo** | INT-012 |
+| **Proveedor** | Google, Apple |
+| **Tipo** | Autenticacion |
+| **Estado** | Planificado |
+| **Multi-tenant** | Si |
+| **Epic Relacionada** | MCH-030 |
+| **Owner** | Backend Team |
+
+---
+
+## 1. Descripcion
+
+Integracion OAuth 2.0 para login social con Google y Apple. Permite a los usuarios registrarse e iniciar sesion con un clic usando sus cuentas existentes.
+
+**Casos de uso principales:**
+- Registro simplificado (un clic)
+- Login sin password
+- Vinculacion de cuenta social a cuenta existente
+- Sync de perfil (nombre, foto)
+
+---
+
+## 2. Credenciales Requeridas
+
+### Google OAuth
+
+| Variable | Descripcion | Tipo | Obligatorio |
+|----------|-------------|------|-------------|
+| `GOOGLE_CLIENT_ID` | Client ID de Google Cloud | string | SI |
+| `GOOGLE_CLIENT_SECRET` | Client Secret | string | SI |
+| `GOOGLE_CALLBACK_URL` | URL de callback | string | SI |
+
+### Apple Sign-In
+
+| Variable | Descripcion | Tipo | Obligatorio |
+|----------|-------------|------|-------------|
+| `APPLE_CLIENT_ID` | Service ID (web) o App ID (iOS) | string | SI |
+| `APPLE_TEAM_ID` | Team ID de Apple Developer | string | SI |
+| `APPLE_KEY_ID` | Key ID del private key | string | SI |
+| `APPLE_PRIVATE_KEY` | Private key (.p8 content) | string | SI |
+| `APPLE_CALLBACK_URL` | URL de callback | string | SI |
+
+### Ejemplo de .env
+
+```env
+# Google OAuth
+GOOGLE_CLIENT_ID=xxxx.apps.googleusercontent.com
+GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxx
+GOOGLE_CALLBACK_URL=https://api.michangarrito.com/auth/google/callback
+
+# Apple Sign-In
+APPLE_CLIENT_ID=com.michangarrito.web
+APPLE_TEAM_ID=XXXXXXXXXX
+APPLE_KEY_ID=XXXXXXXXXX
+APPLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIGT....\n-----END PRIVATE KEY-----"
+APPLE_CALLBACK_URL=https://api.michangarrito.com/auth/apple/callback
+```
+
+---
+
+## 3. Flujo OAuth 2.0
+
+### Google
+
+```
+┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
+│ Client │────>│ /auth/ │────>│ Google │────>│ Callback │
+│ (Web/ │ │ google │ │ OAuth │ │ /auth/ │
+│ Mobile) │ │ │ │ Screen │ │ google/ │
+└──────────┘ └──────────┘ └──────────┘ │ callback │
+ └────┬─────┘
+ │
+ ▼
+┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
+│ JWT │<────│ Create/ │<────│ Verify │<────│ Get │
+│ Token │ │ Link │ │ Token │ │ Profile │
+│ │ │ User │ │ │ │ │
+└──────────┘ └──────────┘ └──────────┘ └──────────┘
+```
+
+### Endpoints
+
+| Ruta | Metodo | Descripcion |
+|------|--------|-------------|
+| `/auth/google` | GET | Inicia flujo OAuth Google |
+| `/auth/google/callback` | GET | Callback de Google |
+| `/auth/apple` | GET | Inicia flujo Apple Sign-In |
+| `/auth/apple/callback` | POST | Callback de Apple |
+| `/auth/link/:provider` | POST | Vincular cuenta social |
+| `/auth/unlink/:provider` | DELETE | Desvincular cuenta |
+
+---
+
+## 4. Implementacion
+
+### Passport.js Strategies
+
+```typescript
+// Google Strategy
+import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
+
+passport.use(new GoogleStrategy({
+ clientID: process.env.GOOGLE_CLIENT_ID,
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET,
+ callbackURL: process.env.GOOGLE_CALLBACK_URL,
+ scope: ['profile', 'email'],
+ },
+ async (accessToken, refreshToken, profile, done) => {
+ const user = await findOrCreateUser({
+ provider: 'google',
+ providerId: profile.id,
+ email: profile.emails[0].value,
+ name: profile.displayName,
+ avatar: profile.photos[0]?.value,
+ });
+ return done(null, user);
+ }
+));
+```
+
+```typescript
+// Apple Strategy
+import { Strategy as AppleStrategy } from 'passport-apple';
+
+passport.use(new AppleStrategy({
+ clientID: process.env.APPLE_CLIENT_ID,
+ teamID: process.env.APPLE_TEAM_ID,
+ keyID: process.env.APPLE_KEY_ID,
+ privateKeyString: process.env.APPLE_PRIVATE_KEY,
+ callbackURL: process.env.APPLE_CALLBACK_URL,
+ scope: ['name', 'email'],
+ },
+ async (accessToken, refreshToken, idToken, profile, done) => {
+ // Apple solo envia nombre en primer login
+ const user = await findOrCreateUser({
+ provider: 'apple',
+ providerId: profile.id,
+ email: profile.email,
+ name: profile.name?.firstName,
+ });
+ return done(null, user);
+ }
+));
+```
+
+---
+
+## 5. Manejo de Errores
+
+| Error | Descripcion | Accion |
+|-------|-------------|--------|
+| access_denied | Usuario cancelo | Redirect a login |
+| invalid_request | Parametros incorrectos | Log + error page |
+| server_error | Error del provider | Retry o fallback |
+| email_exists | Email ya registrado | Ofrecer vincular |
+
+### Error Handling
+
+```typescript
+@Get('google/callback')
+@UseGuards(AuthGuard('google'))
+async googleCallback(
+ @Req() req: Request,
+ @Res() res: Response,
+) {
+ try {
+ const jwt = await this.authService.generateJwt(req.user);
+ res.redirect(`${FRONTEND_URL}/auth/callback?token=${jwt}`);
+ } catch (error) {
+ if (error instanceof EmailExistsError) {
+ res.redirect(`${FRONTEND_URL}/auth/link?provider=google&email=${error.email}`);
+ } else {
+ res.redirect(`${FRONTEND_URL}/auth/error?code=${error.code}`);
+ }
+ }
+}
+```
+
+---
+
+## 6. Tabla oauth_accounts
+
+```sql
+CREATE TABLE auth.oauth_accounts (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ user_id UUID REFERENCES auth.users(id) NOT NULL,
+ provider VARCHAR(20) NOT NULL, -- google, apple
+ provider_user_id VARCHAR(255) NOT NULL,
+ email VARCHAR(255),
+ name VARCHAR(255),
+ avatar_url TEXT,
+ access_token TEXT,
+ refresh_token TEXT,
+ expires_at TIMESTAMP WITH TIME ZONE,
+ raw_profile JSONB,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ UNIQUE(provider, provider_user_id),
+ UNIQUE(user_id, provider)
+);
+
+CREATE INDEX idx_oauth_accounts_user ON auth.oauth_accounts(user_id);
+```
+
+---
+
+## 7. Multi-tenant
+
+### Comportamiento
+
+- OAuth es a nivel de **usuario**, no de tenant
+- Un usuario puede pertenecer a multiples tenants
+- Al login, se selecciona tenant activo
+
+### Flujo Multi-tenant
+
+```
+1. Usuario hace login con Google
+2. Sistema busca/crea usuario por email
+3. Si usuario tiene multiples tenants:
+ - Redirect a selector de tenant
+4. Si usuario tiene un solo tenant:
+ - Login directo a ese tenant
+5. Si usuario no tiene tenant:
+ - Crear tenant o unirse a invitacion pendiente
+```
+
+---
+
+## 8. Mobile Implementation
+
+### Expo/React Native (Google)
+
+```typescript
+import * as Google from 'expo-auth-session/providers/google';
+
+const [request, response, promptAsync] = Google.useAuthRequest({
+ clientId: GOOGLE_CLIENT_ID,
+ iosClientId: GOOGLE_IOS_CLIENT_ID,
+ androidClientId: GOOGLE_ANDROID_CLIENT_ID,
+});
+
+const handleGoogleLogin = async () => {
+ const result = await promptAsync();
+ if (result.type === 'success') {
+ const { id_token } = result.params;
+ await api.post('/auth/google/mobile', { id_token });
+ }
+};
+```
+
+### iOS Native (Apple)
+
+```typescript
+import * as AppleAuthentication from 'expo-apple-authentication';
+
+const handleAppleLogin = async () => {
+ const credential = await AppleAuthentication.signInAsync({
+ requestedScopes: [
+ AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
+ AppleAuthentication.AppleAuthenticationScope.EMAIL,
+ ],
+ });
+
+ await api.post('/auth/apple/mobile', {
+ identityToken: credential.identityToken,
+ fullName: credential.fullName,
+ });
+};
+```
+
+---
+
+## 9. Testing
+
+### Mock Providers
+
+```typescript
+// test/mocks/google-oauth.mock.ts
+export const mockGoogleProfile = {
+ id: 'google-123',
+ displayName: 'Test User',
+ emails: [{ value: 'test@gmail.com', verified: true }],
+ photos: [{ value: 'https://photo.url' }],
+};
+```
+
+### Test de Integracion
+
+```typescript
+describe('Google OAuth', () => {
+ it('should create new user on first login', async () => {
+ const response = await request(app)
+ .get('/auth/google/callback')
+ .query({ code: 'mock-code' });
+
+ expect(response.status).toBe(302);
+ expect(response.headers.location).toContain('token=');
+ });
+});
+```
+
+---
+
+## 10. Configuracion de Consolas
+
+### Google Cloud Console
+
+1. Ir a [Google Cloud Console](https://console.cloud.google.com)
+2. Crear proyecto o seleccionar existente
+3. APIs & Services > Credentials
+4. Create Credentials > OAuth Client ID
+5. Application type: Web application
+6. Authorized redirect URIs:
+ - `https://api.michangarrito.com/auth/google/callback`
+ - `http://localhost:3000/auth/google/callback`
+
+### Apple Developer
+
+1. Ir a [Apple Developer](https://developer.apple.com)
+2. Certificates, Identifiers & Profiles
+3. Identifiers > App IDs > Agregar Sign in with Apple capability
+4. Identifiers > Services IDs > Crear para web
+5. Keys > Crear key con Sign in with Apple
+6. Descargar .p8 (solo se puede una vez)
+
+---
+
+## 11. Referencias
+
+- [Google Identity Platform](https://developers.google.com/identity)
+- [Sign in with Apple](https://developer.apple.com/sign-in-with-apple/)
+- [Passport.js Google OAuth](http://www.passportjs.org/packages/passport-google-oauth20/)
+- [ADR-0010: OAuth Social Strategy](../97-adr/ADR-0010-oauth-social.md)
+
+---
+
+**Ultima actualizacion:** 2026-01-10
+**Autor:** Backend Team
diff --git a/docs/02-integraciones/INT-013-redis-cache.md b/docs/02-integraciones/INT-013-redis-cache.md
new file mode 100644
index 000000000..544f1de29
--- /dev/null
+++ b/docs/02-integraciones/INT-013-redis-cache.md
@@ -0,0 +1,413 @@
+---
+id: INT-013
+type: Integration
+title: "Redis Cache"
+provider: "Redis"
+status: Planificado
+integration_type: "infrastructure"
+created_at: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+tags:
+ - redis
+ - cache
+ - queue
+ - bullmq
+ - infrastructure
+---
+
+# INT-013: Redis Cache
+
+## Metadata
+
+| Campo | Valor |
+|-------|-------|
+| **Codigo** | INT-013 |
+| **Proveedor** | Redis |
+| **Tipo** | Infraestructura |
+| **Estado** | Planificado |
+| **Multi-tenant** | Si |
+| **Epic Relacionada** | MCH-029 |
+| **Owner** | Backend Team |
+
+---
+
+## 1. Descripcion
+
+Redis como servicio de cache y queue para mejorar rendimiento y procesar tareas en background. Utilizado para cache de sesiones, configuracion de tenants, y colas de trabajo con BullMQ.
+
+**Casos de uso principales:**
+- Cache de sesiones JWT
+- Cache de configuracion de tenant
+- Cache de feature flags
+- Queue para emails, webhooks, notificaciones
+- Rate limiting counters
+- Pub/Sub para eventos real-time
+
+---
+
+## 2. Credenciales Requeridas
+
+### Variables de Entorno
+
+| Variable | Descripcion | Tipo | Obligatorio |
+|----------|-------------|------|-------------|
+| `REDIS_HOST` | Host del servidor Redis | string | SI |
+| `REDIS_PORT` | Puerto (default 6379) | number | SI |
+| `REDIS_PASSWORD` | Password (si auth habilitado) | string | NO |
+| `REDIS_DB` | Database number (0-15) | number | NO |
+| `REDIS_TLS` | Usar TLS | boolean | NO |
+| `REDIS_URL` | URL completa (alternativa) | string | NO |
+
+### Ejemplo de .env
+
+```env
+# Redis Configuration
+REDIS_HOST=localhost
+REDIS_PORT=6379
+REDIS_PASSWORD=
+REDIS_DB=0
+
+# O usar URL completa
+# REDIS_URL=redis://:password@host:6379/0
+
+# Redis Cloud (produccion)
+# REDIS_URL=rediss://:password@redis-12345.cloud.redislabs.com:12345
+```
+
+---
+
+## 3. Configuracion NestJS
+
+### Redis Module
+
+```typescript
+// redis.module.ts
+import { Module, Global } from '@nestjs/common';
+import { Redis } from 'ioredis';
+
+@Global()
+@Module({
+ providers: [
+ {
+ provide: 'REDIS_CLIENT',
+ useFactory: () => {
+ return new Redis({
+ host: process.env.REDIS_HOST,
+ port: parseInt(process.env.REDIS_PORT),
+ password: process.env.REDIS_PASSWORD,
+ db: parseInt(process.env.REDIS_DB || '0'),
+ });
+ },
+ },
+ ],
+ exports: ['REDIS_CLIENT'],
+})
+export class RedisModule {}
+```
+
+### Cache Service
+
+```typescript
+// cache.service.ts
+@Injectable()
+export class CacheService {
+ constructor(@Inject('REDIS_CLIENT') private readonly redis: Redis) {}
+
+ async get(key: string): Promise {
+ const data = await this.redis.get(key);
+ return data ? JSON.parse(data) : null;
+ }
+
+ async set(key: string, value: any, ttlSeconds?: number): Promise {
+ const data = JSON.stringify(value);
+ if (ttlSeconds) {
+ await this.redis.setex(key, ttlSeconds, data);
+ } else {
+ await this.redis.set(key, data);
+ }
+ }
+
+ async del(key: string): Promise {
+ await this.redis.del(key);
+ }
+
+ async invalidatePattern(pattern: string): Promise {
+ const keys = await this.redis.keys(pattern);
+ if (keys.length > 0) {
+ await this.redis.del(...keys);
+ }
+ }
+}
+```
+
+---
+
+## 4. BullMQ Queues
+
+### Configuracion
+
+```typescript
+// queue.module.ts
+import { BullModule } from '@nestjs/bullmq';
+
+@Module({
+ imports: [
+ BullModule.forRoot({
+ connection: {
+ host: process.env.REDIS_HOST,
+ port: parseInt(process.env.REDIS_PORT),
+ password: process.env.REDIS_PASSWORD,
+ },
+ }),
+ BullModule.registerQueue(
+ { name: 'email' },
+ { name: 'webhooks' },
+ { name: 'notifications' },
+ { name: 'cleanup' },
+ ),
+ ],
+})
+export class QueueModule {}
+```
+
+### Processor
+
+```typescript
+// email.processor.ts
+@Processor('email')
+export class EmailProcessor {
+ @Process('send')
+ async handleSend(job: Job) {
+ const { to, template, variables } = job.data;
+ await this.emailService.send(to, template, variables);
+ }
+}
+```
+
+### Agregar a Queue
+
+```typescript
+// Agregar job
+await this.emailQueue.add('send', {
+ to: 'user@example.com',
+ template: 'welcome',
+ variables: { name: 'John' },
+}, {
+ attempts: 3,
+ backoff: {
+ type: 'exponential',
+ delay: 1000,
+ },
+});
+```
+
+---
+
+## 5. Estructura de Keys
+
+### Convenciones de Naming
+
+```
+{prefix}:{scope}:{identifier}:{type}
+
+Ejemplos:
+- mch:session:{userId}
+- mch:tenant:{tenantId}:config
+- mch:tenant:{tenantId}:flags
+- mch:rate:{tenantId}:{endpoint}:count
+- mch:cache:products:{productId}
+```
+
+### Keys por Funcionalidad
+
+| Prefijo | TTL | Descripcion |
+|---------|-----|-------------|
+| mch:session:* | 24h | Sesiones de usuario |
+| mch:tenant:*:config | 1h | Config de tenant |
+| mch:tenant:*:flags | 5m | Feature flags |
+| mch:rate:* | 1m | Rate limiting |
+| mch:cache:* | 15m | Cache general |
+
+---
+
+## 6. Rate Limiting
+
+### Implementacion Token Bucket
+
+```typescript
+@Injectable()
+export class RateLimitService {
+ async isAllowed(
+ tenantId: string,
+ endpoint: string,
+ limit: number,
+ windowSeconds: number,
+ ): Promise<{ allowed: boolean; remaining: number; resetAt: Date }> {
+ const key = `mch:rate:${tenantId}:${endpoint}`;
+ const now = Date.now();
+ const windowStart = now - (windowSeconds * 1000);
+
+ // Remover entradas viejas
+ await this.redis.zremrangebyscore(key, 0, windowStart);
+
+ // Contar requests en ventana
+ const count = await this.redis.zcard(key);
+
+ if (count >= limit) {
+ const oldestEntry = await this.redis.zrange(key, 0, 0, 'WITHSCORES');
+ const resetAt = new Date(parseInt(oldestEntry[1]) + (windowSeconds * 1000));
+ return { allowed: false, remaining: 0, resetAt };
+ }
+
+ // Agregar request actual
+ await this.redis.zadd(key, now, `${now}`);
+ await this.redis.expire(key, windowSeconds);
+
+ return {
+ allowed: true,
+ remaining: limit - count - 1,
+ resetAt: new Date(now + (windowSeconds * 1000)),
+ };
+ }
+}
+```
+
+---
+
+## 7. Multi-tenant
+
+### Aislamiento por Prefijo
+
+```typescript
+class TenantCacheService {
+ private getKey(tenantId: string, key: string): string {
+ return `mch:tenant:${tenantId}:${key}`;
+ }
+
+ async getTenantConfig(tenantId: string): Promise {
+ const key = this.getKey(tenantId, 'config');
+ const cached = await this.cache.get(key);
+
+ if (cached) return cached;
+
+ const config = await this.db.getTenantConfig(tenantId);
+ await this.cache.set(key, config, 3600); // 1 hora
+ return config;
+ }
+
+ async invalidateTenantCache(tenantId: string): Promise {
+ await this.cache.invalidatePattern(`mch:tenant:${tenantId}:*`);
+ }
+}
+```
+
+---
+
+## 8. Health Check
+
+```typescript
+// redis.health.ts
+@Injectable()
+export class RedisHealthIndicator extends HealthIndicator {
+ constructor(@Inject('REDIS_CLIENT') private readonly redis: Redis) {
+ super();
+ }
+
+ async isHealthy(key: string): Promise {
+ try {
+ await this.redis.ping();
+ return this.getStatus(key, true);
+ } catch (error) {
+ return this.getStatus(key, false, { error: error.message });
+ }
+ }
+}
+```
+
+### Endpoint
+
+```typescript
+@Get('health')
+@HealthCheck()
+async check() {
+ return this.health.check([
+ () => this.redis.isHealthy('redis'),
+ ]);
+}
+```
+
+---
+
+## 9. Monitoreo
+
+### Metricas
+
+| Metrica | Descripcion | Alerta |
+|---------|-------------|--------|
+| redis_connected | Conexion activa | false |
+| redis_memory_bytes | Memoria usada | > 80% max |
+| redis_keys_total | Total de keys | - |
+| redis_cache_hits | Cache hits | - |
+| redis_cache_misses | Cache misses | ratio < 80% |
+| redis_queue_length | Jobs en queue | > 1000 |
+
+### Comandos de Monitoreo
+
+```bash
+# Info general
+redis-cli INFO
+
+# Memory
+redis-cli INFO memory
+
+# Keys por patron
+redis-cli KEYS "mch:tenant:*" | wc -l
+
+# Queue length
+redis-cli LLEN bull:email:wait
+```
+
+---
+
+## 10. Testing
+
+### Docker Compose
+
+```yaml
+services:
+ redis:
+ image: redis:7-alpine
+ ports:
+ - "6379:6379"
+ volumes:
+ - redis_data:/data
+```
+
+### Mock para Tests
+
+```typescript
+// test/mocks/redis.mock.ts
+export const mockRedis = {
+ get: jest.fn(),
+ set: jest.fn(),
+ setex: jest.fn(),
+ del: jest.fn(),
+ keys: jest.fn().mockResolvedValue([]),
+ ping: jest.fn().mockResolvedValue('PONG'),
+};
+```
+
+---
+
+## 11. Referencias
+
+- [Redis Documentation](https://redis.io/docs/)
+- [ioredis](https://github.com/redis/ioredis)
+- [BullMQ](https://docs.bullmq.io/)
+- [NestJS Caching](https://docs.nestjs.com/techniques/caching)
+
+---
+
+**Ultima actualizacion:** 2026-01-10
+**Autor:** Backend Team
diff --git a/docs/02-integraciones/INT-014-webhooks-outbound.md b/docs/02-integraciones/INT-014-webhooks-outbound.md
new file mode 100644
index 000000000..ecec9c0a1
--- /dev/null
+++ b/docs/02-integraciones/INT-014-webhooks-outbound.md
@@ -0,0 +1,429 @@
+---
+id: INT-014
+type: Integration
+title: "Webhooks Outbound"
+provider: "BullMQ"
+status: Planificado
+integration_type: "events"
+created_at: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+tags:
+ - webhooks
+ - events
+ - bullmq
+ - integration
+ - outbound
+---
+
+# INT-014: Webhooks Outbound
+
+## Metadata
+
+| Campo | Valor |
+|-------|-------|
+| **Codigo** | INT-014 |
+| **Proveedor** | BullMQ (interno) |
+| **Tipo** | Eventos |
+| **Estado** | Planificado |
+| **Multi-tenant** | Si |
+| **Epic Relacionada** | MCH-029 |
+| **Owner** | Backend Team |
+
+---
+
+## 1. Descripcion
+
+Sistema de webhooks outbound que permite a tenants recibir notificaciones HTTP cuando ocurren eventos en el sistema. Incluye firma de payloads, reintentos con backoff y logs de entrega.
+
+**Casos de uso principales:**
+- Notificar sistemas externos de nuevos pedidos
+- Sincronizar inventario con ERP
+- Integraciones con Zapier/Make
+- Alertas personalizadas
+
+---
+
+## 2. Eventos Disponibles
+
+### Eventos por Categoria
+
+| Categoria | Evento | Payload |
+|-----------|--------|---------|
+| **Orders** | order.created | Order completa |
+| | order.updated | Order con cambios |
+| | order.completed | Order finalizada |
+| | order.cancelled | Order cancelada |
+| **Products** | product.created | Producto nuevo |
+| | product.updated | Producto modificado |
+| | product.deleted | Producto eliminado |
+| | product.low_stock | Stock bajo minimo |
+| **Payments** | payment.received | Pago recibido |
+| | payment.failed | Pago fallido |
+| | payment.refunded | Pago reembolsado |
+| **Customers** | customer.created | Cliente nuevo |
+| | customer.updated | Cliente modificado |
+
+---
+
+## 3. Configuracion de Endpoints
+
+### API de Configuracion
+
+```typescript
+// POST /api/webhooks/endpoints
+{
+ "url": "https://example.com/webhook",
+ "events": ["order.created", "payment.received"],
+ "secret": "whsec_xxxxxxxx", // Generado si no se provee
+ "description": "Mi integracion",
+ "is_active": true
+}
+
+// Response
+{
+ "id": "wh_123abc",
+ "url": "https://example.com/webhook",
+ "events": ["order.created", "payment.received"],
+ "secret": "whsec_xxxxxxxx",
+ "is_active": true,
+ "created_at": "2026-01-10T10:00:00Z"
+}
+```
+
+### Endpoints CRUD
+
+| Metodo | Ruta | Descripcion |
+|--------|------|-------------|
+| GET | /api/webhooks/endpoints | Listar endpoints |
+| POST | /api/webhooks/endpoints | Crear endpoint |
+| GET | /api/webhooks/endpoints/:id | Obtener endpoint |
+| PATCH | /api/webhooks/endpoints/:id | Actualizar endpoint |
+| DELETE | /api/webhooks/endpoints/:id | Eliminar endpoint |
+| GET | /api/webhooks/deliveries | Listar entregas |
+| POST | /api/webhooks/endpoints/:id/test | Enviar test |
+
+---
+
+## 4. Payload de Webhook
+
+### Estructura
+
+```json
+{
+ "id": "evt_123abc",
+ "type": "order.created",
+ "created_at": "2026-01-10T10:00:00Z",
+ "data": {
+ "id": "ord_456def",
+ "total": 150.00,
+ "items": [...],
+ "customer": {...}
+ },
+ "tenant_id": "550e8400-e29b-41d4-a716-446655440000"
+}
+```
+
+### Headers
+
+| Header | Valor | Descripcion |
+|--------|-------|-------------|
+| `Content-Type` | application/json | Tipo de contenido |
+| `X-Webhook-Id` | evt_123abc | ID del evento |
+| `X-Webhook-Timestamp` | 1704880800 | Unix timestamp |
+| `X-Webhook-Signature` | sha256=xxx | Firma HMAC |
+| `User-Agent` | MiChangarrito/1.0 | Identificador |
+
+---
+
+## 5. Firma de Payloads
+
+### Generacion de Firma
+
+```typescript
+function signPayload(
+ payload: string,
+ secret: string,
+ timestamp: number,
+): string {
+ const signedPayload = `${timestamp}.${payload}`;
+ const signature = crypto
+ .createHmac('sha256', secret)
+ .update(signedPayload)
+ .digest('hex');
+
+ return `sha256=${signature}`;
+}
+```
+
+### Verificacion en Cliente
+
+```typescript
+// Ejemplo para el receptor del webhook
+function verifySignature(
+ payload: string,
+ signature: string,
+ secret: string,
+ timestamp: number,
+ tolerance: number = 300, // 5 minutos
+): boolean {
+ const currentTime = Math.floor(Date.now() / 1000);
+
+ // Verificar que no sea muy viejo
+ if (currentTime - timestamp > tolerance) {
+ throw new Error('Timestamp too old');
+ }
+
+ const expected = signPayload(payload, secret, timestamp);
+ return crypto.timingSafeEqual(
+ Buffer.from(signature),
+ Buffer.from(expected),
+ );
+}
+```
+
+---
+
+## 6. Estrategia de Reintentos
+
+### Exponential Backoff
+
+```
+Intento 1: Inmediato
+Intento 2: 1 segundo
+Intento 3: 2 segundos
+Intento 4: 4 segundos
+Intento 5: 8 segundos
+Intento 6: 16 segundos (maximo)
+```
+
+### Configuracion BullMQ
+
+```typescript
+await this.webhookQueue.add('deliver', {
+ endpointId: endpoint.id,
+ eventId: event.id,
+ payload: event.data,
+}, {
+ attempts: 6,
+ backoff: {
+ type: 'exponential',
+ delay: 1000,
+ },
+ removeOnComplete: true,
+ removeOnFail: false, // Mantener para logs
+});
+```
+
+### Codigos de Respuesta
+
+| Codigo | Accion | Descripcion |
+|--------|--------|-------------|
+| 2xx | Exito | Entrega exitosa |
+| 3xx | Retry | Seguir redirecciones |
+| 4xx | Fallo | No reintentar (excepto 429) |
+| 429 | Retry | Rate limited, esperar |
+| 5xx | Retry | Error del servidor |
+| Timeout | Retry | Esperar siguiente intento |
+
+---
+
+## 7. Tabla de BD
+
+### Schema webhooks
+
+```sql
+CREATE SCHEMA IF NOT EXISTS webhooks;
+
+CREATE TABLE webhooks.endpoints (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ tenant_id UUID NOT NULL,
+ url VARCHAR(2000) NOT NULL,
+ description VARCHAR(255),
+ events TEXT[] NOT NULL,
+ secret VARCHAR(255) NOT NULL,
+ is_active BOOLEAN DEFAULT true,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
+);
+
+CREATE TABLE webhooks.deliveries (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ endpoint_id UUID REFERENCES webhooks.endpoints(id),
+ event_type VARCHAR(100) NOT NULL,
+ event_id VARCHAR(100) NOT NULL,
+ payload JSONB NOT NULL,
+ status VARCHAR(20) NOT NULL, -- pending, success, failed
+ attempts INTEGER DEFAULT 0,
+ last_attempt_at TIMESTAMP WITH TIME ZONE,
+ response_status INTEGER,
+ response_body TEXT,
+ error_message TEXT,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ completed_at TIMESTAMP WITH TIME ZONE
+);
+
+CREATE INDEX idx_deliveries_endpoint ON webhooks.deliveries(endpoint_id);
+CREATE INDEX idx_deliveries_status ON webhooks.deliveries(status);
+```
+
+---
+
+## 8. Procesador de Webhooks
+
+```typescript
+@Processor('webhooks')
+export class WebhookProcessor {
+ constructor(
+ private readonly httpService: HttpService,
+ private readonly webhookService: WebhookService,
+ ) {}
+
+ @Process('deliver')
+ async handleDelivery(job: Job) {
+ const { endpointId, eventId, payload } = job.data;
+
+ const endpoint = await this.webhookService.getEndpoint(endpointId);
+ if (!endpoint.is_active) return;
+
+ const timestamp = Math.floor(Date.now() / 1000);
+ const payloadString = JSON.stringify(payload);
+ const signature = this.signPayload(payloadString, endpoint.secret, timestamp);
+
+ try {
+ const response = await this.httpService.axiosRef.post(
+ endpoint.url,
+ payload,
+ {
+ headers: {
+ 'Content-Type': 'application/json',
+ 'X-Webhook-Id': eventId,
+ 'X-Webhook-Timestamp': timestamp.toString(),
+ 'X-Webhook-Signature': signature,
+ 'User-Agent': 'MiChangarrito/1.0',
+ },
+ timeout: 30000, // 30 segundos
+ },
+ );
+
+ await this.webhookService.logDelivery(endpointId, eventId, {
+ status: 'success',
+ responseStatus: response.status,
+ attempts: job.attemptsMade + 1,
+ });
+
+ } catch (error) {
+ const shouldRetry = this.shouldRetry(error);
+
+ await this.webhookService.logDelivery(endpointId, eventId, {
+ status: shouldRetry ? 'pending' : 'failed',
+ responseStatus: error.response?.status,
+ errorMessage: error.message,
+ attempts: job.attemptsMade + 1,
+ });
+
+ if (shouldRetry) {
+ throw error; // BullMQ reintentara
+ }
+ }
+ }
+
+ private shouldRetry(error: any): boolean {
+ if (!error.response) return true; // Timeout o network error
+ const status = error.response.status;
+ return status === 429 || status >= 500;
+ }
+}
+```
+
+---
+
+## 9. UI de Administracion
+
+### Funcionalidades
+
+- Lista de endpoints configurados
+- Crear/editar/eliminar endpoints
+- Ver historial de entregas
+- Reintentar entregas fallidas
+- Enviar evento de prueba
+- Rotar secret
+
+### Ejemplo de Vista
+
+```
++--------------------------------------------------+
+| Webhooks [+ Nuevo] |
++--------------------------------------------------+
+| URL | Eventos | Estado |
+|------------------------|--------------|----------|
+| https://example.com/wh | order.* | Activo |
+| https://zapier.com/... | payment.* | Activo |
+| https://erp.local/api | product.* | Inactivo |
++--------------------------------------------------+
+
+Entregas Recientes:
++--------------------------------------------------+
+| Evento | Destino | Estado | Fecha |
+|-----------------|--------------|--------|--------|
+| order.created | example.com | OK | 10:00 |
+| payment.failed | zapier.com | OK | 09:55 |
+| product.updated | erp.local | Failed | 09:50 |
++--------------------------------------------------+
+```
+
+---
+
+## 10. Testing
+
+### Enviar Evento de Prueba
+
+```typescript
+// POST /api/webhooks/endpoints/:id/test
+{
+ "event_type": "test.webhook"
+}
+
+// Payload enviado
+{
+ "id": "evt_test_123",
+ "type": "test.webhook",
+ "created_at": "2026-01-10T10:00:00Z",
+ "data": {
+ "message": "This is a test webhook"
+ }
+}
+```
+
+### Herramientas de Debug
+
+- [webhook.site](https://webhook.site) - Receptor de prueba
+- [ngrok](https://ngrok.com) - Tunel para localhost
+
+---
+
+## 11. Monitoreo
+
+### Metricas
+
+| Metrica | Descripcion | Alerta |
+|---------|-------------|--------|
+| webhook_deliveries_total | Total entregas | - |
+| webhook_deliveries_success | Entregas exitosas | - |
+| webhook_deliveries_failed | Entregas fallidas | > 10% |
+| webhook_delivery_latency | Latencia de entrega | > 5s |
+| webhook_queue_length | Jobs pendientes | > 100 |
+
+---
+
+## 12. Referencias
+
+- [Webhooks Best Practices](https://webhooks.dev/best-practices)
+- [BullMQ Documentation](https://docs.bullmq.io/)
+- [Stripe Webhooks](https://stripe.com/docs/webhooks) (referencia)
+- [ADR-0007: Webhook Retry Strategy](../97-adr/ADR-0007-webhook-retry-strategy.md)
+
+---
+
+**Ultima actualizacion:** 2026-01-10
+**Autor:** Backend Team
diff --git a/docs/02-integraciones/_MAP.md b/docs/02-integraciones/_MAP.md
index d2fda4452..f035f5bd2 100644
--- a/docs/02-integraciones/_MAP.md
+++ b/docs/02-integraciones/_MAP.md
@@ -11,11 +11,11 @@
| Metrica | Valor |
|---------|-------|
-| Total integraciones | 9 |
-| Documentadas | 9 |
+| Total integraciones | 14 |
+| Documentadas | 14 |
| Implementadas | 4 |
| En desarrollo | 2 |
-| Pendientes | 3 |
+| Pendientes | 8 |
| Progreso | 100% documentado |
---
@@ -34,7 +34,12 @@
| [INT-006-codi-banxico.md](./INT-006-codi-banxico.md) | Banxico/STP | Pagos QR | Mock | Pagos CoDi/SPEI |
| [INT-007-firebase-fcm.md](./INT-007-firebase-fcm.md) | Firebase | Notificaciones | Pendiente | Push notifications |
| [INT-008-google-vision.md](./INT-008-google-vision.md) | Google Cloud | OCR | Pendiente | Vision OCR productos |
-| [INT-009-whisper.md](./INT-009-whisper.md) | OpenAI | Speech-to-Text | Pendiente | Transcripcion audio
+| [INT-009-whisper.md](./INT-009-whisper.md) | OpenAI | Speech-to-Text | Pendiente | Transcripcion audio |
+| [INT-010-email-providers.md](./INT-010-email-providers.md) | SendGrid/SES/SMTP | Email | Planificado | Email multi-proveedor |
+| [INT-011-storage-cloud.md](./INT-011-storage-cloud.md) | S3/R2/MinIO | Storage | Planificado | Almacenamiento cloud |
+| [INT-012-oauth-social.md](./INT-012-oauth-social.md) | Google/Apple | Auth | Planificado | OAuth 2.0 social login |
+| [INT-013-redis-cache.md](./INT-013-redis-cache.md) | Redis | Infraestructura | Planificado | Cache y queues |
+| [INT-014-webhooks-outbound.md](./INT-014-webhooks-outbound.md) | BullMQ | Eventos | Planificado | Webhooks salientes |
---
@@ -55,6 +60,19 @@
2. [INT-008 - Google Vision](./INT-008-google-vision.md) - OCR
3. [INT-009 - Whisper](./INT-009-whisper.md) - Speech-to-Text
+### Notificaciones
+1. [INT-010 - Email Providers](./INT-010-email-providers.md) - Email transaccional
+
+### Almacenamiento
+1. [INT-011 - Storage Cloud](./INT-011-storage-cloud.md) - S3/R2/MinIO
+
+### Autenticacion
+1. [INT-012 - OAuth Social](./INT-012-oauth-social.md) - Google/Apple
+
+### Infraestructura
+1. [INT-013 - Redis Cache](./INT-013-redis-cache.md) - Cache y queues
+2. [INT-014 - Webhooks Outbound](./INT-014-webhooks-outbound.md) - Eventos salientes
+
---
## Arquitectura de Integraciones
@@ -118,4 +136,5 @@ MERCADOPAGO_ACCESS_TOKEN=xxxxx
---
**Mantenido por:** Documentation Team
-**Version:** 1.0.0
+**Version:** 2.0.0
+**Total Integraciones:** 14 (INT-001 a INT-014)
diff --git a/docs/04-modelado/trazabilidad/TRACEABILITY-MASTER.yml b/docs/04-modelado/trazabilidad/TRACEABILITY-MASTER.yml
index 720e5532a..02a18ad4b 100644
--- a/docs/04-modelado/trazabilidad/TRACEABILITY-MASTER.yml
+++ b/docs/04-modelado/trazabilidad/TRACEABILITY-MASTER.yml
@@ -1,34 +1,646 @@
-# TRACEABILITY-MASTER.yml v2.0
+# TRACEABILITY-MASTER.yml v3.0
# Proyecto: Mi Changarrito
-# Prefijo v2: MCH
+# Prefijo: MCH
+# Actualizado: 2026-01-10
+# Sistema: SIMCO v4.0.1
-traceability_version: "2.0"
+traceability_version: "3.0"
project:
code: "MCH"
name: "Mi Changarrito - Sistema POS para Pequenos Comercios"
updated: "2026-01-10"
+ simco_version: "4.0.1"
+
+# ============================================================================
+# RESUMEN DE EPICAS
+# ============================================================================
epics_summary:
- total: 0
- completed: 0
+ total: 33
+ completed: 22
in_progress: 0
- planned: 0
+ pending: 6
+ planned: 5
nomenclature_mapping:
- legacy: "MCH-EP"
+ current: "MCH-NNN"
+ legacy: "MCH-EP-NNN"
-epics: []
+# ============================================================================
+# EPICAS POR FASE
+# ============================================================================
-dependency_graph: {}
+epics:
+ # FASE 1: MVP CORE
+ - id: "MCH-001"
+ name: "Infraestructura Base"
+ status: "completed"
+ phase: 1
+ priority: "P0"
+ story_points: 8
+ dependencies: []
+ blocks: ["MCH-002", "MCH-003", "MCH-010"]
+ integrations: []
+ adrs: ["ADR-0001"]
+
+ - id: "MCH-002"
+ name: "Autenticacion"
+ status: "completed"
+ phase: 1
+ priority: "P0"
+ story_points: 13
+ dependencies: ["MCH-001"]
+ blocks: ["MCH-006", "MCH-014"]
+ integrations: []
+ adrs: []
+
+ - id: "MCH-003"
+ name: "Catalogo de Productos"
+ status: "completed"
+ phase: 1
+ priority: "P0"
+ story_points: 13
+ dependencies: ["MCH-001"]
+ blocks: ["MCH-004", "MCH-007"]
+ integrations: []
+ adrs: []
+
+ - id: "MCH-004"
+ name: "Punto de Venta"
+ status: "completed"
+ phase: 1
+ priority: "P0"
+ story_points: 21
+ dependencies: ["MCH-003"]
+ blocks: ["MCH-005", "MCH-008"]
+ integrations: []
+ adrs: []
+
+ - id: "MCH-005"
+ name: "Integraciones de Pago"
+ status: "completed"
+ phase: 1
+ priority: "P0"
+ story_points: 13
+ dependencies: ["MCH-004"]
+ blocks: []
+ integrations: ["INT-002", "INT-004", "INT-005"]
+ adrs: []
+
+ # FASE 2: INTELIGENCIA
+ - id: "MCH-006"
+ name: "Onboarding Inteligente"
+ status: "completed"
+ phase: 2
+ priority: "P1"
+ story_points: 8
+ dependencies: ["MCH-002"]
+ blocks: []
+ integrations: []
+ adrs: []
+
+ - id: "MCH-007"
+ name: "Templates y Catalogos"
+ status: "completed"
+ phase: 2
+ priority: "P1"
+ story_points: 5
+ dependencies: ["MCH-003"]
+ blocks: []
+ integrations: []
+ adrs: []
+
+ - id: "MCH-008"
+ name: "Sistema de Fiados"
+ status: "completed"
+ phase: 2
+ priority: "P1"
+ story_points: 8
+ dependencies: ["MCH-004"]
+ blocks: []
+ integrations: []
+ adrs: []
+
+ - id: "MCH-009"
+ name: "Prediccion Inventario"
+ status: "completed"
+ phase: 2
+ priority: "P1"
+ story_points: 5
+ dependencies: ["MCH-003"]
+ blocks: []
+ integrations: ["INT-008"]
+ adrs: []
+
+ # FASE 3: ASISTENTE IA
+ - id: "MCH-010"
+ name: "MCP Server"
+ status: "completed"
+ phase: 3
+ priority: "P0"
+ story_points: 13
+ dependencies: ["MCH-001"]
+ blocks: ["MCH-011", "MCH-012", "MCH-013"]
+ integrations: ["INT-003"]
+ adrs: ["ADR-0003"]
+
+ - id: "MCH-011"
+ name: "WhatsApp Service"
+ status: "completed"
+ phase: 3
+ priority: "P0"
+ story_points: 13
+ dependencies: ["MCH-010"]
+ blocks: ["MCH-015"]
+ integrations: ["INT-001", "INT-009"]
+ adrs: ["ADR-0002"]
+
+ - id: "MCH-012"
+ name: "Chat LLM Dueno"
+ status: "completed"
+ phase: 3
+ priority: "P1"
+ story_points: 8
+ dependencies: ["MCH-010"]
+ blocks: []
+ integrations: ["INT-003"]
+ adrs: ["ADR-0003"]
+
+ - id: "MCH-013"
+ name: "Chat LLM Cliente"
+ status: "completed"
+ phase: 3
+ priority: "P1"
+ story_points: 5
+ dependencies: ["MCH-010"]
+ blocks: []
+ integrations: ["INT-003"]
+ adrs: ["ADR-0003"]
+
+ # FASE 4: PEDIDOS Y CLIENTES
+ - id: "MCH-014"
+ name: "Gestion de Clientes"
+ status: "completed"
+ phase: 4
+ priority: "P1"
+ story_points: 8
+ dependencies: ["MCH-002"]
+ blocks: ["MCH-015"]
+ integrations: []
+ adrs: []
+
+ - id: "MCH-015"
+ name: "Pedidos via WhatsApp"
+ status: "completed"
+ phase: 4
+ priority: "P1"
+ story_points: 13
+ dependencies: ["MCH-011", "MCH-014"]
+ blocks: ["MCH-016"]
+ integrations: ["INT-001"]
+ adrs: []
+
+ - id: "MCH-016"
+ name: "Entregas a Domicilio"
+ status: "completed"
+ phase: 4
+ priority: "P2"
+ story_points: 5
+ dependencies: ["MCH-015"]
+ blocks: []
+ integrations: []
+ adrs: []
+
+ - id: "MCH-017"
+ name: "Notificaciones"
+ status: "completed"
+ phase: 4
+ priority: "P1"
+ story_points: 5
+ dependencies: ["MCH-011"]
+ blocks: []
+ integrations: ["INT-007"]
+ adrs: []
+
+ # FASE 5: MONETIZACION
+ - id: "MCH-018"
+ name: "Planes y Suscripciones"
+ status: "completed"
+ phase: 5
+ priority: "P0"
+ story_points: 8
+ dependencies: ["MCH-002"]
+ blocks: ["MCH-019", "MCH-020"]
+ integrations: ["INT-002"]
+ adrs: []
+
+ - id: "MCH-019"
+ name: "Tienda de Tokens"
+ status: "completed"
+ phase: 5
+ priority: "P1"
+ story_points: 5
+ dependencies: ["MCH-018"]
+ blocks: []
+ integrations: []
+ adrs: []
+
+ - id: "MCH-020"
+ name: "Pagos Suscripcion"
+ status: "completed"
+ phase: 5
+ priority: "P0"
+ story_points: 8
+ dependencies: ["MCH-018"]
+ blocks: []
+ integrations: ["INT-002"]
+ adrs: []
+
+ - id: "MCH-021"
+ name: "Dashboard Web"
+ status: "completed"
+ phase: 5
+ priority: "P1"
+ story_points: 13
+ dependencies: ["MCH-018"]
+ blocks: []
+ integrations: []
+ adrs: []
+
+ # FASE 6: CRECIMIENTO
+ - id: "MCH-022"
+ name: "Modo Offline"
+ status: "completed"
+ phase: 6
+ priority: "P1"
+ story_points: 13
+ dependencies: ["MCH-004"]
+ blocks: []
+ integrations: []
+ adrs: []
+
+ - id: "MCH-023"
+ name: "Programa de Referidos"
+ status: "pending"
+ phase: 6
+ priority: "P2"
+ story_points: 5
+ dependencies: ["MCH-018"]
+ blocks: []
+ integrations: []
+ adrs: []
+
+ - id: "MCH-024"
+ name: "CoDi y SPEI"
+ status: "pending"
+ phase: 6
+ priority: "P2"
+ story_points: 8
+ dependencies: ["MCH-005"]
+ blocks: []
+ integrations: ["INT-006"]
+ adrs: []
+
+ - id: "MCH-025"
+ name: "Widgets y Atajos"
+ status: "pending"
+ phase: 6
+ priority: "P2"
+ story_points: 5
+ dependencies: ["MCH-004"]
+ blocks: []
+ integrations: []
+ adrs: []
+
+ # FASE 7: EXPANSION
+ - id: "MCH-026"
+ name: "Multi-idioma LATAM"
+ status: "pending"
+ phase: 7
+ priority: "P3"
+ story_points: 5
+ dependencies: []
+ blocks: []
+ integrations: []
+ adrs: []
+
+ - id: "MCH-027"
+ name: "Integracion SAT"
+ status: "pending"
+ phase: 7
+ priority: "P3"
+ story_points: 13
+ dependencies: []
+ blocks: []
+ integrations: []
+ adrs: []
+
+ - id: "MCH-028"
+ name: "Marketplace Proveedores"
+ status: "pending"
+ phase: 7
+ priority: "P3"
+ story_points: 8
+ dependencies: []
+ blocks: []
+ integrations: []
+ adrs: []
+
+ # FASE 7: EXPANSION SAAS (NUEVAS)
+ - id: "MCH-029"
+ name: "Infraestructura SaaS Avanzada"
+ status: "planned"
+ phase: 7
+ priority: "P0"
+ story_points: 24
+ sprint_target: "6-7"
+ dependencies: []
+ blocks: ["MCH-030", "MCH-032", "MCH-033"]
+ integrations: ["INT-010", "INT-011", "INT-013", "INT-014"]
+ adrs: ["ADR-0006", "ADR-0007", "ADR-0009", "ADR-0011"]
+ user_stories:
+ - id: "MCH-US-101"
+ name: "Email Multi-proveedor"
+ story_points: 5
+ - id: "MCH-US-102"
+ name: "Storage Abstracto"
+ story_points: 8
+ - id: "MCH-US-103"
+ name: "Redis Cache y Queue"
+ story_points: 3
+ - id: "MCH-US-104"
+ name: "Webhooks Outbound"
+ story_points: 5
+ - id: "MCH-US-112"
+ name: "Rate Limiting por Plan"
+ story_points: 3
+
+ - id: "MCH-030"
+ name: "Auth Social OAuth 2.0"
+ status: "planned"
+ phase: 7
+ priority: "P1"
+ story_points: 8
+ sprint_target: "8"
+ dependencies: ["MCH-029"]
+ blocks: []
+ integrations: ["INT-012"]
+ adrs: ["ADR-0010"]
+ user_stories:
+ - id: "MCH-US-105"
+ name: "Login con Google"
+ story_points: 5
+ - id: "MCH-US-106"
+ name: "Login con Apple"
+ story_points: 3
+
+ - id: "MCH-031"
+ name: "Auditoria Empresarial"
+ status: "planned"
+ phase: 7
+ priority: "P1"
+ story_points: 5
+ sprint_target: "7"
+ dependencies: []
+ blocks: []
+ integrations: []
+ adrs: ["ADR-0008"]
+ user_stories:
+ - id: "MCH-US-107"
+ name: "Registro de Acciones"
+ story_points: 3
+ - id: "MCH-US-108"
+ name: "Politica de Retencion"
+ story_points: 2
+
+ - id: "MCH-032"
+ name: "Feature Flags por Plan"
+ status: "planned"
+ phase: 7
+ priority: "P1"
+ story_points: 5
+ sprint_target: "8"
+ dependencies: ["MCH-029", "MCH-018"]
+ blocks: []
+ integrations: ["INT-013"]
+ adrs: ["ADR-0005"]
+ user_stories:
+ - id: "MCH-US-109"
+ name: "Feature Flags por Plan"
+ story_points: 3
+ - id: "MCH-US-110"
+ name: "Overrides por Tenant"
+ story_points: 2
+
+ # FASE 8: MEJORAS UX
+ - id: "MCH-033"
+ name: "Onboarding Wizard"
+ status: "planned"
+ phase: 8
+ priority: "P2"
+ story_points: 3
+ sprint_target: "9"
+ dependencies: ["MCH-029"]
+ blocks: []
+ integrations: []
+ adrs: []
+ user_stories:
+ - id: "MCH-US-111"
+ name: "Wizard de Configuracion"
+ story_points: 3
+
+# ============================================================================
+# INTEGRACIONES
+# ============================================================================
+
+integrations:
+ - id: "INT-001"
+ name: "WhatsApp Meta Business"
+ category: "Mensajeria"
+ status: "active"
+ epics: ["MCH-011", "MCH-015"]
+
+ - id: "INT-002"
+ name: "Stripe"
+ category: "Pagos"
+ status: "active"
+ epics: ["MCH-005", "MCH-018", "MCH-020"]
+
+ - id: "INT-003"
+ name: "OpenRouter LLM"
+ category: "AI/LLM"
+ status: "active"
+ epics: ["MCH-010", "MCH-012", "MCH-013"]
+
+ - id: "INT-004"
+ name: "MercadoPago"
+ category: "Pagos"
+ status: "pending"
+ epics: ["MCH-005"]
+
+ - id: "INT-005"
+ name: "Clip Mexico"
+ category: "Pagos"
+ status: "mock"
+ epics: ["MCH-005"]
+
+ - id: "INT-006"
+ name: "CoDi/SPEI Banxico"
+ category: "Pagos"
+ status: "mock"
+ epics: ["MCH-024"]
+
+ - id: "INT-007"
+ name: "Firebase FCM"
+ category: "Notificaciones"
+ status: "pending"
+ epics: ["MCH-017"]
+
+ - id: "INT-008"
+ name: "Google Cloud Vision"
+ category: "AI/ML"
+ status: "pending"
+ epics: ["MCH-009"]
+
+ - id: "INT-009"
+ name: "OpenAI Whisper"
+ category: "AI/ML"
+ status: "pending"
+ epics: ["MCH-011"]
+
+ # NUEVAS INTEGRACIONES SAAS
+ - id: "INT-010"
+ name: "Email Multi-Provider"
+ category: "Notificaciones"
+ status: "planned"
+ epics: ["MCH-029"]
+ providers: ["SendGrid", "AWS SES", "SMTP"]
+
+ - id: "INT-011"
+ name: "Storage Cloud"
+ category: "Almacenamiento"
+ status: "planned"
+ epics: ["MCH-029"]
+ providers: ["AWS S3", "Cloudflare R2", "MinIO"]
+
+ - id: "INT-012"
+ name: "OAuth Social"
+ category: "Autenticacion"
+ status: "planned"
+ epics: ["MCH-030"]
+ providers: ["Google", "Apple"]
+
+ - id: "INT-013"
+ name: "Redis Cache"
+ category: "Infraestructura"
+ status: "planned"
+ epics: ["MCH-029", "MCH-032"]
+
+ - id: "INT-014"
+ name: "Webhooks Outbound"
+ category: "Eventos"
+ status: "planned"
+ epics: ["MCH-029"]
+
+# ============================================================================
+# ADRS
+# ============================================================================
+
+adrs:
+ - id: "ADR-0001"
+ title: "Arquitectura Multi-Tenant"
+ status: "accepted"
+ epics: ["MCH-001"]
+
+ - id: "ADR-0002"
+ title: "WhatsApp First Approach"
+ status: "accepted"
+ epics: ["MCH-011"]
+
+ - id: "ADR-0003"
+ title: "LLM Agnostic Strategy"
+ status: "accepted"
+ epics: ["MCH-010", "MCH-012", "MCH-013"]
+
+ - id: "ADR-0004"
+ title: "Notificaciones en Tiempo Real"
+ status: "accepted"
+ epics: ["MCH-017"]
+
+ - id: "ADR-0005"
+ title: "Feature Flags por Plan"
+ status: "accepted"
+ epics: ["MCH-032"]
+
+ - id: "ADR-0006"
+ title: "Storage Abstraction"
+ status: "accepted"
+ epics: ["MCH-029"]
+
+ - id: "ADR-0007"
+ title: "Webhook Retry Strategy"
+ status: "accepted"
+ epics: ["MCH-029"]
+
+ - id: "ADR-0008"
+ title: "Audit Log Retention"
+ status: "accepted"
+ epics: ["MCH-031"]
+
+ - id: "ADR-0009"
+ title: "Rate Limiting Strategy"
+ status: "accepted"
+ epics: ["MCH-029"]
+
+ - id: "ADR-0010"
+ title: "OAuth Social Strategy"
+ status: "accepted"
+ epics: ["MCH-030"]
+
+ - id: "ADR-0011"
+ title: "Email Multi-Provider"
+ status: "accepted"
+ epics: ["MCH-029"]
+
+# ============================================================================
+# GRAFO DE DEPENDENCIAS
+# ============================================================================
+
+dependency_graph:
+ MCH-001: ["MCH-002", "MCH-003", "MCH-010"]
+ MCH-002: ["MCH-006", "MCH-014", "MCH-018"]
+ MCH-003: ["MCH-004", "MCH-007", "MCH-009"]
+ MCH-004: ["MCH-005", "MCH-008", "MCH-022"]
+ MCH-010: ["MCH-011", "MCH-012", "MCH-013"]
+ MCH-011: ["MCH-015", "MCH-017"]
+ MCH-014: ["MCH-015"]
+ MCH-015: ["MCH-016"]
+ MCH-018: ["MCH-019", "MCH-020", "MCH-021", "MCH-023"]
+ MCH-029: ["MCH-030", "MCH-032", "MCH-033"]
+
+# ============================================================================
+# INVENTARIOS
+# ============================================================================
inventories:
- master: "docs/90-transversal/inventarios/"
+ master: "orchestration/inventarios/MASTER_INVENTORY.yml"
+ backend: "orchestration/inventarios/BACKEND_INVENTORY.yml"
+ frontend: "orchestration/inventarios/FRONTEND_INVENTORY.yml"
+ database: "orchestration/inventarios/DATABASE_INVENTORY.yml"
+
+# ============================================================================
+# HEALTH
+# ============================================================================
health:
last_validated: "2026-01-10"
- score: 0.50
- issues:
- - severity: "low"
- type: "initialization"
- description: "Proyecto en migracion inicial v2"
+ score: 1.0
+ issues: []
+ saas_integration:
+ status: "completed"
+ date: "2026-01-10"
+ new_epics: 5
+ new_integrations: 5
+ new_adrs: 8
+ story_points: 45
diff --git a/docs/97-adr/ADR-0004-notifications-realtime.md b/docs/97-adr/ADR-0004-notifications-realtime.md
new file mode 100644
index 000000000..baefb6ff8
--- /dev/null
+++ b/docs/97-adr/ADR-0004-notifications-realtime.md
@@ -0,0 +1,181 @@
+---
+id: ADR-0004
+type: ADR
+title: "Notificaciones en Tiempo Real"
+status: Accepted
+decision_date: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+stakeholders:
+ - "Equipo MiChangarrito"
+tags:
+ - notifications
+ - websocket
+ - sse
+ - realtime
+---
+
+# ADR-0004: Notificaciones en Tiempo Real
+
+## Metadata
+
+| Campo | Valor |
+|-------|-------|
+| **ID** | ADR-0004 |
+| **Estado** | Accepted |
+| **Fecha** | 2026-01-10 |
+| **Autor** | Architecture Team |
+| **Supersede** | - |
+
+---
+
+## Contexto
+
+MiChangarrito necesita notificar a los usuarios en tiempo real sobre eventos como nuevos pedidos, pagos recibidos, alertas de inventario y actualizaciones de estado. Se requiere una solucion que funcione tanto en web como en mobile.
+
+---
+
+## Decision
+
+**Adoptamos Server-Sent Events (SSE) para notificaciones web y push notifications nativas para mobile.**
+
+SSE es unidireccional (servidor -> cliente), suficiente para notificaciones, mas simple de implementar que WebSockets, y funciona mejor con proxies y load balancers.
+
+```typescript
+// Endpoint SSE
+@Get('notifications/stream')
+@Sse()
+notificationStream(@Req() req: Request): Observable {
+ const userId = req.user.id;
+ return this.notificationService.getUserStream(userId);
+}
+```
+
+---
+
+## Alternativas Consideradas
+
+### Opcion 1: WebSockets (Socket.io)
+- **Pros:**
+ - Bidireccional
+ - Ampliamente soportado
+ - Buena libreria (Socket.io)
+- **Cons:**
+ - Mas complejo de escalar
+ - Requiere sticky sessions
+ - Overhead para notificaciones unidireccionales
+
+### Opcion 2: Server-Sent Events (Elegida)
+- **Pros:**
+ - Simple de implementar
+ - Unidireccional (perfecto para notificaciones)
+ - Reconexion automatica
+ - Funciona sobre HTTP/2
+ - No requiere sticky sessions
+- **Cons:**
+ - Solo unidireccional
+ - Limite de conexiones por dominio
+ - No soportado en IE
+
+### Opcion 3: Polling
+- **Pros:**
+ - Muy simple
+ - Funciona en cualquier navegador
+- **Cons:**
+ - Ineficiente
+ - Latencia alta
+ - Carga innecesaria al servidor
+
+---
+
+## Consecuencias
+
+### Positivas
+
+1. **Simplicidad:** SSE es nativo del navegador
+2. **Escalabilidad:** Funciona con load balancers
+3. **Eficiencia:** Conexion persistente sin overhead
+4. **Resiliencia:** Reconexion automatica
+
+### Negativas
+
+1. **Limite conexiones:** 6 por dominio en HTTP/1.1
+2. **Solo unidireccional:** Si necesitamos bidireccional, agregar WebSocket
+3. **IE no soportado:** Usar polyfill si es necesario
+
+---
+
+## Implementacion
+
+### Backend (NestJS)
+
+```typescript
+@Controller('notifications')
+export class NotificationController {
+ constructor(
+ private readonly notificationService: NotificationService,
+ ) {}
+
+ @Get('stream')
+ @UseGuards(JwtAuthGuard)
+ @Sse()
+ stream(@Req() req: Request): Observable {
+ const userId = req.user.id;
+ const tenantId = req.user.tenantId;
+
+ return this.notificationService
+ .createStream(userId, tenantId)
+ .pipe(
+ map(notification => ({
+ data: notification,
+ type: notification.type,
+ id: notification.id,
+ })),
+ );
+ }
+}
+```
+
+### Frontend (React)
+
+```typescript
+function useNotifications() {
+ const [notifications, setNotifications] = useState([]);
+
+ useEffect(() => {
+ const eventSource = new EventSource('/api/notifications/stream', {
+ withCredentials: true,
+ });
+
+ eventSource.onmessage = (event) => {
+ const notification = JSON.parse(event.data);
+ setNotifications(prev => [notification, ...prev]);
+ toast.info(notification.message);
+ };
+
+ eventSource.onerror = () => {
+ // Reconexion automatica
+ };
+
+ return () => eventSource.close();
+ }, []);
+
+ return notifications;
+}
+```
+
+### Mobile (Push Notifications)
+
+Para mobile, usamos push notifications nativas en lugar de SSE para mejor experiencia cuando la app esta en background.
+
+---
+
+## Referencias
+
+- [MDN Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
+- [NestJS SSE](https://docs.nestjs.com/techniques/server-sent-events)
+
+---
+
+**Fecha decision:** 2026-01-10
+**Autores:** Architecture Team
diff --git a/docs/97-adr/ADR-0005-feature-flags.md b/docs/97-adr/ADR-0005-feature-flags.md
new file mode 100644
index 000000000..2837d8521
--- /dev/null
+++ b/docs/97-adr/ADR-0005-feature-flags.md
@@ -0,0 +1,227 @@
+---
+id: ADR-0005
+type: ADR
+title: "Feature Flags por Plan"
+status: Accepted
+decision_date: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+stakeholders:
+ - "Equipo MiChangarrito"
+tags:
+ - feature-flags
+ - plans
+ - multi-tenant
+---
+
+# ADR-0005: Feature Flags por Plan
+
+## Metadata
+
+| Campo | Valor |
+|-------|-------|
+| **ID** | ADR-0005 |
+| **Estado** | Accepted |
+| **Fecha** | 2026-01-10 |
+| **Autor** | Architecture Team |
+| **Supersede** | - |
+
+---
+
+## Contexto
+
+MiChangarrito ofrece multiples planes de suscripcion (Basic, Pro, Enterprise) con diferentes funcionalidades. Necesitamos un sistema que:
+
+1. Habilite/deshabilite features segun el plan
+2. Permita overrides para beta testing
+3. Sea rapido en evaluacion (no impacte rendimiento)
+4. Funcione tanto en backend como frontend
+
+---
+
+## Decision
+
+**Implementamos un sistema de feature flags propio con cache en Redis y evaluacion en tiempo real.**
+
+Los flags se definen globalmente, se asocian a planes, y pueden tener overrides por tenant o usuario. La evaluacion usa cache Redis para latencia <10ms.
+
+```typescript
+// Evaluacion de flag
+const hasFeature = await featureFlagService.evaluate('ai_assistant', {
+ tenantId,
+ userId,
+ planId,
+});
+```
+
+---
+
+## Alternativas Consideradas
+
+### Opcion 1: LaunchDarkly/Flagsmith (SaaS)
+- **Pros:**
+ - Funcionalidad completa
+ - Dashboard listo
+ - SDKs para todo
+- **Cons:**
+ - Costo adicional
+ - Dependencia externa
+ - Datos salen del sistema
+
+### Opcion 2: Unleash (Open Source)
+- **Pros:**
+ - Open source
+ - Self-hosted
+ - Feature completo
+- **Cons:**
+ - Infraestructura adicional
+ - Complejidad de mantener
+ - Overhead para nuestro caso
+
+### Opcion 3: Implementacion propia (Elegida)
+- **Pros:**
+ - Sin dependencias externas
+ - Integrado con nuestro sistema de planes
+ - Cache en Redis existente
+ - Control total
+- **Cons:**
+ - Desarrollo inicial
+ - Sin UI avanzada (la construimos)
+ - Mantenimiento propio
+
+---
+
+## Consecuencias
+
+### Positivas
+
+1. **Integracion:** Se integra directamente con plans y tenants
+2. **Performance:** Cache Redis garantiza <10ms
+3. **Control:** Logica de negocio en nuestro codigo
+4. **Costo:** Sin gastos adicionales
+
+### Negativas
+
+1. **Desarrollo:** Tiempo de implementacion
+2. **Features:** Menos features que soluciones SaaS
+3. **Mantenimiento:** Responsabilidad propia
+
+---
+
+## Implementacion
+
+### Modelo de Datos
+
+```sql
+-- Flags globales
+CREATE TABLE feature_flags.flags (
+ id UUID PRIMARY KEY,
+ key VARCHAR(100) UNIQUE NOT NULL,
+ description TEXT,
+ default_value BOOLEAN DEFAULT false
+);
+
+-- Flags por plan
+CREATE TABLE feature_flags.plan_flags (
+ flag_id UUID REFERENCES flags(id),
+ plan_id UUID REFERENCES billing.plans(id),
+ value BOOLEAN NOT NULL,
+ PRIMARY KEY (flag_id, plan_id)
+);
+
+-- Overrides
+CREATE TABLE feature_flags.flag_overrides (
+ flag_id UUID REFERENCES flags(id),
+ tenant_id UUID,
+ user_id UUID,
+ value BOOLEAN NOT NULL,
+ expires_at TIMESTAMP
+);
+```
+
+### Evaluador
+
+```typescript
+async evaluate(key: string, context: FlagContext): Promise {
+ // 1. Buscar en cache
+ const cacheKey = `flags:${key}:${context.tenantId}:${context.userId}`;
+ const cached = await this.redis.get(cacheKey);
+ if (cached !== null) return cached === 'true';
+
+ // 2. Buscar override de usuario
+ const userOverride = await this.findOverride(key, { userId: context.userId });
+ if (userOverride) {
+ await this.cache(cacheKey, userOverride.value);
+ return userOverride.value;
+ }
+
+ // 3. Buscar override de tenant
+ const tenantOverride = await this.findOverride(key, { tenantId: context.tenantId });
+ if (tenantOverride) {
+ await this.cache(cacheKey, tenantOverride.value);
+ return tenantOverride.value;
+ }
+
+ // 4. Evaluar por plan
+ const planValue = await this.getPlanValue(key, context.planId);
+ if (planValue !== null) {
+ await this.cache(cacheKey, planValue);
+ return planValue;
+ }
+
+ // 5. Valor por defecto
+ const flag = await this.getFlag(key);
+ await this.cache(cacheKey, flag.default_value);
+ return flag.default_value;
+}
+```
+
+### Uso en Backend
+
+```typescript
+@UseGuards(FeatureFlagGuard)
+@FeatureFlag('advanced_reports')
+@Get('reports/advanced')
+getAdvancedReports() {
+ // Solo accesible si el flag esta habilitado
+}
+```
+
+### Uso en Frontend
+
+```tsx
+function Dashboard() {
+ const canUseAI = useFeatureFlag('ai_assistant');
+
+ return (
+
+ );
+}
+```
+
+---
+
+## Flags Iniciales
+
+| Key | Descripcion | Basic | Pro | Enterprise |
+|-----|-------------|-------|-----|------------|
+| ai_assistant | Asistente IA | false | true | true |
+| advanced_reports | Reportes avanzados | false | true | true |
+| api_access | API publica | false | false | true |
+| white_label | Sin branding | false | false | true |
+| multi_location | Multiples ubicaciones | false | true | true |
+| custom_integrations | Integraciones custom | false | false | true |
+
+---
+
+## Referencias
+
+- [Feature Flags Best Practices](https://martinfowler.com/articles/feature-toggles.html)
+- [MCH-032: Feature Flags](../01-epicas/MCH-032-feature-flags.md)
+
+---
+
+**Fecha decision:** 2026-01-10
+**Autores:** Architecture Team
diff --git a/docs/97-adr/ADR-0006-storage-abstraction.md b/docs/97-adr/ADR-0006-storage-abstraction.md
new file mode 100644
index 000000000..b0e867161
--- /dev/null
+++ b/docs/97-adr/ADR-0006-storage-abstraction.md
@@ -0,0 +1,209 @@
+---
+id: ADR-0006
+type: ADR
+title: "Storage Abstraction"
+status: Accepted
+decision_date: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+stakeholders:
+ - "Equipo MiChangarrito"
+tags:
+ - storage
+ - s3
+ - r2
+ - abstraction
+ - multi-cloud
+---
+
+# ADR-0006: Storage Abstraction
+
+## Metadata
+
+| Campo | Valor |
+|-------|-------|
+| **ID** | ADR-0006 |
+| **Estado** | Accepted |
+| **Fecha** | 2026-01-10 |
+| **Autor** | Architecture Team |
+| **Supersede** | - |
+
+---
+
+## Contexto
+
+MiChangarrito necesita almacenar archivos (imagenes de productos, facturas, documentos) en la nube. Queremos:
+
+1. Flexibilidad para cambiar de proveedor
+2. Desarrollo local sin depender de cloud
+3. Optimizacion de costos (R2 es mas barato que S3)
+
+---
+
+## Decision
+
+**Implementamos una capa de abstraccion con Factory Pattern que soporta S3, Cloudflare R2 y MinIO.**
+
+Todos los proveedores implementan la misma interfaz, permitiendo cambiar de proveedor sin modificar codigo de negocio.
+
+```typescript
+interface StorageProvider {
+ upload(key: string, file: Buffer, options?: UploadOptions): Promise;
+ download(key: string): Promise;
+ delete(key: string): Promise;
+ getSignedUrl(key: string, expiresIn: number): Promise;
+ list(prefix: string): Promise;
+}
+```
+
+---
+
+## Alternativas Consideradas
+
+### Opcion 1: Usar S3 directamente
+- **Pros:**
+ - Simple
+ - Bien documentado
+- **Cons:**
+ - Vendor lock-in
+ - Sin desarrollo local facil
+ - Costos pueden ser altos
+
+### Opcion 2: Abstraccion con Factory (Elegida)
+- **Pros:**
+ - Flexibilidad de proveedor
+ - MinIO para desarrollo local
+ - Optimizacion de costos con R2
+ - Codigo limpio
+- **Cons:**
+ - Complejidad adicional
+ - Mantener multiples providers
+
+### Opcion 3: Usar libreria existente (flydrive)
+- **Pros:**
+ - Ya implementado
+ - Multiples drivers
+- **Cons:**
+ - Dependencia externa
+ - Menos control
+ - Puede no cubrir todos nuestros casos
+
+---
+
+## Consecuencias
+
+### Positivas
+
+1. **Flexibilidad:** Cambiar proveedor sin impacto en negocio
+2. **Desarrollo:** MinIO local sin credenciales cloud
+3. **Costos:** Migrar a R2 reduce costos ~75%
+4. **Testing:** Facil mock de storage
+
+### Negativas
+
+1. **Complejidad:** Mantener 3 implementaciones
+2. **Features especificos:** Podemos perder algunas features unicas
+
+---
+
+## Implementacion
+
+### Factory
+
+```typescript
+@Injectable()
+export class StorageFactory {
+ create(provider: StorageProviderType): StorageProvider {
+ switch (provider) {
+ case 's3':
+ return new S3StorageProvider(this.configService);
+ case 'r2':
+ return new R2StorageProvider(this.configService);
+ case 'minio':
+ return new MinIOStorageProvider(this.configService);
+ default:
+ throw new Error(`Unknown storage provider: ${provider}`);
+ }
+ }
+}
+```
+
+### Provider S3
+
+```typescript
+class S3StorageProvider implements StorageProvider {
+ private client: S3Client;
+
+ constructor(config: ConfigService) {
+ this.client = new S3Client({
+ region: config.get('S3_REGION'),
+ credentials: {
+ accessKeyId: config.get('S3_ACCESS_KEY'),
+ secretAccessKey: config.get('S3_SECRET_KEY'),
+ },
+ });
+ }
+
+ async upload(key: string, file: Buffer, options?: UploadOptions): Promise {
+ const command = new PutObjectCommand({
+ Bucket: this.bucket,
+ Key: key,
+ Body: file,
+ ContentType: options?.contentType,
+ });
+
+ await this.client.send(command);
+
+ return {
+ key,
+ url: `https://${this.bucket}.s3.amazonaws.com/${key}`,
+ };
+ }
+
+ // ... otros metodos
+}
+```
+
+### Uso
+
+```typescript
+@Injectable()
+export class FileService {
+ constructor(private readonly storageFactory: StorageFactory) {}
+
+ async uploadProductImage(productId: string, file: Buffer): Promise {
+ const storage = this.storageFactory.create(process.env.STORAGE_PROVIDER);
+ const key = `products/${productId}/image.jpg`;
+
+ const result = await storage.upload(key, file, {
+ contentType: 'image/jpeg',
+ });
+
+ return result.url;
+ }
+}
+```
+
+---
+
+## Configuracion por Ambiente
+
+| Ambiente | Proveedor | Razon |
+|----------|-----------|-------|
+| Development | MinIO | Local, sin credenciales |
+| Staging | R2 | Costos bajos |
+| Production | S3 o R2 | Segun necesidad |
+
+---
+
+## Referencias
+
+- [AWS S3 SDK](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/)
+- [Cloudflare R2](https://developers.cloudflare.com/r2/)
+- [MinIO](https://min.io/)
+- [INT-011: Storage Cloud](../02-integraciones/INT-011-storage-cloud.md)
+
+---
+
+**Fecha decision:** 2026-01-10
+**Autores:** Architecture Team
diff --git a/docs/97-adr/ADR-0007-webhook-retry-strategy.md b/docs/97-adr/ADR-0007-webhook-retry-strategy.md
new file mode 100644
index 000000000..ea9cd739e
--- /dev/null
+++ b/docs/97-adr/ADR-0007-webhook-retry-strategy.md
@@ -0,0 +1,236 @@
+---
+id: ADR-0007
+type: ADR
+title: "Webhook Retry Strategy"
+status: Accepted
+decision_date: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+stakeholders:
+ - "Equipo MiChangarrito"
+tags:
+ - webhooks
+ - retry
+ - bullmq
+ - resilience
+---
+
+# ADR-0007: Webhook Retry Strategy
+
+## Metadata
+
+| Campo | Valor |
+|-------|-------|
+| **ID** | ADR-0007 |
+| **Estado** | Accepted |
+| **Fecha** | 2026-01-10 |
+| **Autor** | Architecture Team |
+| **Supersede** | - |
+
+---
+
+## Contexto
+
+MiChangarrito ofrece webhooks outbound para notificar a sistemas externos sobre eventos. Los endpoints destino pueden fallar temporalmente, y necesitamos una estrategia de reintentos que:
+
+1. Sea resiliente a fallos temporales
+2. No sobrecargue el destino
+3. Eventualmente falle despues de intentos razonables
+4. Proporcione visibilidad del estado
+
+---
+
+## Decision
+
+**Adoptamos exponential backoff con jitter usando BullMQ, con maximo 6 intentos y timeout de 30 segundos por request.**
+
+```
+Intento 1: Inmediato
+Intento 2: 1s + jitter
+Intento 3: 2s + jitter
+Intento 4: 4s + jitter
+Intento 5: 8s + jitter
+Intento 6: 16s + jitter
+```
+
+Despues del intento 6, el webhook se marca como fallido y se registra en logs.
+
+---
+
+## Alternativas Consideradas
+
+### Opcion 1: Retry inmediato
+- **Pros:**
+ - Simple
+- **Cons:**
+ - Puede sobrecargar el destino
+ - Fallos en cascada
+
+### Opcion 2: Fixed interval
+- **Pros:**
+ - Predecible
+- **Cons:**
+ - No se adapta a la situacion
+ - Thundering herd problem
+
+### Opcion 3: Exponential backoff con jitter (Elegida)
+- **Pros:**
+ - Reduce carga en destino
+ - Evita thundering herd
+ - Estandar de industria
+- **Cons:**
+ - Mas tiempo total antes de fallo definitivo
+
+---
+
+## Consecuencias
+
+### Positivas
+
+1. **Resilencia:** Tolera fallos temporales
+2. **Cortesia:** No sobrecarga destinos
+3. **Predecible:** Comportamiento conocido
+
+### Negativas
+
+1. **Latencia:** Puede tomar ~31 segundos en fallar definitivamente
+2. **Complejidad:** Manejo de estados de entrega
+
+---
+
+## Implementacion
+
+### Configuracion BullMQ
+
+```typescript
+await this.webhookQueue.add('deliver', payload, {
+ attempts: 6,
+ backoff: {
+ type: 'exponential',
+ delay: 1000, // Base: 1 segundo
+ },
+ removeOnComplete: {
+ age: 86400, // 24 horas
+ count: 1000,
+ },
+ removeOnFail: false,
+});
+```
+
+### Logica de Retry
+
+```typescript
+@Process('deliver')
+async handleDelivery(job: Job) {
+ try {
+ const response = await this.httpService.axiosRef.post(
+ job.data.url,
+ job.data.payload,
+ {
+ timeout: 30000,
+ headers: this.buildHeaders(job.data),
+ }
+ );
+
+ if (response.status >= 200 && response.status < 300) {
+ return { success: true, status: response.status };
+ }
+
+ throw new Error(`Unexpected status: ${response.status}`);
+ } catch (error) {
+ const shouldRetry = this.shouldRetry(error);
+
+ this.logger.warn('Webhook delivery failed', {
+ attempt: job.attemptsMade + 1,
+ maxAttempts: job.opts.attempts,
+ willRetry: shouldRetry,
+ error: error.message,
+ });
+
+ if (!shouldRetry) {
+ // No reintentar, marcar como fallido definitivo
+ await this.markAsFailed(job.data.deliveryId, error.message);
+ return { success: false, permanent: true };
+ }
+
+ throw error; // BullMQ reintentara
+ }
+}
+
+private shouldRetry(error: any): boolean {
+ // No reintentar errores del cliente (4xx) excepto 429
+ if (error.response) {
+ const status = error.response.status;
+ if (status === 429) return true; // Rate limited
+ if (status >= 400 && status < 500) return false; // Client error
+ if (status >= 500) return true; // Server error
+ }
+
+ // Reintentar errores de red y timeouts
+ return true;
+}
+```
+
+### Jitter
+
+BullMQ aplica jitter automaticamente. Si queremos control manual:
+
+```typescript
+function getBackoffDelay(attempt: number): number {
+ const baseDelay = 1000;
+ const maxDelay = 16000;
+ const exponentialDelay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
+ const jitter = Math.random() * 1000; // 0-1 segundo de jitter
+ return exponentialDelay + jitter;
+}
+```
+
+---
+
+## Codigos de Respuesta y Acciones
+
+| Codigo | Categoria | Accion | Retry |
+|--------|-----------|--------|-------|
+| 200-299 | Exito | Marcar entregado | No |
+| 301-308 | Redirect | Seguir redirect | - |
+| 400 | Bad Request | Marcar fallido | No |
+| 401 | Unauthorized | Marcar fallido | No |
+| 403 | Forbidden | Marcar fallido | No |
+| 404 | Not Found | Marcar fallido | No |
+| 429 | Rate Limited | Retry con delay | Si |
+| 500-599 | Server Error | Retry | Si |
+| Timeout | Network | Retry | Si |
+| ECONNREFUSED | Network | Retry | Si |
+
+---
+
+## Monitoreo
+
+### Metricas
+
+```typescript
+// Prometheus metrics
+webhook_delivery_attempts_total{status="success|retry|failed"}
+webhook_delivery_duration_seconds
+webhook_delivery_retries_total
+```
+
+### Alertas
+
+- `webhook_delivery_failure_rate > 0.1` - Mas del 10% fallando
+- `webhook_queue_length > 100` - Cola creciendo
+- `webhook_delivery_duration_seconds_p99 > 25` - Latencia alta
+
+---
+
+## Referencias
+
+- [Exponential Backoff](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/)
+- [BullMQ Retries](https://docs.bullmq.io/guide/retrying-failing-jobs)
+- [Stripe Webhooks](https://stripe.com/docs/webhooks/best-practices)
+- [INT-014: Webhooks Outbound](../02-integraciones/INT-014-webhooks-outbound.md)
+
+---
+
+**Fecha decision:** 2026-01-10
+**Autores:** Architecture Team
diff --git a/docs/97-adr/ADR-0008-audit-log-retention.md b/docs/97-adr/ADR-0008-audit-log-retention.md
new file mode 100644
index 000000000..75cef5953
--- /dev/null
+++ b/docs/97-adr/ADR-0008-audit-log-retention.md
@@ -0,0 +1,263 @@
+---
+id: ADR-0008
+type: ADR
+title: "Audit Log Retention"
+status: Accepted
+decision_date: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+stakeholders:
+ - "Equipo MiChangarrito"
+tags:
+ - audit
+ - retention
+ - compliance
+ - storage
+---
+
+# ADR-0008: Audit Log Retention
+
+## Metadata
+
+| Campo | Valor |
+|-------|-------|
+| **ID** | ADR-0008 |
+| **Estado** | Accepted |
+| **Fecha** | 2026-01-10 |
+| **Autor** | Architecture Team |
+| **Supersede** | - |
+
+---
+
+## Contexto
+
+MiChangarrito registra audit logs de todas las acciones del sistema para compliance, debugging y seguridad. Necesitamos definir:
+
+1. Cuanto tiempo mantener los logs
+2. Como archivar logs antiguos
+3. Como purgar datos sin perder trazabilidad
+
+---
+
+## Decision
+
+**Implementamos politica de retencion configurable por tenant con archivado opcional a storage antes de purga.**
+
+- **Default:** 90 dias en base de datos
+- **Archivado:** Opcional a S3/R2 antes de purga
+- **Notificacion:** 7 dias antes de purga
+- **Configuracion:** Por tenant segun plan
+
+---
+
+## Alternativas Consideradas
+
+### Opcion 1: Retencion infinita
+- **Pros:**
+ - Nunca se pierde informacion
+ - Simple
+- **Cons:**
+ - Crecimiento ilimitado de BD
+ - Costos de almacenamiento
+ - Performance degradada
+
+### Opcion 2: Retencion fija (30 dias)
+- **Pros:**
+ - Simple de implementar
+ - Predecible
+- **Cons:**
+ - No flexible para diferentes necesidades
+ - Puede no cumplir regulaciones
+
+### Opcion 3: Retencion configurable + archivado (Elegida)
+- **Pros:**
+ - Flexible por tenant
+ - Archivado economico
+ - Cumple regulaciones
+- **Cons:**
+ - Mas complejo
+ - Necesita job de limpieza
+
+---
+
+## Consecuencias
+
+### Positivas
+
+1. **Compliance:** Tenants pueden configurar segun sus necesidades
+2. **Performance:** BD no crece indefinidamente
+3. **Economia:** Archivado en storage es barato
+4. **Flexibilidad:** Diferentes politicas por plan
+
+### Negativas
+
+1. **Complejidad:** Job de limpieza y archivado
+2. **Acceso:** Logs archivados requieren restauracion
+
+---
+
+## Implementacion
+
+### Configuracion por Plan
+
+| Plan | Retencion BD | Archivado | Restauracion |
+|------|--------------|-----------|--------------|
+| Basic | 30 dias | No | N/A |
+| Pro | 90 dias | Si (1 ano) | Bajo demanda |
+| Enterprise | 365 dias | Si (7 anos) | Autoservicio |
+
+### Job de Limpieza
+
+```typescript
+@Cron('0 3 * * *') // 3 AM diario
+async cleanupAuditLogs() {
+ const tenants = await this.tenantService.findAll();
+
+ for (const tenant of tenants) {
+ const config = await this.getRetentionConfig(tenant.id);
+ const cutoffDate = subDays(new Date(), config.retentionDays);
+
+ // 1. Archivar si esta habilitado
+ if (config.archiveBeforeDelete) {
+ await this.archiveLogs(tenant.id, cutoffDate);
+ }
+
+ // 2. Purgar logs antiguos
+ await this.purgeLogs(tenant.id, cutoffDate);
+
+ this.logger.log(`Cleaned audit logs for tenant ${tenant.id}`, {
+ cutoffDate,
+ archived: config.archiveBeforeDelete,
+ });
+ }
+}
+```
+
+### Archivado
+
+```typescript
+async archiveLogs(tenantId: string, olderThan: Date) {
+ const logs = await this.auditRepository.find({
+ where: {
+ tenantId,
+ createdAt: LessThan(olderThan),
+ },
+ });
+
+ if (logs.length === 0) return;
+
+ // Comprimir y subir a storage
+ const archive = await this.compressLogs(logs);
+ const key = `audit-archives/${tenantId}/${format(new Date(), 'yyyy-MM')}.json.gz`;
+
+ await this.storageService.upload(key, archive, {
+ contentType: 'application/gzip',
+ metadata: {
+ tenantId,
+ recordCount: logs.length.toString(),
+ dateRange: `${logs[0].createdAt}-${logs[logs.length - 1].createdAt}`,
+ },
+ });
+}
+```
+
+### Notificacion Pre-Purga
+
+```typescript
+@Cron('0 9 * * *') // 9 AM diario
+async notifyUpcomingPurge() {
+ const tenants = await this.tenantService.findAll();
+
+ for (const tenant of tenants) {
+ const config = await this.getRetentionConfig(tenant.id);
+ if (!config.notifyBeforePurge) continue;
+
+ const warningDate = subDays(new Date(), config.retentionDays - 7);
+ const count = await this.countLogsOlderThan(tenant.id, warningDate);
+
+ if (count > 0) {
+ await this.notificationService.send(tenant.adminEmail, {
+ template: 'audit-purge-warning',
+ variables: {
+ count,
+ purgeDate: addDays(warningDate, 7),
+ archiveEnabled: config.archiveBeforeDelete,
+ },
+ });
+ }
+ }
+}
+```
+
+---
+
+## Formato de Archivo
+
+### Estructura
+
+```
+audit-archives/
+└── {tenant_id}/
+ ├── 2026-01.json.gz
+ ├── 2026-02.json.gz
+ └── ...
+```
+
+### Contenido (descomprimido)
+
+```json
+{
+ "tenant_id": "550e8400-...",
+ "exported_at": "2026-01-10T03:00:00Z",
+ "record_count": 15000,
+ "date_range": {
+ "from": "2025-10-01T00:00:00Z",
+ "to": "2025-10-31T23:59:59Z"
+ },
+ "records": [
+ {
+ "id": "...",
+ "user_id": "...",
+ "action": "UPDATE",
+ "entity_type": "Product",
+ "entity_id": "...",
+ "old_value": {...},
+ "new_value": {...},
+ "created_at": "2025-10-15T10:30:00Z"
+ }
+ ]
+}
+```
+
+---
+
+## Restauracion
+
+### API de Restauracion (Enterprise)
+
+```typescript
+// POST /api/audit/restore
+{
+ "month": "2025-10",
+ "reason": "Auditoria externa"
+}
+
+// Response
+{
+ "status": "processing",
+ "estimatedTime": "5 minutes",
+ "jobId": "restore-123"
+}
+```
+
+---
+
+## Referencias
+
+- [GDPR Data Retention](https://gdpr.eu/data-retention/)
+- [MCH-031: Auditoria Empresarial](../01-epicas/MCH-031-auditoria-empresarial.md)
+
+---
+
+**Fecha decision:** 2026-01-10
+**Autores:** Architecture Team
diff --git a/docs/97-adr/ADR-0009-rate-limiting.md b/docs/97-adr/ADR-0009-rate-limiting.md
new file mode 100644
index 000000000..6f2b96248
--- /dev/null
+++ b/docs/97-adr/ADR-0009-rate-limiting.md
@@ -0,0 +1,251 @@
+---
+id: ADR-0009
+type: ADR
+title: "Rate Limiting Strategy"
+status: Accepted
+decision_date: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+stakeholders:
+ - "Equipo MiChangarrito"
+tags:
+ - rate-limiting
+ - api
+ - redis
+ - security
+---
+
+# ADR-0009: Rate Limiting Strategy
+
+## Metadata
+
+| Campo | Valor |
+|-------|-------|
+| **ID** | ADR-0009 |
+| **Estado** | Accepted |
+| **Fecha** | 2026-01-10 |
+| **Autor** | Architecture Team |
+| **Supersede** | - |
+
+---
+
+## Contexto
+
+MiChangarrito expone una API REST que puede ser abusada por clientes mal configurados o ataques maliciosos. Necesitamos rate limiting para:
+
+1. Proteger la infraestructura
+2. Garantizar uso justo entre tenants
+3. Diferenciar limites por plan
+4. Informar a clientes sobre limites
+
+---
+
+## Decision
+
+**Implementamos Token Bucket algorithm con Redis, limites por plan/tenant y headers estandar de rate limit.**
+
+```
+Header: X-RateLimit-Limit: 1000
+Header: X-RateLimit-Remaining: 999
+Header: X-RateLimit-Reset: 1704880800
+```
+
+---
+
+## Alternativas Consideradas
+
+### Opcion 1: Fixed Window
+- **Pros:**
+ - Simple de implementar
+ - Facil de entender
+- **Cons:**
+ - Vulnerable a bursts al cambiar ventana
+ - No es smooth
+
+### Opcion 2: Sliding Window Log
+- **Pros:**
+ - Preciso
+ - Sin bursts
+- **Cons:**
+ - Alto uso de memoria
+ - Queries complejas
+
+### Opcion 3: Token Bucket (Elegida)
+- **Pros:**
+ - Permite bursts controlados
+ - Eficiente en memoria
+ - Smooth rate limiting
+- **Cons:**
+ - Ligeramente mas complejo
+
+---
+
+## Consecuencias
+
+### Positivas
+
+1. **Proteccion:** API protegida contra abusos
+2. **Justicia:** Cada tenant tiene su cuota
+3. **Transparencia:** Headers informan estado
+4. **Flexibilidad:** Limites por plan
+
+### Negativas
+
+1. **Dependencia Redis:** Requiere Redis disponible
+2. **Complejidad:** Logica adicional en cada request
+
+---
+
+## Implementacion
+
+### Limites por Plan
+
+| Plan | Requests/minuto | Requests/dia | Burst |
+|------|-----------------|--------------|-------|
+| Basic | 60 | 10,000 | 10 |
+| Pro | 300 | 100,000 | 50 |
+| Enterprise | 1,000 | 1,000,000 | 100 |
+
+### Guard
+
+```typescript
+@Injectable()
+export class RateLimitGuard implements CanActivate {
+ constructor(
+ @Inject('REDIS_CLIENT') private readonly redis: Redis,
+ private readonly planService: PlanService,
+ ) {}
+
+ async canActivate(context: ExecutionContext): Promise {
+ const request = context.switchToHttp().getRequest();
+ const response = context.switchToHttp().getResponse();
+ const tenantId = request.user?.tenantId;
+
+ if (!tenantId) return true; // Sin tenant, skip
+
+ const plan = await this.planService.getTenantPlan(tenantId);
+ const limit = this.getLimitForPlan(plan);
+
+ const result = await this.checkLimit(tenantId, limit);
+
+ // Agregar headers
+ response.setHeader('X-RateLimit-Limit', limit.requestsPerMinute);
+ response.setHeader('X-RateLimit-Remaining', result.remaining);
+ response.setHeader('X-RateLimit-Reset', result.resetAt);
+
+ if (!result.allowed) {
+ response.setHeader('Retry-After', result.retryAfter);
+ throw new HttpException({
+ statusCode: 429,
+ message: 'Too Many Requests',
+ retryAfter: result.retryAfter,
+ }, 429);
+ }
+
+ return true;
+ }
+
+ private async checkLimit(
+ tenantId: string,
+ limit: RateLimit,
+ ): Promise {
+ const key = `rate:${tenantId}`;
+ const now = Date.now();
+ const windowMs = 60 * 1000; // 1 minuto
+
+ const pipe = this.redis.pipeline();
+
+ // Remover tokens viejos
+ pipe.zremrangebyscore(key, 0, now - windowMs);
+
+ // Contar tokens actuales
+ pipe.zcard(key);
+
+ // Agregar token actual
+ pipe.zadd(key, now, `${now}-${Math.random()}`);
+
+ // Expirar key
+ pipe.expire(key, 60);
+
+ const results = await pipe.exec();
+ const count = results[1][1] as number;
+
+ const allowed = count < limit.requestsPerMinute;
+ const remaining = Math.max(0, limit.requestsPerMinute - count - 1);
+ const resetAt = Math.floor((now + windowMs) / 1000);
+
+ return {
+ allowed,
+ remaining,
+ resetAt,
+ retryAfter: allowed ? 0 : Math.ceil(windowMs / 1000),
+ };
+ }
+}
+```
+
+### Bypass
+
+Algunas rutas no tienen rate limit:
+
+```typescript
+@RateLimitBypass()
+@Get('health')
+healthCheck() {
+ return { status: 'ok' };
+}
+
+// Decorator
+export const RateLimitBypass = () => SetMetadata('rateLimitBypass', true);
+```
+
+### Response 429
+
+```json
+{
+ "statusCode": 429,
+ "message": "Too Many Requests",
+ "error": "Rate limit exceeded. Please retry after 45 seconds.",
+ "retryAfter": 45
+}
+```
+
+---
+
+## Headers Estandar
+
+| Header | Descripcion |
+|--------|-------------|
+| `X-RateLimit-Limit` | Limite maximo de requests |
+| `X-RateLimit-Remaining` | Requests restantes |
+| `X-RateLimit-Reset` | Unix timestamp cuando se resetea |
+| `Retry-After` | Segundos a esperar (solo en 429) |
+
+---
+
+## Monitoreo
+
+### Metricas
+
+```typescript
+rate_limit_requests_total{tenant, plan, allowed}
+rate_limit_exceeded_total{tenant, plan}
+```
+
+### Alertas
+
+- Rate limit hits > 100/minuto por tenant
+- Mismo IP excediendo multiples tenants
+
+---
+
+## Referencias
+
+- [Token Bucket Algorithm](https://en.wikipedia.org/wiki/Token_bucket)
+- [RFC 6585 - 429 Too Many Requests](https://tools.ietf.org/html/rfc6585)
+- [GitHub API Rate Limiting](https://docs.github.com/en/rest/rate-limit)
+
+---
+
+**Fecha decision:** 2026-01-10
+**Autores:** Architecture Team
diff --git a/docs/97-adr/ADR-0010-oauth-social.md b/docs/97-adr/ADR-0010-oauth-social.md
new file mode 100644
index 000000000..96f6297b2
--- /dev/null
+++ b/docs/97-adr/ADR-0010-oauth-social.md
@@ -0,0 +1,258 @@
+---
+id: ADR-0010
+type: ADR
+title: "OAuth Social Strategy"
+status: Accepted
+decision_date: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+stakeholders:
+ - "Equipo MiChangarrito"
+tags:
+ - oauth
+ - authentication
+ - google
+ - apple
+ - passport
+---
+
+# ADR-0010: OAuth Social Strategy
+
+## Metadata
+
+| Campo | Valor |
+|-------|-------|
+| **ID** | ADR-0010 |
+| **Estado** | Accepted |
+| **Fecha** | 2026-01-10 |
+| **Autor** | Architecture Team |
+| **Supersede** | - |
+
+---
+
+## Contexto
+
+MiChangarrito quiere permitir registro e inicio de sesion con cuentas sociales (Google, Apple) para reducir friccion de onboarding. Necesitamos decidir:
+
+1. Que proveedores soportar
+2. Como integrar con nuestro sistema de auth existente
+3. Como manejar vinculacion de cuentas
+
+---
+
+## Decision
+
+**Implementamos OAuth 2.0 con Passport.js para Google y Apple, con tabla separada oauth_accounts vinculada a users.**
+
+- Google: Principal proveedor social
+- Apple: Requerido para iOS App Store
+- Passport.js: Strategies bien mantenidas
+
+---
+
+## Alternativas Consideradas
+
+### Opcion 1: Auth0/Firebase Auth
+- **Pros:**
+ - Todo manejado
+ - Multiples providers
+- **Cons:**
+ - Costo adicional
+ - Dependencia externa
+ - Menos control
+
+### Opcion 2: Passport.js (Elegida)
+- **Pros:**
+ - Open source
+ - Bien documentado
+ - Control total
+ - Sin costos adicionales
+- **Cons:**
+ - Mas trabajo de implementacion
+ - Mantener actualizaciones
+
+### Opcion 3: Implementacion manual
+- **Pros:**
+ - Control absoluto
+- **Cons:**
+ - Mucho trabajo
+ - Propenso a errores de seguridad
+ - Mantener cambios de API
+
+---
+
+## Consecuencias
+
+### Positivas
+
+1. **Control:** Logica de negocio en nuestro codigo
+2. **Flexibilidad:** Agregar providers facilmente
+3. **Integracion:** Se integra con nuestro JWT flow
+4. **Costo:** Sin gastos adicionales
+
+### Negativas
+
+1. **Mantenimiento:** Actualizar strategies
+2. **Configuracion:** Setup en consolas de providers
+
+---
+
+## Implementacion
+
+### Modelo de Datos
+
+```sql
+CREATE TABLE auth.oauth_accounts (
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+ user_id UUID REFERENCES auth.users(id) NOT NULL,
+ provider VARCHAR(20) NOT NULL, -- google, apple
+ provider_user_id VARCHAR(255) NOT NULL,
+ email VARCHAR(255),
+ name VARCHAR(255),
+ avatar_url TEXT,
+ access_token TEXT,
+ refresh_token TEXT,
+ expires_at TIMESTAMP WITH TIME ZONE,
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
+ UNIQUE(provider, provider_user_id)
+);
+```
+
+### Flujo de Autenticacion
+
+```
+1. Usuario hace clic en "Continuar con Google"
+2. Redirect a Google OAuth
+3. Usuario autoriza
+4. Callback a nuestro servidor con code
+5. Intercambiar code por tokens
+6. Obtener perfil de usuario
+7. Buscar/crear usuario en nuestra BD
+8. Generar JWT nuestro
+9. Redirect a frontend con JWT
+```
+
+### Casos de Vinculacion
+
+| Escenario | Accion |
+|-----------|--------|
+| Nuevo usuario, nuevo email | Crear user + oauth_account |
+| Email existe, mismo provider | Error (ya vinculado) |
+| Email existe, otro provider | Ofrecer vincular cuentas |
+| Usuario logueado vincula nueva | Agregar oauth_account |
+
+### Codigo de Vinculacion
+
+```typescript
+async findOrCreateFromOAuth(profile: OAuthProfile): Promise {
+ // 1. Buscar oauth_account existente
+ const existingOAuth = await this.oauthRepo.findOne({
+ where: {
+ provider: profile.provider,
+ providerUserId: profile.id,
+ },
+ });
+
+ if (existingOAuth) {
+ return existingOAuth.user;
+ }
+
+ // 2. Buscar user por email
+ const existingUser = await this.userRepo.findOne({
+ where: { email: profile.email },
+ });
+
+ if (existingUser) {
+ // Vincular automaticamente si email verificado en provider
+ if (profile.emailVerified) {
+ await this.createOAuthAccount(existingUser, profile);
+ return existingUser;
+ }
+
+ // Sino, pedir confirmacion
+ throw new EmailExistsError(profile.email, profile.provider);
+ }
+
+ // 3. Crear nuevo usuario
+ const user = await this.createUser({
+ email: profile.email,
+ name: profile.name,
+ avatarUrl: profile.avatar,
+ emailVerified: profile.emailVerified,
+ });
+
+ await this.createOAuthAccount(user, profile);
+
+ return user;
+}
+```
+
+---
+
+## Providers Soportados
+
+### Google
+
+```typescript
+passport.use(new GoogleStrategy({
+ clientID: process.env.GOOGLE_CLIENT_ID,
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET,
+ callbackURL: '/auth/google/callback',
+ scope: ['profile', 'email'],
+}, verify));
+```
+
+### Apple
+
+```typescript
+passport.use(new AppleStrategy({
+ clientID: process.env.APPLE_CLIENT_ID,
+ teamID: process.env.APPLE_TEAM_ID,
+ keyID: process.env.APPLE_KEY_ID,
+ privateKeyString: process.env.APPLE_PRIVATE_KEY,
+ callbackURL: '/auth/apple/callback',
+ scope: ['name', 'email'],
+}, verify));
+```
+
+---
+
+## Mobile
+
+### Google (Expo)
+
+```typescript
+const [request, response, promptAsync] = Google.useAuthRequest({
+ clientId: GOOGLE_CLIENT_ID,
+ iosClientId: GOOGLE_IOS_CLIENT_ID,
+ androidClientId: GOOGLE_ANDROID_CLIENT_ID,
+});
+```
+
+### Apple (iOS)
+
+```typescript
+import * as AppleAuthentication from 'expo-apple-authentication';
+
+const credential = await AppleAuthentication.signInAsync({
+ requestedScopes: [
+ AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
+ AppleAuthentication.AppleAuthenticationScope.EMAIL,
+ ],
+});
+```
+
+---
+
+## Referencias
+
+- [Passport.js](http://www.passportjs.org/)
+- [Google Identity](https://developers.google.com/identity)
+- [Sign in with Apple](https://developer.apple.com/sign-in-with-apple/)
+- [INT-012: OAuth Social](../02-integraciones/INT-012-oauth-social.md)
+- [MCH-030: Auth Social](../01-epicas/MCH-030-auth-social.md)
+
+---
+
+**Fecha decision:** 2026-01-10
+**Autores:** Architecture Team
diff --git a/docs/97-adr/ADR-0011-email-multi-provider.md b/docs/97-adr/ADR-0011-email-multi-provider.md
new file mode 100644
index 000000000..e8ab95adc
--- /dev/null
+++ b/docs/97-adr/ADR-0011-email-multi-provider.md
@@ -0,0 +1,295 @@
+---
+id: ADR-0011
+type: ADR
+title: "Email Multi-Provider"
+status: Accepted
+decision_date: 2026-01-10
+updated_at: 2026-01-10
+simco_version: "4.0.1"
+stakeholders:
+ - "Equipo MiChangarrito"
+tags:
+ - email
+ - notifications
+ - sendgrid
+ - ses
+ - multi-provider
+---
+
+# ADR-0011: Email Multi-Provider
+
+## Metadata
+
+| Campo | Valor |
+|-------|-------|
+| **ID** | ADR-0011 |
+| **Estado** | Accepted |
+| **Fecha** | 2026-01-10 |
+| **Autor** | Architecture Team |
+| **Supersede** | - |
+
+---
+
+## Contexto
+
+MiChangarrito necesita enviar emails transaccionales (bienvenida, verificacion, notificaciones, facturas). Queremos:
+
+1. Alta deliverability
+2. Fallback si un proveedor falla
+3. Flexibilidad para cambiar proveedor
+4. Costos optimizados
+
+---
+
+## Decision
+
+**Implementamos Factory Pattern con soporte para SendGrid, AWS SES y SMTP generico, con fallback automatico.**
+
+Orden de prioridad:
+1. SendGrid (principal)
+2. AWS SES (fallback)
+3. SMTP (ultimo recurso)
+
+---
+
+## Alternativas Consideradas
+
+### Opcion 1: Solo SendGrid
+- **Pros:**
+ - Simple
+ - Buena API
+- **Cons:**
+ - Single point of failure
+ - Vendor lock-in
+
+### Opcion 2: Solo AWS SES
+- **Pros:**
+ - Integrado con AWS
+ - Muy economico
+- **Cons:**
+ - Setup complejo
+ - Sandbox restrictivo
+
+### Opcion 3: Multi-Provider con fallback (Elegida)
+- **Pros:**
+ - Alta disponibilidad
+ - Flexibilidad
+ - Optimizacion de costos
+- **Cons:**
+ - Mas complejidad
+ - Mantener multiples integraciones
+
+---
+
+## Consecuencias
+
+### Positivas
+
+1. **Disponibilidad:** Fallback automatico
+2. **Flexibilidad:** Cambiar provider por tenant
+3. **Economia:** Usar el mas economico como default
+4. **Deliverability:** SendGrid tiene buena reputacion
+
+### Negativas
+
+1. **Complejidad:** Tres implementaciones
+2. **Configuracion:** Multiples sets de credenciales
+
+---
+
+## Implementacion
+
+### Factory
+
+```typescript
+@Injectable()
+export class EmailProviderFactory {
+ private providers: EmailProvider[];
+
+ constructor(
+ private sendgrid: SendGridProvider,
+ private ses: SESProvider,
+ private smtp: SMTPProvider,
+ ) {
+ // Orden de prioridad
+ this.providers = [sendgrid, ses, smtp].filter(p => p.isConfigured());
+ }
+
+ async send(email: EmailDto): Promise {
+ for (const provider of this.providers) {
+ try {
+ return await provider.send(email);
+ } catch (error) {
+ this.logger.warn(`Provider ${provider.name} failed: ${error.message}`);
+ continue;
+ }
+ }
+ throw new Error('All email providers failed');
+ }
+}
+```
+
+### Interface
+
+```typescript
+interface EmailProvider {
+ name: string;
+ isConfigured(): boolean;
+ send(email: EmailDto): Promise;
+}
+
+interface EmailDto {
+ to: string | string[];
+ subject: string;
+ html?: string;
+ text?: string;
+ template?: string;
+ variables?: Record;
+ from?: string;
+ replyTo?: string;
+ attachments?: Attachment[];
+}
+```
+
+### SendGrid Provider
+
+```typescript
+@Injectable()
+export class SendGridProvider implements EmailProvider {
+ name = 'sendgrid';
+
+ private client: MailService;
+
+ constructor(config: ConfigService) {
+ if (config.get('SENDGRID_API_KEY')) {
+ this.client = new MailService();
+ this.client.setApiKey(config.get('SENDGRID_API_KEY'));
+ }
+ }
+
+ isConfigured(): boolean {
+ return !!this.client;
+ }
+
+ async send(email: EmailDto): Promise {
+ const msg = {
+ to: email.to,
+ from: email.from || process.env.EMAIL_FROM,
+ subject: email.subject,
+ html: email.html,
+ text: email.text,
+ };
+
+ const [response] = await this.client.send(msg);
+
+ return {
+ messageId: response.headers['x-message-id'],
+ provider: this.name,
+ };
+ }
+}
+```
+
+---
+
+## Templates
+
+### Almacenamiento
+
+- Templates en base de datos (tenant-specific)
+- Templates por defecto en codigo (fallback)
+
+### Renderizado
+
+```typescript
+async renderTemplate(
+ key: string,
+ variables: Record,
+ tenantId?: string,
+): Promise<{ html: string; text: string }> {
+ // Buscar template custom del tenant
+ let template = await this.findTemplate(key, tenantId);
+
+ // Fallback a template por defecto
+ if (!template) {
+ template = this.getDefaultTemplate(key);
+ }
+
+ // Renderizar con Handlebars
+ const html = Handlebars.compile(template.html)(variables);
+ const text = Handlebars.compile(template.text)(variables);
+
+ return { html, text };
+}
+```
+
+---
+
+## Rate Limiting
+
+### Por Tenant
+
+```typescript
+async checkTenantEmailLimit(tenantId: string): Promise {
+ const plan = await this.getPlan(tenantId);
+ const key = `email:count:${tenantId}:${format(new Date(), 'yyyy-MM-dd-HH')}`;
+
+ const count = await this.redis.incr(key);
+ await this.redis.expire(key, 3600);
+
+ return count <= plan.emailsPerHour;
+}
+```
+
+### Limites
+
+| Plan | Por Hora | Por Dia |
+|------|----------|---------|
+| Basic | 100 | 500 |
+| Pro | 1,000 | 10,000 |
+| Enterprise | Ilimitado | Ilimitado |
+
+---
+
+## Tracking
+
+### Webhooks de Estado
+
+```typescript
+// POST /webhooks/email/sendgrid
+async handleSendGridWebhook(events: SendGridEvent[]) {
+ for (const event of events) {
+ await this.emailLogRepo.update(
+ { providerMessageId: event.sg_message_id },
+ {
+ status: this.mapStatus(event.event),
+ [event.event + 'At']: new Date(event.timestamp * 1000),
+ }
+ );
+ }
+}
+```
+
+### Estados
+
+- sent: Email enviado al proveedor
+- delivered: Entregado al servidor destino
+- opened: Abierto por destinatario (si tracking habilitado)
+- clicked: Link clickeado
+- bounced: Rebotado
+- spam: Marcado como spam
+
+---
+
+## Referencias
+
+- [SendGrid API](https://docs.sendgrid.com/api-reference)
+- [AWS SES](https://docs.aws.amazon.com/ses/)
+- [Nodemailer](https://nodemailer.com/)
+- [INT-010: Email Providers](../02-integraciones/INT-010-email-providers.md)
+- [MCH-029: Infraestructura SaaS](../01-epicas/MCH-029-infraestructura-saas.md)
+
+---
+
+**Fecha decision:** 2026-01-10
+**Autores:** Architecture Team
diff --git a/docs/97-adr/_MAP.md b/docs/97-adr/_MAP.md
index f51239333..7cf2f4564 100644
--- a/docs/97-adr/_MAP.md
+++ b/docs/97-adr/_MAP.md
@@ -11,8 +11,8 @@
| Metrica | Valor |
|---------|-------|
-| Total ADRs | 3 |
-| Aceptados | 3 |
+| Total ADRs | 11 |
+| Aceptados | 11 |
| Propuestos | 0 |
| Deprecated | 0 |
@@ -27,6 +27,14 @@
| [ADR-0001](./ADR-0001-multi-tenant-architecture.md) | Arquitectura Multi-Tenant | Accepted | 2026-01-06 | Alto |
| [ADR-0002](./ADR-0002-whatsapp-first-approach.md) | WhatsApp como Canal Principal | Accepted | 2026-01-06 | Alto |
| [ADR-0003](./ADR-0003-llm-agnostic-strategy.md) | Estrategia LLM Agnostica | Accepted | 2026-01-06 | Medio |
+| [ADR-0004](./ADR-0004-notifications-realtime.md) | Notificaciones en Tiempo Real | Accepted | 2026-01-10 | Medio |
+| [ADR-0005](./ADR-0005-feature-flags.md) | Feature Flags por Plan | Accepted | 2026-01-10 | Alto |
+| [ADR-0006](./ADR-0006-storage-abstraction.md) | Storage Abstraction | Accepted | 2026-01-10 | Alto |
+| [ADR-0007](./ADR-0007-webhook-retry-strategy.md) | Webhook Retry Strategy | Accepted | 2026-01-10 | Medio |
+| [ADR-0008](./ADR-0008-audit-log-retention.md) | Audit Log Retention | Accepted | 2026-01-10 | Medio |
+| [ADR-0009](./ADR-0009-rate-limiting.md) | Rate Limiting Strategy | Accepted | 2026-01-10 | Alto |
+| [ADR-0010](./ADR-0010-oauth-social.md) | OAuth Social Strategy | Accepted | 2026-01-10 | Medio |
+| [ADR-0011](./ADR-0011-email-multi-provider.md) | Email Multi-Provider | Accepted | 2026-01-10 | Medio |
---
@@ -34,12 +42,24 @@
### Arquitectura
- [ADR-0001 - Multi-Tenant](./ADR-0001-multi-tenant-architecture.md)
+- [ADR-0006 - Storage Abstraction](./ADR-0006-storage-abstraction.md)
+- [ADR-0009 - Rate Limiting](./ADR-0009-rate-limiting.md)
### Producto
- [ADR-0002 - WhatsApp First](./ADR-0002-whatsapp-first-approach.md)
+- [ADR-0005 - Feature Flags](./ADR-0005-feature-flags.md)
### Tecnologia
- [ADR-0003 - LLM Agnostico](./ADR-0003-llm-agnostic-strategy.md)
+- [ADR-0011 - Email Multi-Provider](./ADR-0011-email-multi-provider.md)
+
+### Infraestructura
+- [ADR-0004 - Notificaciones Realtime](./ADR-0004-notifications-realtime.md)
+- [ADR-0007 - Webhook Retry Strategy](./ADR-0007-webhook-retry-strategy.md)
+
+### Seguridad y Compliance
+- [ADR-0008 - Audit Log Retention](./ADR-0008-audit-log-retention.md)
+- [ADR-0010 - OAuth Social](./ADR-0010-oauth-social.md)
---
@@ -106,4 +126,5 @@ Crear un ADR cuando:
---
**Mantenido por:** Architecture Team
-**Version:** 1.0.0
+**Version:** 2.0.0
+**Total ADRs:** 11 (ADR-0001 a ADR-0011)
diff --git a/orchestration/00-guidelines/HERENCIA-SIMCO.md b/orchestration/00-guidelines/HERENCIA-SIMCO.md
index 6d3bc23bc..0dfdbbe73 100644
--- a/orchestration/00-guidelines/HERENCIA-SIMCO.md
+++ b/orchestration/00-guidelines/HERENCIA-SIMCO.md
@@ -1,77 +1,107 @@
# Herencia SIMCO - michangarrito
-**Sistema:** SIMCO v4.0.0 + CAPVED + SCRUM
+**Sistema:** SIMCO v4.0.1 + CAPVED + SCRUM
**Fecha:** 2026-01-10
+**Version anterior:** v3.8.0 (workspace-v1) + v4.0.0 (workspace-v2)
---
-## Configuración del Proyecto
+## 1. Configuracion del Proyecto
| Propiedad | Valor |
|-----------|-------|
| **Proyecto** | Mi Changarrito - Sistema POS para Pequenos Comercios |
-| **Código v2** | MCH |
-| **SIMCO Version** | 4.0.0 |
+| **Codigo v2** | MCH |
+| **Nivel** | STANDALONE (Nivel 2A) |
+| **Padre** | workspace-v2/orchestration |
+| **SIMCO Version** | 4.0.1 |
| **CAPVED** | Habilitado |
| **SCRUM** | Habilitado |
+| **CCA Protocol** | Habilitado |
---
-## Metodología CAPVED+SCRUM
+## 2. Jerarquia de Herencia
-Este proyecto utiliza la metodología integrada CAPVED+SCRUM definida en SIMCO v4.0.0.
+```
+Nivel 0: workspace-v2/orchestration/ <- WORKSPACE (directivas globales)
+ |
+ +-- STANDALONE: michangarrito/orchestration/ <- ESTE PROYECTO
+ michangarrito/docs/ <- DOCUMENTACION
+```
+
+**Regla:** Las directivas locales pueden EXTENDER las del workspace, nunca REDUCIRLAS.
+
+**Estado del Proyecto:** MVP 95% Implementado
+
+---
+
+## 3. Directivas Heredadas de WORKSPACE (OBLIGATORIAS)
+
+Ubicacion: `workspace-v2/orchestration/`
+
+| Alias | Archivo | Proposito |
+|-------|---------|-----------|
+| `@CARGA-CONTEXTO` | `directivas/DIRECTIVA-CARGA-CONTEXTO.md` | Como cargar contexto segun nivel |
+| `@INDICE` | `INDICE-DIRECTIVAS-WORKSPACE.yml` | Indice maestro de directivas |
+
+---
+
+## 4. Metodologia CAPVED+SCRUM
+
+Este proyecto utiliza la metodologia integrada CAPVED+SCRUM definida en SIMCO v4.0.
### Ciclo CAPVED dentro de Sprint
```
Sprint Start
- │
- ├── Sprint Planning (usar @TPL_SPRINT_PLANNING)
- │
- └── Por cada HU:
- ├── [C] Contexto → Cargar directivas, verificar DoR
- ├── [A] Análisis → Analizar requerimientos
- ├── [P] Plan → Planificar implementación
- ├── [V] Validación → Validar plan técnico
- ├── [E] Ejecución → Implementar código
- └── [D] Documentar → Actualizar docs, verificar DoD
- │
- ├── Sprint Review
- └── Sprint Retrospective (usar @TPL_RETROSPECTIVA)
+ |
+ +-- Sprint Planning (usar @TPL_SPRINT_PLANNING)
+ |
+ +-- Por cada HU:
+ +-- [C] Contexto -> Cargar directivas, verificar DoR
+ +-- [A] Analisis -> Analizar requerimientos
+ +-- [P] Plan -> Planificar implementacion
+ +-- [V] Validacion -> Validar plan tecnico
+ +-- [E] Ejecucion -> Implementar codigo
+ +-- [D] Documentar -> Actualizar docs, verificar DoD
+ |
+ +-- Sprint Review
+ +-- Sprint Retrospective (usar @TPL_RETROSPECTIVA)
```
---
-## Directivas SCRUM (SIMCO v4.0.0)
+## 5. Directivas SCRUM (SIMCO v4.0)
-### Ejecución de Sprint
+### Ejecucion de Sprint
-| Alias | Directiva | Propósito |
+| Alias | Directiva | Proposito |
|-------|-----------|-----------|
| `@SPRINT_EXECUTION` | `SIMCO-SPRINT-EXECUTION.md` | Ciclo completo de Sprint |
-| `@AGILE_METRICS` | `SIMCO-AGILE-METRICS.md` | Métricas Velocity, Burndown |
-| `@SCRUM_INTEGRATION` | `SIMCO-SCRUM-INTEGRATION.md` | Integración CAPVED+SCRUM |
+| `@AGILE_METRICS` | `SIMCO-AGILE-METRICS.md` | Metricas Velocity, Burndown |
+| `@SCRUM_INTEGRATION` | `SIMCO-SCRUM-INTEGRATION.md` | Integracion CAPVED+SCRUM |
### Definition of Ready (DoR)
-| Criterio | Descripción |
+| Criterio | Descripcion |
|----------|-------------|
| ID asignado | `MCH-US-NNN` |
| Historia completa | Como/Quiero/Para |
-| Criterios de aceptación | 3-8 criterios |
+| Criterios de aceptacion | 3-8 criterios |
| Story Points | Fibonacci (1,2,3,5,8,13) |
| Dependencias identificadas | Sin bloqueos |
-| PO aprobado | ✓ |
+| PO aprobado | Si |
### Definition of Done (DoD)
-| Criterio | Descripción |
+| Criterio | Descripcion |
|----------|-------------|
-| Código implementado | Según especificación |
+| Codigo implementado | Segun especificacion |
| Build pasa | Sin errores |
-| Tests pasando | Unitarios + integración |
+| Tests pasando | Unitarios + integracion |
| Code review | Completado |
-| Documentación | Actualizada |
+| Documentacion | Actualizada |
| TRACEABILITY.yml | Actualizado |
### Templates SCRUM
@@ -91,50 +121,264 @@ Sprint Start
---
-## Directivas CAPVED (Heredadas)
+## 6. Directivas de Ciclo de Vida (USAR SIEMPRE)
-### Ciclo de Vida
-
-| Alias | Archivo | Propósito |
+| Alias | Archivo | Proposito |
|-------|---------|-----------|
-| `@TAREA` | `SIMCO-TAREA.md` | Punto de entrada |
-| `@CAPVED` | `PRINCIPIO-CAPVED.md` | Ciclo de 6 fases |
-| `@INICIALIZACION` | `SIMCO-INICIALIZACION.md` | Bootstrap de agentes |
-
-### Operaciones
-
-| Alias | Archivo | Propósito |
-|-------|---------|-----------|
-| `@CREAR` | `SIMCO-CREAR.md` | Crear archivos |
-| `@MODIFICAR` | `SIMCO-MODIFICAR.md` | Modificar archivos |
-| `@VALIDAR` | `SIMCO-VALIDAR.md` | Validar código |
-| `@DOCUMENTAR` | `SIMCO-DOCUMENTAR.md` | Documentar trabajo |
-| `@BUSCAR` | `SIMCO-BUSCAR.md` | Buscar información |
+| `@TAREA` | `directivas/simco/SIMCO-TAREA.md` | Punto de entrada para toda HU |
+| `@CAPVED` | `directivas/principios/PRINCIPIO-CAPVED.md` | Ciclo de 6 fases |
+| `@INICIALIZACION` | `directivas/simco/SIMCO-INICIALIZACION.md` | Bootstrap de agentes |
+| `@DOC-DEFINITIVA` | `directivas/DIRECTIVA-DOCUMENTACION-DEFINITIVA.md` | Docs como estado final |
---
-## Directivas de Documentación
+## 7. Operaciones Universales
-| Alias | Directiva | Propósito |
+| Alias | Archivo | Proposito |
+|-------|---------|-----------|
+| `@CREAR` | `SIMCO-CREAR.md` | Crear archivos nuevos |
+| `@MODIFICAR` | `SIMCO-MODIFICAR.md` | Modificar existentes |
+| `@VALIDAR` | `SIMCO-VALIDAR.md` | Validar codigo |
+| `@DOCUMENTAR` | `SIMCO-DOCUMENTAR.md` | Documentar trabajo |
+| `@BUSCAR` | `SIMCO-BUSCAR.md` | Buscar informacion |
+| `@DELEGAR` | `SIMCO-DELEGACION.md` | Delegar a subagentes |
+
+---
+
+## 8. Directivas de Subagentes (SIMCO v4.0.0)
+
+| Alias | Archivo | Descripcion |
+|-------|---------|-------------|
+| `@SUBAGENTE` | `SIMCO-SUBAGENTE.md` | Protocolo cuando recibes delegacion |
+| `@CCA_SUBAGENTE` | `SIMCO-CCA-SUBAGENTE.md` | CCA ligero (~1500 tokens) |
+| `@CONTROL_TOKENS` | `SIMCO-CONTROL-TOKENS.md` | Gestion de limites de tokens |
+| `@DELEGACION_PARALELA` | `SIMCO-DELEGACION-PARALELA.md` | Delegacion a multiples agentes |
+
+---
+
+## 9. Directivas de Context Engineering
+
+| Alias | Archivo | Descripcion |
+|-------|---------|-------------|
+| `@CONTEXT_ENGINEERING` | `SIMCO-CONTEXT-ENGINEERING.md` | Ingenieria de contexto |
+| `@CONTEXT_RESOLUTION` | `SIMCO-CONTEXT-RESOLUTION.md` | Resolucion de contextos |
+
+---
+
+## 10. Directivas de Niveles y Propagacion
+
+| Alias | Archivo | Descripcion |
+|-------|---------|-------------|
+| `@NIVELES` | `SIMCO-NIVELES.md` | Jerarquia de niveles |
+| `@PROPAGACION` | `SIMCO-PROPAGACION.md` | Propagacion de directivas |
+
+---
+
+## 11. Directivas Git y Gobernanza
+
+| Alias | Archivo | Descripcion |
+|-------|---------|-------------|
+| `@GIT` | `SIMCO-GIT.md` | Operaciones Git |
+| `@GIT_REMOTES` | `SIMCO-GIT-REMOTES.md` | Gestion de remotos |
+| `@ESCALAMIENTO` | `SIMCO-ESCALAMIENTO.md` | Escalamiento de decisiones |
+
+---
+
+## 12. Principios Fundamentales (5)
+
+| Alias | Resumen |
+|-------|---------|
+| `@CAPVED` | Toda tarea pasa por 6 fases |
+| `@DOC_PRIMERO` | Consultar docs/ antes de implementar |
+| `@ANTI_DUP` | Verificar que no existe antes de crear |
+| `@VALIDACION` | Build y lint DEBEN pasar |
+| `@TOKENS` | Desglosar tareas grandes |
+
+---
+
+## 13. Directivas por Dominio Tecnico
+
+| Alias | Aplica | Notas |
+|-------|--------|-------|
+| `@OP_DDL` | **SI** | 11 schemas, 53 tablas |
+| `@OP_BACKEND` | **SI** | NestJS, 18 modulos |
+| `@OP_FRONTEND` | **SI** | React + Vite |
+| `@OP_MOBILE` | **SI** | React Native (Expo) |
+| `@OP_ML` | NO | (LLM via MCP, no ML propio) |
+
+---
+
+## 14. Directivas de Documentacion
+
+| Alias | Directiva | Proposito |
|-------|-----------|-----------|
| `@DOC_PROYECTO` | `SIMCO-DOCUMENTACION-PROYECTO.md` | Estructura docs/ |
| `@NOMENCLATURA` | `SIMCO-NOMENCLATURA.md` | Convenciones de IDs |
| `@ESTRUCTURA_DOCS` | `SIMCO-ESTRUCTURA-DOCS.md` | Estructura interna |
| `@INVENTARIOS` | `SIMCO-INVENTARIOS.md` | Inventarios YAML |
| `@MANTENIMIENTO_DOCS` | `SIMCO-MANTENIMIENTO-DOCUMENTACION.md` | Ciclo mantenimiento |
-| `@SYNC_BD` | `SIMCO-SINCRONIZACION-BD.md` | Sincronización BD↔Docs |
+| `@SYNC_BD` | `SIMCO-SINCRONIZACION-BD.md` | Sincronizacion BD<->Docs |
+| `@TESTING` | `SIMCO-TESTING.md` | Cobertura y estandares de testing |
+| `@MIGRACIONES` | `SIMCO-MIGRACIONES-BD.md` | Migraciones y DDL |
+| `@INTEGRACIONES` | `SIMCO-INTEGRACIONES-EXTERNAS.md` | Documentacion de integraciones |
+
+### Checklists de Documentacion
+
+| Alias | Checklist | Items |
+|-------|-----------|-------|
+| `@CHK_DOCUMENTACION` | `CHECKLIST-DOCUMENTACION-PROYECTO.md` | 44 |
+| `@CHK_INVENTARIOS` | `CHECKLIST-INVENTARIOS.md` | 63 |
+| `@CHK_NOMENCLATURA` | `CHECKLIST-NOMENCLATURA.md` | 40 |
+| `@CHK_MANTENIMIENTO` | `CHECKLIST-MANTENIMIENTO-DOCS.md` | 80 |
+| `@CHK_SYNC_BD` | `CHECKLIST-SINCRONIZACION-BD.md` | 70 |
+
+### Templates de Documentacion
+
+| Alias | Template | Uso |
+|-------|----------|-----|
+| `@TPL_INVENTARIO` | `TEMPLATE-INVENTARIO-PROYECTO.md` | Crear inventarios YAML |
+| `@TPL_INTEGRACION` | `TEMPLATE-INTEGRACION-EXTERNA.md` | Documentar integraciones |
+| `@TPL_MODULO_ESTANDAR` | `TEMPLATE-MODULO-ESTANDAR.md` | Documentar modulos |
+| `@TPL_DEPRECACION` | `TEMPLATE-DEPRECACION.md` | Marcar documentos como deprecados |
---
-## Trazabilidad v2
+## 15. Patrones Aplicables
+
+| Patron | Uso en MiChangarrito |
+|--------|----------------------|
+| `MAPEO-TIPOS-DDL-TYPESCRIPT.md` | 11 schemas -> Entities |
+| `PATRON-VALIDACION.md` | class-validator en DTOs |
+| `PATRON-EXCEPTION-HANDLING.md` | Filtros NestJS |
+| `PATRON-TESTING.md` | Jest + e2e tests |
+| `PATRON-SEGURIDAD.md` | JWT, multi-tenant RLS |
+| `PATRON-TRANSACCIONES.md` | TypeORM transactions |
+| `ANTIPATRONES.md` | Evitar siempre |
+
+---
+
+## 16. Variables de Contexto CCA
+
+```yaml
+# Identificacion del Proyecto
+PROJECT_NAME: "michangarrito"
+PROJECT_CODE: "MCH"
+PROJECT_LEVEL: "STANDALONE"
+PROJECT_ROOT: "/home/isem/workspace-v2/projects/michangarrito"
+
+# Rutas principales
+APPS_ROOT: "apps"
+DOCS_ROOT: "docs"
+ORCHESTRATION: "orchestration"
+
+# Base de Datos
+DB_NAME: "michangarrito"
+DB_DDL_PATH: "database/schemas"
+DB_SCRIPTS_PATH: "database"
+DB_SEEDS_PATH: "database/seeds"
+
+# Backend (NestJS)
+BACKEND_ROOT: "apps/backend"
+BACKEND_SRC: "apps/backend/src"
+BACKEND_FRAMEWORK: "NestJS"
+ORM: "TypeORM"
+BACKEND_PORT: 3141
+
+# Frontend (React)
+FRONTEND_ROOT: "apps/web"
+FRONTEND_SRC: "apps/web/src"
+FRONTEND_FRAMEWORK: "React"
+BUILD_TOOL: "Vite"
+FRONTEND_PORT: 3140
+
+# Mobile (React Native)
+MOBILE_ROOT: "apps/mobile"
+MOBILE_FRAMEWORK: "React Native (Expo)"
+MOBILE_PORT: 8081
+
+# Servicios Adicionales
+MCP_SERVER_ROOT: "apps/mcp-server"
+MCP_SERVER_PORT: 3142
+WHATSAPP_SERVICE_ROOT: "apps/whatsapp-service"
+WHATSAPP_PORT: 3143
+
+# Multi-tenant
+TENANT_COLUMN: "tenant_id"
+RLS_CONTEXT: "app.current_tenant_id"
+
+# Inventarios
+MASTER_INVENTORY: "orchestration/inventarios/MASTER_INVENTORY.yml"
+```
+
+---
+
+## 17. Schemas de Base de Datos (11)
+
+| Schema | Descripcion | Tablas |
+|--------|-------------|--------|
+| `public` | Tenants, configuracion global | ~3 |
+| `auth` | Autenticacion, tokens | ~4 |
+| `catalog` | Productos, categorias | ~5 |
+| `sales` | Ventas, transacciones, CoDi, SPEI | ~6 |
+| `inventory` | Stock, movimientos | ~4 |
+| `customers` | Clientes, fiados | ~4 |
+| `orders` | Pedidos WhatsApp | ~5 |
+| `subscriptions` | Planes, tokens, referidos | ~5 |
+| `messaging` | Conversaciones, mensajes | ~4 |
+| `billing` | CFDI 4.0, facturas | ~6 |
+| `marketplace` | Proveedores B2B | ~7 |
+
+**Total:** ~53 tablas
+
+---
+
+## 18. Integraciones Externas
+
+### Integraciones Core (INT-001 a INT-009)
+
+| ID | Integracion | Proveedor | Estado | Doc |
+|----|-------------|-----------|--------|-----|
+| INT-001 | WhatsApp | Meta Business API | Activo | [INT-001](../docs/02-integraciones/INT-001-whatsapp.md) |
+| INT-002 | Pagos | Stripe | Activo | [INT-002](../docs/02-integraciones/INT-002-stripe.md) |
+| INT-003 | Terminal | Mercado Pago | Activo | [INT-003](../docs/02-integraciones/INT-003-mercadopago.md) |
+| INT-004 | Terminal | Clip | Pendiente | [INT-004](../docs/02-integraciones/INT-004-clip.md) |
+| INT-005 | CoDi | Banxico via Openpay | Activo | [INT-005](../docs/02-integraciones/INT-005-codi.md) |
+| INT-006 | SPEI | STP | Activo | [INT-006](../docs/02-integraciones/INT-006-spei.md) |
+| INT-007 | Facturacion | Facturapi/PAC CFDI 4.0 | Activo | [INT-007](../docs/02-integraciones/INT-007-facturacion.md) |
+| INT-008 | LLM Gateway | OpenRouter | Activo | [INT-008](../docs/02-integraciones/INT-008-llm.md) |
+| INT-009 | Push | Firebase FCM | Activo | [INT-009](../docs/02-integraciones/INT-009-push.md) |
+
+### Integraciones SaaS (INT-010 a INT-014)
+
+| ID | Integracion | Proveedor | Estado | Doc |
+|----|-------------|-----------|--------|-----|
+| INT-010 | Email Multi-Provider | SendGrid/SES/SMTP | Planificado | [INT-010](../docs/02-integraciones/INT-010-email-providers.md) |
+| INT-011 | Storage Cloud | S3/R2/MinIO | Planificado | [INT-011](../docs/02-integraciones/INT-011-storage-cloud.md) |
+| INT-012 | OAuth Social | Google/Apple | Planificado | [INT-012](../docs/02-integraciones/INT-012-oauth-social.md) |
+| INT-013 | Redis Cache/Queue | Redis/BullMQ | Planificado | [INT-013](../docs/02-integraciones/INT-013-redis-cache.md) |
+| INT-014 | Webhooks Outbound | BullMQ | Planificado | [INT-014](../docs/02-integraciones/INT-014-webhooks-outbound.md) |
+
+### Integraciones Pendientes
+
+| Integracion | Proveedor | Estado | Notas |
+|-------------|-----------|--------|-------|
+| OCR | Google Vision | Backlog | MCH-018 |
+| Audio | Whisper | Activo | Via OpenRouter |
+| Web Push | OneSignal/Firebase | Backlog | MCH-034 |
+
+**Total Integraciones:** 14 documentadas (9 activas, 5 planificadas)
+
+---
+
+## 19. Trazabilidad v2
### TRACEABILITY-MASTER.yml
-Ubicación: `docs/04-modelado/trazabilidad/TRACEABILITY-MASTER.yml`
+Ubicacion: `docs/04-modelado/trazabilidad/TRACEABILITY-MASTER.yml`
Este archivo consolida:
-- Mapeo de nomenclatura v1 → v2
-- Lista de épicas con estados
+- Mapeo de nomenclatura v1 -> v2
+- Lista de epicas con estados
- Grafo de dependencias
- Health score del proyecto
@@ -142,7 +386,7 @@ Este archivo consolida:
| Tipo | Formato | Ejemplo |
|------|---------|---------|
-| Épica | `MCH-EP-NNN` | MCH-EP-001 |
+| Epica | `MCH-NNN` | MCH-001 |
| Requerimiento | `MCH-RF-NNN` | MCH-RF-001 |
| User Story | `MCH-US-NNN` | MCH-US-001 |
| Tarea | `MCH-TT-NNN` | MCH-TT-001 |
@@ -150,7 +394,20 @@ Este archivo consolida:
---
-## Flujo de Trabajo Sprint
+## 20. Perfiles de Agentes
+
+| Perfil | Especializacion | Frecuencia |
+|--------|-----------------|------------|
+| `PERFIL-DATABASE.md` | PostgreSQL, 11 schemas | Alta |
+| `PERFIL-BACKEND.md` | NestJS, TypeORM | Alta |
+| `PERFIL-FRONTEND.md` | React, Vite | Alta |
+| `PERFIL-MOBILE.md` | React Native, Expo | Alta |
+| `PERFIL-CODE-REVIEWER.md` | Revision de codigo | Media |
+| `PERFIL-DOC-MAINTAINER.md` | Mantenimiento docs | Media |
+
+---
+
+## 21. Flujo de Trabajo Sprint (SCRUM)
```yaml
# Sprint Planning
@@ -178,14 +435,95 @@ Este archivo consolida:
---
-## Referencias
+## 22. Flujo de Trabajo Desarrollo (CAPVED)
+
+```yaml
+# PASO 1: Cargar contexto (CCA)
+CARGAR:
+ - @TAREA
+ - @CAPVED
+ - @INICIALIZACION
+ - ./CONTEXTO-PROYECTO.md
+
+# PASO 2: Seleccionar operacion
+OPERACION:
+ - @OP_DDL # 11 schemas
+ - @OP_BACKEND # NestJS
+ - @OP_FRONTEND # React
+ - @OP_MOBILE # React Native
+
+# PASO 3: Aplicar patrones
+PATRONES:
+ - @PATRON-VALIDACION
+ - @PATRON-EXCEPTION-HANDLING
+ - @PATRON-SEGURIDAD
+
+# PASO 4: Validar
+VALIDAR:
+ - npm run build
+ - npm run lint
+ - npm run test
+
+# PASO 5: Documentar
+CIERRE:
+ - @DOCUMENTAR
+ - Actualizar inventarios
+ - Actualizar TRACEABILITY.yml
+```
+
+---
+
+## 23. Referencias
- Directivas SIMCO: `workspace-v2/orchestration/directivas/simco/`
+- Principios: `workspace-v2/orchestration/directivas/principios/`
- Templates SCRUM: `workspace-v2/orchestration/templates/scrum/`
- Checklists: `workspace-v2/orchestration/checklists/`
+- Perfiles: `workspace-v2/orchestration/agents/perfiles/`
- TRACEABILITY-MASTER: `docs/04-modelado/trazabilidad/TRACEABILITY-MASTER.yml`
---
-**Sistema:** SIMCO v4.0.0 + CAPVED + SCRUM
-**Última actualización:** 2026-01-10
+## 24. Roadmap SaaS (Fases 7-9)
+
+### Épicas SaaS Planificadas
+
+| ID | Épica | SP | Fase | Sprint |
+|----|-------|----|------|--------|
+| MCH-029 | Infraestructura SaaS | 24 | 7 | 6-7 |
+| MCH-030 | Auth Social (OAuth) | 8 | 7 | 8 |
+| MCH-031 | Auditoría Empresarial | 5 | 7 | 7 |
+| MCH-032 | Feature Flags | 5 | 7 | 8 |
+| MCH-033 | Onboarding Wizard | 3 | 8 | 9 |
+
+**Total SaaS:** 45 Story Points
+
+### Capacidades SaaS Agregadas
+
+| Capacidad | Integración | ADR | Prioridad |
+|-----------|-------------|-----|-----------|
+| Email Multi-provider | INT-010 | ADR-0011 | P0 |
+| Storage Abstracto | INT-011 | ADR-0006 | P0 |
+| Redis Cache/Queue | INT-013 | - | P0 |
+| Webhooks Outbound | INT-014 | ADR-0007 | P1 |
+| Rate Limiting | INT-013 | ADR-0009 | P1 |
+| OAuth Google/Apple | INT-012 | ADR-0010 | P1 |
+| Audit Logs | - | ADR-0008 | P1 |
+| Feature Flags | INT-013 | ADR-0005 | P1 |
+| Onboarding Wizard | - | - | P2 |
+
+### Documentación SaaS
+
+| Tipo | Cantidad | IDs |
+|------|----------|-----|
+| Épicas | 5 | MCH-029 a MCH-033 |
+| Integraciones | 5 | INT-010 a INT-014 |
+| ADRs | 8 | ADR-0004 a ADR-0011 |
+| **Total** | **18** | - |
+
+---
+
+**Sistema:** SIMCO v4.0.1 + CAPVED + SCRUM + CCA Protocol
+**Nivel:** STANDALONE (2A)
+**Versión HERENCIA:** 2.0.0
+**Ultima actualizacion:** 2026-01-10
diff --git a/orchestration/CONTEXT-MAP.yml b/orchestration/CONTEXT-MAP.yml
index 0adf2ef81..f01951fc2 100644
--- a/orchestration/CONTEXT-MAP.yml
+++ b/orchestration/CONTEXT-MAP.yml
@@ -10,8 +10,8 @@ metadata:
nivel: "STANDALONE"
version: "2.1.0"
ultima_actualizacion: "2026-01-10"
- workspace_root: "/home/isem/workspace-v1"
- project_root: "/home/isem/workspace-v1/projects/michangarrito"
+ workspace_root: "/home/isem/workspace-v2"
+ project_root: "/home/isem/workspace-v2/projects/michangarrito"
codigo: "MCH"
# ===============================================================================
@@ -27,37 +27,37 @@ variables:
# Base de datos
DB_NAME: "michangarrito"
- DB_DDL_PATH: "/home/isem/workspace-v1/projects/michangarrito/database/schemas"
- DB_SCRIPTS_PATH: "/home/isem/workspace-v1/projects/michangarrito/database"
- DB_SEEDS_PATH: "/home/isem/workspace-v1/projects/michangarrito/database/seeds"
+ DB_DDL_PATH: "/home/isem/workspace-v2/projects/michangarrito/database/schemas"
+ DB_SCRIPTS_PATH: "/home/isem/workspace-v2/projects/michangarrito/database"
+ DB_SEEDS_PATH: "/home/isem/workspace-v2/projects/michangarrito/database/seeds"
RECREATE_CMD: "drop-and-recreate-database.sh"
# Backend
- BACKEND_ROOT: "/home/isem/workspace-v1/projects/michangarrito/apps/backend"
- BACKEND_SRC: "/home/isem/workspace-v1/projects/michangarrito/apps/backend/src"
- BACKEND_TESTS: "/home/isem/workspace-v1/projects/michangarrito/apps/backend/tests"
+ BACKEND_ROOT: "/home/isem/workspace-v2/projects/michangarrito/apps/backend"
+ BACKEND_SRC: "/home/isem/workspace-v2/projects/michangarrito/apps/backend/src"
+ BACKEND_TESTS: "/home/isem/workspace-v2/projects/michangarrito/apps/backend/tests"
BACKEND_PORT: 3141
# Frontend Web
- FRONTEND_ROOT: "/home/isem/workspace-v1/projects/michangarrito/apps/web"
- FRONTEND_SRC: "/home/isem/workspace-v1/projects/michangarrito/apps/web/src"
+ FRONTEND_ROOT: "/home/isem/workspace-v2/projects/michangarrito/apps/web"
+ FRONTEND_SRC: "/home/isem/workspace-v2/projects/michangarrito/apps/web/src"
FRONTEND_PORT: 3140
# Mobile
- MOBILE_ROOT: "/home/isem/workspace-v1/projects/michangarrito/apps/mobile"
+ MOBILE_ROOT: "/home/isem/workspace-v2/projects/michangarrito/apps/mobile"
MOBILE_PORT: 8081
# MCP Server
- MCP_SERVER_ROOT: "/home/isem/workspace-v1/projects/michangarrito/apps/mcp-server"
+ MCP_SERVER_ROOT: "/home/isem/workspace-v2/projects/michangarrito/apps/mcp-server"
MCP_SERVER_PORT: 3142
# WhatsApp Service
- WHATSAPP_ROOT: "/home/isem/workspace-v1/projects/michangarrito/apps/whatsapp-service"
+ WHATSAPP_ROOT: "/home/isem/workspace-v2/projects/michangarrito/apps/whatsapp-service"
WHATSAPP_PORT: 3143
# Documentacion
- DOCS_PATH: "/home/isem/workspace-v1/projects/michangarrito/docs"
- ORCHESTRATION_PATH: "/home/isem/workspace-v1/projects/michangarrito/orchestration"
+ DOCS_PATH: "/home/isem/workspace-v2/projects/michangarrito/docs"
+ ORCHESTRATION_PATH: "/home/isem/workspace-v2/projects/michangarrito/orchestration"
# ===============================================================================
# ALIASES RESUELTOS
@@ -65,32 +65,32 @@ variables:
aliases:
# Directivas globales
- "@SIMCO": "/home/isem/workspace-v1/orchestration/directivas/simco"
- "@PRINCIPIOS": "/home/isem/workspace-v1/orchestration/directivas/principios"
- "@PERFILES": "/home/isem/workspace-v1/orchestration/agents/perfiles"
- "@CATALOG": "/home/isem/workspace-v1/shared/catalog"
+ "@SIMCO": "/home/isem/workspace-v2/orchestration/directivas/simco"
+ "@PRINCIPIOS": "/home/isem/workspace-v2/orchestration/directivas/principios"
+ "@PERFILES": "/home/isem/workspace-v2/orchestration/agents/perfiles"
+ "@CATALOG": "/home/isem/workspace-v2/shared/catalog"
# Proyecto especifico
- "@DDL": "/home/isem/workspace-v1/projects/michangarrito/database/schemas"
- "@SEEDS": "/home/isem/workspace-v1/projects/michangarrito/database/seeds"
- "@BACKEND": "/home/isem/workspace-v1/projects/michangarrito/apps/backend/src"
- "@WEB": "/home/isem/workspace-v1/projects/michangarrito/apps/web/src"
- "@MOBILE": "/home/isem/workspace-v1/projects/michangarrito/apps/mobile"
- "@MCP": "/home/isem/workspace-v1/projects/michangarrito/apps/mcp-server"
- "@WHATSAPP": "/home/isem/workspace-v1/projects/michangarrito/apps/whatsapp-service"
- "@DOCS": "/home/isem/workspace-v1/projects/michangarrito/docs"
+ "@DDL": "/home/isem/workspace-v2/projects/michangarrito/database/schemas"
+ "@SEEDS": "/home/isem/workspace-v2/projects/michangarrito/database/seeds"
+ "@BACKEND": "/home/isem/workspace-v2/projects/michangarrito/apps/backend/src"
+ "@WEB": "/home/isem/workspace-v2/projects/michangarrito/apps/web/src"
+ "@MOBILE": "/home/isem/workspace-v2/projects/michangarrito/apps/mobile"
+ "@MCP": "/home/isem/workspace-v2/projects/michangarrito/apps/mcp-server"
+ "@WHATSAPP": "/home/isem/workspace-v2/projects/michangarrito/apps/whatsapp-service"
+ "@DOCS": "/home/isem/workspace-v2/projects/michangarrito/docs"
# Inventarios
- "@INVENTORY": "/home/isem/workspace-v1/projects/michangarrito/orchestration/inventarios"
- "@INV_MASTER": "/home/isem/workspace-v1/projects/michangarrito/orchestration/inventarios/MASTER_INVENTORY.yml"
- "@INV_DB": "/home/isem/workspace-v1/projects/michangarrito/orchestration/inventarios/DATABASE_INVENTORY.yml"
- "@INV_BE": "/home/isem/workspace-v1/projects/michangarrito/orchestration/inventarios/BACKEND_INVENTORY.yml"
- "@INV_FE": "/home/isem/workspace-v1/projects/michangarrito/orchestration/inventarios/FRONTEND_INVENTORY.yml"
+ "@INVENTORY": "/home/isem/workspace-v2/projects/michangarrito/orchestration/inventarios"
+ "@INV_MASTER": "/home/isem/workspace-v2/projects/michangarrito/orchestration/inventarios/MASTER_INVENTORY.yml"
+ "@INV_DB": "/home/isem/workspace-v2/projects/michangarrito/orchestration/inventarios/DATABASE_INVENTORY.yml"
+ "@INV_BE": "/home/isem/workspace-v2/projects/michangarrito/orchestration/inventarios/BACKEND_INVENTORY.yml"
+ "@INV_FE": "/home/isem/workspace-v2/projects/michangarrito/orchestration/inventarios/FRONTEND_INVENTORY.yml"
# Trazas
- "@TRAZA_DB": "/home/isem/workspace-v1/projects/michangarrito/orchestration/trazas/TRAZA-TAREAS-DATABASE.md"
- "@TRAZA_BE": "/home/isem/workspace-v1/projects/michangarrito/orchestration/trazas/TRAZA-TAREAS-BACKEND.md"
- "@TRAZA_FE": "/home/isem/workspace-v1/projects/michangarrito/orchestration/trazas/TRAZA-TAREAS-FRONTEND.md"
+ "@TRAZA_DB": "/home/isem/workspace-v2/projects/michangarrito/orchestration/trazas/TRAZA-TAREAS-DATABASE.md"
+ "@TRAZA_BE": "/home/isem/workspace-v2/projects/michangarrito/orchestration/trazas/TRAZA-TAREAS-BACKEND.md"
+ "@TRAZA_FE": "/home/isem/workspace-v2/projects/michangarrito/orchestration/trazas/TRAZA-TAREAS-FRONTEND.md"
# ===============================================================================
# CONTEXTO POR NIVEL
@@ -102,25 +102,25 @@ contexto_por_nivel:
tokens_estimados: 4500
obligatorio: true
archivos:
- - path: "/home/isem/workspace-v1/orchestration/directivas/principios/PRINCIPIO-CAPVED.md"
+ - path: "/home/isem/workspace-v2/orchestration/directivas/principios/PRINCIPIO-CAPVED.md"
proposito: "Ciclo de vida de tareas"
tokens: 800
- - path: "/home/isem/workspace-v1/orchestration/directivas/principios/PRINCIPIO-DOC-PRIMERO.md"
+ - path: "/home/isem/workspace-v2/orchestration/directivas/principios/PRINCIPIO-DOC-PRIMERO.md"
proposito: "Documentacion antes de codigo"
tokens: 500
- - path: "/home/isem/workspace-v1/orchestration/directivas/principios/PRINCIPIO-ANTI-DUPLICACION.md"
+ - path: "/home/isem/workspace-v2/orchestration/directivas/principios/PRINCIPIO-ANTI-DUPLICACION.md"
proposito: "Verificar catalogo antes de crear"
tokens: 600
- - path: "/home/isem/workspace-v1/orchestration/directivas/principios/PRINCIPIO-VALIDACION-OBLIGATORIA.md"
+ - path: "/home/isem/workspace-v2/orchestration/directivas/principios/PRINCIPIO-VALIDACION-OBLIGATORIA.md"
proposito: "Build/lint deben pasar"
tokens: 600
- - path: "/home/isem/workspace-v1/orchestration/directivas/principios/PRINCIPIO-ECONOMIA-TOKENS.md"
+ - path: "/home/isem/workspace-v2/orchestration/directivas/principios/PRINCIPIO-ECONOMIA-TOKENS.md"
proposito: "Limites de contexto"
tokens: 500
- - path: "/home/isem/workspace-v1/orchestration/directivas/principios/PRINCIPIO-NO-ASUMIR.md"
+ - path: "/home/isem/workspace-v2/orchestration/directivas/principios/PRINCIPIO-NO-ASUMIR.md"
proposito: "Preguntar si falta informacion"
tokens: 500
- - path: "/home/isem/workspace-v1/orchestration/referencias/ALIASES.yml"
+ - path: "/home/isem/workspace-v2/orchestration/referencias/ALIASES.yml"
proposito: "Resolucion de @ALIAS"
tokens: 400
@@ -129,16 +129,16 @@ contexto_por_nivel:
tokens_estimados: 3500
obligatorio: true
archivos:
- - path: "/home/isem/workspace-v1/projects/michangarrito/orchestration/00-guidelines/CONTEXTO-PROYECTO.md"
+ - path: "/home/isem/workspace-v2/projects/michangarrito/orchestration/00-guidelines/CONTEXTO-PROYECTO.md"
proposito: "Variables y configuracion del proyecto"
tokens: 1500
- - path: "/home/isem/workspace-v1/projects/michangarrito/orchestration/PROXIMA-ACCION.md"
+ - path: "/home/isem/workspace-v2/projects/michangarrito/orchestration/PROXIMA-ACCION.md"
proposito: "Estado actual y siguiente paso"
tokens: 500
- - path: "/home/isem/workspace-v1/projects/michangarrito/orchestration/PROJECT-STATUS.md"
+ - path: "/home/isem/workspace-v2/projects/michangarrito/orchestration/PROJECT-STATUS.md"
proposito: "Estado detallado del proyecto"
tokens: 1000
- - path: "/home/isem/workspace-v1/projects/michangarrito/orchestration/PLAN-IMPLEMENTACION.md"
+ - path: "/home/isem/workspace-v2/projects/michangarrito/orchestration/PLAN-IMPLEMENTACION.md"
proposito: "Plan de fases del proyecto"
tokens: 500
@@ -147,27 +147,27 @@ contexto_por_nivel:
tokens_estimados: 2500
archivos_por_operacion:
CREAR:
- - "/home/isem/workspace-v1/orchestration/directivas/simco/SIMCO-CREAR.md"
+ - "/home/isem/workspace-v2/orchestration/directivas/simco/SIMCO-CREAR.md"
MODIFICAR:
- - "/home/isem/workspace-v1/orchestration/directivas/simco/SIMCO-MODIFICAR.md"
+ - "/home/isem/workspace-v2/orchestration/directivas/simco/SIMCO-MODIFICAR.md"
VALIDAR:
- - "/home/isem/workspace-v1/orchestration/directivas/simco/SIMCO-VALIDAR.md"
+ - "/home/isem/workspace-v2/orchestration/directivas/simco/SIMCO-VALIDAR.md"
DELEGAR:
- - "/home/isem/workspace-v1/orchestration/directivas/simco/SIMCO-DELEGACION.md"
+ - "/home/isem/workspace-v2/orchestration/directivas/simco/SIMCO-DELEGACION.md"
archivos_por_dominio:
DDL:
- - "/home/isem/workspace-v1/orchestration/directivas/simco/SIMCO-DDL.md"
- - "/home/isem/workspace-v1/projects/michangarrito/orchestration/inventarios/DATABASE_INVENTORY.yml"
+ - "/home/isem/workspace-v2/orchestration/directivas/simco/SIMCO-DDL.md"
+ - "/home/isem/workspace-v2/projects/michangarrito/orchestration/inventarios/DATABASE_INVENTORY.yml"
BACKEND:
- - "/home/isem/workspace-v1/orchestration/directivas/simco/SIMCO-BACKEND.md"
- - "/home/isem/workspace-v1/projects/michangarrito/orchestration/inventarios/BACKEND_INVENTORY.yml"
+ - "/home/isem/workspace-v2/orchestration/directivas/simco/SIMCO-BACKEND.md"
+ - "/home/isem/workspace-v2/projects/michangarrito/orchestration/inventarios/BACKEND_INVENTORY.yml"
FRONTEND:
- - "/home/isem/workspace-v1/orchestration/directivas/simco/SIMCO-FRONTEND.md"
- - "/home/isem/workspace-v1/projects/michangarrito/orchestration/inventarios/FRONTEND_INVENTORY.yml"
+ - "/home/isem/workspace-v2/orchestration/directivas/simco/SIMCO-FRONTEND.md"
+ - "/home/isem/workspace-v2/projects/michangarrito/orchestration/inventarios/FRONTEND_INVENTORY.yml"
MOBILE:
- - "/home/isem/workspace-v1/orchestration/directivas/simco/SIMCO-MOBILE.md"
+ - "/home/isem/workspace-v2/orchestration/directivas/simco/SIMCO-MOBILE.md"
MCP:
- - "/home/isem/workspace-v1/orchestration/directivas/simco/SIMCO-MCP.md"
+ - "/home/isem/workspace-v2/orchestration/directivas/simco/SIMCO-MCP.md"
L3_tarea:
descripcion: "Contexto especifico de la tarea"
@@ -382,7 +382,7 @@ validacion_tokens:
herencia:
tipo: "STANDALONE"
hereda_de:
- - "/home/isem/workspace-v1/orchestration/"
+ - "/home/isem/workspace-v2/orchestration/"
usa_catalog:
- payments (Stripe, Mercado Pago)
- notifications (WhatsApp, Push)
@@ -446,8 +446,8 @@ integraciones:
busqueda_historico:
habilitado: true
ubicaciones:
- - "/home/isem/workspace-v1/projects/michangarrito/orchestration/trazas/"
- - "/home/isem/workspace-v1/projects/michangarrito/orchestration/analisis/"
- - "/home/isem/workspace-v1/projects/michangarrito/orchestration/reportes/"
- - "/home/isem/workspace-v1/orchestration/errores/REGISTRO-ERRORES.yml"
- - "/home/isem/workspace-v1/shared/knowledge-base/lessons-learned/"
+ - "/home/isem/workspace-v2/projects/michangarrito/orchestration/trazas/"
+ - "/home/isem/workspace-v2/projects/michangarrito/orchestration/analisis/"
+ - "/home/isem/workspace-v2/projects/michangarrito/orchestration/reportes/"
+ - "/home/isem/workspace-v2/orchestration/errores/REGISTRO-ERRORES.yml"
+ - "/home/isem/workspace-v2/shared/knowledge-base/lessons-learned/"
diff --git a/orchestration/inventarios/MASTER_INVENTORY.yml b/orchestration/inventarios/MASTER_INVENTORY.yml
index 0704289bd..1f47ac69f 100644
--- a/orchestration/inventarios/MASTER_INVENTORY.yml
+++ b/orchestration/inventarios/MASTER_INVENTORY.yml
@@ -1,8 +1,8 @@
# MASTER INVENTORY - MiChangarrito
-# Version: 2.2.0
+# Version: 4.0.0
# Ultima actualizacion: 2026-01-10
-# Sistema: SIMCO v3.8.0 + CAPVED
-# Actualizado: Sincronizacion con desarrollo - inventarios completos
+# Sistema: SIMCO v4.0.1 + CAPVED + SCRUM
+# Actualizado: Integracion capacidades SaaS de template-saas
metadata:
proyecto: "michangarrito"
@@ -290,12 +290,50 @@ modulos:
nombre: "Marketplace Proveedores"
estado: "pendiente"
+ - id: "MCH-029"
+ nombre: "Infraestructura SaaS Avanzada"
+ estado: "planificado"
+ story_points: 24
+ sprint: "6-7"
+ descripcion: "Email, Storage, Redis, Webhooks, Rate Limiting"
+ integraciones: ["INT-010", "INT-011", "INT-013", "INT-014"]
+
+ - id: "MCH-030"
+ nombre: "Auth Social OAuth 2.0"
+ estado: "planificado"
+ story_points: 8
+ sprint: "8"
+ descripcion: "Login con Google y Apple"
+ integraciones: ["INT-012"]
+
+ - id: "MCH-031"
+ nombre: "Auditoria Empresarial"
+ estado: "planificado"
+ story_points: 5
+ sprint: "7"
+ descripcion: "Audit logs, retencion, compliance"
+
+ - id: "MCH-032"
+ nombre: "Feature Flags por Plan"
+ estado: "planificado"
+ story_points: 5
+ sprint: "8"
+ descripcion: "Toggles por plan/tenant"
+
+ fase_8:
+ - id: "MCH-033"
+ nombre: "Onboarding Wizard"
+ estado: "planificado"
+ story_points: 3
+ sprint: "9"
+ descripcion: "Guia interactiva de setup"
+
# ============================================================================
-# INTEGRACIONES EXTERNAS
+# INFRAESTRUCTURA BASE
# ============================================================================
-integraciones:
- - nombre: "PostgreSQL 15"
+infraestructura:
+ - nombre: "PostgreSQL 16"
estado: "activo"
puerto: 5432
@@ -304,23 +342,135 @@ integraciones:
puerto: 6379
db: 8
- - nombre: "WhatsApp Business (Meta)"
- estado: "listo"
+# ============================================================================
+# INTEGRACIONES EXTERNAS (SIMCO v4.0.0)
+# ============================================================================
+
+integraciones:
+ - id: "INT-001"
+ nombre: "WhatsApp Meta Business"
+ categoria: "Mensajeria"
+ estado: "activo"
+ multi_tenant: true
+ modulo_relacionado: "MCH-011"
+ spec: "docs/02-integraciones/INT-001-whatsapp-meta.md"
notas: "Requiere cuenta Business verificada"
- - nombre: "Stripe"
- estado: "integrado"
+ - id: "INT-002"
+ nombre: "Stripe"
+ categoria: "Pagos"
+ estado: "activo"
+ multi_tenant: false
+ modulo_relacionado: "MCH-020"
+ spec: "docs/02-integraciones/INT-002-stripe.md"
notas: "SDK configurado, requiere API keys produccion"
- - nombre: "OpenRouter/OpenAI"
- estado: "multi-tenant"
+ - id: "INT-003"
+ nombre: "OpenRouter LLM"
+ categoria: "AI/LLM"
+ estado: "activo"
+ multi_tenant: true
+ modulo_relacionado: "MCH-012"
+ spec: "docs/02-integraciones/INT-003-openrouter.md"
notas: "Soporte credenciales por tenant + fallback plataforma"
- - nombre: "MercadoPago"
+ - id: "INT-004"
+ nombre: "MercadoPago"
+ categoria: "Pagos"
estado: "pendiente"
+ multi_tenant: true
+ modulo_relacionado: "MCH-005"
+ spec: "docs/02-integraciones/INT-004-mercadopago.md"
- - nombre: "Clip"
+ - id: "INT-005"
+ nombre: "Clip Mexico"
+ categoria: "Pagos"
+ estado: "mock"
+ multi_tenant: true
+ modulo_relacionado: "MCH-005"
+ spec: "docs/02-integraciones/INT-005-clip.md"
+
+ - id: "INT-006"
+ nombre: "CoDi/SPEI Banxico"
+ categoria: "Pagos"
+ estado: "mock"
+ multi_tenant: true
+ modulo_relacionado: "MCH-024"
+ spec: "docs/02-integraciones/INT-006-codi-banxico.md"
+
+ - id: "INT-007"
+ nombre: "Firebase FCM"
+ categoria: "Notificaciones"
estado: "pendiente"
+ multi_tenant: true
+ modulo_relacionado: "MCH-017"
+ spec: "docs/02-integraciones/INT-007-firebase-fcm.md"
+
+ - id: "INT-008"
+ nombre: "Google Cloud Vision"
+ categoria: "AI/ML"
+ estado: "pendiente"
+ multi_tenant: true
+ modulo_relacionado: "MCH-009"
+ spec: "docs/02-integraciones/INT-008-google-vision.md"
+
+ - id: "INT-009"
+ nombre: "OpenAI Whisper"
+ categoria: "AI/ML"
+ estado: "pendiente"
+ multi_tenant: true
+ modulo_relacionado: "MCH-011"
+ spec: "docs/02-integraciones/INT-009-whisper.md"
+
+ # === NUEVAS INTEGRACIONES SAAS (v4.0.0) ===
+
+ - id: "INT-010"
+ nombre: "Email Multi-Provider"
+ categoria: "Notificaciones"
+ estado: "planificado"
+ multi_tenant: true
+ modulo_relacionado: "MCH-029"
+ spec: "docs/02-integraciones/INT-010-email-providers.md"
+ proveedores: ["SendGrid", "AWS SES", "SMTP"]
+ notas: "Fallback automatico entre proveedores"
+
+ - id: "INT-011"
+ nombre: "Storage Cloud"
+ categoria: "Almacenamiento"
+ estado: "planificado"
+ multi_tenant: true
+ modulo_relacionado: "MCH-029"
+ spec: "docs/02-integraciones/INT-011-storage-cloud.md"
+ proveedores: ["AWS S3", "Cloudflare R2", "MinIO"]
+ notas: "URLs firmadas, limites por plan"
+
+ - id: "INT-012"
+ nombre: "OAuth Social"
+ categoria: "Autenticacion"
+ estado: "planificado"
+ multi_tenant: true
+ modulo_relacionado: "MCH-030"
+ spec: "docs/02-integraciones/INT-012-oauth-social.md"
+ proveedores: ["Google", "Apple"]
+ notas: "Passport.js strategies"
+
+ - id: "INT-013"
+ nombre: "Redis Cache"
+ categoria: "Infraestructura"
+ estado: "planificado"
+ multi_tenant: true
+ modulo_relacionado: "MCH-029"
+ spec: "docs/02-integraciones/INT-013-redis-cache.md"
+ notas: "Cache, queues (BullMQ), rate limiting"
+
+ - id: "INT-014"
+ nombre: "Webhooks Outbound"
+ categoria: "Eventos"
+ estado: "planificado"
+ multi_tenant: true
+ modulo_relacionado: "MCH-029"
+ spec: "docs/02-integraciones/INT-014-webhooks-outbound.md"
+ notas: "Firma HMAC, reintentos exponenciales"
# ============================================================================
# DOCUMENTACION
@@ -376,3 +526,45 @@ notas:
- "Integraciones WhatsApp y LLM soportan credenciales por tenant"
- "75 productos predefinidos para onboarding rapido"
- "Sistema de tokens IA con planes y recargas"
+
+# ============================================================================
+# TRAZABILIDAD (SIMCO v4.0.0)
+# ============================================================================
+
+trazabilidad:
+ archivo: "docs/04-modelado/trazabilidad/TRACEABILITY-MASTER.yml"
+ tipo: "YAML"
+ ultima_actualizacion: "2026-01-10"
+ modulos_trazados: 33
+ integraciones_trazadas: 14
+ cobertura_trazabilidad: 100
+ metricas:
+ modulos_completados: 22
+ modulos_pendientes: 6
+ modulos_planificados: 5
+ integraciones_activas: 3
+ integraciones_mock: 2
+ integraciones_pendientes: 4
+ integraciones_planificadas: 5
+ saas_integration:
+ fecha: "2026-01-10"
+ epicas_nuevas: ["MCH-029", "MCH-030", "MCH-031", "MCH-032", "MCH-033"]
+ integraciones_nuevas: ["INT-010", "INT-011", "INT-012", "INT-013", "INT-014"]
+ adrs_nuevos: 8
+ story_points_total: 45
+
+# ============================================================================
+# METADATA MIGRACION
+# ============================================================================
+
+migracion:
+ version_anterior: "SIMCO v3.8.0"
+ version_actual: "SIMCO v4.0.0"
+ fecha_migracion: "2026-01-10"
+ cambios_aplicados:
+ - "Reestructuracion integraciones con IDs INT-*"
+ - "Separacion infraestructura de integraciones"
+ - "Agregada seccion trazabilidad"
+ - "Agregados modulos relacionados a integraciones"
+ - "Agregadas referencias a specs de integracion"
+ actualizado_por: "Claude Code (Migracion SIMCO v4.0.0)"