ClinicPulse
A multi-tenant clinic management system.


- Project
- Our own product
- Our role
- Architecture · Full stack · Integrations
- Duration
- 4 months
01 / Behind the product
A real need. A considered solution.
Challenge
Doing tenant isolation in the application layer is risky for health data; one missing filter exposes another clinic’s patient record. Reminders had to go over WhatsApp, but Meta templates are per-language and approved per clinic.
Approach
Tenant isolation lives in the database: ten tables and 34 row-level-security policies, with no reliance on application code behaving. Profiles, clinics, staff, subscriptions, patients, appointments, treatments, documents and WhatsApp logs share one schema; sensitive fields are encrypted with AES-256-GCM. The WhatsApp Cloud API integration picks the template by the clinic’s language; 24-hour reminders fire from a cron route and the send endpoints are rate-limited. Staff join through invite links; a platform admin manages clinics and subscriptions from a separate panel.
Result
Adding a clinic is one row; no separate deployment. Turkish and English interfaces, PDF templates, a blog and an eight-file unit test suite. Live as an installable PWA.
02 / Inside the product
The experience, on screen.
Open a screen to explore the details.03 images
03 / Scope & details
The details make the experience.
- 01
Tenant isolation through database row-level security
- 02
Appointments, treatments and billing in one model
- 03
WhatsApp reminder integration
Technology
Next.js / Supabase / PostgreSQL
INSIDE THE PRODUCT
The engineering behind the interface.
Systems we built and concrete problems we addressed in this project.
34 policies, zero application filters
The first migration creates ten tables and row-level security together, with admin policies in a separate migration. Tenant isolation never relies on application code remembering where clinic_id = ….
WhatsApp templates are per-language
lib/whatsapp.ts talks to the Meta Graph API; because templates are per-language, a clinic must carry an approved template for its own language. The 24-hour reminder runs from api/cron/reminders, and the send endpoint is capped at ten requests a minute.
Field encryption and tests
lib/encryption.ts uses AES-256-GCM with a 12-byte IV and an enc: prefix; the key is a 64-character hex string and the app refuses to start without it. The Vitest suite covers admin, API, constants, env, i18n, subscriptions, utils and validations.
Your idea could be next.
What could we build for you?
From a first release to a growing platform. Let’s plan the design, development and launch together.
From Türkiye to the US, UK, Australia and everywhere in between.