Per-Clinic Notification Preferences + New Crons
Problem
- All clinics get all email notifications regardless of whether they want them — waste of emails
- No missed-appointment emails exist yet
- No post-appointment feedback/Google Review email exists
- WhatsApp events fire toasts in the frontend even when the WhatsApp module is OFF for that clinic
- The admin notification settings page has only 2 toggles; needs 3 more
What We’re Building
- Extend
notificationPreferencesJSONB with 3 new fields + Google Review URL - New cron: Missed Appointments email/WhatsApp
- New cron: Feedback & Review email
- Extend
NotificationSettings.tsxwith new toggles (plain language, no jargon) - Gate WhatsApp toasts in the frontend behind module-ON check
- Superadmin: per-clinic notification preferences view
1. Extended notificationPreferences
Schema change (no migration needed — JSONB is additive)
New fields added toclinics.notificationPreferences:
true for reminders (preserves existing behaviour), false for new features (opt-in).
Type update
UpdateNotificationPreferences interface in serverComm.ts and clinics.ts schema type.
2. New Cron: Missed Appointments
File:server/src/scheduled/missed-appointments.ts
Logic
- Run every day at 9 AM UTC (14:00 PKT) — existing
0 9 * * *trigger - Find appointments where:
status = 'confirmed'(never completed/cancelled)appointmentDate= yesterday (PKT)
- Group by clinic
- For each clinic: check
notificationPreferences.missedAppointmentsEnabled === true - For each missed appointment:
- Send email to patient: “We missed you — [clinic name]” — short, friendly message with rebook link
- If WhatsApp module ON for clinic: send
missed_appointmentWhatsApp template (template already exists inwhatsapp.ts:sendMissedAppointment())
- Mark appointment
status = 'missed'after notifying
Guard
- Skip if
missedAppointmentsEnabled !== true - Skip if patient has no email
- No duplicate sends: check if appointment already in
missedstatus
3. New Cron: Feedback & Review Email
File:server/src/scheduled/feedback-email.ts
Logic
- Run every day at 9 AM UTC — existing
0 9 * * *trigger - Find appointments where:
status = 'completed'appointmentDate= 2 days ago (PKT) — give patient time before asking for review- No feedback email already sent (check
feedbackEmailSentAtfield on appointment, or use activity log)
- Group by clinic
- For each clinic: check
notificationPreferences.feedbackEmailEnabled === trueANDnotificationPreferences.googleReviewUrlis set - Send friendly email: “How was your visit? — [clinic name]” with Google Review button
- Mark appointment to prevent duplicate sends
Appointment schema addition
AddfeedbackEmailSentAt timestamp to appointments table (via ensureAppointmentsSchema).
Email template
- Subject: “How was your visit at [Clinic Name]?”
- Body: short thank-you note + prominent “Leave a Review on Google” button
- Footer: clinic address, phone
4. Admin Notifications UI
File:ui/src/components/settings/NotificationSettings.tsx
Current state
Two toggles: inventory alerts, EOD report.New state — 5 toggles total
Section: Patient Emails| Toggle | Label | Default |
|---|---|---|
appointmentRemindersEnabled | Appointment reminders | ON |
missedAppointmentsEnabled | Missed visit follow-ups | OFF |
feedbackEmailEnabled | Post-visit feedback & review request | OFF |
feedbackEmailEnabled is turned ON, show a text input:
“Google Review link — paste your clinic’s Google review URL here so we can include it in feedback emails”Section: Staff Emails (existing)
- Low stock alerts
- End-of-day report
Language rules
- No “cron”, “trigger”, “event”, “notification preference” — plain English only
- Every toggle has a one-line subtitle explaining what it does and when it fires
- Example: “Appointment reminders — We’ll remind patients by email (and WhatsApp if enabled) 24 hours before their visit.”
5. WhatsApp Toast Gating
Problem
WhatsApp-related toasts show in the UI regardless of whether the clinic has WhatsApp configured.Solution
- Fetch WhatsApp module status once on clinic context load:
- Already have
GET /whatsapp/configwhich returns{ isConfigured: boolean, ... } - Store
whatsappEnabled: booleanin clinic context
- Already have
- In every place that shows a WhatsApp toast or triggers a WhatsApp action in the UI:
- Gate:
if (!whatsappEnabled) return— no toast, no action shown
- Gate:
- Affected files: any component that renders WhatsApp send buttons or shows WhatsApp delivery status toasts
Implementation
- Add
whatsappEnabledtoClinicContexttype - Fetch once in
ClinicProvideralongside other clinic data - Export a
useWhatsApp()hook that returns{ enabled: boolean }for simple gating
6. Superadmin: Per-Clinic Notifications
Location: Superadmin portal → Clinic detail page → “Notifications” tab Shows a read-only summary of each clinic’s notification preferences:- Which emails are on/off
- Google Review URL (truncated)
- WhatsApp module status
Out of Scope
- Per-doctor notification routing
- SMS notifications
- Patient-side notification opt-out portal
- Cron execution logs/history UI (separate ops feature)

