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

19 KiB

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:

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

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

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

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

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

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

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

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

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

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

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