← All systems

MK-01 · Case study · Physio Clinic System

A clinic platform,
one isolated copy
per clinic.

How I designed, built and now run a white-label platform for physiotherapy clinics: a bilingual website, a real-time staff dashboard and an API, live in production with We Treat.

Role
Sole engineer · design to operation
Year
2026
Platform
Cloudflare Workers · D1 · R2
Status
Live · wetreatlb.com ↗
01 /

The brief.

Clinics wanted online booking, patient records with treatment history, and a site in Arabic and English. I wanted one product I could sell to many clinics and run alone, safely, for years.

  • Medical data Patient files and treatment notes: who saw what must be provable.
  • Small clinics Running costs have to stay close to zero per clinic.
  • Shared front-desk PCs Strong sign-in, without passwords to forget or share.
  • Non-technical owners Backups, security and updates must happen by themselves.
  • One engineer I build it and run every copy, so operations must be scripted.
  • Two languages Arabic right-to-left is a first-class layout, not a translation.
02 /

The architecture.

Three apps per clinic on Cloudflare’s edge. Hover or tab through the drawing: every part explains itself.

Schematic · Physio Clinic System Data Secured External
bookings REST Patients browser · EN / AR Clinic staff approved devices Website Next.js 16 · RTL Cloudflare Access email code / Google Dashboard Next.js 16 · MobX API Worker Express 5 · Inversify Durable Object live updates D1 · SQLite Drizzle ORM R2 files · backups Cron nightly backups Control API HMAC-signed
Inspect

Website Next.js 16 · RTL

One-page bilingual site branded from the dashboard: services, team, online booking (or WhatsApp when offline).

03 /

Decision records.

D-01

One isolated copy per clinic

Decision
Each clinic gets its own Worker, D1 database and R2 bucket, deployed from one codebase with wrangler deploy --env <clinic>.
Why
No query can ever reach another clinic’s patients, and backup, restore, migration or lock happen per clinic.
Trade-off
Migrations run once per clinic, so deploys and migrations are scripted.

D-02

No passwords: zero-trust sign-in plus approved devices

Decision
The dashboard sits behind Cloudflare Access (email code or Google). The API verifies Access’s signed token and looks the email up among active staff; a new browser stays pending until the owner approves it.
Why
Nothing to leak or reuse; a stolen login alone is useless on an unapproved device, and revoking a device signs it out at once.
Trade-off
Depends on Access, so the Access policy is kept in sync with the staff list automatically. Device tokens are stored only as SHA-256 hashes.

D-03

Roles and an audit log for medical data

Decision
Owner, admin, doctor and reception roles; reception never sees clinical notes. Sign-ins, every change, and every time a patient file is opened are logged.
Why
Clinics can answer “who looked at this patient?” and staff only see what their job needs.
Trade-off
More checks per request; kept in middleware so services stay simple.

D-04

Live dashboards on a Durable Object

Decision
One Durable Object per clinic holds the open dashboards’ WebSockets and fans out every change (a new booking, an approval).
Why
The front desk sees new bookings instantly; with WebSocket hibernation, idle connections cost nothing.
Trade-off
A second runtime piece to reason about, isolated per clinic like the rest.

D-05

A public booking form that can’t be abused

Decision
Rate-limited per IP, optional Turnstile check, at most two pending requests per phone number, and every request waits for staff approval.
Why
The only endpoint open to the internet is also the one bots would target.
Trade-off
A booking isn’t final until staff approve it; that matches how clinics already work.

D-06

Backups an owner never has to think about

Decision
Every night the whole clinic (every table and file) is zipped, encrypted with AES-256 and emailed to the owner’s addresses; any single email can restore everything with a tested script.
Why
Recovery doesn’t depend on me or on one provider; a failed backup sends a “FAILED” email instead of silence.
Trade-off
The archive password lives with the owner, outside the system: without it, no backup opens.

D-07

Moving a live clinic off its old server

Decision
The first clinic ran on a Node/MongoDB backend. A one-way copy script moved every record and file to D1 and R2, keeping the original ids.
Why
Every link and dashboard URL kept working, and row counts were compared after the copy.
Trade-off
Old password hashes were dropped on purpose: staff now sign in with Access.

D-08

A signed control API for the operator

Decision
A separate HMAC-signed API lets my operator panel read status, trigger a backup, approve the owner’s devices, or lock an unpaid clinic to read-only.
Why
Billing and support without touching the clinic’s data; the website stays up even when locked.
Trade-off
Locking is manual by design: no automation can switch off a clinic.
04 /

Proof it holds.

The risky parts are covered by automated tests that run against a real local database, not mocks.

  • PASS Booking race conditions (no double booking under concurrent requests)
  • PASS CORS, cookies and sign-out behaviour
  • PASS Access rules and role permissions
  • PASS Hardening: headers, validation, rate limits
  • PASS Control API signatures
  • PASS Backup restore
05 /

The result.

Need a system like this built, or someone to own one?