1. Introducción y Propósito

Un VIC (Visualizador Interactivo Conectado) es una aplicación web externa que se ejecuta dentro de un iframe en el entorno de SmartTable.

SmartTable actúa como el Host: se encarga de la autenticación, la navegación por carpetas, el filtrado de datos y la gestión del estado global. Cuando el usuario visualiza un conjunto de datos, el Host inyecta esos datos filtrados y el contexto de seguridad al VIC para que este ejecute su propósito (visualización, gestión, formularios, etc.).

Nota de Diseño: Un VIC puede ser tan simple como una página dedicada a una sola regla específica ("Formulario de Bitácora") o tan complejo como una suite multifuncional ("Gestor de Incidentes Genérico"). La implementación depende enteramente del caso de uso.

2. El Protocolo de Comunicación

El Host envía actualizaciones de datos en tiempo real mediante eventos message. El VIC debe estar "escuchando" estos eventos desde el momento en que se monta.

2.1 El Evento (Trigger)

El evento se dispara en los siguientes casos:

  1. Carga Inicial: Al terminar de cargar el iframe.
  2. Navegación: El usuario profundiza en el árbol de carpetas del Host.
  3. Filtrado: El usuario aplica un filtro de color o busca texto.
  4. Polling: El Host detecta cambios en el backend y actualiza la vista.

2.2 Estructura del Payload (Contrato de Datos)

El objeto event.data recibido tendrá siempre la siguiente estructura JSON:

{
  type: "DATA_SYNC",      // Identificador fijo del evento
  
  // Array de objetos. Contiene las filas visibles en el Host.
  // La estructura de las filas es dinámica (depende de la regla visualizada).
  data: Array<Record<string, any>>, 

  // Metadatos de contexto, seguridad y estado
  meta: {
    ruleId: string,       // UUID único de la regla activa en el Host
    ruleName: string,     // Nombre legible (ej: "Incidentes Críticos")
    
    // Métricas
    totalRows: number,    // Total de registros sin filtrar
    filteredCount: number,// Cantidad de registros enviados en 'data'
    
    // Tiempos (Epoch ms)
    timestamp: number,    // Momento del envío del mensaje
    dataTimestamp: number,// Momento de generación de datos en backend (Para consistencia)

    // Seguridad
    token: string,        // JWT Access Token activo. Permite al VIC consumir APIs del ecosistema sin relogin.

    // Filtros aplicados por el usuario (Contexto visual)
    activeFilters: Record<string, string>, // Ej: { "Estado": "Abierto" }
    
    activeColor: {        // Filtro de semáforo (si aplica)
        groupId: string,
        groupName: string,
        conditionId: string | null,
        conditionName: string
    } | null
  }
}

3. Ejemplos de Data Transmitida

El desarrollador debe tener en cuenta que el contenido de data cambia según la regla que el usuario esté mirando en el Host.

Ejemplo A: Regla de Negocio (Incidentes)

{
    "type": "DATA_SYNC",
    "data": [
        {
            "Incident Number": "INC000008641380",
            "Status": "Resuelto",
            "Encargada": "Carolina",
            "AlertResult": "Atencion Inmediata..."
        }
        // ... más filas
    ],
    "meta": {
        "ruleName": "Monitoreo Incidentes",
        "filteredCount": 7,
        "token": "eyJhbGciOi...",
        "activeFilters": { "Encargada": "Carolina" }
    }
}

Ejemplo B: Infraestructura (Servidores)

{
    "type": "DATA_SYNC",
    "data": [
        {
            "Servidor": "AWS Ubuntu (eva)",
            "Archivo": "/etc/hosts",
            "Ultima_Modificacion_Epoch": 1766949252000
        }
    ],
    "meta": {
        "ruleName": "Archivos Críticos",
        "activeFilters": {}
    }
}

4. Guía de Implementación

Para integrar un VIC, se deben seguir estos pasos técnicos mínimos.

Paso 1: Configurar el Listener

El VIC debe ser capaz de recibir y procesar el mensaje.

// Ejemplo genérico en JS
function initListener() {
    window.addEventListener('message', (event) => {
        // 1. Validar estructura básica
        const payload = event.data;
        if (!payload || payload.type !== 'DATA_SYNC') return;

        console.log(`[VIC] Datos recibidos: ${payload.data.length} filas`);

        // 2. Procesar datos (Renderizar UI, guardar en Store, etc.)
        updateApplicationState(payload.data, payload.meta);
    });
}

Paso 2: Autenticación (Uso del Token)

El VIC no debe implementar pantalla de login. Debe utilizar el meta.token proporcionado para realizar peticiones HTTP a las APIs del ecosistema (si su funcionalidad lo requiere).

async function fetchAdditionalDetails(id) {
    // Asumimos que el token se guardó en un estado global al recibir el mensaje
    const token = globalState.token; 

    const response = await fetch(`https://api.dominio.com/recurso/${id}`, {
        headers: {
            'Authorization': `Bearer ${token}`, // Inyección del token
            'Content-Type': 'application/json'
        }
    });
    return response.json();
}

Paso 3: Validación de Contexto (Opcional pero Recomendado)

Dependiendo de la naturaleza del VIC, puede ser necesario validar si los datos recibidos son "compatibles" con la funcionalidad que ofrece.

  • VIC Ad-Hoc (Dedicado): Si el VIC fue construido exclusivamente para la regla "Vacaciones", puede verificar meta.ruleId o meta.ruleName. Si no coinciden, muestra un mensaje "Configuración incorrecta" o pantalla en blanco.
  • VIC Genérico/Dinámico: Si el VIC es una herramienta multipropósito (ej. un graficador), debe inspeccionar las columnas dentro de data para decidir si puede graficar la información o qué tipo de gráfico mostrar.

5. Recomendaciones y Best Practices

  1. Reactividad Total: El Host puede enviar actualizaciones frecuentes (el usuario filtra, busca o cambia de carpeta). El VIC debe estar preparado para reemplazar completamente su dataset visualizado en cualquier momento, no solo al cargar la página.
  2. Consistencia de Datos: Si el VIC necesita consultar más detalles al backend para un registro específico (patrón Double Fetch), se recomienda enviar el meta.dataTimestamp en la petición. Esto asegura que el backend devuelva la versión del dato coherente con lo que el usuario está viendo en ese instante.
  3. Idempotencia: Si el VIC permite ejecutar acciones (ej. botones de "Aprobar", "Reintentar"), genere claves de idempotencia locales. Los usuarios pueden hacer doble clic accidentalmente o el Host puede reenviar datos.
  4. Manejo de Estados Vacíos: Si meta.filteredCount es 0 o el array data está vacío, el VIC debe mostrar un estado amigable ("Sin registros seleccionados") en lugar de una pantalla en blanco o error.

6. Ejemplos Adicionales y Variantes de Filtrado

A continuación, se presentan cuatro trazas reales de comunicación. Estos ejemplos ilustran cómo varía el payload DATA_SYNC dependiendo de la interacción del usuario en el Host (navegación, selección de alertas, cambio de regla, etc.). El VIC debe ser capaz de interpretar estos estados.

Caso A: Filtrado por Navegación (Drill-down)

Escenario: El usuario ha navegado a través de las carpetas del árbol de la regla (ej. Seleccionó "Encargada: Carolina" y luego el sub-grupo "StatusFinal: Op - Sin Contacto").

Nota para el VIC: activeFilters contiene la ruta de navegación. activeColor es nulo porque no se ha seleccionado un estado específico del dashboard.
{
    "type": "DATA_SYNC",
    "data": [
        {
            "Incident Number": "INC000008641380",
            "StatusFinal": "Op - Sin Contacto con Cliente",
            "Encargada": "Carolina",
            "Status": "Resuelto",
            "AlertResult": "Monitores: Atencion Inmediata..."
        },
        {
            "Incident Number": "INC000008642177",
            "StatusFinal": "Op - Sin Contacto con Cliente",
            "Encargada": "Carolina",
            "Status": "Resuelto",
            "AlertResult": "Monitores: Atencion Inmediata..."
        }
        // ... 5 items más
    ],
    "meta": {
        "ruleId": "2a25e2d3-f272-45ac-a12e-1dc4fa537c61",
        "ruleName": "Monitoreo (ESTE SI)",
        "totalRows": 59,
        "filteredCount": 7,
        "timestamp": 1767021924174,
        "activeFilters": {
            "Encargada": "Carolina",
            "StatusFinal": "Op - Sin Contacto con Cliente"
        },
        "activeColor": null
    }
}

Caso B: Cambio de Contexto (Estructura de Datos Diferente)

Escenario: El usuario cambió de la regla de "Incidentes" a una regla de "Auditoría de Archivos".

Nota para el VIC: El esquema de data ha cambiado radicalmente (nuevas columnas). Si el VIC es genérico, debe redibujar la tabla/gráfico. Si el VIC es específico para Incidentes, debería mostrar un estado de "Esperando datos compatibles" o desactivarse.
{
    "type": "DATA_SYNC",
    "data": [
        {
            "Alias del Servidor": "AWS Ubuntu (eva)",
            "Archivo": "/home/ubuntu/dev/headers.json",
            "Ultima_Modificacion_Epoch": 1766949252000,
            "Servidor": "localhost"
        },
        {
            "Alias del Servidor": "minimobs",
            "Archivo": "/var/opt/helix-sql/cookies.json",
            "Ultima_Modificacion_Epoch": 1766950507000,
            "Servidor": "143...."
        }
        // ... más items
    ],
    "meta": {
        "ruleId": "d6b773eb-b3fe-461b-a9e0-eccf76df72c6",
        "ruleName": "Archivos Críticos",
        "totalRows": 6,
        "filteredCount": 6,
        "timestamp": 1767021985551,
        "activeFilters": {},
        "activeColor": null
    }
}

Caso C: Filtrado Global por Estado/Color

Escenario: El usuario hizo clic en una "burbuja" o KPI de color en el dashboard (ej. Alerta "Crítica") sin haber navegado por carpetas.

Nota para el VIC: activeFilters está vacío (estamos en la raíz), pero activeColor está poblado. El array data contiene solo los registros que cumplen con esa condición de color.
{
    "type": "DATA_SYNC",
    "data": [
        {
            "Incident Number": "INC000008644404",
            "StatusFinal": "Op - Sin Contacto con Cliente",
            "AlertResult": "Monitores: Critico Resuelto...",
            "Status": "Resuelto"
        },
        {
            "Incident Number": "INC000008637472",
            "StatusFinal": "Op - En Observacion con Client",
            "AlertResult": "Monitores: Critico Resuelto...",
            "Status": "Resuelto"
        }
        // ... 1 item más
    ],
    "meta": {
        "ruleId": "2a25e2d3-f272-45ac-a12e-1dc4fa537c61",
        "ruleName": "Monitoreo (ESTE SI)",
        "totalRows": 59,
        "filteredCount": 3,
        "timestamp": 1767022118878,
        "activeFilters": {},
        "activeColor": {
            "groupId": "e90dd8ea-1446-4e08-8878-07986db27b26",
            "groupName": "Alertas",
            "conditionId": "ef68c7da-2b96-436d-a812-720942e1d73e",
            "conditionName": "Critica"
        }
    }
}

Caso D: Selección Específica y Filtros Combinados

Escenario: El usuario navegó profundamente hasta seleccionar un registro específico (o grupo muy pequeño) Y ADEMÁS tiene activo un filtro de color ("Urgente").

Nota para el VIC: filteredCount es muy bajo (1). activeFilters incluye identificadores únicos (como el número de incidente). activeColor también está aplicando restricción. Esta es la vista más específica posible.
{
    "type": "DATA_SYNC",
    "data": [
        {
            "Incident Number": "INC000008638921",
            "StatusFinal": "Op - En Observacion con Client",
            "AlertResult": "Monitores: Urgente Resuelto...",
            "Encargada": "Carolina",
            "Status": "Resuelto"
        }
    ],
    "meta": {
        "ruleId": "2a25e2d3-f272-45ac-a12e-1dc4fa537c61",
        "ruleName": "Monitoreo (ESTE SI)",
        "totalRows": 59,
        "filteredCount": 1,
        "timestamp": 1767022207936,
        "activeFilters": {
            "Encargada": "Carolina",
            "StatusFinal": "Op - En Observacion con Client",
            "Incident Number": "INC000008638921"
        },
        "activeColor": {
            "groupId": "e90dd8ea-1446-4e08-8878-07986db27b26",
            "groupName": "Alertas",
            "conditionId": "533fe54b-6fb0-4a45-be74-c82c3a532379",
            "conditionName": "Urgente"
        }
    }
}