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:
- Human coordinator joins the same chat conversation — real-time messaging alongside the AI, with handoff/takeover semantics
- Coordinator dashboard — separate admin view of the case with chat, internal notes, case status, and document management
- 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_typefield 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¶
-
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.
-
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.
-
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.py—sender_typefield addedconfig/feature_flags.yaml—enable_response_streaming(enabled)- SSE endpoints:
cases.py:935(chat tokens),cases.py:855(messages),documents.py:286(doc progress)