Skip to content

Clinical Dental Engine

The Clinical Dental Engine is the core feature of the ClinicFlow Pro tier. Unlike traditional CRM software, ClinicFlow provides a highly interactive, clinically accurate charting engine. The system is split into three primary modules: the Odontogram, the Periogram, and the Treatment Planner.

This engine relies on complex SVG geometry for visual accuracy, specialized UI interfaces for rapid clinical input, and secure backend RPCs for automated plan generation.


1. Tooth Geometry Architecture (toothGeometry.ts)

Section titled “1. Tooth Geometry Architecture (toothGeometry.ts)”

To provide accurate visual representations of clinical findings, the Odontogram does not use static images. Instead, it relies on a dynamic, math-driven SVG geometry engine that distinctively maps Anterior (Incisors, Canines) and Posterior (Molars, Premolars) teeth.

The geometry maps exact viewBox coordinates and hit-targets for tooth surfaces (B, L, M, D, O, I).

  • Posterior Geometry (Molars/Premolars): Uses a 40x56 viewBox. The surfaces are mapped geometrically: the Mesial (M) and Distal (D) zones are calculated as Left and Right Triangles, while the Occlusal (O) zone is represented by a central diamond polygon (M 20 16 L 30 28 L 20 40 L 10 28 Z).
  • Anterior Geometry (Incisors/Canines): Uses a 30x60 viewBox. The Incisal (I) edge is represented as a top band, and the body is split into left and right panels with distinct bottom corner trapezoids.

Because standard SVG path onClick events can be imprecise for rapid clinical clicking, the system utilizes explicit hitTargets (min 44x44 pixels) centered around the visual centroid of each zone, ensuring an accessible and fast charting experience on both desktop and tablet devices.


2. Periogram Interface (PeriogramDial.tsx)

Section titled “2. Periogram Interface (PeriogramDial.tsx)”

Periodontal charting requires massive data entry (6 measurements per tooth, times two for Recession and Pocket Depth). To solve this UX challenge, ClinicFlow abandons traditional spreadsheet views in favor of the Periogram Dial.

The PeriogramDial component mounts an overlay focusing on a single tooth.

  1. Site Clusters: The interface maps 6 sites (mesial-vestibular, central-vestibular, distal-vestibular, mesial-lingual, central-lingual, distal-lingual) around a central graphic.
  2. Abstract State Machine: The user selects either MG (Recesión) or PS (Bolsa) mode.
  3. Periogram Numpad: Clicking the custom PeriogramNumpad immediately updates the state and auto-advances the cursor to the next site. Once all 6 sites are completed for Recession, it automatically cycles to Pocket Depth input.

This dramatically reduces the cognitive load and mouse movement required by the dentist.


3. Automated Treatment Planner (generateTreatmentPlan.ts)

Section titled “3. Automated Treatment Planner (generateTreatmentPlan.ts)”

Once clinical findings are charted on the Odontogram or Periogram, they must be converted into actionable, billable treatment plans.

The API endpoint (POST /api/dental/patients/:patientId/treatment-plans/generate) strictly follows ClinicFlow’s tenant isolation principles. The clinicId is never accepted from the req.body or req.params. It is securely extracted from the authenticated user’s JWT (req.user.clinicId). Zod validates that the array of findingIds are valid UUIDs before processing.

The backend executes a secure Supabase RPC via the chartService, transforming the clinical findings into a logical plan structure. Because generating complex financial quotes can be CPU intensive, the route offloads the final pricing calculations to a BullMQ worker:

flowchart LR
A["Clinician Charts Finding (Odontogram / Periogram)"] -->|POST /api/dental/charts/entries| B["Database RPC (add_dental_finding)"]
B -->|Materializes Chart State| C["dental_chart_current Table"]
C -->|POST /generate-plan| D["RPC (generate_treatment_plan_from_findings)"]
D -->|Creates Plan Record| E["treatment_plans Table"]
E -->|Enqueues Job| F["BullMQ Queue (dental-messages)"]
F -->|Asynchronous Pricing Worker| G["Generates Financial Quote Draft & PDF"]
style A fill:#1e293b,stroke:#0284c7,color:#ffffff
style B fill:#0f172a,stroke:#0284c7,color:#ffffff
style C fill:#1e293b,stroke:#0284c7,color:#ffffff
style D fill:#0f172a,stroke:#0284c7,color:#ffffff
style E fill:#1e293b,stroke:#0284c7,color:#ffffff
style F fill:#0369a1,stroke:#38bdf8,color:#ffffff
style G fill:#0369a1,stroke:#38bdf8,color:#ffffff
// Offload to background worker to prevent request blocking
const job = await dentalQueue.add('generate_quote_draft', {
type: 'generate_quote_draft',
clinicId,
patientId,
planId,
});

The client immediately receives the jobId and planId to subscribe to realtime updates via WebSockets as the quote draft is populated.