Appointments created via WhatsApp had null patientId — lookup_appointments
couldn't find them. Now resolves patient before booking and includes
patientId in the createAppointment mutation. Fixed in both flow tool
registry and legacy messaging service.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Groups + Blocks execution model adapted from Typebot:
- FlowExecutionService: walks through groups/blocks, pauses at InputBlocks
- FlowSessionService: Redis-backed session state (24h TTL)
- FlowStoreService: loads flow definitions from data/flows/ JSON files
- FlowVariableService: {{variable}} interpolation + expressions
- ToolRegistry: registered tool handlers (departments, doctors, slots, booking)
- Default appointment-booking.json flow seeded on first run
MessagingService delegates to flow engine when published flows exist,
falls back to hardcoded AI chat otherwise (backward compatible).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Check for duplicate patient+doctor+date and max 3 slots per time before
creating the appointment. Returns actionable message if conflict found.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Matched the working agent tool mutation — platform expects 'status'
for AppointmentCreateInput, not 'appointmentStatus'.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
WhatsApp list messages have strict limits: section title max 24 chars,
row title max 24 chars. Long doctor names + dates in section titles
caused Gupshup to silently drop the list options.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
AI wasn't calling send_slot_list after doctor selection because it didn't
know how to extract doctorId from "doc:{uuid}:{name}" format. Updated
system prompt with explicit selection_id parsing instructions for each
step of the booking flow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Gupshup list_reply has empty id field — postbackText carries our ID.
Fixed ?? to || fallback. Also inject selection_id into user message so
AI can extract doctorId from "doc:{uuid}:{name}" format.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Was reading non-existent availableSlots field. Now reads raw visitSlots,
matches target date's day-of-week, and generates hourly time slots from
startTime to endTime. Doctors with 08:00-20:00 get 10 hourly options.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
AI was asking "which department?" in text instead of sending the
interactive list. Updated system prompt to be prescriptive: IMMEDIATELY
call send_department_list, never ask in text. Also injects hospital name
from theme config.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Provider-agnostic WhatsApp integration for AI-driven appointment booking:
- MessagingProvider interface (sendText, sendButtons, sendList, parseInbound)
- GupshupProvider implementation (Gupshup WhatsApp API)
- MessagingService — AI orchestration with tools (department/doctor/slot
lists via interactive WhatsApp messages, appointment booking, caller
resolution + context injection)
- Redis conversation history (24h TTL, matches WhatsApp session window)
- Webhook controller at POST /api/messaging/webhook
Swappable to Ozonetel or Meta Cloud API by implementing MessagingProvider
and switching MESSAGING_PROVIDER env var.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>