DocPilot
An outpatient clinic platform with a live queue, telehealth and an AI scribe that turns consultations into structured notes. I owned the data and security layer.
- Role
- Backend developer. I designed the Firestore data model and real-time listeners, wrote the security rules, set up Firebase Auth and connected Appwrite storage.
- Stack
-
- React 19
- TypeScript
- Firebase Auth
- Cloud Firestore
- Appwrite Storage
- Gemini API
- Flutter
The problem
Outpatient clinics lose hours to paper queues and handwritten notes. Our team set out to digitize the whole visit: booking, the waiting-room queue, the consultation and the paperwork after it.
My part was the layer everything else stands on: where data lives, who can read it, and how changes reach every screen at once.
How it's built
The React web app talks to Firebase directly and listens for changes instead of polling. A companion Flutter app records the consultation, has Gemini turn the transcript into a structured SOAP note, then saves the note to Firestore and a PDF to Appwrite.
Key decisions
Enforce access in the database, not the UI
With no server of our own, the database rules are the security boundary. Appointments, consultations and invoices can only be read by the doctor and patient named on them. A user's role is fixed at sign-up, and every write is checked against the expected fields, types and allowed values.
match /users/{userId} {
allow create: if isOwner(userId) && isValidUser(request.resource.data);
// the role can never change after sign-up
allow update: if isOwner(userId) && isValidUser(request.resource.data) &&
request.resource.data.role == resource.data.role;
}
match /appointments/{appointmentId} {
allow read: if isAuthenticated() &&
(request.auth.uid == resource.data.doctorId ||
request.auth.uid == resource.data.patientId);
} Keep large files out of Firestore
Scans and reports (DICOM, JPG, PDF) go to Appwrite storage buckets. Firestore keeps only the metadata and a link, so queries stay small and fast while files can be as large as they need to be.
Push changes instead of polling
The queue, appointments, analytics and chat all use Firestore onSnapshot listeners. When a doctor calls the next patient, the waiting-room display and the patient's phone update from the same write.
Results
- of 440 labelled data points extracted correctly by the scribe
- 95.5%
- average wait, traditional queue vs DocPilot
- 45 → 18 min
Team results from our EPICS Phase II report. Scribe accuracy comes from prototype testing and ranged from 94.6% on symptoms to 96.6% on dosage and frequency. The wait-time figures are the report's comparison of a traditional clinic queue with DocPilot's dynamic queue, about 60% lower.
Notes from the scribe can't be finalized until the doctor reviews and confirms them.