erp-core/docs/04-modelado/VALIDACION-DEPENDENCIAS-MGN-015-018.md

560 lines
19 KiB
Markdown

# Validación de Dependencias: MGN-015, MGN-016, MGN-017, MGN-018
**Fecha:** 2025-12-05
**Estado:** REQUIERE ADAPTACIONES
**Revisión:** v1.0
## Resumen Ejecutivo
Se realizó un análisis exhaustivo de las dependencias entre los módulos nuevos/modificados (MGN-015 a MGN-018) y los módulos existentes (MGN-001 a MGN-014). Se identificaron **dependencias faltantes críticas**, **impactos no contemplados**, y **adaptaciones necesarias**.
### Veredicto General
| Módulo | Estado | Dependencias Faltantes | Impactos No Contemplados |
|--------|--------|------------------------|--------------------------|
| MGN-015 | ⚠️ Requiere ajustes | MGN-014, MGN-004 | 3 críticos |
| MGN-016 | ⚠️ Requiere ajustes | MGN-014 | 4 altos |
| MGN-017 | ⚠️ Requiere ajustes | MGN-014 | 3 altos |
| MGN-018 | ⚠️ Requiere ajustes | MGN-014 | 4 altos |
---
## 1. Dependencias Faltantes Críticas
### 1.1 Todos los módulos → MGN-014 (Mensajería y Notificaciones)
**Problema:** Ninguno de los módulos nuevos declara dependencia con MGN-014, pero TODOS requieren:
- Auditoría de cambios (Tracking automático)
- Notificaciones de eventos
- Sistema de mensajes internos
**Módulos Afectados:**
```
MGN-015 (Billing) → Notificar cambios de suscripción, facturas
MGN-016 (Pagos) → Confirmar pagos, alertar fallas
MGN-017 (WhatsApp) → Logging de mensajes, escalaciones
MGN-018 (AI Agents) → Historial de conversaciones, feedback
```
**Acción Requerida:** Agregar `MGN-014` como dependencia en todos los READMEs.
---
### 1.2 MGN-015 → MGN-004 (Financiero)
**Problema:** MGN-015 genera facturas de suscripción pero no tiene integración para generar asientos contables.
**Impacto:**
- Ingresos por suscripción no se registran en contabilidad
- No hay conciliación entre facturación SaaS y libro mayor
- Imposible cerrar mes contable correctamente
**Acción Requerida:**
```sql
-- Agregar a MGN-015 esquema de integración con MGN-004
CREATE TABLE billing.accounting_mappings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
event_type VARCHAR(50) NOT NULL, -- subscription_payment, refund, credit
debit_account_id UUID REFERENCES financial.accounts(id),
credit_account_id UUID REFERENCES financial.accounts(id),
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
```
---
### 1.3 MGN-016 → MGN-004 (Financiero)
**Problema:** Los pagos procesados por MercadoPago/Clip deben generar asientos contables automáticos.
**Impacto:**
- Pagos recibidos no se reflejan en contabilidad
- Comisiones de procesadores no se registran
- Conciliación bancaria imposible
**Acción Requerida:** Crear webhook interno que dispare asientos:
```typescript
// Al confirmar pago en MGN-016
async function onPaymentConfirmed(payment: PaymentTransaction) {
await createAccountingEntry({
journal: 'bank',
entries: [
{ account: 'bank_account', debit: payment.net_amount },
{ account: 'payment_fees', debit: payment.fee_amount },
{ account: 'accounts_receivable', credit: payment.amount }
],
reference: payment.id,
date: payment.approved_at
});
}
```
---
## 2. Interdependencia Circular: MGN-017 ↔ MGN-018
### Problema Identificado
```
MGN-017 (WhatsApp)
└─ RF-005 (Chatbot) necesita MGN-018 (AI Agents)
MGN-018 (AI Agents)
└─ Necesita MGN-017 como canal de comunicación
```
### Riesgo
- Ciclo de dependencia que complica el orden de implementación
- ¿Quién se implementa primero?
### Solución: Arquitectura en Capas
```
┌─────────────────────────────────────────────────────────────┐
│ CAPA DE APLICACIÓN │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ MGN-017-005 (Chatbot) = Orquestador de flujos ││
│ │ - Usa MGN-017 para enviar/recibir mensajes ││
│ │ - Usa MGN-018 para respuestas inteligentes ││
│ └─────────────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────────────┤
│ CAPA DE SERVICIOS │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ │ MGN-017 (WhatsApp) │ │ MGN-018 (AI Core) │ │
│ │ - Conexión API │ │ - LLM Processing │ │
│ │ - Mensajería │ │ - Knowledge Base │ │
│ │ - Templates │ │ - Tools │ │
│ └────────────────────┘ └────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
**Orden de Implementación:**
1. MGN-017 RF-001 a RF-004 (infraestructura WhatsApp) - NO requiere MGN-018
2. MGN-018 RF-001 a RF-006 (infraestructura AI) - NO requiere MGN-017
3. MGN-017 RF-005 (Chatbot) - Integra ambos módulos
---
## 3. Impactos en Módulos Existentes
### 3.1 Impacto en MGN-001 (Autenticación/Multi-Tenant)
**Cambios Requeridos:**
| Entidad | Cambio | Razón |
|---------|--------|-------|
| `core_tenants.tenants` | Agregar `subscription_status` | Bloquear acceso si suscripción vencida |
| `core_rbac.roles` | Nuevos roles | `billing_admin`, `ai_admin`, `messaging_admin` |
| `core_rbac.permissions` | Nuevos permisos | `billing:*`, `ai:*`, `whatsapp:*`, `payments:*` |
**SQL Requerido:**
```sql
-- Agregar campo de estado de suscripción para control de acceso
ALTER TABLE core_tenants.tenants
ADD COLUMN IF NOT EXISTS subscription_status VARCHAR(20) DEFAULT 'trial';
-- Nuevos roles
INSERT INTO core_rbac.roles (code, name, description, is_system) VALUES
('billing_admin', 'Administrador de Facturación', 'Gestiona planes y suscripciones', true),
('ai_admin', 'Administrador de IA', 'Configura agentes y knowledge bases', true),
('messaging_admin', 'Administrador de Mensajería', 'Gestiona WhatsApp y chatbots', true),
('payments_admin', 'Administrador de Pagos', 'Configura terminales y procesa pagos', true)
ON CONFLICT (code) DO NOTHING;
```
---
### 3.2 Impacto en MGN-003 (Catálogos)
**Cambios Requeridos:**
| Entidad | Cambio | Razón |
|---------|--------|-------|
| `catalogs.contacts` | Agregar `whatsapp_number` | MGN-017 necesita identificar contactos |
| `catalogs.contacts` | Agregar `whatsapp_opt_in` | Cumplimiento legal para marketing |
| `catalogs.payment_methods` | Agregar tipos | `mercadopago`, `clip`, `stripe_terminal` |
**SQL Requerido:**
```sql
-- Campos para WhatsApp en contactos
ALTER TABLE catalogs.contacts
ADD COLUMN IF NOT EXISTS whatsapp_number VARCHAR(20),
ADD COLUMN IF NOT EXISTS whatsapp_opt_in BOOLEAN DEFAULT false,
ADD COLUMN IF NOT EXISTS whatsapp_opt_in_date TIMESTAMPTZ;
CREATE INDEX IF NOT EXISTS idx_contacts_whatsapp
ON catalogs.contacts(whatsapp_number) WHERE whatsapp_number IS NOT NULL;
-- Validación de formato
ALTER TABLE catalogs.contacts
ADD CONSTRAINT chk_whatsapp_format
CHECK (whatsapp_number IS NULL OR whatsapp_number ~ '^\+[1-9][0-9]{6,14}$');
```
---
### 3.3 Impacto en MGN-007 (Ventas)
**Cambios Requeridos:**
| Entidad | Cambio | Razón |
|---------|--------|-------|
| `sales.orders` | Agregar `payment_status` | Rastrear estado de pago de MGN-016 |
| `sales.orders` | Agregar `payment_transaction_id` | Referencia a transacción |
| Workflow | Nuevo estado | `awaiting_payment` antes de `confirmed` |
**SQL Requerido:**
```sql
-- Campos para integración con MGN-016
ALTER TABLE sales.orders
ADD COLUMN IF NOT EXISTS payment_status VARCHAR(20) DEFAULT 'pending',
ADD COLUMN IF NOT EXISTS payment_transaction_id UUID,
ADD COLUMN IF NOT EXISTS paid_at TIMESTAMPTZ;
-- Actualizar constraint de estados
ALTER TABLE sales.orders DROP CONSTRAINT IF EXISTS chk_order_status;
ALTER TABLE sales.orders ADD CONSTRAINT chk_order_status
CHECK (status IN ('draft', 'sent', 'awaiting_payment', 'confirmed', 'done', 'cancelled'));
```
---
### 3.4 Impacto en MGN-009 (CRM)
**Cambios Requeridos:**
| Entidad | Cambio | Razón |
|---------|--------|-------|
| `crm.leads` | Agregar `whatsapp_conversation_id` | Vincular con MGN-017 |
| `crm.leads` | Agregar `source_channel` | Identificar origen (whatsapp, web, etc.) |
| `crm.leads` | Agregar `ai_score` | Lead scoring de MGN-018 |
**SQL Requerido:**
```sql
-- Campos para integración con WhatsApp y AI
ALTER TABLE crm.leads
ADD COLUMN IF NOT EXISTS whatsapp_conversation_id UUID,
ADD COLUMN IF NOT EXISTS source_channel VARCHAR(50) DEFAULT 'manual',
ADD COLUMN IF NOT EXISTS ai_score DECIMAL(5,2),
ADD COLUMN IF NOT EXISTS ai_score_updated_at TIMESTAMPTZ;
-- Índice para búsqueda por conversación
CREATE INDEX IF NOT EXISTS idx_leads_whatsapp_conv
ON crm.leads(whatsapp_conversation_id) WHERE whatsapp_conversation_id IS NOT NULL;
```
---
## 4. Feature Flags Centralizados
### Problema
Cada módulo nuevo define sus propios feature flags en `subscription_plans.features`, pero no hay una forma centralizada de consultarlos.
### Solución: Función Auxiliar
```sql
-- Crear en schema billing
CREATE OR REPLACE FUNCTION billing.has_feature(
p_tenant_id UUID,
p_feature_name VARCHAR
) RETURNS BOOLEAN AS $$
DECLARE
v_features JSONB;
BEGIN
SELECT sp.features INTO v_features
FROM billing.subscriptions bs
JOIN billing.subscription_plans sp ON bs.plan_id = sp.id
WHERE bs.tenant_id = p_tenant_id
AND bs.status = 'active'
ORDER BY bs.created_at DESC
LIMIT 1;
IF v_features IS NULL THEN
RETURN false;
END IF;
RETURN COALESCE((v_features->>p_feature_name)::boolean, false);
END;
$$ LANGUAGE plpgsql STABLE;
-- Función para obtener límite numérico
CREATE OR REPLACE FUNCTION billing.get_feature_limit(
p_tenant_id UUID,
p_feature_name VARCHAR
) RETURNS INTEGER AS $$
DECLARE
v_features JSONB;
BEGIN
SELECT sp.features INTO v_features
FROM billing.subscriptions bs
JOIN billing.subscription_plans sp ON bs.plan_id = sp.id
WHERE bs.tenant_id = p_tenant_id
AND bs.status = 'active'
ORDER BY bs.created_at DESC
LIMIT 1;
IF v_features IS NULL THEN
RETURN 0;
END IF;
RETURN COALESCE((v_features->>p_feature_name)::integer, 0);
END;
$$ LANGUAGE plpgsql STABLE;
```
### Uso en Módulos
```typescript
// En cualquier módulo que necesite verificar feature
async function checkFeatureEnabled(tenantId: string, feature: string): Promise<boolean> {
const result = await db.query(
'SELECT billing.has_feature($1, $2) as enabled',
[tenantId, feature]
);
return result.rows[0].enabled;
}
// Ejemplo en MGN-018
const canUseAI = await checkFeatureEnabled(tenantId, 'ai_agents_enabled');
const tokenLimit = await db.query(
'SELECT billing.get_feature_limit($1, $2) as limit',
[tenantId, 'ai_monthly_token_limit']
);
```
---
## 5. Matriz de Features por Plan
### Features que deben definirse en planes
```json
{
"starter": {
"max_users": 5,
"max_companies": 1,
"mercadopago_enabled": false,
"clip_enabled": false,
"stripe_enabled": false,
"whatsapp_enabled": false,
"whatsapp_chatbot": false,
"whatsapp_marketing": false,
"whatsapp_max_accounts": 0,
"ai_agents_enabled": false,
"ai_max_agents": 0,
"ai_kb_max_documents": 0,
"ai_monthly_token_limit": 0
},
"professional": {
"max_users": 25,
"max_companies": 3,
"mercadopago_enabled": true,
"clip_enabled": true,
"stripe_enabled": false,
"whatsapp_enabled": true,
"whatsapp_chatbot": true,
"whatsapp_marketing": false,
"whatsapp_max_accounts": 1,
"ai_agents_enabled": true,
"ai_max_agents": 3,
"ai_kb_max_documents": 100,
"ai_monthly_token_limit": 500000
},
"enterprise": {
"max_users": -1,
"max_companies": -1,
"mercadopago_enabled": true,
"clip_enabled": true,
"stripe_enabled": true,
"whatsapp_enabled": true,
"whatsapp_chatbot": true,
"whatsapp_marketing": true,
"whatsapp_max_accounts": 10,
"ai_agents_enabled": true,
"ai_max_agents": -1,
"ai_kb_max_documents": 500,
"ai_monthly_token_limit": 5000000,
"ai_custom_tools": true
}
}
```
---
## 6. Webhooks de Integración Requeridos
### Eventos que deben propagarse entre módulos
```typescript
// Eventos de MGN-015 (Billing)
type BillingEvents = {
'subscription.created': { tenant_id: string; plan_id: string; };
'subscription.upgraded': { tenant_id: string; old_plan: string; new_plan: string; };
'subscription.downgraded': { tenant_id: string; old_plan: string; new_plan: string; };
'subscription.canceled': { tenant_id: string; reason: string; };
'subscription.payment_failed': { tenant_id: string; invoice_id: string; };
'invoice.paid': { tenant_id: string; invoice_id: string; amount: number; };
};
// Eventos de MGN-016 (Pagos)
type PaymentEvents = {
'payment.approved': { tenant_id: string; order_id: string; amount: number; };
'payment.declined': { tenant_id: string; order_id: string; reason: string; };
'payment.refunded': { tenant_id: string; transaction_id: string; amount: number; };
'terminal.connected': { tenant_id: string; terminal_id: string; };
'terminal.disconnected': { tenant_id: string; terminal_id: string; };
};
// Eventos de MGN-017 (WhatsApp)
type WhatsAppEvents = {
'message.received': { tenant_id: string; conversation_id: string; from: string; };
'message.sent': { tenant_id: string; conversation_id: string; to: string; };
'conversation.escalated': { tenant_id: string; conversation_id: string; reason: string; };
'quality.warning': { tenant_id: string; account_id: string; rating: string; };
};
// Eventos de MGN-018 (AI Agents)
type AIAgentEvents = {
'conversation.started': { tenant_id: string; agent_id: string; channel: string; };
'conversation.completed': { tenant_id: string; conversation_id: string; resolved: boolean; };
'tokens.threshold_reached': { tenant_id: string; usage_percent: number; };
'tokens.limit_exceeded': { tenant_id: string; };
'feedback.received': { tenant_id: string; conversation_id: string; rating: number; };
};
```
### Sistema de Eventos Centralizado
```sql
-- Tabla de eventos del sistema (para debugging y auditoría)
CREATE TABLE IF NOT EXISTS system.event_log (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID,
event_type VARCHAR(100) NOT NULL,
source_module VARCHAR(20) NOT NULL,
payload JSONB NOT NULL,
processed BOOLEAN DEFAULT false,
processed_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_events_tenant ON system.event_log(tenant_id);
CREATE INDEX idx_events_type ON system.event_log(event_type);
CREATE INDEX idx_events_unprocessed ON system.event_log(processed) WHERE processed = false;
```
---
## 7. Plan de Implementación de Adaptaciones
### Fase 1: Preparación de Infraestructura (Semana 1)
| Tarea | Prioridad | Esfuerzo |
|-------|-----------|----------|
| Crear funciones `has_feature()` y `get_feature_limit()` | CRÍTICA | 2h |
| Crear tabla `system.event_log` | CRÍTICA | 1h |
| Actualizar roles en MGN-001 | ALTA | 4h |
| Agregar campos en MGN-003 (contacts) | ALTA | 2h |
### Fase 2: Integración MGN-015 ↔ MGN-004 (Semana 2)
| Tarea | Prioridad | Esfuerzo |
|-------|-----------|----------|
| Crear `billing.accounting_mappings` | CRÍTICA | 4h |
| Implementar auto-generación de asientos | CRÍTICA | 8h |
| Crear job de conciliación diaria | ALTA | 4h |
### Fase 3: Integración MGN-016 ↔ MGN-007 ↔ MGN-004 (Semana 3)
| Tarea | Prioridad | Esfuerzo |
|-------|-----------|----------|
| Agregar campos en MGN-007 (orders) | ALTA | 2h |
| Webhook `payment.approved` → actualizar orden | CRÍTICA | 4h |
| Auto-generar asientos de pagos | CRÍTICA | 8h |
| Reconciliador de comisiones | MEDIA | 4h |
### Fase 4: Integración MGN-017 ↔ MGN-009 (Semana 4)
| Tarea | Prioridad | Esfuerzo |
|-------|-----------|----------|
| Agregar campos en MGN-009 (leads) | ALTA | 2h |
| Auto-crear leads desde WhatsApp | ALTA | 8h |
| Vincular conversaciones a leads | ALTA | 4h |
### Fase 5: Integración MGN-018 ↔ MGN-015 (Semana 5)
| Tarea | Prioridad | Esfuerzo |
|-------|-----------|----------|
| Implementar control de tokens | CRÍTICA | 8h |
| Alertas de consumo | ALTA | 4h |
| Rate limiting por tenant | ALTA | 4h |
---
## 8. Riesgos y Mitigaciones
| Riesgo | Probabilidad | Impacto | Mitigación |
|--------|--------------|---------|------------|
| Feature flags no sincronizados | ALTA | CRÍTICO | Función centralizada + cache |
| Ciclo de dependencia 017↔018 | MEDIA | ALTO | Arquitectura en capas |
| Fallo en webhook de pago | MEDIA | CRÍTICO | Dead letter queue + retry |
| Exceso de tokens en AI | ALTA | ALTO | Rate limiting estricto |
| Datos sensibles en logs | MEDIA | CRÍTICO | PII masking automático |
| Asientos contables incorrectos | BAJA | CRÍTICO | Validación + rollback |
---
## 9. Checklist de Validación Pre-Implementación
### MGN-015 (Billing)
- [ ] Agregar dependencia con MGN-014 en README
- [ ] Agregar dependencia con MGN-004 en README
- [ ] Crear `billing.has_feature()` function
- [ ] Definir eventos de suscripción
- [ ] Mapear cuentas contables
### MGN-016 (Pagos)
- [ ] Agregar dependencia con MGN-014 en README
- [ ] Definir estados de pago en MGN-007
- [ ] Crear webhooks de integración
- [ ] Mapear asientos de pagos y comisiones
### MGN-017 (WhatsApp)
- [ ] Agregar dependencia con MGN-014 en README
- [ ] Agregar campos en MGN-003 (contacts)
- [ ] Agregar campos en MGN-009 (leads)
- [ ] Definir templates de notificación para MGN-007
### MGN-018 (AI Agents)
- [ ] Agregar dependencia con MGN-014 en README
- [ ] Implementar control de tokens en MGN-015
- [ ] Definir tools para MGN-007 y MGN-009
- [ ] Implementar rate limiting
---
## 10. Conclusión
Las modificaciones a los módulos MGN-015, MGN-016, MGN-017 y MGN-018 **pueden implementarse** pero requieren las adaptaciones documentadas en este análisis. Las principales áreas de atención son:
1. **Dependencia faltante con MGN-014** en todos los módulos nuevos
2. **Integración contable** entre MGN-015/MGN-016 y MGN-004
3. **Control centralizado de features** mediante funciones auxiliares
4. **Interdependencia 017↔018** resuelta con arquitectura en capas
5. **Campos adicionales** en MGN-003, MGN-007 y MGN-009
Implementando estas adaptaciones, el sistema quedará correctamente integrado y sin impactos inesperados.