DEV Community

Bhuvanesh M P
Bhuvanesh M P

Posted on

AyurSutra: Why I Built a Treatment Engine, Not a Booking App

Built for The ZerOps Challenge (@WeMakeDevs Γ— @zeropsio)
🟒 Live: https://web-2c8a.prg1.zerops.app/ πŸ’» Code: https://github.com/bhuvaneshmp15-glitch/ayursutra


Panchakarma Clinical Dashboard

The problem nobody's solving

Panchakarma β€” traditional Ayurvedic detoxification therapy β€” isn't a single appointment. A patient undergoing Basti therapy goes through 7 sessions across 3 distinct clinical stages (Purvakarma preparation, Pradhankarma primary treatment, Paschatkarma recovery) spread over 2+ weeks.

The problem nobody's solving

Panchakarma β€” traditional Ayurvedic detoxification therapy β€” isn't a single appointment. A patient undergoing Basti therapy goes through 7 sessions across 3 distinct clinical stages (Purvakarma preparation, Pradhankarma primary treatment, Paschatkarma recovery) spread over 2+ weeks.

Yet almost every clinic manages this using tools built for booking a haircut: pick a date, pick a time, done. That mismatch causes real problems:
-->No protocol memory β€” the system has no idea Session 4 depends on Session 3 being completed
-->No conflict prevention β€” practitioners and treatment rooms get double-booked across overlapping sessions
-->Broken continuity β€” vitals, pulse diagnostics, and clinical notes end up scattered across paper files instead of tied to a specific treatment stage
So I built AyurSutra β€” a system that treats Panchakarma as what it actually is: a stateful, multi-stage clinical protocol.
What it actually does

When a practitioner selects a therapy type (Vamana, Virechana, Basti, Nasya, or Raktamokshana), AyurSutra:

1.Auto-generates the complete session sequence across all three stages
Assigns a practitioner and checks for scheduling conflicts at the database transaction level
2.Auto-shifts any colliding session to the next open time slot, instead of just rejecting the booking
3.Tracks stage-linked vitals (Nadi pulse, BP, weight) as structured data, not loose notes
4.Serves the daily schedule from a Valkey cache so the dashboard loads instantly, even under load


Pick a therapy type β€” the backend generates the entire multi-week protocol automatically.


Every patient's journey is tracked stage by stage β€” not just as a list of appointments.
Architecture β€” built to actually use Zerops, not just deploy on it

I wanted this to genuinely demonstrate multi-service infrastructure, not a single monolith with a database bolted on. Here's the full stack, all running on Zerops:

Client Browser
β”‚
β–Ό
web (nginx) ── serves React frontend, proxies /api to β†’
β”‚
β–Ό
api (Bun + Hono) ── the core engine
β”‚
β”œβ”€β”€β–Ί db (PostgreSQL) ── patients, plans, sessions, vitals
β”œβ”€β”€β–Ί cache (Valkey) ── today's schedule, sub-ms reads
└──► storage (S3) ── clinical documents, progress photos

worker (Node.js) ── runs every 2 minutes:
re-audits conflicts, syncs Valkey cache, logs reminders

Six services, one project, wired entirely through Zerops' internal networking β€” no manual VPC config, no separate hosting for each piece.


All six services, one Zerops project, zero manual networking config.
The interesting engineering bit: conflict auto-shifting

Most booking systems just reject a request if there's a conflict. I didn't want that β€” a practitioner shouldn't have to manually retry five times to book a valid slot. Instead, the scheduling engine runs inside a Postgres transaction, checks for interval overlaps against existing sessions:

ts
candidateStart < slot.end && candidateEnd > slot.start

If it finds a collision, it automatically walks forward through the day's slot grid (09:00, 10:30, 12:00, 14:00, 15:30, 17:00) until it finds one that's free β€” and logs the shift so it's fully auditable.

Why Valkey matters here

The clinical dashboard needs to load instantly β€” a practitioner glancing at "who's next" shouldn't wait on a SQL query. The background worker recomputes and writes today's full schedule into Valkey every 2 minutes (ayursutra:today_schedule), and the dashboard reads from there first, falling back to Postgres only if the cache is cold. That's the difference between a demo that feels production-grade and one that doesn't.

"Live schedule, served from cache β€” not a database query on every page load."

What's next

If I keep building on this: WhatsApp/SMS reminders triggered off the worker's queue, multi-clinic support for practitioner networks, and a mobile companion app for practitioners to log Nadi diagnostics hands-free during a session.

Top comments (0)