Saltar a contenido

Referencia: eventos SSE

Inventario de los eventos Server-Sent Events (SSE) que emite el backend de Camarero IA. Esta página es material de referencia: describe cada canal, cada tipo de evento y la forma resumida de su payload, tal como están implementados.

Fuente de verdad

El contrato canónico vive en backend/tests/contract/sse_events_inventory.md (snapshot exhaustivo bloqueado por tests de contrato). Esta página resume ese inventario. Ante cualquier discrepancia, el inventario manda.

Términos:

  • Canal / topic: cola lógica del bus de eventos a la que se suscribe un cliente SSE. Hay dos relevantes para esta página: session:{token} (cliente) y manager:{restaurant_id} (dashboard del manager).
  • Frame: una línea data: <json>\n\n enviada por el stream.
  • Envoltura: el JSON de cada frame del bus, con los campos type, data y timestamp.

Formato de envoltura

Los eventos publicados vía bus (EventService) llevan siempre esta envoltura:

{
  "type": "cart_updated",
  "data": { },
  "timestamp": "2026-01-01T00:00:00.000000+00:00"
}
Campo Tipo Significado
type string Identificador del evento (p.ej. cart_updated). Viaja dentro del JSON, no como cabecera SSE event:.
data object Payload específico del evento.
timestamp string (ISO-8601) Instante de emisión, UTC.

El tipo NO viaja como cabecera SSE

A nivel de wire solo se usa el campo data:. Las cabeceras SSE event:, id: y retry: no se emiten. El cliente debe leer type del JSON.

Cabeceras de respuesta de todos los streams SSE:

  • Content-Type: text/event-stream
  • Cache-Control: no-cache
  • Connection: keep-alive
  • X-Accel-Buffering: no

Canal cliente

GET /api/v1/sessions/{token}/events

Stream de la sesión de mesa. El cliente (ChatWidget) se suscribe al topic session:{token} y recibe todo lo que ocurre en su sesión: chat, carrito, comandas, llamadas al manager y eventos de ciclo de vida disparados por el manager.

Mecanismo: pub/sub en memoria con buffer de los últimos eventos para late-joiners; al timeout de cada ciclo (30 s) emite un heartbeat.

connected

Handshake inicial al conectar. Es el primer frame que recibe el cliente.

{ "type": "connected", "data": { "status": "ok" } }

heartbeat

Keepalive emitido al expirar el ciclo de 30 s sin eventos.

{ "type": "heartbeat", "data": {} }

cart_updated

El carrito ha cambiado (CRUD del cliente o modificación por la IA).

Campo Tipo Nota
items array Líneas del carrito.
items[].id string (UUID) PK del item.
items[].product_id integer FK al catálogo.
items[].name string Nombre del producto.
items[].price integer Precio unitario en céntimos.
items[].quantity integer Cantidad.
items[].extras array o null IDs de extras.
items[].selected_options array o null Opciones estructuradas [{group_id, option_ids[]}].
items[].comment string o null Comentario del cliente.
items[].image_url string o null URL de imagen.
total integer Suma en céntimos.

chat_message

Mensaje persistido en la conversación (usuario, asistente, saludo de apertura, mensaje proactivo o split-welcome).

Cinco variantes de payload

chat_message tiene cinco formas según el origen, con distintos sets de claves. El cliente debe tratar todos los campos como opcionales. Núcleo común:

Campo Tipo Nota
role string user o assistant. Presente en todas las variantes.
content string Texto del mensaje. Presente en todas las variantes.
id / message_id integer ID del mensaje (ausentes en split-welcome).
conversation_id integer ID de conversación (ausente en split-welcome).
created_at string (ISO-8601) Timestamp (ausente en split-welcome).
session_id integer Solo en variantes user/assistant.
thinking_content string o null Solo en greeting y proactivo.
message_type / extra_data varios Solo en proactivo.

Datos estructurados por mensaje

Las tarjetas de recomendación y los chips de respuesta rápida llegan en extra_data.{recommendations, suggestions} de este evento (no solo en el frame done del canal de chat), porque el chat_message del bus suele ganar la carrera al crear el mensaje en el store del front.

typing_started / typing_stopped

La IA empieza o termina de "escribir". Se emiten al streamear respuestas, el saludo de apertura o mensajes proactivos. typing_started también se reenvía como replay si el cliente se conecta mientras la IA ya estaba escribiendo.

Campo Tipo Nota
conversation_id integer Conversación afectada.

chat_streaming

Cada chunk de la respuesta de la IA durante el streaming por el bus.

Campo Tipo Nota
conversation_id integer Conversación.
content string Texto acumulado (no incremental); el cliente calcula el diff.

Eventos de comanda (batch_*)

Eventos del ciclo de vida de la comanda (Comanda / batch). Algunos los dispara el cliente; otros, staff/admin, pero llegan igualmente al canal del cliente.

Evento Trigger Payload resumido
batch_updated Alta/edición/borrado de línea, aprobación, rechazo, etc. Polimórfico: Forma A { "batch": {…} } (batch completo) o Forma B { "batch_id": int, "status": str }. Discriminar por presencia de claves.
batch_ai_result Submit de comanda → validación IA { "batch_id": int, "passed": bool, "validation_result": object }
batch_manager_result Manager aprueba/rechaza { "batch_id": int, "approved": bool }
batch_approved Manager aprueba { "batch_id": int }
batch_rejected Manager rechaza { "batch_id": int }
batch_confirmed Staff confirma (pasa a cocina) { "batch_id": int }
batch_ready Staff marca como lista { "batch_id": int }
batch_served Staff sirve en mesa { "batch_id": int }
phase_updated Avance de fase al servir { "phase": str } (valor de ConversationPhase)

batch_updated es polimórfico

Tiene dos formas de payload. La Forma A incluye el batch completo (con lines[], totales en céntimos, timestamps); la Forma B solo batch_id + status. Un cliente debe comprobar si existe la clave batch antes de leer.

manager_call_created / manager_call_responded

Llamadas al manager desde la mesa y su respuesta.

manager_call_created (POST /sessions/{token}/call-manager):

Campo Tipo
call_id integer
session_token string
table_id integer
restaurant_id integer
status string ("pending")
reason string

manager_call_responded (staff responde): añade status, responded_by (integer) y responded_at (ISO-8601) al conjunto anterior.

session_closed

La sesión se cierra (cliente pide la cuenta o expira).

{ "type": "session_closed", "data": { "reason": "session_invalidated" } }

Otros eventos del canal cliente

Evento Trigger Payload resumido
guest_count_updated PATCH /sessions/{token}/guest-count { "session_token": str, "guest_count": int }
proactive_suggestion Scheduler de sugerencias { "type": str, "message": str, "suggested_products": array }
lifecycle_state_changed Acción de ciclo de vida del manager { "state": str, "session_id": int } (ver canal manager)
courtesy_round El manager invita una ronda { "items": [str], "note": str }

Canal manager

GET /api/v1/admin/manager/restaurants/{id}/events

Stream del dashboard de control de sala. Suscribe al topic manager:{restaurant_id}, distinto del topic del cliente.

Autenticación por query param

EventSource no envía cabeceras, así que el JWT de admin viaja como ?token=... y se valida con require_restaurant_access. Mismo mecanismo de bus, envoltura y cabeceras que el canal cliente.

sala_snapshot

Primer frame al conectar: estado inicial de todas las mesas activas.

{ "type": "sala_snapshot", "data": { "sessions": [ /* SessionSnapshot[] */ ] } }
Campo Tipo Nota
sessions array Lista de SessionSnapshot (forma de SessionSnapshotResponse del OpenAPI).

table_state_changed

Transición de ciclo de vida de una mesa (entrega del manager, reconciliación de pedido, alerta de retraso).

Campo Tipo Nota
(todos los de SessionSnapshot) varios Estado actual de la mesa.
previous_state string Estado anterior.

Se acompaña de lifecycle_state_changed

Cada table_state_changed del canal manager va acompañado de un lifecycle_state_changed ({ "state", "session_id" }) publicado al canal del cliente afectado, para que el chat reaccione (p.ej. a un DELAY_ALERT).

silent_table_alert

Tarea de fondo (cada 60 s): mesa en DRINKS_DELIVERED sin actividad > 15 min.

Campo Tipo
session_id integer
table_id integer
session_token string
minutes_silent integer
message string

Resumen de eventos

Evento Canal Disparado por
connected cliente conexión
heartbeat cliente / manager timeout 30 s
cart_updated cliente CRUD carrito / IA
chat_message cliente mensaje persistido
typing_started / typing_stopped cliente streaming IA
chat_streaming cliente chunk de respuesta IA
batch_updated cliente ciclo de vida comanda
batch_ai_result cliente validación IA
batch_manager_result cliente manager aprueba/rechaza
batch_approved / batch_rejected cliente manager
batch_confirmed / batch_ready / batch_served cliente staff
phase_updated cliente servir comanda
manager_call_created / manager_call_responded cliente llamada al manager
session_closed cliente cierre / expiración
guest_count_updated cliente cambio de comensales
proactive_suggestion cliente scheduler
lifecycle_state_changed cliente acción del manager
courtesy_round cliente invitación del manager
sala_snapshot manager conexión
table_state_changed manager transición de mesa
silent_table_alert manager tarea de fondo

Páginas relacionadas