Skip to content

Communications

Outbound customer and staff messaging — segmented WhatsApp/email reminders, two-way WhatsApp inbox, and staff push notifications.

Scope

This module covers external comms to customers plus internal push blasts. One-to-one internal chat lives under /internal/chat (see docs/features/internal.md).

Pages

  • src/pages/communications/Communications.tsx — reminder composer + scheduled queue at /communications.
  • src/pages/communications/WhatsAppInbox.tsx — live two-way WhatsApp conversation list at /whatsapp.

Route guards (src/App.tsx:179-180):

<Route path="/communications" element={<ProtectedRoute requiredPermissions={['customers.view']}><Communications /></ProtectedRoute>} />
<Route path="/whatsapp" element={<ProtectedRoute requiredPermissions={['customers.view']}><WhatsAppInbox /></ProtectedRoute>} />

Permission drift

Both routes use customers.view today. Tracked as drift item #4 in docs/PERMISSIONS.md §8 — should migrate to a dedicated communications.view.

Channels supported

Channel Surface Delivery backend
WhatsApp (outbound) Reminder composer, WhatsApp Inbox WhatsApp Cloud API, configured via Admin → Integrations. getWhatsAppConfig() must return a valid config or the inbox shows a config error.
WhatsApp (inbound) WhatsApp Inbox Inbound webhooks into WhatsAppMessage + WhatsAppContact tables. Realtime subscription via Supabase.
Email Reminder composer Resend provider (configured under Admin → Integrations)
Push Staff Push card (StaffPushCard) Supabase Edge Function push-send. Targets only devices with push enabled under Settings → Security.
Call / SMS / in-app Log Contact dialog on Approvals, Requests, WhatsApp Manual log only — no actual SMS send wiring exists today.

Surface: Communications (/communications)

Three sub-cards on the same page (Communications.tsx:554 onwards):

Reminder Composer

Target customers by segment and channel:

Segment Meaning
All Active Any customer with ≥1 active (non-cancelled, non-rejected) booking
Payment Due Active customers with balanceAmount > 0
Visa Pending Customers whose visa case is not approved/rejected/collected/completed
Departure in 7 Days Customers whose group departs in the next 7 days

Quick templates map to segments: Payment Due, Passport & Documents, Travel Readiness.

Delivery modes: Send now or Schedule (uses DateTimeInput).

All sends go through POST /operations/communications (batched via Promise.allSettled).

100-recipient cap

The client refuses to send to more than 100 recipients in one batch.

Staff Push Notification (StaffPushCard)

  • Target: all staff, by role, or a specific user.
  • Title (≤80 chars), body (≤200 chars), optional click-through URL.
  • Invokes Edge Function push-send with a bearer token from the current Supabase session.
  • Counts successes ("Sent to N of M subscribed devices") — non-subscribed devices are silently skipped.

Scheduled Queue

Read-only list of up to 12 pending items from GET /communications/queue?status=pending&limit=12. Updated optimistically when Schedule is used.

Surface: WhatsApp Inbox (/whatsapp)

Full two-way chat window (WhatsAppInbox.tsx):

  • Contact list with unread + last-message preview.
  • Conversation pane with per-message status icons (sent → delivered → read → failed).
  • Quick templates (QUICK_TEMPLATES from src/types/whatsapp.ts).
  • RealtimesubscribeToMessages() + subscribeToContacts() keep the list and open thread live.
  • New chat dialog uses PhoneInput to look up or create a contact with findOrCreateContact().

Contact resolution

A WhatsApp contact can be linked to a Customer, an Agent, or stand alone as a bare phone number. Display name falls back through displayName → customer → agent → profileName → +phone (getContactDisplayName in WhatsAppInbox.tsx:65).

API endpoints

Method Path Purpose
GET /operations/communications Log list (filters: entityType, entityId, limit)
POST /operations/communications Create a log entry; triggers actual delivery if channel is WhatsApp/email and sendNow !== false
GET /communications/queue?status=pending Scheduled queue
Edge fn push-send Staff push delivery
Supabase RPC / table ops whatsapp_contacts, whatsapp_messages Two-way WhatsApp

Permissions

Action Permission Enforcement
View /communications or /whatsapp customers.view Route guard (drift)
Send communication admin.users.edit Server gate in handleOperationsCommunications, src/lib/api.ts:13201 (drift — should be communications.create)
Send staff push Authenticated staff session Edge function validates bearer; no matrix permission today
View scheduled queue customers.view Inherits route
  • Admin → Integrations (Resend + WhatsApp Cloud API setup) → docs/features/admin.md.
  • Push opt-in / opt-out per device → docs/features/settings.md.
  • Internal staff chat → docs/features/internal.md.