Skip to content

Chatbot Architecture

The WhatsApp conversation engine that powers patient self-service booking.

sequenceDiagram
autonumber
actor P as Patient
participant WA as WhatsApp Client
participant Meta as Meta Cloud API
participant BE as ClinicFlow Backend
participant Redis as Redis (Cache)
participant Claude as Claude Haiku NLU
participant DB as Supabase PostgreSQL
rect rgb(30, 41, 59)
Note right of P: 1. Intent & Auth Phase
P->>WA: "Hola, quisiera agendar una cita"
WA->>Meta: Inbound Message
Meta->>BE: POST /webhooks/whatsapp
BE->>BE: HMAC-SHA256 Signature Verification
BE->>Redis: Check 24h Message Deduplication
Redis-->>BE: Not Duplicate
BE->>Redis: Acquire Per-Phone Concurrency Lock
BE->>DB: Load or Create chat_session
end
rect rgb(15, 23, 42)
Note right of BE: 2. Intelligence Phase
BE->>DB: Fetch Clinic Context & Availability Slots
BE->>DB: Validate bot_enabled and patient status
BE->>Claude: NLU Query (Context + Slots + History)
Claude-->>BE: Response { action: "ask", collected: {...}, reply: "..." }
BE->>Meta: Dispatch WhatsApp Text Payload
Meta->>WA: Deliver Message
WA->>P: "¡Con gusto! ¿Qué día te gustaría venir?"
end
Note over P,BE: Conversation loops until date & time slot are selected
rect rgb(3, 105, 161)
Note right of P: 3. Booking & Confirmation
P->>WA: "Mañana a las 3:30 PM"
WA->>Meta: Inbound Message
Meta->>BE: POST /webhooks/whatsapp
BE->>Claude: NLU Evaluation
Claude-->>BE: Response { action: "confirm", readyToConfirm: true }
BE->>DB: Verify Slot Availability & Insert Appointment
BE->>BE: Enqueue BullMQ Reminders (24h + 2h)
BE->>Meta: Dispatch Interactive Confirmation Card
Meta->>WA: Deliver Interactive Buttons (Confirm / Edit / Cancel)
WA->>P: "✅ Cita reservada — Mañana 3:30 PM"
BE->>Redis: Release Concurrency Lock
end
stateDiagram-v2
[*] --> IDLE
IDLE --> COLLECTING_DATE : Inbound Message
COLLECTING_DATE --> COLLECTING_TIME : Date Selected
COLLECTING_TIME --> COLLECTING_NAME : Time Selected
COLLECTING_NAME --> CONFIRMING : Name Confirmed
CONFIRMING --> CONFIRMED : Button Click / Confirmation
CONFIRMED --> [*]
state IDLE {
[*] --> Waiting
}
COLLECTING_DATE --> IDLE : RESET / Timeout
COLLECTING_TIME --> IDLE : RESET / Timeout
COLLECTING_NAME --> IDLE : RESET / Timeout
CONFIRMING --> COLLECTING_DATE : EDIT_BOOKING Click

Each state is tracked in chat_sessions.current_state with collected fields stored in chat_sessions.collected_fields (JSONB).

The system prompt injects live clinic context:

  • Clinic name and address
  • Doctor names and specialties
  • Real-time availability slots for the requested date
  • FAQ entries for keyword matching
Button ID Action
CONFIRM_BOOKING Short-circuit: write appointment, send confirmation
EDIT_BOOKING Reset to COLLECTING_DATE
CANCEL_BOOKING Cancel appointment flow
RESET Reset entire conversation
RECALL_REPLY_* Dental recall campaign responses

Short-circuits skip the Claude API call entirely — faster and cheaper.