Case Study · 2026
01
Executive Summary

A healthcare ecosystem where patients, doctors, and administrators finally run on the same source of truth.

Tabibi replaces phone-call scheduling, paper prescriptions, and disconnected clinic admin with three interconnected applications — a Patient app, a Doctor app, and an Admin web portal — built on one shared Flutter design system and one Firebase backbone. Every appointment, chat, and prescription moves through a role-guarded, security-hardened pipeline: a race-condition-proof booking engine, algorithmically isolated chat channels, and a single-use cryptographic doctor invitation system that make cross-role data leakage structurally impossible, not just policy-discouraged.

FlutterBLoCFirebase (Firestore · Auth · Cloud Functions · FCM)SupabaseCustom PDF Canvas EngineIconsaxFlutter Web
3
Interconnected cross-platform applications
1
Shared internal UI design system package
100%
Data & role isolation — zero cross-role contamination
3
User roles: Patient · Doctor · Admin
Real-Time
Appointment slot engine with race-condition guard
Server-Enforced
Chat access secured by Firestore rules, not the client
Multi-Page
PDF & high-resolution image prescription generator
6-Digit
Single-use cryptographic doctor invitation code
02
Problem Statement & UX Challenges

Six failure modes of clinic operations that Tabibi was built to close, one by one.

Fragmented scheduling
Before Tabibi, booking a consultation meant a phone call or a walk-in, with no visibility into which slots were actually free and no path for a doctor to automatically re-book a patient for a follow-up. Every re-examination had to be re-negotiated manually, and double-booking was only caught after the fact.
Prescription management crisis
Paper prescriptions get lost between the clinic and the pharmacy, are frequently illegible, and leave no digital trail for the patient to reference during a future visit. There was no single place a patient could open six months later to check what medication a doctor had prescribed and for how long.
Security & identity risk
Without a role guard sitting between authentication and the home screen, a doctor's credentials could open the patient app (or vice-versa), and a leaked or reused registration code could let a malicious actor fraudulently claim a doctor account and gain clinical-side access.
Email verification gap
Any signup flow that doesn't enforce verification before granting access lets bot accounts and typo'd emails pollute the patient directory — inflating doctor-side patient lists with contacts that can never actually be reached for appointment confirmations.
Admin operational blindness
Without a centralized console, there is no way to vet an incoming doctor's medical license, manage the specialty taxonomy patients search against, or see — in real time — how many appointments, doctors, and pending requests exist across the whole platform at any given moment.
Communication breakdown
Patients and doctors had no secure, auditable, in-app channel for post-booking questions — lab result follow-ups, dosage clarifications, or "can I come in earlier" requests were pushed onto unencrypted, unlogged personal channels outside the clinic's control.
03
Solution Architecture & Ecosystem Diagram

Three apps, one Firebase backbone, and a security model enforced at the database — not the screen.

3.1 — Three-platform interconnection

The Patient app (appointment_doctor), Doctor app (doctor_app_project), and Admin web portal (appointment_doctor_admin) never talk to each other directly — they read and write the same shared Firestore collections, and every write from one app becomes an instant, real-time read for the others. A doctor approving a booking on their phone updates the same appointments document a patient is watching on theirs, and the same row an admin is auditing from the web console.

Patient App appointment_doctor Doctor App doctor_app_project Admin Web Portal appointment_doctor_admin Firebase Core Firestore · Auth · Cloud Functions · FCM users doctors appointments chats specialties invitation_ codes support_ tickets announcements Every write is a real-time stream — a doctor's approval, a patient's booking, and an admin's audit all resolve against the same document.

3.2 — Security foundation

Every guard below is enforced in at least two independent layers, so a compromised client can never bypass it on its own.

Role enforcement at sign-in

smartLogin validates the authenticated user's role field the moment credentials are checked — before any home screen renders. A wrong role produces an immediate sign-out and a localized error, never a silent fallback.

Email verification guard

The AuthWrapper checks user.emailVerified before granting access to any authenticated screen. An unverified account is routed to a pending-verification state and cannot reach the patient directory, the chat, or the booking flow.

Router guard — AuthWrapper

AuthWrapper continuously listens to the Firebase Auth state stream. If an admin blocks a patient or suspends a doctor mid-session, the guard evicts that session in real time — no re-login required to enforce the change.

Chat algorithmic isolation

createOrGetChat only opens or resumes a thread when matchesPatient && matchesDoctor both evaluate true — a strict logical conjunction that makes a misrouted conversation structurally unreachable, not merely unlikely.

if (!matchesPatient || !matchesDoctor) → reject

Firestore security rules

Access to /chats/{chatId} is restricted server-side, independent of any client code:

allow read, write: if isChatParticipant(resource.data) || isAdmin();

3.3 — Shared UI design system

Rather than re-implement buttons, cards, and colors three times, every design decision was extracted once into an internal Flutter package, tabibi_ui, imported by all three applications. This is what makes a TabibiButton in the Doctor app pixel-identical to the one a patient taps, with zero duplicated styling code to drift out of sync.

TabibiColors
TabibiSpacing
TabibiRadius
TabibiTypography
TabibiCard
TabibiButton
TabibiStatusBadge
UserAvatar
TabibiEmptyState
04
Patient App — Deep Feature Walkthrough

The patient's entire relationship with their care — search, book, message, and remember — lives in one place.

1. Auth, role isolation & email verification guard

Registration collects name, email, phone, gender, and password, then a Firebase confirmation email is sent immediately. AuthCubit.signInPatient enforces expectedRole: 'patient', so even a valid doctor account entered into this login screen is rejected before it reaches a home screen.

Patient login
Login — email/password entry point where smartLogin checks the role field before proceeding.

The login screen is intentionally unstyled toward any single role — the same shape is reused across apps, and it's the backend check, not the UI, that decides who gets through. A patient typing correct credentials for a doctor-role account is bounced here with a clear, localized message rather than a generic error.

Patient registration
Create account — full name, email, phone, gender toggle, and a 6-character-minimum password.

Immediately after submission, Firebase Auth issues a verification email and the account is provisioned in the users collection with emailVerified: false. The account exists, but AuthWrapper will hold it at the door until that flag flips.

Forgot password
Forgot password — email-only recovery flow that dispatches a reset link without exposing whether the address exists.

Password recovery sits one tap away from login. It's deliberately minimal — a single email field and a "Send Link" action — keeping account recovery fast for a patient who may be trying to reach a doctor about something urgent.

2. Doctor discovery & specialty filter

The home screen queries Firestore scoped to role == 'doctor' && status == 'active', so a doctor who hasn't cleared admin approval never appears in a patient's search results in the first place.

Patient home and doctor discovery
Home — search bar, next-appointment card, and live specialty grid (Dentistry, Pediatrics, Internal Medicine, Dermatology...) each showing a real-time doctor count.

Manar's home screen shows an Awaiting Approval appointment with Dr. منار صلاح in Dermatology, alongside a specialty grid pulled live from the specialties collection — the same collection an admin manages from the web portal. Add a specialty on the web, and it appears in this grid instantly, with zero app redeploy.

Doctor profile card
Doctor profile — Dr. منار صلاح, Dermatology, with working hours (02:00 PM – 10:00 PM) and consultation fee (250 EGP).

A doctor card carries exactly what a patient needs to decide: specialty, bio, working hours, and fee, with a direct Book Appointment Now action and a shortcut into the direct chat — both of which respect the same role and matching guards described in Section 3.2.

3. Smart appointment booking engine & anti-abuse guards

  • Daily booking quota limit guard — once a doctor's configured maximum daily bookings is reached, the entire day locks and disappears from the selector, preventing overbooking abuse.
  • Consultation vs. re-examination non-collision guard — an algorithm keeps Initial Consultation slots and Re-examination slots from ever overlapping on the same calendar.
  • Real-time slot exclusion & race condition guard — the instant one patient's booking is written, that slot is pulled from every other active booking session, closing the double-booking window entirely.

The scenario below is the full three-step flow, screen by screen: pick a date, pick a time, add context, confirm.

Choose date step 1
Step 1 of 3 — Choose Date. August 31, 2026 is selected; past dates and days already at quota are visually disabled in the same calendar grid.

The progress bar at the top of the teal header commits to a three-step contract with the patient before they've entered any data — reducing the anxiety of an open-ended form.

Choose time step 2
Step 2 of 3 — Choose Time. Only unbooked, valid slots for the selected date render as tappable chips; 09:00 PM is selected here.

This grid is the live output of the anti-abuse engine: it dynamically filters out any slot already carrying a pending or confirmed appointment, so what the patient sees is guaranteed bookable at render time.

Confirm booking step 3
Step 3 of 3 — Additional Notes. An optional free-text field ("e.g. I have chest pain...") plus a booking summary card recapping the date and time before commitment.

Confirming here writes a new document to appointments with initial status pending and immediately broadcasts the real-time slot exclusion — every other patient's Step 2 screen for that doctor updates within the same session.

Booking success
Booking Request Received. Confirmation for Monday, 31 August 2026 at 08:30 PM with Dr. منار صلاح, plus quick links to appointments and home.

This success state closes the loop the moment the write completes — no waiting for a push notification to know the request went through, even though one is dispatched to the doctor immediately after.

Bookings list
Bookings — tabbed Past (6) / Upcoming (3) / Cancelled (1), each card carrying its own status badge and a contextual action (View Medical Examination once completed, or Cancel Appointment while pending).

The same appointment document changes shape as it moves through its lifecycle — a Pending card offers cancellation, a Completed one swaps that action for a direct link into the clinical record, without the patient ever leaving this screen.

4. Direct consultation chat & advanced messaging

  • Real-time 1-on-1 chat restricted to a booked patient/doctor pair.
  • Delete for me / delete for everyone message removal with live UI sync.
  • In-place message editing with an (edited) label.
  • Star / favorite critical medical instructions for rapid retrieval later.
  • Automatic + manual archiving — chats lock to read-only once the appointment completes.
  • Doctor-side blocking/muting as a safeguard against abusive patients.
  • Media attachments — lab reports, scans, PDFs, and voice notes.
  • Read receipts and unread badge counters.
Active chat with options menu
Active chat with the message options menu open — Archive, Starred Messages, and Delete — above a pinned message and the live message thread with a teal outbound bubble and neutral inbound ones.

This single screen demonstrates three of the eight sub-features at once: the pin at the top surfaces a message the patient chose to keep visible, the overflow menu exposes archiving and starring without cluttering the primary composer, and the composer itself keeps a voice-note affordance one tap away from the text field.

5. Patient profile & app settings

  • Language switcher — Arabic (RTL) to English (LTR) at runtime, no restart.
  • Dark / light mode persisted via SharedPreferences.
  • Profile editing — name, phone, blood type, avatar.
  • Issue reporting straight into the Admin Support Hub.
Patient profile menu
Profile — manar's account card, then My Data (Edit Profile, Change Password) and General (App Settings, Support Center), with Logout isolated at the bottom.

Grouping account edits separately from general app behavior keeps a patient from accidentally wandering into a destructive action (Logout) while trying to reach something routine like a language toggle.

Support ticket form
Support Center — New Ticket. Subject field, a Priority dropdown (Medium), and a free-text Message box beneath a New Ticket / My Tickets tab pair.

Submitting here writes directly to the support_tickets collection, where it appears — with the same subject and priority — inside the admin's Support Ticket Hub in real time, closing Problem #6 from Section 2.

6. Medical records & prescription hub

Every completed consultation leaves behind a structured clinical record the patient can revisit indefinitely — diagnosis, vitals, medications, and doctor's notes, plus a downloadable prescription PDF.

Medical examination record
Medical Examination — dated 31 August 2026, 9:35 AM. Diagnosis, Vitals (Weight, Blood Pressure), Medications with dosage/frequency, and free-text Notes, capped by a View Prescription action.

This is the exact record a doctor authored moments after the visit (see Section 5, Feature 4) — rendered here read-only for the patient, with a direct path into the print-ready PDF a pharmacy will accept.

7. Push notification engine

  • Appointment acceptance alert — instant FCM push on doctor approval.
  • Rejection/cancellation alert with the stated reason.
  • Re-examination booking alert, auto-triggered by the doctor scheduling a follow-up.
  • Platform broadcast announcements pushed down from Admin.
Notifications feed
Notifications — a confirmed-appointment alert with Dr. يارا مصطفي, and new-message alerts from "manoura," each tagged New until opened.

A Cloud Function listens for status mutations on the appointments collection and dispatches a targeted FCM payload to the patient's fcmToken the moment a doctor taps Approve — the notification and the in-app bookings list update within the same second.

05
Doctor App — Deep Feature Walkthrough

Practice management, scheduling, and prescriptions — run entirely from a phone.

1. Dual-path doctor onboarding system

A clinic can bring doctors in two different ways, and the app supports both from the same registration screen.

Path A — Invitation CodePath B — Direct Registration
Doctor enters an admin-issued 6-digit codeDoctor registers with no code, uploading proof of medical license
System validates isUsed == falseAccount enters a pending state on submission
Account is activated immediately (active)Admin reviews the uploaded credential and approves or rejects
Code is marked isUsed: true — one-time use onlyDoctor receives a push notification the moment a decision is made
Doctor proceeds straight to schedule setupOnly an approved account can configure a schedule or appear in patient search
Doctor registration form
Doctor Registration — part 1. Full Name, Email, Password, medical_specialty dropdown, and a Professional Proof upload dropzone.

The Professional Proof uploader is mandatory for Path B — this file becomes the proofDocumentUrl an admin will inspect before flipping the account to active.

Invitation code entry
Doctor Registration — part 2. A dedicated Invitation Code field under "Clinic Access Code," with the reminder banner "Registration is restricted to doctors only."

Entering a valid code here shortcuts the entire review process — validateInvitationCode checks the code against invitation_codes, and a match sets status: 'active' and isUsed: true in the same atomic write, so the code can never be handed off and reused by someone else.

Doctor login screen
Doctor Login. A dedicated "Doctor Login" heading and helper banner ("Enter your credentials to access your account") make the role of this screen explicit before a single field is filled in.

This is the twin of the patient login screen from Section 4, but wired to expectedRole: 'doctor' — a patient's valid credentials entered here are rejected the same way a doctor's are rejected on the patient side.

Doctor forgot password
Forgot Password — email-only reset flow, identical in structure to the patient version, keeping recovery muscle-memory consistent across both apps.

Consistency here isn't accidental: it's the shared tabibi_ui package's form components rendering the same way regardless of which app imports them.

2. Clinic schedule & availability configuration

Working hours settings
Working Hours Settings — Daily Working Period (10:00–18:00), a day-of-week toggle row (Tue/Thu/Fri/Sat active here), and an Appointment Duration dropdown set to 30 Minutes.

Saving this form persists directly to doctors/{uid}, and a dynamic slot generator recalculates every collision-free 30-minute block across the selected working days — instantly reflected in the patient app's Choose Time screen shown earlier.

3. Appointment & visit history management

Appointments tabbed queue
Appointments — tabbed by status (Cancelled 0 / Completed 2 visible), with a per-patient card showing visit count and a View Patient History shortcut.

Approving, cancelling, or completing an appointment here updates the status field in the shared appointments collection and triggers the same real-time push notification pipeline the patient side depends on.

Patient history
Patient History for manar — two completed visits (2 September and 1 September 2026), each expandable into Medical Examination or View Prescription.

A doctor opening a returning patient's history sees the exact same clinical entries the patient can see from their own Medical Records Hub — the same document, two authorized viewers.

4. Tabibi prescription engine (PDF & canvas)

Medical file with visits and prescriptions
Medical File for manar — specialty and notes header, then a Visits & Prescriptions list with inline PDF and edit icons per entry, and an add_prescription action at the bottom.

Each visit row already carries its diagnosis, weight, blood pressure, and notes inline — a doctor can scan a patient's whole history without opening a single sub-page.

Add prescription modal
add_prescription modal — Diagnosis, Note, Weight/Blood Pressure fields, a revisit_date picker, an Add Medication list-builder, and a Before Images attachment slot.

Saving this form is what PrescriptionPdfBuilder renders into a multi-page, print-ready vector PDF, while PrescriptionImageRenderer produces a high-resolution PNG/JPG alternative sized for sharing over WhatsApp — the same clinic-branded header appears on both outputs. Setting revisit_date here is also what auto-triggers the re-examination push alert on the patient's device.

5. Doctor profile & app settings

Doctor dashboard home
Home — "Good Morning, Dr. يارا مصطفي," three live KPI tiles (Today's Appointments, Pending Requests, Completed Today), and quick links to Appointments, Working Hours, and Settings.

This dashboard is a doctor-scoped mirror of the admin's platform-wide dashboard in Section 6 — same visual language, same real-time counters, scoped to one practice instead of the whole platform.

Doctor profile
Profile — يارا مصطفي, "الباطنة والجهاز الهضمي" (Internal Medicine & Gastroenterology), an About Me bio, and Contact Info (email, phone).

Fee, bio, and clinic address edits made here update the same doctors/{uid} document the patient-facing profile card in Section 4 reads from — there's no separate "public profile" to keep in sync.

Doctor app settings
Settings — Working Hours shortcut, a Dark Mode toggle, and Appointment Notifications, alongside a Theme Color picker offering Emerald Teal, Royal Blue, and Medical Purple.

The theme-color picker is a lightweight personalization layer — it lets an individual doctor choose an accent that suits their own taste without touching the platform's actual design tokens (covered in Section 7), which stay fixed regardless of this setting.

Doctor chat list
Chat list — a single active thread with manar, last message timestamped 28 أغسطس, plus an archive shortcut in the top bar.

This is the doctor-side entry point into the same encrypted, algorithmically-isolated messaging system detailed in Section 4, Feature 4.

Doctor notifications
Notifications — a confirmed-appointment alert for manoura and three new-appointment alerts, each timestamped and tagged New.

Every incoming booking request lands here the instant a patient confirms Step 3 of the booking flow — a doctor never has to refresh the Appointments tab to know a new request has arrived.

Doctor support ticket
Support Center — New Ticket for the doctor app, structurally identical to the patient version, feeding the same support_tickets collection.

Whether a bug report comes from a patient or a doctor, it surfaces in the exact same Admin Support Ticket Hub queue, tagged by role, shown in Section 6.

06
Admin Web Portal — Deep Feature Walkthrough

Everything a platform operator needs to see and control, in one Flutter Web console.

1. Main dashboard analytics & overview

Admin dashboard
Dashboard. Four live KPI cards — 12 Total Doctors, 32 Total Patients, 111 Total Appointments, 0 Pending Join Requests — above a Recent Doctors list showing each doctor's active status at a glance.

These four numbers are real-time aggregations over Firestore snapshots on users, appointments, doctors, and invitation_codes — an admin refreshing this page mid-morning sees the exact booking volume as it happens, not a nightly batch report.

2. Modern responsive web header & navigation

Visible in every screenshot in this section: a fixed dark sidebar (Dashboard, Pending Join Requests, Doctors, Patients, Appointments, Specialization, Invitation Codes, Support Tickets, Announcements, Settings) paired with a light top bar carrying a dark/light toggle and an Arabic/English switcher (عربي) — so an Arabic-speaking admin can flip the entire console's direction without losing their place.

3. Comprehensive doctor management & moderation

Doctors directory
Doctors. A specialty-filterable directory (All, Dentistry, Ophthalmology, Pediatrics & Neonatology, Internal Medicine & Gastroenterology, Dermatology & Aesthetics...) with per-card actions: schedule view, edit, appointments, and delete.

The four icons under every doctor card map directly to the moderation controls the brief calls for: inspecting that doctor's appointment load, editing their specialty/fee/phone/address, opening a credential-verification dialog for their uploaded license, and — as a last resort — permanently deleting the account. An Approve / Reject / Suspend decision and a CSV export of the approved roster both live one click deeper from this same list.

4. Patient management & moderation

Patients table
Patients. A searchable, sortable table (All / Active / Blocked) with contact info, registration date, and a status badge plus a block-toggle icon per row.

Flagging a fraudulent account here sets isActive: false on that patient's record — and because AuthWrapper is watching the auth state stream on the mobile side, the affected device is signed out within the same session, not on its next cold start.

5. Appointments monitoring & status management

Appointments monitor with tabs
Appointments. Tabbed filters (All / Pending Payment / Pending / Confirmed / Completed / Cancelled) over every doctor–patient booking, each row carrying date, time, and a colour-coded status badge with an inspect action.

The row for Aug 10, 2026 shows a rejected status next to an inspect icon — clicking through surfaces the cancellation reason an admin or doctor logged, giving full audit visibility into why a specific slot didn't go ahead.

6. Dynamic specialties management (CRUD)

Add new specialty modal
Specialization — Add New Specialty modal, layered over the existing grid (Dentistry, Pediatrics, Internal Medicine, Dermatology, Orthopedics, Cardiology, Gynecology), each already marked Approved Specialty.

Typing "Orthopedic Surgery" and confirming here writes to the specialties collection with an automated Arabic/English translation lookup and an internal _normalizeArabic text normalizer — the new specialty appears in the Doctor app's registration dropdown and the Patient app's discovery grid at the same instant.

7. Single-use invitation code generator

Invitation codes dashboard
Invitation Codes. Five live codes (077179, 428780, 268837, 598788, 580505), each stamped Available for use with a creation date and a one-click copy icon.

Code 077179 was generated on 2026-08-31 — the same day this dashboard was captured — by buildInvitationCode, a 6-digit cryptographic random generator. The moment a doctor consumes it during registration, its badge flips from Available for use to Used, with the consuming doctor's name and timestamp recorded, and the code is permanently locked against replay.

8. Announcements & broadcast system

Announcements management
Announcements. A live broadcast — "خصم: عرض خاص لمدة 24 ساعه الكشف مجاني" — created 2025/12/28, with an enable/disable toggle and delete action.

Every announcement carries a title, body, type (info / warning / success), and optional expiry date; once created, it renders as a banner inside both the Patient and Doctor mobile apps without either app needing a fresh deploy.

9. Support ticket hub

Support tickets
Support Tickets. Four live tickets — a doctor's "تاخير في الرد علي الرسائل" (IN_PROGRESS, already carrying an Admin Reply) alongside three patient-submitted tickets still OPEN.

Each card is tagged by submitter role (DOCTOR / PATIENT) so an admin can triage clinical-side complaints separately from patient-side ones, reply inline, and move the status through Open → In Progress → Closed as the issue is resolved.

07
Design System & Visual Architecture

One visual language, expressed identically across a phone screen and a browser tab.

7.1 — The Tabibi healthcare design philosophy

The platform's primary colour, Emerald Teal #0D9488, was chosen deliberately for its association with medical trust, cleanliness, and calm — visible in every header gradient, primary button, and status accent across all three apps. Full dark and light mode support runs throughout, which matters most for the Doctor app during long night shifts, and the overall visual language favours clean surgical spacing, high-contrast readability, soft glass-like card surfaces, Iconsax's medical-appropriate iconography, and understated micro-interactions over decorative noise.

7.2 — Shared design token system

All three platforms import the same tabibi_ui tokens rather than hard-coding values locally:

primary
#0D9488
ink
#06211F
surface
#EEF7F5
warning
#A9600D
danger
#A3312A
TabibiSpacing — a four-value scale used for every gap and padding in the system:
xs · 4
sm · 8
md · 16
lg · 24
xl · 32
TabibiRadius — the corner-rounding scale behind every card, button, and modal:
sm · 8
md · 12
lg · 16
xl · 24

7.3 — Component reuse across platforms

A TabibiCard, TabibiButton, TabibiStatusBadge, and UserAvatar render with identical corner radii, shadow depth, and type scale whether they're compiled into the Patient app, the Doctor app, or Flutter Web — compare the status-badge pill on the Patient app's Completed booking card against the admin's Completed appointment badge: same component, same styling, two different runtimes.

One layer sits outside this shared system by design: the Doctor app's Settings screen offers an individual Theme Color picker (Emerald Teal, Royal Blue, Medical Purple) so a single doctor can personalize their own accent colour without altering the tabibi_ui tokens every other user relies on — a preference, not a platform-wide redesign.

08
Security, Engineering Hardening & Technical Excellence

Seven engineering decisions that turn "should be secure" into "structurally can't fail."

1. Firestore security rules — server-side enforcement

Chat access is gated at the database, not the app: /chats/{chatId} only permits reads and writes from isChatParticipant(resource.data) || isAdmin(). A modified or jailbroken client gains nothing, because the rule lives outside any code the client controls.

2. Role guard at the authentication layer

smartLogin checks the role field before any token is issued for app access — a doctor's credentials simply cannot open the patient app, and the reverse holds symmetrically.

3. Mandatory email verification guard

AuthWrapper checks user.emailVerified before routing to any authenticated screen, closing the patient-database pollution risk described in Section 2.

4. Chat algorithmic isolation

createOrGetChat's conjunctive guard — matchesPatient && matchesDoctor — prevents any possibility of chat misrouting between unrelated accounts.

5. Anti-abuse booking engine (three layers)

Daily quota lock closes an entire day once its booking maximum is hit; a consultation-vs-re-examination algorithm keeps the two appointment types from ever colliding; and real-time slot exclusion removes a booked slot from every other active session the instant it's claimed.

6. Single-use invitation code enforcement

Each 6-digit code is consumed exactly once via an atomic Firestore write — isUsed: true plus usedByUid — permanently blocking reuse even if the code leaks after being consumed.

7. FCM push notification architecture

Cloud Functions listen for mutations on the appointments collection and dispatch targeted FCM payloads to the recipient's fcmToken the moment a status changes — the notification pipeline is entirely event-driven, with no polling on either client.

09
Impact, Outcomes & Portfolio Reflection

What building Tabibi actually proved.

Clinical impact

Tabibi replaces the phone-call-and-walk-in scheduling model with a self-service booking engine patients can use at any hour, removes paper prescriptions from the loop entirely in favour of a permanent digital record, and turns re-examination follow-ups from a manual phone chase into an automatic push alert the moment a doctor schedules one.

Engineering achievement

The final system is a production-grade, three-application ecosystem sharing a single design package, with zero cross-role data contamination enforced at the database layer, real-time synchronization across every screen shown in this document, and security hardening applied consistently at authentication, chat, booking, and invitation-code layers rather than bolted on after the fact.

Design achievement

Every screenshot in Sections 4 through 6 comes from the same tabibi_ui token set, delivering consistent, accessible healthcare UX across mobile and web, with full bilingual Arabic (RTL) / English (LTR) support and dark/light mode available from day one — not retrofitted later.

Developer reflection

The decisions that mattered most in hindsight were the ones invisible to any single screenshot: designing the role guard before a single UI screen existed, working out the booking-collision algorithm on paper before writing the Firestore query, extracting the shared UI package early enough that no app ever had to "catch up" to it, and treating every Firestore security rule as the real access-control layer — with the client-side guard only ever a convenience on top.