❯ Health · Platform · 2024
PHMS
A multi-tenant hospital management SaaS covering the full clinical and revenue cycle — registration, billing, service fulfilment, discharge — with audit-first logging and race-condition-safe financial paths.
The problem
Hospitals run on tight margins and dense paperwork, and the financial and clinical cycles are one system, not two. A visit touches registration, service orders, billing, pharmacy stock, and discharge. When two clerks bill the same visit, or two staff deduct the same stock, the error lands in money and patient records, the two places it can least afford to.
The approach
PHMS is a multi-tenant hospital SaaS covering the whole loop: registration,
billing, service fulfilment, discharge. Tenancy is split-identity: global users
plus per-tenant staff memberships, so staff at multiple hospitals switch
context without re-authenticating while isolation holds. Isolation is
dual-layer: mandatory tenant_id scoping on every query plus PostgreSQL
row-level security, and a cross-tenant attempt raises a critical audit alert
instead of failing quietly.
Architecture
- React SPA
- API Layer
- Tenant Isolation + RLS
- Billing Engine
- Append-Only Audit
- PostgreSQL + Read Replica
FLOWS
- React SPArequestsAPI Layer
- API Layertenant_id scopeTenant Isolation + RLS
- API Layerservice ordersBilling Engine
- Billing Enginelocked writesPostgreSQL + Read Replica
- API Layerappend-onlyAppend-Only Audit
- PostgreSQL + Read Replicareplica readsAPI Layer
Everything important is audited first: an append-only log captures user,
tenant, role, module, action, and old and new values. The billing engine
auto-generates bills from service orders against tariff catalogues, applies HMO
and NHIS co-pay rules, takes multi-mode payments, and only allows reversals
with mandatory second-level authorization. Money and stock paths are
race-condition-safe: bill creation, payment posting, and pharmacy stock
deduction all run under SELECT FOR UPDATE, so there are no duplicate bills,
double postings, or negative stock. Pharmacy dispensing follows FEFO
(first-expired-first-out) batch ordering, atomic deduction, partial dispense
with auto re-prescription, and stock mutations that only happen through system
events. Clinical workflow is modeled: SOAP consultations, order entry,
payment-gated service queues, result review with a mandatory reason for
amendments, and a visit lifecycle state machine. Production pairs PostgreSQL
with a read replica for OLTP and OLAP separation, Redis, S3-compatible object
storage, magic-link auth with account lockout, NDPR/NDPA 2023 compliance, and
30-day backups with point-in-time recovery. The spec package that shipped with
it: 30 JSON Schema entities, 49 prioritized features with acceptance criteria.
Key decisions
Two layers of tenant isolation
Query scoping alone depends on every future query remembering to filter; row-level security is the backstop that does not.
`SELECT FOR UPDATE` on money paths
Optimistic retries are fine for profile edits; bills and stock need locks.
FEFO for pharmacy
First-expired-first-out is the difference between a stock system and a safe dispensary.
Audit written synchronously
An audit log that can lag the event it records is not an audit log.
What I'd do differently
This was a spec-heavy build and the breadth shows. I would cut the feature surface for the first version and prove the billing and stock paths against a real hospital's numbers before adding modules. The schema count is a strength for evaluation, but it made the early development loop heavier than it needed to be.