Skip to main content

Estructura del frontend

Repo aura-front: React 18 + TypeScript + Vite, Tailwind + shadcn/ui (Radix), TanStack Query, lucide-react. Auth con @cuatro-quinas/ajolote-client-web.

Separación socket / hook / UI

El core del dashboard separa la fuente de eventos del consumidor:

  • CopilotSocket (src/api/socket/): interface con dos implementaciones — RealCopilotSocket (WebSocket nativo, reconexión con backoff) y MockCopilotSocket (fixtures para demos/dev). Se elige por VITE_USE_MOCK.
  • useAgentSocket(socket) (src/hooks/): hook puro con useReducer sobre los eventos. Sin datos hardcodeados, testeable con un socket fake.
  • Componentes de presentación (src/components/copilot/): reciben estado y disparan callbacks; no tocan el WebSocket.

Cliente API

Todo el acceso al backend pasa por src/api/client.tsapiFetch(path, init), que resuelve la base URL y usa fetchAuthed (Bearer + refresh). Los módulos de src/api/* (metrics, audit, feedback, audio-fork, retell) lo importan; no redefinen el fetch.

Siempre apiFetch / fetchAuthed

Cualquier request autenticado debe ir por apiFetch. Un fetch plano no manda el Bearer, y el backend no puede identificar al usuario (req.user vacío) → los eventos de auditoría salen sin user_id y los endpoints gateados dan 403.

Data fetching (React Query)

Los paneles usan useQuery con key [endpoint, ...filtros]. Esto:

  • evita races: al cambiar filtros rápido, respuestas viejas no pisan a las nuevas (React Query descarta resultados de keys obsoletas);
  • da caché y dedupe gratis.

No usar useEffect + fetch manual para data de servidor.

Componentes y helpers compartidos

Para no duplicar entre paneles:

MóduloQué es
components/copilot/shared/segmented-control.tsxToggle group (Día/Semana/Mes, filtros) — accesible (role=group, aria-pressed)
components/copilot/shared/period-selector.tsxDropdown de período
components/copilot/shared/kpi-card.tsxTarjeta de KPI (label + número + delta) sobre ui/Card
lib/period.tsgetPeriodOptions, isoDate, daysInRange, pct, deltaLabel, tipos
lib/chart-colors.tsPaleta compartida de recharts
components/ui/*Primitivos shadcn (Card, Badge, Button, Select, PanelCard…)

Reusar los primitivos ui/ en vez de <div> con clases repetidas.

Roles en la UI

Ver Autenticación. En resumen: useRole() + RequireRole (rutas) + roles? en NAV_ITEMS (nav). El front solo oculta; la autoridad es el backend.

Agregar una pantalla nueva

  1. Crear el componente en components/copilot/.
  2. Cliente en src/api/<recurso>.ts usando apiFetch.
  3. Data con useQuery.
  4. Ruta en agent-copilot.tsx (envuelta en <RequireRole> si aplica).
  5. Item en app-nav.tsx (con roles? si es de supervisor).
  6. Reusar SegmentedControl / PeriodSelector / KpiCard / ui/*.