Skip to content

ADR-0015: Coordinator Interaction Model

Status: Accepted Date: 2026-04-10 Decision Makers: Srikanth Donthi (CPO/CTO)

Context

Curaway currently supports one interaction mode: AI ↔ Patient via the conversational UI. As the platform moves toward production with real patients, human coordinators need to interact with patients for tasks the AI cannot handle — visa coordination, hospital scheduling, payment processing, and clinical clarifications requiring human judgment.

Three interaction modes are needed:

  1. Human coordinator joins the same chat conversation — real-time messaging alongside the AI, with handoff/takeover semantics
  2. Coordinator dashboard — separate admin view of the case with chat, internal notes, case status, and document management
  3. Out-of-band channels — phone calls, WhatsApp, email logged back to the case timeline

Decision

Transport: SSE now, WebSocket when coordinators come online

Phase 1 (now): SSE for AI ↔ Patient streaming. Already built (Session 31), production-ready, zero additional complexity.

Phase 2 (post-seed): WebSocket for coordinator ↔ patient real-time chat. SSE is unidirectional — when two humans need real-time messaging in the same conversation, WebSocket's bidirectional channel is the right choice. The migration is additive — SSE endpoints remain for backward compatibility, WebSocket layer added alongside.

Rationale for not starting with WebSocket: - AI chat is request/response — patient sends, AI responds. No simultaneous typing from both sides. SSE is sufficient. - WebSocket adds connection manager, heartbeat, reconnection, state tracking — complexity that's premature without coordinators. - SSE works through all CDNs, proxies, and corporate firewalls. WebSocket requires specific proxy configuration. - The Redis pub/sub layer is transport-agnostic — same RPUSH/LPOP pattern works for SSE polling and WebSocket push.

Data model: sender_type field on messages

Added sender_type column to the Message model: - ai — response from Claude/GPT (default, backward-compatible) - patient — message from the patient - coordinator — message from a human coordinator

This is a non-breaking additive column with server_default="ai", so existing messages are unaffected. The field enables the frontend to render different message styles per sender (e.g., coordinator messages with a staff badge, AI messages with the Curaway avatar).

Escalation model (Phase 2 design)

Patient: "Can someone help with my visa?"
AI:      [detects escalation intent]
AI:      "Let me connect you with a coordinator who can help with visa logistics."
         [emits escalation event → coordinator dashboard]
Coordinator: [accepts the case]
Coordinator: "Hi Aisha, I'm Priya. I'll help with your visa letter."
         [AI pauses auto-responses while coordinator is active]
Patient: "Thanks! What documents do I need?"
Coordinator: "You'll need: 1. Passport copy, 2. Medical visa letter from the hospital..."
Coordinator: [releases case back to AI]
AI:      [resumes auto-responses]

Key design rules: - AI pauses when coordinator is active — no competing responses - Coordinator sees full context — conversation history, EHR, documents, match results, patient preferences - Internal notes — coordinator can add notes the patient doesn't see (message.role = "system", sender_type = "coordinator") - Handoff is explicit — coordinator accepts/releases, not automatic

Consequences

Positive

  • Platform supports the full patient journey (AI intake → human coordination → provider communication)
  • sender_type field is zero-cost to add now, eliminates a schema migration later
  • Transport decision (SSE now, WS later) avoids premature complexity

Negative

  • Phase 2 requires a coordinator dashboard (new frontend, separate auth roles, admin routes)
  • WebSocket migration adds infrastructure complexity (connection manager, reconnection, state sync)
  • Escalation flow needs intent detection in the AI (new classifier category)

Risks

  • Coordinator dashboard becomes a large feature (scope creep). Mitigate: build the thinnest viable coordinator view first — just a chat thread
  • case summary, no full admin panel.
  • WebSocket connection management on Railway — monitor concurrent connections. Railway Pro supports WS natively but connection limits are shared with HTTP.

Alternatives Considered

  1. WebSocket from day one — rejected because AI chat doesn't need bidirectional streaming, and it adds 2-3 weeks of infrastructure work before any user benefit.

  2. Third-party chat SDK (Intercom, Zendesk) — rejected because clinical context (EHR, match results, documents) must be inline in the conversation, not in a separate widget. Third-party SDKs don't support rich clinical cards.

  3. Email-only coordination — rejected because real-time messaging is expected by patients in a healthcare context. Email introduces delays that erode trust.

References

  • Session 35 streaming architecture assessment
  • app/models/message.pysender_type field added
  • config/feature_flags.yamlenable_response_streaming (enabled)
  • SSE endpoints: cases.py:935 (chat tokens), cases.py:855 (messages), documents.py:286 (doc progress)