Dentolize · CRM Module Walkthrough
On this pageWhat this isWhy it was builtHow the pieces fit togetherWhere it runsRead next

Dentolize CRM Module — Overview

Status: unreleased / beta-gated. Every surface described here ships behind FEATURE_CRM_* feature flags and is intended for controlled beta clinics. Nothing in this module is generally available yet. This walkthrough documents what the code actually does in the PR (feat/crm-module, PR #159), verified against /work/repo — not marketing copy.

What this is

The CRM module turns Dentolize from a clinic-operations system into a full patient-acquisition pipeline. It connects a clinic's paid-social and ad accounts, captures the leads those ads generate, routes conversations from every social channel into one inbox, automates the busywork of following up, measures real return on ad spend against clinic revenue, and asks happy patients for public reviews.

It is built as five cooperating capabilities, each independently flag-gated:

CapabilityOne-line purposeFlag
Social & Ad IntegrationsConnect Meta / TikTok / Snapchat / Google; discover pages, IG accounts, lead forms, ad accountsFEATURE_CRM_INTEGRATIONS_{META,TIKTOK,SNAPCHAT,GOOGLE}
Lead Capture & AttributionTurn ad clicks, form fills, and DMs into deduplicated leads with a full source trail(part of integrations)
Unified InboxOne inbox for WhatsApp, Messenger, Instagram DMs, and FB/IG comments, with SLA timersFEATURE_CRM_INBOX_UNIFIED
Marketing Hub & ROISync campaigns and spend; compute CPL, CPA, ROAS, and revenue-based ROIFEATURE_CRM_MARKETING_HUB
Automation EngineTrigger → condition → action rules for assigning, tagging, moving, and messaging leadsFEATURE_CRM_AUTOMATION
Reviews & ReputationWhatsApp review requests with tracked links, cooldowns, and click trackingFEATURE_CRM_REVIEWS

Why it was built

The module is the follow-up to a lead-management gap analysis. Before it, a clinic's ad budget lived on Meta's dashboard, leads arrived by phone or walk-in with no source attribution, social messages were scattered across apps, and there was no way to prove whether a campaign actually produced paying patients. The CRM closes that loop: ad spend → lead → conversation → patient → revenue → ROI, all inside Dentolize.

How the pieces fit together

  Ad platforms (Meta / Google / …)
        │  signed webhooks + OAuth-synced data
        ▼
  Webhook inbox  ──►  Lead capture  ──►  Lead pipeline (stages)
  (verify→persist       (dedupe by phone,     │
   →enqueue→200)         round-robin,         ├─►  Unified Inbox (SLA timers)
                         attribution spine)    ├─►  Automation rules (assign/tag/move/message)
                                               └─►  Reviews (WhatsApp → tracked /r/ link)
        │
        ▼
  Marketing Hub  ──►  CPL · CPA · ROAS · revenue-based ROI
        │  daily ad spend
        ▼
  Accounting general ledger (optional "Post ad spend to GL")

Two architectural ideas run through the whole module:

  • Everything ingested is idempotent and replayable. Inbound webhooks are

signature-verified, persisted to a durable WebhookEvent inbox, and only then processed. Redeliveries collapse on database unique keys, so a platform can retry a webhook a hundred times and produce exactly one lead. See Lead Capture & Attribution.

  • Two-layer gating. GraphQL Shield permissions decide who may call a mutation;

feature flags decide whether the capability exists for that clinic at all. A user with the right permission but no flag still cannot reach the write path. See Security, Flags & Data Retention.

Where it runs

  • Web app (clinic-web) — the primary surface. OAuth "Connect" flows are

web-only by design; the Marketing Hub, unified inbox, automation builder, and review tools all live here.

  • Mobile app (clinic-mobile) — a near-complete companion: inbox, automations,

reviews, marketing dashboards, and integration management (view / refresh / disconnect / map assets). It cannot initiate an OAuth connection.

  • Gateway service (whatsapp-official) — hosts the public webhook endpoints, the

BullMQ queue workers, and the automation executor.

  • API server (server) — GraphQL API, permissions, and the scheduled cron jobs

that reconcile counters, sync insights, and redact old data.

screenshots from the beta sandbox.

  • Presenting it to a team? Jump to your By team page.
  • Building or testing against it? The In depth pages carry file:line

references into the code.

  • Wondering what's not done, or why the PR contains more than CRM? Read

Scope, Gaps & Honest Notes first.