Skip to main content

OdontoX Enterprise — Multi-Branch Organization Design

Date: 2026-06-11
Status: Approved
Client: DentoCorrect (dentocorrect.pk) — Pakistan’s first ISO-certified dental chain, 11+ branches, targeting 40

1. Background

DentoCorrect is a corporate DSO (Dental Service Organization) — centrally owned, standardized protocols across all branches, no franchise. They currently have no integrated clinic management platform (likely Excel/ad-hoc). OdontoX is greenfield here. Key requirements:
  • One account for the whole org (head office sees all branches)
  • Each branch is fully isolated (patients, staff, appointments are per-branch)
  • Cross-branch analytics and reporting from day one
  • Shared protocol/template management from head office
  • Scales from 11 to 40 branches without re-architecture
  • Dedicated compute — no shared DB with other OdontoX tenants

2. Instance Model (Org Island)

DentoCorrect gets a single dedicated OdontoX instance. All branches live inside it as clinic rows. The instance is physically separate from the shared OdontoX platform.
ResourceValue
CF Workerodonto-dentocorrect
CF Pages projectodontox-dentocorrect
Neon databaseodontox_dentocorrect
Default URLdc.odontox.io
White-label URL (add-on)app.dentocorrect.pk → CNAME
Same codebase, same git repo. Isolation is at the deployment layer only — deploy/instances/dentocorrect/ holds the Wrangler config, env template, and instance manifest. No fork, no branch.

White-Label Add-on (PKR ~30k/mo)

  • Custom domain: app.dentocorrect.pk (1 CNAME from their DNS → CF custom domain + SSL)
  • Custom email sender: [email protected] (Zepto sender verification under their domain)
  • Reversible: revert to default URL/sender at any time

3. Data Model

New tables (in the DentoCorrect isolated DB)

organizations
id              uuid pk
slug            text unique  -- 'dentocorrect'
name            text         -- 'DentoCorrect'
plan_tier       text         -- 'enterprise'
billing_contact_email text
white_label_domain    text nullable   -- 'app.dentocorrect.pk'
custom_email_sender   text nullable   -- '[email protected]'
created_at      timestamptz
organization_clinics
organization_id uuid fk → organizations.id
clinic_id       uuid fk → clinics.id
branch_display_name text   -- 'Gulberg, Lahore'
city            text
sort_order      integer
primary key (organization_id, clinic_id)
Existing clinics table is unchanged. organization_clinics is a mapping layer only. organization_templates
id              uuid pk
organization_id uuid fk → organizations.id
type            text  -- 'treatment_plan' | 'prescription' | 'whatsapp_flow' | 'document' | 'fee_schedule'
name            text
content_json    jsonb
created_by      uuid fk → users.id
created_at      timestamptz

New role

org_admin — scoped to organization_id, not clinic_id. Has all clinic_admin permissions across every branch in their org, plus access to the 6 org-level modules. Cannot access data outside their organization (enforced by existing clinic-scoping middleware, extended to check org membership). In the dedicated DentoCorrect instance there is only one organization, so this is implicit — but the model is correct for future multi-org instances.

4. Network Hub — Navigation Model

When an org_admin logs in to dc.odontox.io they land on the Network Hub (/network), not inside a branch. The sidebar shows org-level modules. Branches are listed as drill-down targets at the bottom of the sidebar. Clicking a branch → sidebar transforms to full branch view. A persistent ”← DentoCorrect HQ” back button at the top of the sidebar returns to the Network Hub. Branch staff log in and land on their branch as before. They never see the Network Hub or org-level modules.
◉ DentoCorrect HQ
─────────────────
⬛ Network Overview
📊 Analytics
🏢 Branches
👥 Staff
📋 Templates
💳 Billing
─────────────────
BRANCHES
→ Gulberg, Lahore
→ Johar Town, Lahore
→ Karachi PECHS
→ ...

5. Org-Level Modules

5.1 Network Overview

Live stats grid showing — today’s appointments, revenue (PKR), active branches, and no-show rate — aggregated across all branches. Refreshes in real time via existing TanStack Query patterns.

5.2 Cross-Branch Analytics

Existing analytics module extended with an org-scope filter. Filterable by branch, city, date range. Revenue trends, top treatments, doctor performance, no-show rates. CSV/PDF export.

5.3 Branch Management

  • List all branches with status, city, appointment count
  • Create new branch (provisions a new clinics row + organization_clinics mapping)
  • Configure branch hours, slot snap interval, enabled modules
  • Deactivate a branch (sets clinic status inactive — data retained)

5.4 Staff & Permissions

  • View all staff across the network with their branch assignment
  • Invite a new user to any branch from head office
  • Transfer a doctor between branches
  • Set network-wide role defaults (applied to new branches automatically)

5.5 Shared Templates

Org admin publishes templates to the network. Branch users see inherited templates with an HQ badge. Branches can add their own local templates but cannot delete or override org templates. Template types covered:
  • Treatment plan templates
  • Prescription presets
  • WhatsApp automation flows
  • Document/consent templates
  • Standard fee schedules
New table: organization_templates (org_id, type, content_json, created_by, created_at). All org templates are automatically visible to every branch in the org — no per-branch opt-in required.

5.6 Billing

  • Enterprise plan summary (tier, branch count, seat counts)
  • Add-on management (white-label, storage, etc.)
  • Superadmin invoices directly — no self-serve payment flow
  • Branches cannot change their own plan; only org_admin can

6. Provisioning

Extended provisioning script

scripts/provision-enterprise.sh <slug> <org-name> <default-subdomain> Extends existing provision-instance.sh to also:
  1. Write deploy/instances/<slug>/instance.json with org metadata
  2. Generate wrangler.instance.toml (Worker name, routes, env vars)
  3. Generate .env.template (DATABASE_URL, OPENAI_API_KEY, ZEPTO keys, etc.)
  4. Output seed SQL: INSERT INTO organizations … + first org_admin user
  5. Print operator checklist:
    • Create Neon database odontox_<slug>
    • Fill .env.template and add secrets to CF Worker
    • Run migrations against isolated DB
    • Create CF Pages project odontox-<slug>
    • Add CF Worker route for <subdomain>
    • Run seed SQL
    • Verify login at <subdomain>

Claude Code skill

A new odontox-enterprise-provision skill wraps this script with guided prompts — collects slug, org name, subdomain, billing contact — then runs the script and prints the checklist with copy-ready commands for each step.

7. Billing Model

Enterprise BaseWhite-Label Add-on
Dedicated instance
Unlimited branches
Unlimited staff seats
Unlimited patients/storage
All modules
Network Hub (6 org modules)
Default URL (dc.odontox.io)
Custom domain (app.dentocorrect.pk)
Custom email sender
White-label add-on price~PKR 30k/mo
Billing is manual (superadmin raises invoice → payment → activate), consistent with existing marketplace billing model. Enterprise base price is TBD — to be set by ssh before the DentoCorrect pitch.

8. What Stays Unchanged

  • Existing clinics table and all clinic-scoped logic — branches are just regular clinics
  • Patient records, appointments, treatment plans, documents — always per-branch, never cross-branch
  • Existing roles (clinic_admin, doctor, receptionist) — untouched
  • Existing permission enforcement middleware — extended only at the org layer
  • Superadmin portal — gets a new “Organizations” section to manage enterprise accounts

9. Out of Scope (this phase)

  • Audit & compliance log (excluded by decision)
  • Cross-branch patient transfer (patients are branch-local)
  • Per-branch sub-domains (all branches share the one instance URL)
  • Self-serve enterprise signup (manual superadmin provisioning only)
  • Multi-organization instances (one org per instance for now)