Inbox
El modulo de Inbox gestiona la bandeja de entrada de cada usuario: mensajes internos, notificaciones push (mobile y browser), y preferencias de notificacion. Es el punto central donde convergen alertas de todos los modulos.Arquitectura
Tipos de mensaje
Prioridades
Estados
unread → read → resolved → archived
Soft delete con campo deleted_at.
API Endpoints
Filtros
Los endpoints de listado aceptan:sourceTool— filtrar por herramienta origen (chat,community,notifications,system,ai)messageTypes— array de tipos de mensajepriority— filtrar por prioridadstatus— filtrar por estado
Preferencias de usuario
Cada usuario puede configurar:Push Notifications
El inbox soporta dos canales de push:- Expo Push — para vivla-mobile (iOS/Android)
- Web Push — para el panel web via VAPID/service worker
urgent).
Helpers del servicio
InboxService expone metodos helper para crear mensajes tipados desde otros modulos:
createChatBookingCreateMessage()— notificacion de reservacreateChatTicketCreatedMessage()— nuevo ticketcreateChatTicketAssignedMessage()— ticket asignadocreateChatShiftCreatedMessage()— turno creadocreateChatPropertyAssignedMessage()— propiedad asignadacreateGuideIncompleteMessage()— guia incompletacreateAIDailySummaryMessage()— resumen IA diario
Tickets via Automation Engine (ticket.*)
Los avisos de ticket no pasan por los helpers createChatTicket*Message()
de arriba (ese camino ad-hoc se retiro con VIV-2081) — llegan al buzón vía el
motor de notificaciones (apps/backend/src/notifications/engine/), que
escribe directamente en inbox_messages cuando el flow tiene una accion con
canal tools_inbox. En este camino las filas quedan con
message_type: 'automation' y source_tool: 'notifications'; el tipo de
evento real vive en metadata.event_type.
Eventos emitidos por ticket-events-emitter.service.ts (uno por transicion,
nunca dos para el mismo cambio logico):
Flows + plantillas:
171_seed_ticket_notification_flows.sql (created,
updated, assigned, comment_added) y 178_seed_ticket_resolved_notification_flow.sql
(resolved). Todos avisan a creador + asignado por tools_inbox + email,
excluyendo al actor del cambio y deduplicando cuando creador == asignado
(skipIfTargetEquals).
Metadata enriquecida para la card del buzón
Para que la card del sidebar (TicketMessageCard, en
apps/frontend/app/components/inbox/) se pinte sin un fetch adicional a
getTicket, el motor añade un bloque metadata.ticket solo para eventos
ticket.* (aditivo — no toca el shape de metadata de otros flows):
metadata.ticket son best-effort (la resolucion de
contexto en el emitter puede fallar en un miss puntual) — el frontend
degrada campo a campo en vez de todo-o-nada. message.deepLink es siempre
null para estos mensajes; el link se construye en el cliente como
/app/tickets/list/{ticketId} a partir de metadata.aggregate_id.