Skip to main content

Tenant Isolation Audit: PDF, WhatsApp, Notifications

Audit date: 2026-06-08

Scope

  • PDF tenant/clinic branding and letterhead resolution
  • WhatsApp clinic naming, inbound routing, and unknown-sender handling
  • Notification preference isolation and clinic-scoped dispatch

Summary

The audited Sprint 2 paths are largely clinic-scoped already. No active hardcoded "Dental Square" dependency was found in the reviewed WhatsApp, PDF, or notification execution paths. The remaining work completed in this pass was to keep unknown WhatsApp inbound traffic inside the inbox, expose the sender’s number when no patient match exists, and keep visiting-doctor booking alerts behind a clinic preference.

Audited Areas

PDF

Reviewed paths:
  • server/src/pdf/PatientInvoicePdf.tsx
  • server/src/routes/public-documents.ts
  • related tenant-aware resolver usage in invoice/document generation paths
Result:
  • Letterhead resolution is clinic-aware.
  • No branch name hardcoding found in the reviewed PDF generation path.

WhatsApp

Reviewed paths:
  • server/src/routes/whatsapp-webhook.ts
  • server/src/routes/whatsapp.ts
  • server/src/routes/conversations.ts
  • server/src/lib/whatsapp.ts
  • server/src/lib/whatsapp-assistant-dispatch.ts
  • server/src/lib/ai/whatsapp-knowledge.ts
  • ui/src/components/chat-v2/inbox/ConversationRowMenu.tsx
Result:
  • Unknown inbound WhatsApp messages now land directly in inbox conversations.
  • Unknown senders are labelled with their phone number instead of a hardcoded "Unknown" identity.
  • Unknown inbound is not pushed into leads. This is an explicit product decision for this sprint.
  • Inbox operators can mark those conversations as spam.
  • Inbox operators can convert an unknown sender into a patient record directly from the conversation menu.
  • Clinic naming in assistant and messaging paths resolves from clinic data or neutral fallback copy rather than a fixed clinic string.

Notifications

Reviewed paths:
  • server/src/lib/appointment-notifications.ts
  • server/src/lib/email-gate.ts
  • server/src/routes/clinics.ts
  • ui/src/components/settings/NotificationSettings.tsx
Result:
  • Notification matrix remains clinic-scoped.
  • Appointment email dispatch respects clinic preferences.
  • Visiting-doctor booking alerts now have an explicit clinic-level toggle instead of implicit always-on behavior.

Findings

  1. No cross-tenant clinic-name hardcode was found in the audited execution paths.
  2. Unknown WhatsApp inbound previously had lead-creation behavior in flight; the current sprint direction correctly keeps these messages in the inbox instead.
  3. Notification isolation is strong where dispatch passes through the existing clinic preference gate.

Residual Risks

  • Any future background job or assistant prompt path that bypasses email-gate could weaken notification isolation.
  • Any new WhatsApp entrypoint must continue resolving clinic context before creating or broadcasting conversations.
  • Shared/group reporting work must aggregate across clinics on the read side only and must not loosen transactional clinic boundaries.

Recommendation

Keep clinic-scoped routing as the default contract for PDF assets, WhatsApp inbox traffic, and notifications. New features should extend the existing gate/resolver layers instead of introducing parallel shortcuts.