Skip to content

Live chat transfer (escalated.admin.chat.transfer) and chat.transferred - #146

Merged
mpge merged 2 commits into
mainfrom
feat/chat-transfer
Oct 23, 2026
Merged

mpge merged 2 commits into
mainfrom
feat/chat-transfer

Conversation

@mpge

@mpge mpge commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Ports escalated-laravel's live chat transfer (ChatController::transfer, ChatSessionService::transferChat), so this package can emit chat.transferred (ADR 2026-10-21 event vocabulary), as escalated-go #167 and escalated-phoenix #176 did.

What

  • POST /escalated/api/agent/chat/{sessionId}/transfer, behind the agent check like the rest of the agent chat API.
  • POST /escalated/agent/chat/{session}/transfer from the agent's browser session (agent gate + CSRF, like End Chat in Serve escalated.admin.chat.end from the agent UI session #145), registered in UiRoutes as escalated.admin.chat.transfer (Laravel's name), so the shared Agent/TicketShow transfer menu, which passes chat_session_id, reaches it. Both share one handler.
  • Body {agent_id, department_id} (either or both); the shared ChatActionBar body {type, id} is accepted too.
  • Agent given: session and ticket reassigned. Department only: ticket and session move there, chat goes back to the queue (unassigned, waiting, acceptedAt cleared) and chat routing runs again for the new department. Same semantics as Laravel; the ticket is updated directly (as Laravel does), and a re-route goes through accept.
  • 422 for no target, a non-integer or unknown department, an ended chat, or an agent who is not active staff or cannot be assigned the ticket in its new department (TicketAccess.canAssign); a refusal rolls back. 404 unknown session. Response {"message": "Chat transferred.", "session": {...}}.
  • ChatEvent.Type.TRANSFERRED with getTransfer(); webhook data adds from_agent_id, to_agent_id, to_department_id (no widget token). EventNames.EMITTED now includes chat.transferred, so the webhook form and workflow builder offer it.

Tests

ChatTransferTest through MockMvc and the real context: route name, agent transfer (webhook data + workflow run), department transfer with re-routing, department transfer with no agent (waiting), both, ChatActionBar body, refusals (anonymous, no target, blank target, unknown/non-integer department, unknown agent, non-staff, inactive agent, unknown session, ended chat) with no event sent. All 8 red before, green after. AgentChatTransferUiTest covers the named UI route from a browser session (CSRF, non-agent, 422/404). Full suite + checkstyle green on H2, PostgreSQL 17 and MySQL 8.4.

mpge added 2 commits October 22, 2026 21:19
Ports escalated-laravel ChatController::transfer and
ChatSessionService::transferChat as POST agent/chat/{session}/transfer,
named escalated.admin.chat.transfer, and emits chat.transferred to
webhooks and workflows.
The page posts escalated.admin.chat.transfer from the browser session,
which the stateless API chain ignores, so the name now points at
POST /escalated/agent/chat/{session}/transfer, as End Chat does.
@mpge
mpge merged commit bf1e1f6 into main Oct 23, 2026
4 checks passed
@mpge mpge mentioned this pull request Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant