bryan_garcia 9f86dc0d0d Ran command: git status --short
Ran command: `git diff --cached`
Ran command: `git diff --cached SPECIFICATION.md src/components/layout/AppShell.tsx`

feat(ws): handle nested WS payload envelope and handle assigned conversation events

* Automatically unwrap double-nested WS payloads (`payload.payload`) in `WsClient`.
* Handle `conversation_assigned` WS event in `AppShell` by fetching details via REST.
* Deduplicate `upsertConversation` calls and update conversation handling logic.
* Add comprehensive test suites for WS unwrapping and store deduplication.
2026-07-31 14:13:57 -05:00
2026-07-31 14:13:57 -05:00

Claro Cases — Dashboard HITL

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

┌──────────────────────────────────────────────────┐
│              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) │
└──────────────────────────────────────────────────┘
  • 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)

📂 Estructura del Proyecto

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

🚀 Ejecución

Prerrequisitos

  • Node.js 20+

Instalación

npm install

Desarrollo (con MSW — sin backend real)

npm run dev
  • http://localhost:5173/cases — Gestión de casos HITL
  • http://localhost:5173/monitor — Monitoreo de conversaciones

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.

Build de producción

npm run build     # Genera dist/
npm run preview   # Previsualiza el build

🎨 Sistema de Diseño

El tema está definido en src/index.css mediante la directiva @theme de Tailwind v4:

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


📡 Contratos de Integración

El backend Python debe implementar los contratos documentados en 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:

# .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 Bitácora completa: fases de diseño, auditoría, implementación y QA
BACKEND_HANDOFF.md Contratos REST/WS detallados para el equipo Python
Consulta de aplicativos - Claro - Facturación.csv 53 tipos de caso con pasos, objetivos y formatos de respuesta
legacy/README.md Documentación del backend legacy (Node.js + SQLite)
S
Description
No description provided
Readme
337 KiB
Languages
TypeScript 86.9%
JavaScript 8.9%
CSS 3.6%
HTML 0.6%