feat: migrar dashboard a React 19 + TypeScript + Vite + Tailwind v4
- Módulo HITL (/cases): 6 patrones de formularios dinámicos para 53 tipos de caso con validación Zod - Módulo Monitor (/monitor): streaming token-a-token en tiempo real, auto-scroll y notas internas vía WebSocket - Arquitectura híbrida: REST (canal autoritativo) + WebSocket (difusión/streaming) - MSW para desarrollo sin backend, hooks de notificaciones/sonido/título preservados - Backend legacy movido a legacy/, archivos residuales eliminados de raíz
This commit is contained in:
@@ -1,122 +1,219 @@
|
||||
# Claro Cases Tracking System - Manual Técnico
|
||||
# Claro Cases — Dashboard HITL
|
||||
|
||||
Este documento detalla el funcionamiento técnico, arquitectura y endpoints de la aplicación **Claro Cases**, un sistema en tiempo real para rastrear solicitudes de clientes, gestionar casos y registrar métricas de tiempo de atención.
|
||||
Dashboard *Human-in-the-Loop* (HITL) para que asesores humanos gestionen peticiones enviadas por un agente virtual durante conversaciones con clientes, y monitoreen la operación en tiempo real.
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Arquitectura del Sistema
|
||||
## 🏗️ Arquitectura
|
||||
|
||||
La aplicación sigue una arquitectura desacoplada monolítica simple basada en Node.js, Express y SQLite:
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Client[Cliente Externo / API Client] -->|POST /api/requests| ExpressServer[Express Server Node.js]
|
||||
ExpressServer -->|Guarda Datos| SQLite[SQLite database.sqlite]
|
||||
ExpressServer -->|SSE Broadcast| Frontend[Frontend SPA HTML/JS]
|
||||
Frontend -->|Interacción de Operador| ExpressServer
|
||||
```
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ Frontend React (este repo) │
|
||||
│ │
|
||||
│ /cases ──▶ Gestión HITL (formularios dinámicos)│
|
||||
│ /monitor ──▶ Monitoreo en tiempo real │
|
||||
│ │
|
||||
│ REST (POST) ──▶ Backend Python (canal escritura) │
|
||||
│ WebSocket ◀── Backend Python (difusión/stream) │
|
||||
└──────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
1. **Frontend (SPA - Single Page Application)**: Desarrollado con Vanilla HTML5, Javascript (ES6) y CSS3 adaptativo con soporte para temas Claro/Oscuro.
|
||||
2. **Backend**: Servidor REST Express que provee persistencia y notificaciones en tiempo real a través de Server-Sent Events (SSE).
|
||||
3. **Persistencia**: Base de datos ligera embebida SQLite gestionada eficientemente de manera síncrona por medio del driver `better-sqlite3`.
|
||||
- **REST** es el canal autoritativo de escritura (resolución de casos)
|
||||
- **WebSocket** es para difusión de eventos y streaming en tiempo real
|
||||
- **MSW** (Mock Service Worker) simula el backend en modo desarrollo
|
||||
|
||||
### Stack
|
||||
|
||||
| Componente | Tecnología |
|
||||
|-----------|-----------|
|
||||
| Framework | React 19 + TypeScript |
|
||||
| Build | Vite 6 |
|
||||
| Estado global | Zustand |
|
||||
| Ruteo | React Router (`/cases`, `/monitor`) |
|
||||
| Estilos | Tailwind CSS v4 (CSS-first con `@theme`) |
|
||||
| Validación | Zod |
|
||||
| Iconos | Lucide React |
|
||||
| Mocks | MSW (Mock Service Worker) |
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ Esquema de la Base de Datos
|
||||
## 📂 Estructura del Proyecto
|
||||
|
||||
La tabla principal es `requests`. La inicialización del esquema y las migraciones automáticas de columnas se gestionan dinámicamente en el módulo [db.js](file:///c:/Users/pepit/Desktop/doc/NODE/autonomus/Claro%20Cases/db.js).
|
||||
|
||||
```sql
|
||||
CREATE TABLE IF NOT EXISTS requests (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
status TEXT DEFAULT 'Pending',
|
||||
external_id TEXT,
|
||||
cedula TEXT,
|
||||
tipo_solicitud TEXT,
|
||||
payload TEXT, -- Objeto JSON guardado como String
|
||||
handling_time INTEGER DEFAULT 0, -- Tiempo de gestión en segundos
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
```
|
||||
claro-cases/
|
||||
├── index.html # Vite entry point
|
||||
├── package.json # Dependencias y scripts
|
||||
├── vite.config.ts # Configuración Vite + Tailwind + alias @/
|
||||
├── tsconfig.json # TypeScript config
|
||||
├── .env # Variables de entorno (VITE_*)
|
||||
├── SPECIFICATION.md # Bitácora de desarrollo
|
||||
├── BACKEND_HANDOFF.md # Contratos para equipo Python
|
||||
├── Consulta de aplicativos... # CSV con 53 tipos de caso
|
||||
│
|
||||
├── src/
|
||||
│ ├── main.tsx # Entry point React + MSW condicional
|
||||
│ ├── App.tsx # Router principal
|
||||
│ ├── index.css # Tailwind v4 @theme + @custom-variant dark
|
||||
│ │
|
||||
│ ├── types/
|
||||
│ │ ├── index.ts # Interfaces: CaseRequest, Conversation, Message, etc.
|
||||
│ │ └── wsProtocol.ts # Schemas Zod de eventos WebSocket
|
||||
│ │
|
||||
│ ├── data/
|
||||
│ │ └── caseTypeDefinitions.ts # 53 tipos de caso con uiPattern y formFields
|
||||
│ │
|
||||
│ ├── services/
|
||||
│ │ ├── api.ts # Cliente REST (fetch nativo)
|
||||
│ │ └── wsClient.ts # Cliente WebSocket con reconexión
|
||||
│ │
|
||||
│ ├── store/
|
||||
│ │ └── useAppStore.ts # Zustand store: cases, conversations, ui
|
||||
│ │
|
||||
│ ├── hooks/
|
||||
│ │ ├── useNotification.ts # Notificaciones escritorio HTML5
|
||||
│ │ ├── useSound.ts # Alerta sonora Web Audio API
|
||||
│ │ ├── useTitleFlash.ts # Parpadeo de título de pestaña
|
||||
│ │ └── index.ts # Barrel export
|
||||
│ │
|
||||
│ ├── components/
|
||||
│ │ ├── layout/
|
||||
│ │ │ ├── AppShell.tsx # Shell global (WS init, tema oscuro)
|
||||
│ │ │ ├── Header.tsx # Logo, badge, indicador WS, toggle tema
|
||||
│ │ │ └── Sidebar.tsx # Nav: Casos / Monitor
|
||||
│ │ │
|
||||
│ │ ├── cases/
|
||||
│ │ │ ├── CaseCard.tsx # Tarjeta de caso (sidebar)
|
||||
│ │ │ ├── CaseDetail.tsx # Panel de detalle
|
||||
│ │ │ ├── FormRenderer.tsx # Formulario dinámico (6 patrones UI)
|
||||
│ │ │ ├── TypeBadge.tsx # Badge de tipo de solicitud
|
||||
│ │ │ └── ApplicativeFilter.tsx # Filtro por aplicativo
|
||||
│ │ │
|
||||
│ │ ├── monitor/
|
||||
│ │ │ ├── ConversationCard.tsx # Tarjeta de conversación
|
||||
│ │ │ ├── ChatFeed.tsx # Feed de mensajes con auto-scroll
|
||||
│ │ │ ├── MessageBubble.tsx # Burbuja por rol (user/agent/system/internal)
|
||||
│ │ │ ├── InternalNoteBanner.tsx # Inyección de notas internas
|
||||
│ │ │ └── InternalNotesGroup.tsx # Acordeón de notas agrupadas
|
||||
│ │ │
|
||||
│ │ └── shared/
|
||||
│ │ ├── StatusBadge.tsx # Badge de estado (PENDING/IN_PROGRESS/RESOLVED/FAILED)
|
||||
│ │ ├── SearchBar.tsx # Input con debounce 300ms
|
||||
│ │ ├── TabsBar.tsx # Pestañas: Todos/Pendientes/Finalizados
|
||||
│ │ ├── EmptyState.tsx # Estado vacío centrado
|
||||
│ │ ├── Modal.tsx # Overlay modal con backdrop blur
|
||||
│ │ └── Timer.tsx # Cronómetro independiente (localStorage)
|
||||
│ │
|
||||
│ ├── pages/
|
||||
│ │ ├── CasesPage.tsx # Vista /cases: sidebar + detalle
|
||||
│ │ └── MonitorPage.tsx # Vista /monitor: conversaciones + chat
|
||||
│ │
|
||||
│ └── mocks/
|
||||
│ ├── browser.ts # MSW setup
|
||||
│ └── handlers.ts # 10 casos mock + 3 conversaciones
|
||||
│
|
||||
├── public/
|
||||
│ └── mockServiceWorker.js # MSW service worker
|
||||
│
|
||||
└── legacy/ # Backend legacy Node.js + SQLite
|
||||
├── server.js
|
||||
├── db.js
|
||||
├── schema.sql
|
||||
├── package.json
|
||||
└── public/ # Frontend vanilla original
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔌 API Endpoints (Backend)
|
||||
## 🚀 Ejecución
|
||||
|
||||
### 1. Registrar Nuevo Caso
|
||||
* **Endpoint**: `POST /api/requests`
|
||||
* **Content-Type**: `application/json`
|
||||
* **Payload**:
|
||||
```json
|
||||
{
|
||||
"title": "Título del Caso",
|
||||
"description": "Detalle descriptivo",
|
||||
"external_id": "EXT-12345",
|
||||
"cedula": "10203040",
|
||||
"tipo_solicitud": "validacion_usuario",
|
||||
"payload": {
|
||||
"nombre": "Juan Pérez",
|
||||
"telefono": "31000000"
|
||||
}
|
||||
}
|
||||
```
|
||||
* **Comportamiento**: Guarda la solicitud y transmite en tiempo real la información a todos los operadores conectados usando SSE.
|
||||
### Prerrequisitos
|
||||
- Node.js 20+
|
||||
|
||||
### 2. Stream de Actualizaciones en Tiempo Real
|
||||
* **Endpoint**: `GET /api/sse`
|
||||
* **Content-Type**: `text/event-stream`
|
||||
* **Comportamiento**: Registra el cliente para recibir eventos unidireccionales desde el servidor en tiempo real.
|
||||
### Instalación
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### 3. Obtener Solicitudes
|
||||
* **Endpoint**: `GET /api/requests`
|
||||
* **Comportamiento**: Devuelve todos los casos de la base de datos en orden descendente por fecha de creación.
|
||||
### Desarrollo (con MSW — sin backend real)
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
- `http://localhost:5173/cases` — Gestión de casos HITL
|
||||
- `http://localhost:5173/monitor` — Monitoreo de conversaciones
|
||||
|
||||
### 4. Actualizar Estado / Finalizar Caso
|
||||
* **Endpoint**: `PUT /api/requests/:id`
|
||||
* **Payload**:
|
||||
```json
|
||||
{
|
||||
"status": "Finalizado",
|
||||
"handling_time": 125,
|
||||
"payload": {
|
||||
"valor_cierre": "Comentario de finalización"
|
||||
}
|
||||
}
|
||||
```
|
||||
Con `VITE_ENABLE_MSW=true` en `.env`, el MSW simula el backend automáticamente. Para usar un backend real, cambia a `VITE_ENABLE_MSW=false`.
|
||||
|
||||
### 5. Eliminar Solicitud
|
||||
* **Endpoint**: `DELETE /api/requests/:id`
|
||||
### Build de producción
|
||||
```bash
|
||||
npm run build # Genera dist/
|
||||
npm run preview # Previsualiza el build
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Lógica del Operador (Frontend)
|
||||
## 🎨 Sistema de Diseño
|
||||
|
||||
El flujo interactivo se gestiona en [public/app.js](file:///c:/Users/pepit/Desktop/doc/NODE/autonomus/Claro%20Cases/public/app.js) y se compone de:
|
||||
El tema está definido en `src/index.css` mediante la directiva `@theme` de Tailwind v4:
|
||||
|
||||
* **Sincronización en Tiempo Real (SSE)**: Permite la llegada instantánea de nuevos casos al panel de control del operador sin recargar la página. Al ingresar un caso nuevo:
|
||||
- Se reproduce una alerta de sonido usando la API nativa de **Web Audio**.
|
||||
- Se genera una **Notificación de Escritorio HTML5** en el sistema operativo.
|
||||
- El título de la pestaña del navegador destella con la cantidad de casos pendientes.
|
||||
* **Filtros e Historial**:
|
||||
- Buscador integrado que busca en tiempo real por título, ID de referencia, descripción, cédula y tipo de solicitud.
|
||||
- Pestañas rápidas para clasificar casos entre *Todos*, *Pendientes* y *Finalizados*.
|
||||
* **Flujos Especiales al Gestionar Casos**:
|
||||
- Al dar clic en **Gestionar Caso**, se inicia un cronómetro individual para medir el tiempo que el operador tarda en resolver la solicitud.
|
||||
- **Solicitud de Validación**: Si el caso contiene la palabra `"validacion"` en su campo `tipo_solicitud`, la UI cambia dinámicamente y despliega los botones **Sí** y **No** integrados bajo la pregunta *"¿El usuario es válido?"*. Al hacer clic en cualquiera de ellos, el caso se cierra.
|
||||
- **Otras Solicitudes**: Si es de cualquier otro tipo, la interfaz le exige al operador ingresar un valor de resolución en una entrada de texto antes de dar clic en **Finalizar Caso**. Este valor se inyecta en el objeto JSON de `payload` del caso.
|
||||
| Token | Valor |
|
||||
|-------|-------|
|
||||
| `--color-accent-orange` | `#ff4e00` |
|
||||
| `--color-accent-yellow` | `#ffa600` |
|
||||
| `--color-accent-red` | `#f80018` |
|
||||
| `--color-accent-green` | `#10b981` |
|
||||
| `--color-bg-base` | `#f0f2f5` |
|
||||
| `--color-bg-surface` | `#ffffff` |
|
||||
| `--color-bg-elevated` | `#f8fafc` |
|
||||
| Tipografía | Inter (Google Fonts) |
|
||||
|
||||
Modo oscuro: toggle vía `@custom-variant dark` + clase `.dark` en `<html>`.
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Ejecución Local
|
||||
## 📡 Contratos de Integración
|
||||
|
||||
1. Instalar dependencias:
|
||||
```cmd
|
||||
npm install
|
||||
```
|
||||
2. Ejecutar servidor en modo desarrollo (con recarga automática vía nodemon):
|
||||
```cmd
|
||||
npm run dev
|
||||
```
|
||||
El servidor levantará en http://localhost:3000.
|
||||
El backend Python debe implementar los contratos documentados en [`BACKEND_HANDOFF.md`](./BACKEND_HANDOFF.md). Resumen rápido:
|
||||
|
||||
### REST (canal autoritativo)
|
||||
| Método | Ruta | Descripción |
|
||||
|--------|------|-------------|
|
||||
| `GET` | `/api/v1/cases?status=&applicative=&search=&offset=&limit=` | Listar casos (filtrable, paginado) |
|
||||
| `GET` | `/api/v1/cases/:id` | Obtener caso |
|
||||
| `POST` | `/api/v1/cases/:id/resolve` | Resolver caso (**único canal de escritura**) |
|
||||
| `GET` | `/api/v1/conversations/active` | Conversaciones activas |
|
||||
|
||||
### WebSocket (`/ws/dashboard`)
|
||||
- **Server → Client**: `init_state`, `conversation_started`, `agent_stream_started/chunk/completed`, `hitl_request`, `hitl_resolved`
|
||||
- **Client → Server**: `internal_note` (notas internas del asesor)
|
||||
- Envelope: `{ type, eventId, occurredAt, payload }`
|
||||
|
||||
---
|
||||
|
||||
## 🤖 Modo Mock (MSW)
|
||||
|
||||
El proyecto incluye 10 casos de ejemplo y 3 conversaciones simuladas para desarrollo sin backend:
|
||||
|
||||
```bash
|
||||
# .env
|
||||
VITE_ENABLE_MSW=true
|
||||
```
|
||||
|
||||
Los mocks cubren los 6 patrones de UI (`SIMPLE_CONFIRMATION`, `CONFIRMATION_WITH_VALUE`, `MULTI_FIELD_FORM`, `DATE_SIMPLE`, `FREE_TEXT`, `READ_ONLY`) y múltiples aplicativos (AC+, ASCARD, DiMe, Formatos SGCS, Mi asistencia 360, RR).
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Seguridad
|
||||
|
||||
- **`advisorId` NUNCA es enviado por el frontend**. El backend deriva la identidad del asesor desde el token de sesión (REST) o conexión WebSocket autenticada.
|
||||
- La resolución de casos es exclusivamente REST — no hay ruta de escritura por WebSocket que pueda ser explotada.
|
||||
|
||||
---
|
||||
|
||||
## 📚 Documentación Adicional
|
||||
|
||||
| Archivo | Contenido |
|
||||
|---------|-----------|
|
||||
| [`SPECIFICATION.md`](./SPECIFICATION.md) | Bitácora completa: fases de diseño, auditoría, implementación y QA |
|
||||
| [`BACKEND_HANDOFF.md`](./BACKEND_HANDOFF.md) | Contratos REST/WS detallados para el equipo Python |
|
||||
| [`Consulta de aplicativos - Claro - Facturación.csv`](./Consulta%20de%20aplicativos%20-%20Claro%20-%20Facturaci%C3%B3n.csv) | 53 tipos de caso con pasos, objetivos y formatos de respuesta |
|
||||
| [`legacy/README.md`](./legacy/README.md) | Documentación del backend legacy (Node.js + SQLite) |
|
||||
|
||||
Reference in New Issue
Block a user