No-show recovery, warm lead nurture, and long-term drip sequences
Re-engagement starts automatically — no one has to notice the gap or remember to follow up. Three distinct triggers kick off the process: a patient no-shows for a confirmed appointment, a warm lead goes quiet after initial contact, or a converted patient hasn't rebooked within the expected window after completing a care plan.
src/nurture.jssrc/contacts.js → markWarmLead() (line 270)
booking.noShow webhook when a patient misses their appointment. The webhook handler marks the contact and queues a re-engagement job immediately.
markWarmLead() in contacts.js tags the contact, and an inactivity check fires enrollment.
contacts, nurture_enrollmentsOnce a trigger fires, Karen selects the right sequence based on the contact's situation. Each sequence is sized and paced for the relationship: a warm lead that ghosted needs gentle re-entry over two weeks; a no-show needs faster, more direct outreach; a lapsed patient gets a warmer "we miss you" tone that acknowledges the prior relationship.
src/nurture.js → enrollContact(), createSequence(), activateSequence()
enrollContact() checks whether the contact is already in an active sequence (no double-enrollment). createSequence() builds the appropriate sequence definition based on trigger type:
activateSequence() schedules each step as a BullMQ delayed job. The jobs sit in the queue and fire at the right time without any manual intervention.
nurture_sequences, nurture_steps, nurture_enrollmentsOver the coming days and weeks, Karen sends personalized messages — not generic blasts. She remembers what procedure the patient asked about, references their previous conversation, and varies the content type across the sequence. A 5-touch warm lead sequence looks like this: Day 1 (helpful information about the procedure they asked about), Day 3 (social proof — a patient story or result), Day 7 (a limited-time offer or availability nudge), Day 10 (educational content that deepens the "why"), Day 14 (a final, direct booking nudge).
src/nurture.js BullMQ worker (processes queued steps)src/ai.js → chat() (generates personalized content per step)
chat() with the contact's full context — their conversation history, the procedure they asked about, their stated interests, and the step's content objective (info / social proof / offer / education / nudge). Karen generates a unique, personalized message for each contact rather than sending a template. The message is delivered via the contact's preferred channel (WhatsApp or Instagram) through Chatwoot.nurture_enrollmentsAs the sequence runs, Karen pays attention. If a contact opens and replies quickly at 7pm, she notes that timing. If they engage with educational content but skip the offer messages, she adjusts emphasis. Price sensitivity signals — questions about cost, hesitation language — are stored and used to calibrate future messaging tone.
src/actions/engage/preferences.jssrc/contacts.js → contact_preferences table
contact_preferences with a confidence score that increases with each matching signal. These preferences feed back into buildContext() on the next interaction, so future messages from Karen — not just nurture steps — reflect what this person actually responds to.contact_preferences, memory_knowledgeIf the patient books at any point during the sequence, the remaining nurture steps are automatically cancelled — no awkward follow-ups after they've already committed. They flow into Journey 2 (booking confirmed) and then Journey 4 (post-care) as normal. If the full sequence completes without a booking, the contact enters a monthly long-term drip: one thoughtful message per month for at least three months, keeping Oshun top-of-mind without being pushy.
src/nurture.js (auto-cancellation on booking event)
booking.created webhook triggers a lookup of all active nurture enrollments for that contact. Any pending steps are cancelled by removing them from the BullMQ queue. If no booking occurs after the final step, the system creates a low-frequency drip enrollment — one message per month — and schedules the first job 30 days out.nurture_enrollments, nurture_steps