Client background
In 2017, when we started planning Garuda, the clinic management software market in India had a gap that wasn't being filled well. The enterprise hospital management systems that existed were designed for large hospitals — expensive to license, slow to implement, and built around workflows that only made sense at the scale of a 200-bed facility. For a 3-doctor multi-specialty outpatient clinic, an enterprise HMS was over-engineered and under-usable.
The other end of the market — basic billing and appointment software — did the opposite. It handled invoicing adequately but treated EMR, lab management, pharmacy, and everything else as afterthoughts or paid add-ons that never quite integrated properly.
Clinics in between — multi-specialty outpatient practices with 2 to 15 doctors, growing patient volumes, and real operational complexity — were either on paper records, spreadsheets, or patched combinations of software that didn't talk to each other.
The initial target was exactly this kind of clinic: the practice owner or senior administrator who needed the full stack of functionality, had no dedicated IT staff, couldn't survive a six-month enterprise implementation project, and needed software that reception staff could actually use from day one.
The core insight that shaped every design decision: clinic management software has to serve clinical speed, not just administrative compliance. EMR that doctors use because it slows them down less than paper. Scheduling that cuts phone calls. Billing that assembles itself from consultation data rather than requiring manual entry.
The challenge
Healthcare software operates under constraints that generic SaaS does not. Building Garuda meant working through every one of them in production — not in a workshop.
Patient data isolation at the database layer. In a multi-tenant clinic system, one clinic's patient records must be completely inaccessible to any other tenant — not just at the application layer, but at the database layer. We implement tenant isolation using PostgreSQL row-level security (RLS) policies rather than application-level filtering. If isolation is only enforced in the API, a single application bug can expose data across tenants. A database policy enforces the boundary regardless of code path. The trade-off is more complex schema migrations and harder query plan reasoning — a price worth paying.
Role-based access with clinical logic. A receptionist should never see clinical notes. A junior doctor can add consultation notes but cannot approve certain prescriptions. A billing administrator sees charges but not diagnoses. Getting this wrong has real patient-care consequences, not just compliance ones. We built the permission model before we built any module, and it has shaped every feature added since.
Integration reliability. Lab provider APIs in India are not standardised. We integrated with Agappe, Trivitron, and several custom lab systems — each with different authentication mechanisms, different result formats, and very limited test environment support. A failed lab result delivery should retry with notification, not silently drop data that a clinician will rely on for a treatment decision. We built integration test harnesses against recorded API responses because we couldn't trust the lab test environments to behave like production.
Zero-downtime deployments. Clinics do not have maintenance windows. A schema migration that takes the system down for twenty minutes is not acceptable when there is a waiting room full of patients. This forced us to develop zero-downtime migration practices early — additive-only schema changes, rolling updates, blue-green deployments for major releases. The constraint made us a better engineering team.
How we engaged
Building Garuda involved four architecture decisions that still shape how we approach healthcare software today.
Tenant isolation at the database layer, not the application layer. We use PostgreSQL row-level security policies to ensure that every query, regardless of which code path triggers it, is automatically scoped to the correct clinic's data. An API bug can cause many problems — exposing one clinic's patient records to another is not among them. The trade-off is that database schema work is more complex, and developers have to think about RLS policies alongside their migrations. We consider that trade-off mandatory.
Synchronous confirmation for patient-critical operations. Lab result delivery, appointment confirmations, prescription generation — these operations do not return success until we have confirmed delivery at least one step into the pipeline. The alternative is fire-and-forget with async retry, which is simpler to build but creates situations where a clinician believes a result has been delivered when it hasn't. We chose the higher-latency, more complex path because the clinical consequence of a silent failure is unacceptable.
AI as a completely isolated, additive service. AI failures — model timeouts, unexpected outputs, provider outages — cannot cascade into a doctor's ability to pull up a patient record. The AI layer is additive, never load-bearing. This principle, applied from the start, has meant that every AI feature we have added has been genuinely usable in production: if it fails, the clinician works without it, not around it.
Shared API designed for mobile constraints from day one. The Flutter patient portal and the React web frontend both consume the same API, designed with mobile bandwidth and intermittent connectivity in mind — better pagination, smaller default payloads, explicit handling of connectivity interruptions. We later saw the alternative — a mobile app that had drifted from the web data model — as a major technical problem in a client's HealthTech platform.
What we built
Eight integrated modules, all in continuous production since 2018:
🏥 EMR — Electronic Medical Records. Patient history, diagnoses, prescriptions, vitals, allergies, and document management. Structured for clinical speed — a doctor should be able to open a patient's complete history in under three seconds. Supports multi-visit longitudinal records: a patient who has seen multiple doctors in the same clinic has a unified record visible to all treating doctors.
📅 Appointment & Scheduling. Multi-doctor, multi-location calendar management. Online booking via patient portal with real-time availability. SMS and WhatsApp confirmation and reminder automation via Twilio and MSG91. Waitlist management with automatic offer when a cancellation occurs.
💊 Pharmacy & Inventory. Drug dispensing linked directly to EMR prescriptions — a prescription generates a dispense queue item, no re-entry required. Stock level tracking with configurable reorder thresholds, expiry date management, and supplier integration.
🔬 Lab Management. Lab order creation from the consultation screen, result capture with reference ranges per test type, automatic delivery to patient portal, and abnormal result flagging for clinical review. Integrated with Agappe, Trivitron, and custom lab provider APIs via HL7/FHIR where available.
💳 Billing & Insurance. IP/OP/day-care billing, package billing for multi-session treatment plans, GST-compliant invoicing with correct HSN codes for medical services, insurance claim generation, and Stripe and Razorpay payment gateway integration.
🤖 AI-Assisted Workflows. Diagnosis suggestions from symptoms and vitals, clinical note summarisation, and triage classification for incoming patient queries. Every AI-generated output is clearly labelled as a suggestion, displayed alongside the inputs that generated it, and dismissible by the clinician in a single action. AI assists — it does not replace clinical judgment. This is an architectural constraint, not a product decision.
📊 Analytics & Reporting. Real-time revenue dashboards, patient flow reports, doctor performance metrics, appointment utilisation rates, and pharmacy margin analysis. All reports available without configuration — the most-used views are accessible from the main navigation without setup.
📱 Patient Portal. Web and Flutter mobile application. Patients book appointments, view lab results, download prescriptions, pay outstanding bills, and message the clinic. Designed for low-friction adoption — the portal should work for a patient who has never used healthcare software before.
Technical approach
The platform is built on a React web frontend and a Flutter mobile application, both consuming a shared Node.js API. Patient data is stored in PostgreSQL with row-level security policies enforcing per-clinic tenant isolation at the database layer. Document storage uses object storage for clinical files, lab reports, and prescription PDFs.
Four decisions define the architecture:
Tenant isolation at the database layer. Every table in Garuda's patient data schema has RLS policies attached. A query issued via the Node.js API automatically has the clinic context injected — it is structurally impossible for a query to return data from another tenant. Application-layer bugs cannot become data exposure incidents.
Synchronous confirmation for patient-critical operations. Lab result delivery and appointment confirmation use a request-confirm pattern rather than fire-and-forget. The API does not return success until the delivery pipeline has confirmed receipt at the next step. This eliminates a class of silent failure that would otherwise only surface when a clinician asks why a result was never received.
AI features as a completely isolated, additive service. The AI layer connects to the EMR API but has no write access to core patient records. AI features can fail — model provider outages, unexpected inputs, latency spikes — without affecting the EMR, scheduling, billing, or any other module. Degraded AI is invisible to the clinical workflow.
Shared API designed for mobile constraints from day one. The Flutter patient portal and the React web frontend both use the same API — paginated responses, small default payloads, explicit reconnection handling. This prevents the data model drift that is one of the most expensive technical problems to fix in a running product.
Deployment: single clinic setup takes 1–2 weeks including data migration and staff training. Multi-facility rollouts take 4–8 weeks. All production deployments use zero-downtime migrations — the clinic never goes offline for a Garuda update.
Results
Garuda has been in continuous production since 2018 — across multiple clinic deployments, with real patients, real doctors, and real clinical data flowing through it every day. That continuity is the primary result. The platform has been maintained, extended, and operated long enough that we have encountered and resolved problems that only appear at scale and over time.
What we got wrong — and what it cost to fix. The honest account of building healthcare software for production is more valuable than the polished one.
The tablet interface problem. We designed the EMR screen for keyboard-first use on a desktop, assuming doctors would use the web frontend and patients would use the Flutter mobile app. What we found in practice: several specialties — general medicine with high appointment volume, physiotherapy, ward-based care — wanted to use the Flutter app on a tablet as their primary clinical interface. The EMR consultation screen had to be substantially rebuilt for touch interaction. Designing for both interaction modes from day one would have saved a significant rebuild.
Billing edge cases take a full year to discover. Package billing — a patient paying upfront for a set of physiotherapy sessions delivered over several weeks — has edge cases around partial completion, refunds, insurance overlaps, and mid-package rate changes that only appear in real operational data. We handled the common cases well in version one. The tail of edge cases emerged over the first year in production and required several iterative billing module revisions.
What building and running Garuda means when we take on a healthcare software project for a client: we are not learning the domain on their time. We have already encountered the multi-tenant data isolation failure modes, the lab integration reliability problems, the billing edge cases, the clinical AI guardrail requirements, and the deployment discipline that running clinics demand. We build with those constraints as first-class concerns — not as things we discover during the engagement.
