9 Featured WorksProjects
  1. Home
  2. /Projects
  3. /MediConnect
full stack2026Featured

MediConnect

Clinic CRM

Start a project
rohith-a.me/projects/proj-9
01

The challenge

Small Indian clinics run on paper, Excel and WhatsApp, while enterprise hospital systems are too heavy and too expensive for them to adopt.

02

The approach

Built a multi-tenant CRM as a pnpm monorepo: a NestJS + Prisma + PostgreSQL API, and one React/Vite + Tailwind + shadcn/ui frontend served both on the web and as a native desktop app through a Tauri v2 shell. Every clinic-scoped table carries a tenant key and every query is scoped from the authenticated session, never from client input.

03

The outcome

Patients, doctors, slot-based appointments with double-booking prevention, consultations, structured e-prescriptions and invoicing with split payments, with no server setup required from the clinic.

At a glance

Year
2026
Type
full stack
Stack
6 technologies

Built with

NestJSPrismaPostgreSQLReactTauriMulti-Tenant
System design

How MediConnect is put together

A pnpm monorepo with one rule: the clients hold no rules. A single NestJS API on Postgres serves the clinic web app, the same build wrapped as a Tauri desktop app, and a public Next.js website generated from each clinic’s CMS content. Tenant isolation, booking and billing are all enforced in the API.

concurrent bookings, one winner (tested)
10 → 1
NestJS domain modules
25
Postgres models
49
desktop installer (Tauri)
~3 MB

01 · Clients

client

Clinic staff

admin, doctor, reception

client

Patients

02 · Applications

service

Clinic web app

React · Vite · React Query

Vercel

service

Desktop app

Tauri v2

same web build inside

service

Clinic website

Next.js

per-clinic pages from the CMS

03 · API

service

Clinic API

NestJS · Prisma · Render

25 modules: auth, tenancy, booking, billing, audit

04 · Data

database

PostgreSQL

Supabase

all records, JSONB notes

object store

Object storage

Oracle OCI

documents and scans

Hover a component to trace its connections, or a request-flow step to follow it through the system.

clientservicedatabaseobject storerequest / responseoptional · fallback

9 connections

  • Clinic staff→Clinic web appHTTPS
  • Clinic staff→Desktop app
  • Patients→Clinic websiteHTTPS
  • Clinic web app→Clinic APIJSON · JWT
  • Desktop app→Clinic APIJSON · JWT
  • Clinic website→Clinic APIpublic overview
  • Clinic API→PostgreSQLSQL
  • Clinic API→Object storageupload · sign URL
  • Clinic web app→Object storage5-min signed download · optional
›9 connections as text
  • Clinic staff→Clinic web appHTTPS
  • Clinic staff→Desktop app
  • Patients→Clinic websiteHTTPS
  • Clinic web app→Clinic APIJSON · JWT
  • Desktop app→Clinic APIJSON · JWT
  • Clinic website→Clinic APIpublic overview
  • Clinic API→PostgreSQLSQL
  • Clinic API→Object storageupload · sign URL
  • Clinic web app→Object storage5-min signed download · optional

Request flow · Booking an appointment under contention

  1. 1Reception picks patient, doctor and time; the app sends POST /api/v1/appointments with a 15-minute access token.
  2. 2The API validates the token and takes the clinic from the session, never from the request body.
  3. 3It checks the doctor’s schedule and inserts. A partial unique index decides any race: exactly one booking commits, the other receives 409 “slot just taken”.
  4. 4Audit and usage rows are written in the same request and the booking returns to the screen.

Design decisions

The database settles double-booking
Application checks can both pass under concurrency; a partial unique index cannot. Verified with ten simultaneous requests.
Tenancy from the session only
Every clinic table carries clinic_id, read from the signed-in session. A record from another clinic returns “not found”, so existence can’t be probed.
Rotating single-use refresh tokens
15-minute access and 30-day refresh tokens; each refresh token works once, and replaying one is treated as theft and recorded.
Shared contracts package
Request and response types live in packages/types and compile into both API and clients, so a changed field breaks the build on both sides.
Deliberately not used
No MongoDB (Postgres JSONB covers flexible notes), no Redis (the index already prevents double-booking), no Docker (nothing to orchestrate yet).

Trade-offs & known limits

  • The API runs as a single instance; scaling out needs the Redis slot-lock that is configured but not yet wired.
  • WhatsApp, SMS and push dispatch are interfaces with logging stubs; no messages are delivered yet.
  • The OTP-verified public booking API is built, but the patient-facing booking page that would call it is not.

Have something similar in mind?

I'm open for freelance and contract work — let's talk about what you're building.

Get in touchSee more workBack to home
←PreviousCmdVaultdeveloper toolsNext→HomeFlowfull stack
Rohith. A

© 2026 All rights reserved.

Available for work