Sockets
El frontend usa socket.io-client con dos servicios que abren cada uno su propia conexión al namespace /chat de environment.socketUrl, con transports: ['websocket']:
| Servicio | Archivo | Eventos |
|---|---|---|
ChatSocketService | core/services/ui/chat-socket.service.ts | Tickets, mensajes, notas, WhatsApp, mensajes programados (SOCKET_EVENTS) |
InternalChatSocketService | core/services/ui/internal-chat-socket.service.ts | Chat interno entre agentes (IM_SOCKET_EVENTS, prefijo im:) |
Las constantes están en core/helpers/global/chat-socket.constants.ts e internal-chat-socket.constants.ts; los payloads tipados en core/interfaces/ui/chat-socket.interface.ts. Contraparte en el backend: Chat.
Ciclo de vida
ContentComponentconecta ambos servicios cuando el perfil tiene_idy los desconecta enngOnDestroy.ChatPageComponentyInternalChatPageComponenttambién llaman aconnect; es idempotente (si ya está conectado no hace nada, y reutiliza el socket existente para no duplicar listeners).- Al evento
connectemiteauthenticatecon{ sendType: 'agent', token, userId, lang, isPaused? }. Eltokenes el JWT del agente (el mismo dex-api-key); el backend deriva el tenant del usuario, no se envía ningún token de tenant. - Estado de conexión:
ChatConnectionStatus = 'idle' | 'connecting' | 'authenticated' | 'error', expuesto enconnectionStatus$(lo consumeconnection-status-bar, que combina ambos sockets). reconnected$emite en cada reautenticación posterior a la primera: los socket.io no reenvían los eventos perdidos durante la caída, quien escuche debe recargar su estado.- Reintento acotado ante
io server disconnect: hasta 5 reintentos con espera creciente de 1 s por intento (SERVER_DISCONNECT_MAX_RETRIES,SERVER_DISCONNECT_RETRY_DELAY_MS), porque socket.io no reintenta ese motivo por sí solo. - Modo pausa del agente:
setAgentStatus(isPaused)emiteset-agent-status;isPaused$refleja el valor y se reenvía al autenticar.
Eventos emitidos por el frontend (chat)
| Evento | Método | Payload |
|---|---|---|
authenticate | interno | AuthenticateEmit |
join-ticket / leave-ticket | joinTicket, leaveTicket | { ticketId } |
send-message | sendMessage | { ticketId, content, parentId?, signature? } |
send-file | sendFile | { ticketId, fileId, parentId?, caption? } |
send-note | sendNote | SendNoteEmit |
mark-read | markRead | { ticketId } |
message-delivered | markDelivered | { ticketId, messageIds } |
set-agent-status | setAgentStatus | { isPaused } |
MessageService no tiene método de alta: el envío de mensajes, archivos y notas del agente usa estos emits. El enrutado al canal (WhatsApp, Instagram, Web) lo resuelve el backend; ver Meta.
Eventos recibidos
| Evento | Observable / efecto |
|---|---|
authenticated, exception, connect_error, disconnect | Actualizan connectionStatus$ |
new_message, new-file-message, new_note | newMessage$, newFileMessage$, newNote$ |
ticket-joined | ticketJoined$ |
message_ack_changed | messageAckChanged$; payload { ticketId, messageIds, ack, at, failureReason? } |
ticket_updated | Despacha ticketUpdatedFromSocket + ticketUpdated$ |
ticket_assigned | Despacha ticketAssignedFromSocket + ticketAssigned$ |
ticket_created | ticketCreated$ |
ticket_status_changed | Despacha ticketStatusChangedFromSocket + ticketStatusChanged$ |
ticket_reactivated, ticket_deleted | Despachan la acción de NgRx y emiten el subject |
ticket_lock_changed | Despacha ticketLockChangedFromSocket |
contact_presence_changed | Despacha contactPresenceChangedFromSocket |
scheduled_message_sent, _cancelled, _failed, _created, _updated | Acciones del slice scheduledMessages |
whatsapp_qr | whatsappQr$: { connectionId, qr } |
whatsapp_session_status | whatsappSessionStatus$: { connectionId, sessionState, phoneJid? } |
Consumo por componentes
ChatConversationComponentfiltramessageAckChanged$por su ticket y llama aapplyAck; ver Estado failed.ChatListComponentdespachaticketLastMessageAckChangedyticketClearUnread(cuandoack === 'read').ConnectionsTableComponentyConnectionWhatsappModalComponentescuchanwhatsapp_*para pintar el estado de la sesión y el QR; ver UI de conexiones.
Chat interno (im:)
Eventos emitidos: im:join-conversation, im:leave-conversation, im:send-message, im:mark-read, im:typing, im:stop-typing. Eventos recibidos: im:conversation-joined, im:new-message, im:conversation-created, im:conversation-updated, im:group-updated, im:member-added, im:member-removed, im:messages-read, im:presence-changed, im:user-typing, im:user-stop-typing. Autentica con el mismo evento authenticate y comparte los eventos de estado (authenticated, exception, connect_error, disconnect).