LabFlow โ a project by Ahsan Mahmood
Multi-tenant laboratory information system across five production surfaces.
A tube arrives at the front desk with a name written on it.
From that moment every step is a chance for the name and the tube to come apart. Accessioning. The run. The read. The signature. The release to whoever ordered it.
A laboratory is a chain of custody before it is anything else.
Software that treats a result as a row in a table has already dropped the part that matters, which is not the value in the field but the question of who is allowed to say that value is final.
LabFlow runs on the Firebase free tier wherever Firestore security rules can enforce the policy, and reaches for Cloud Functions only where a rule genuinely cannot.
That line is drawn on purpose. A rule runs on every read and costs nothing; a function is a bill and a cold start.
Multi-tenancy makes the question sharper still. A list query has to prove its own tenant from its own filters, because a rule inspecting a document cannot rescue a query that asked for everything, and the difference between those two is invisible to a green build.
Patient and order management, sample accessioning and tracking, results entry and validation, billing, inventory, quality control, equipment integration, EMR bridging.
Results move Draft, then Reviewed, then Approved, then Released. A role gates every transition.
Every patient record, order and result is tenant-scoped and audit-logged, so the question of who changed what has an answer that does not rely on anybody remembering.
Five production surfaces share one tenant model: a React web application, a Capacitor mobile build, a WXT lab-assistant extension, a Chrome extension for EMR integration, and Firebase Functions.
Underneath them sits one domain-service layer of 151 services, 28 Zustand stores and 60+ page modules.
It exists so that five surfaces cannot drift into five different definitions of what approved means.
The mobile build keeps core workflows usable offline through Dexie and IndexedDB, because a collection round does not stop where the signal does.
Then the costs, which in this domain are mostly about restraint.
A status machine that refuses is a status machine people will try to route around. So it has to be strict enough to be worth having and loose enough that the laboratory does not quietly start keeping a parallel spreadsheet, and that balance is a product judgement rather than a technical one.
Tenant isolation fails silently.
A correct rule and an over-broad query look identical from the outside, and the only defence is that every list read carries its own tenant filter and an explicit limit. That is checked by reading the queries, not by watching the build go green.
No patient identifier reaches a log or an error report. That is right, and it means a production incident tells me less than it otherwise would, so reproducing one takes longer.
Offline work means conflicts, and conflicts mean somebody has to decide which version of a result is the real one.
No iOS. There is no Apple Developer account behind this work, so the web and Android are the two surfaces it actually reaches.
The workflow is the product. Everything else listed above is scaffolding around one rule: a result does not leave the laboratory until a person with the authority to release it has said that it can.
What it does, and what that costs to build
- Full specimen lifecycle (accession to release)
- Role-gated Draft->Reviewed->Approved->Released workflow
- Multi-tenant isolation + audit trails
- Chrome EMR-integration extension
- Billing, inventory, quality control
- Offline-first mobile via Dexie/IndexedDB
- HIPAA-conscious data handling (no PHI in logs)
Built with
- React 19
- TypeScript
- Vite 8
- TailwindCSS
- TanStack Query
- Firebase
- Cloud Functions
- CapacitorJS
- WXT
Worth knowing
- healthcare
- lims
- multi-tenant
- medtech
- emr-integration
- react
Who built LabFlow?
Ahsan Mahmood built it alone, and it is live at labflow.aoneahsan.com. One person designed the tenant model, wrote the security rules that hold one laboratory's records away from another's, built all five production surfaces and wrote the domain-service layer they share.
What does the LabFlow result workflow enforce?
A result moves Draft, then Reviewed, then Approved, then Released, and each transition is gated by role rather than left to convention. Nothing reaches the ordering clinician until somebody with the authority to release it has done so, and every step is written to an audit trail. The order cannot be skipped, which is the entire point of encoding it in software instead of in a habit.
Does LabFlow work on iPhone?
No. LabFlow ships a web application and a Capacitor mobile build for Android, and there is no iOS build because there is no Apple Developer account behind this work. A laboratory running iPhones would use the web application, which is responsive, rather than an installed app.
How is one laboratory's data kept separate from another's?
Every patient, order and result is tenant-scoped, and the security rules enforce that on every read rather than the interface hiding what it should not show. The part that matters is that a list query has to prove its own tenant from its own filters โ a rule that inspects a document cannot rescue a query that asked for everything, and that specific mistake is invisible to a passing build.
Does LabFlow work without a network connection?
The mobile build keeps core workflows usable offline through Dexie and IndexedDB, so collection rounds do not stop where the signal does. Anything that has not been loaded yet is not available while offline, and the interface says so rather than showing an empty screen.
https://aoneahsan.com/projects/com.aoneahsan.labflow