Documentation

Messaging overview

Real-time chat with presence, queue routing, and AI assistant hand-off — backed by a single WebSocket gateway.

The Messaging module powers live conversations between customers and staff. One namespace, one Redis-backed presence store, one queue. The same socket carries customer widget traffic and the agent admin console — role is derived from the JWT and gating happens server-side.

What's in the box

  • ChatGateway — Socket.IO gateway at namespace /chat. Customers and agents both connect here. JWT in the handshake; role (customer vs agent) is derived from the principal datatype, never from the client.
  • ChatService — REST endpoints under /chat/* for message CRUD, history, transcripts, file uploads, and chat config lookup.
  • ChatPresenceService — Redis-backed online/away/offline state for agents and customers. Multi-pod safe. Identity sets, per-socket TTLs, keyspace-expiry timers for inactivity timeouts.
  • ChatQueueService — Sorted Redis queues with priority and skill-based routing. ETA = ceil(position / availableAgents) * avgHandleTimeSeconds.
  • AI assistant integrationAIAssistantService streams tokens straight into the chat room. AI chats can be observed live by agents and handed off via transfer_chat_to_agent.
  • WebRTC bridge — Agents can broadcast audio/video to customer widgets using ICE servers from GET /chat/ice-servers.

How a customer chat actually flows

  1. 1

    Customer connects

    The widget opens a socket to /chat with { token, orgId, context } in the handshake. Server verifies the JWT, derives role = 'customer', joins the customer to:

    • identity:{orgId}:customer:{email} — every tab/device for this user
    • chat:{orgId}:{chatId} — the active conversation

    If context.configId is set, the server resolves the chat config and sends the AI greeting on first connect.

  2. 2

    Customer sends chat-message

    If the config has an ai assistant and no human agent is assigned, the message goes to AIAssistantService.executeStream(). Tokens stream back as chat-stream events (event: 'chunk' | 'tool-use' | 'tool-result' | 'end').

    If there's no AI configured, no assistant selected, or the chat has been transferred — the message is enqueued via ChatQueueService and online agents are notified with queue-notification.

  3. 3

    Agent picks up

    An agent emits pick-next. The customer is moved out of the queue, both parties are joined to the same chat room, an "agent has joined" system message is broadcast, and inactivity timers start ticking (4-min warning, 30-min hard close).

  4. 4

    Either side can transfer or end

    Agents can transfer-chat, takeover-chat (from AI), resume-ai, or close-chat. Each emits structured events that update the customer widget without a reload.

Where to go next

The chat namespace is the same across customers, staff, and broadcast viewers. Authentication and per-handler ACLs decide what each role can do — there are no separate "customer" and "agent" gateways.