On this page

Patient flows

Technical reference 27 screenshots

View the PDF Download

Who this is for#

This document is for product, QA and new team members. It describes what a patient can do on thehealint, step by step, as the code behaves today. It covers both the patient website and the patient mobile app. Every screen, button, endpoint and status here was traced from the source. Anything missing, half-built or inconsistent is listed under Gaps & known limitations rather than described as working.

A patient is any signed-in person whose account holds no workforce or admin role. The role list lives in packages/config/src/constants.ts: userWorkspaceForRoles() returns PATIENT when no other role applies. One patient account can also manage family members (dependents) who have no login of their own.

Where they work#

SurfaceAppHow the patient gets around
Webapps/patient-web (Next.js), the "User" web appTop navigation: Find care /search, Appointments /appointments, Profile /profile, Health records /records, Pharmacy & labs /fulfillment, Family /family, Privacy /consent. Other routes: / (public landing when signed out, home when signed in), /providers/[branchId], /practitioners/[practitionerId], /book/[practitionerBranchId], /appointments/[appointmentId], /records/prescriptions/[prescriptionId] (prescription and dose timetable), /records/reports/[documentId] (lab report viewer).
Mobileapps/patient-mobile (Flutter), the unified "thehealint User" appA bottom tab bar: Home, Appointments, Records, Profile. Home links to Find care (search), Describe your symptoms (care navigation), Pharmacy & labs, Family and Privacy & consent. From search: Branch profile → Practitioner profile → Book. Profile holds Sign out.

The mobile app routes by role. patient-mobile is the single "User" app. After sign-in, AppRoot sends each account to the workspace for its role:

RoleWhere the account lands
PatientThe patient screens in this document
DoctorThe doctor workspace from apps/doctor-mobile (see 02-doctor.md)
StaffThe provider-mobile home screen
Provider adminA "Use ProviderOS" screen
Platform adminA "Use Platform Admin web" screen

patient-web does the same in a simpler way: doctors, front-desk staff, pharmacy and lab staff and provider admins see "Your work is in ProviderOS" with an Open ProviderOS button, and platform staff see "Continue in Platform Admin". The old staff page at /workspace is gone (it redirects to /).

Patient web at phone width with the menu open
Patient web (phone width) — the menu button opens Find care, Appointments, Profile, Health records, Pharmacy & labs, Family and Privacy; My appointments is underneath, with Reserved, Expired and Completed cards.

Signed-out visitors can open the landing page /, /search, /providers/*, /practitioners/* and /book/* on web, and Find care on mobile. Every other page shows the sign-in card.

At a glance#

JourneyWhereOutcome
Landing page (web, signed out)/Search started, a specialty opened, or sign-in / sign-up from beside the hero
Sign up / sign inWeb: the landing page, or the sign-in card on any protected route. Mobile: Sign inA signed-in account with a name on file
Search & discoveryWeb: /search, /providers/[id], /practitioners/[id]. Mobile: Find care and the profile screensThe patient picks a doctor at a branch
BookingWeb: /book/[practitionerBranchId]. Mobile: BookAn appointment in status "Confirmed" and a confirmation email
Pre-visit formWeb: the appointment card and visit page. Mobile: the appointment cardSymptoms, medicines and allergies shared with the doctor
Family membersWeb: /family. Mobile: Family profilesDependents the patient can book for
Manage appointmentsWeb: /appointments. Mobile: My appointmentsRescheduled or cancelled bookings, with emails
Visit dayWeb: /appointments, /appointments/[id]. Mobile: My appointmentsChecked in, with a live token and queue position
After the visitWeb: /appointments/[id], /records, /fulfillment. Mobile: Health records, Pharmacy & labsPrescription, orders, reports, bill and review
Health recordsWeb: /records, /records/prescriptions/[id], /records/reports/[id]. Mobile: Health recordsTimeline, documents (including uploads), prescriptions with a dose timetable, lab reports and invoices
Care navigation (AI)Mobile only: Describe your symptomsSuggested specialties and nearby providers, or an emergency warning
Privacy & consentWeb: /consent. Mobile: Privacy and consentConsents granted or withdrawn, with history
Profile & accountWeb: /profile. Mobile: ProfileContact and health details updated
NotificationsEmail onlyBooking, payment, prescription and follow-up emails

1. Sign up and sign in#

Landing page (web, signed out)#

Patient web landing page
Patient web (desktop, signed out) — the landing page at /: "Find the right care, and book a real time." with a search box ("Try "knee pain" or "cardiologist"", Search, "No account needed to search or browse.") and the Sign in card beside it; then Common specialties, How booking works (Search, Pick a time, Visit and keep it), "Built to be trusted with your health" (verified clinics, verified pharmacies and labs, consent, private records), and "Keep your family's care in one place" with Create an account and Sign in.
  1. A signed-out visitor at / sees the public landing page instead of the bare sign-in card.
  2. Search submits the typed text to /search?q=…. Common specialties shows up to eight specialties from GET /api/v1/specialties (General Physician, Pediatrics, Gynaecology and so on first), each opening /search?specialtyKey=…; All doctors and clinics opens /search.
  3. Sign in sits beside the hero (email and password, "New here? Create an account"). Create an account further down opens /?mode=signup.
  4. Below the fold: How booking works (three steps), Built to be trusted with your health (four points on verification, consent and private records) and Keep your family's care in one place (what comes out of a visit: appointment, prescription with a day-by-day dose timetable, lab reports, bill).
  5. A / link with ?next= or ?mode= shows the sign-in or sign-up card directly, as before.

Signing in#

Both apps use email and password through Supabase Auth. Neither app offers one-time-code sign-in or phone sign-up. Phone sign-up is turned off until SMS (TRAI DLT registration) is available.

  1. Sign-in card → enter email and password → "Sign in".
    • Web shows the card on any protected route. Mobile shows the Sign in screen.
    • The system calls Supabase signInWithPassword. While it works the button reads "Signing in…", and it stays disabled until both fields are filled.
    • The patient lands where they were going. On web, a ?next= parameter is carried through sign-in, so a patient who was mid-booking returns to the booking page.
    • Errors:
      • Wrong password: "That email and password did not match an account. If you normally sign in with a code, use that instead."
      • Rate limit: "Too many attempts. Please wait a minute and try again."
  2. "New here? Create an account" → email and password → "Create account".
    • The system checks for an "@" ("Create an account with email for now. Phone signup needs SMS verification.") and a password of at least 8 characters ("Choose a password with at least 8 characters.").
    • It then calls Supabase signUp. Email confirmation is off, so the session is live straight away.
  3. Profile completion.
    • The first GET /api/v1/me returns 404, so the app shows the name step:
      • Web: "One last thing — What should we call you? This is the name your doctor will see."
      • Mobile: "Almost there — What should we call you?"
    • Enter full name → "Continue". This calls POST /api/v1/me and then refreshes the session so the new token carries the profile id. The patient lands on Home, or on the next page on web.
  4. Two-factor check (mobile only, and only if already set up).
    • If the account already has a verified authenticator, mobile shows the shared challenge screen: "Enter the 6-digit code from your authenticator app".
    • Patients have no screen to set up two-factor sign-in.
  5. Consent is not part of sign-up. Consents are managed later on the Privacy screen (section 11).
  6. "Browse doctors and clinics without signing in" (web) or "Browse doctors & clinics without signing in" (mobile) opens search without an account.
Mobile sign in
Patient app (iPhone) — Sign in: email and password, a Sign in button that stays grey until both are filled, "New here? Create an account" and "Browse doctors & clinics without signing in".

Home after sign-in

  • Web greets the patient ("Hello, {first name}.") and shows four cards: Find a doctor or clinic, My appointments, Health records, Family profiles.
  • Mobile greets the patient by time of day ("Good evening, {first name}") and shows, top to bottom:
    • a Find a doctor or clinic search bar;
    • the queue card when they are checked in somewhere (token, "You're next" or how many are ahead);
    • a Next visit card: date and time, doctor, place, who it is for, a status badge and "+ n more upcoming". Tapping it opens the Appointments tab;
    • Quick actions: Describe symptoms, Pharmacy & labs, Family, Privacy & consent.
  • The bottom tab bar switches between Home, Appointments, Records and Profile. Sign out is at the bottom of Profile.
Mobile home
Patient app (iPhone) — Home: the "Find a doctor or clinic" search bar, the queue card ("Token 1 · Checked in · You're next."), the Next visit card with "+ 7 more upcoming", quick actions and the bottom tabs.

2. Search and discovery#

  1. Find care → type a need, or tap a suggestion.
    • Search runs automatically 350 ms after the patient stops typing and calls GET /api/v1/search/providers with q, lat/lng/radiusKm, specialtyKey, maxFee, availableToday, tenantType and cursor.
    • Specialties come from GET /api/v1/specialties.
    • Web extras:
      • Suggestion chips: "Knee pain", "Cardiologist", "Hospital near me", "Available today".
      • Filter chips: "Within 5 km", "Under ₹800", "Available today", "Hospital", "Clinic", "Doctor".
      • Specialty and radius dropdowns.
    • Mobile has specialty chips and radius chips (5/10/20/50 km, shown only once a location is set). It has no fee, availability or provider-type filters.
  2. "📍 Use my current location" (web) or "📍 Use my location" (mobile).
    • The browser or OS asks for location permission.
    • Results then show distances, and the radius control turns on.
    • If nothing is found inside the radius, a banner says "No results within X km — showing results within Y km instead."
  3. List / Map toggle.
    • The map uses OpenStreetMap tiles with one pin per branch. Tapping a pin shows that branch's result card.
  4. Result cards.
    • Each card shows type, clinic name, branch, locality, specialties and distance.
    • Web also shows the fee ("₹500 onward" or "Fee on enquiry"), the practitioner count, and an "Available today" band.
    • On web, the top result can carry a "Recommended" badge with its reasons.
    • Tapping a card opens the branch profile.

States

StateWebMobile
Loading"Searching…"Spinner
Empty, no filters"No results yet.""No results yet. Try a different search, specialty or location."
Empty, with filters (web)"Nothing matches all of those filters. Try removing one." with Clear filters—
ErrorThe server message or "Could not reach the search service.", with RetryThe same message

"Load more" (web) and infinite scroll (mobile, list view only) page through results with cursor.

Mobile search
Patient app (iPhone) — Find care: search box, specialty chips, "Use my location", the List / Map switch and result cards with specialties and practitioner count (no fee on mobile).

2.2 Branch profile (/providers/[branchId])#

  1. Open a result → the branch profile loads from GET /api/v1/public/branches/{branchId}. On web it is server-rendered and cached for one hour.
  2. What the patient sees:
    • Address, landmark, phone, and "Get directions ↗" (opens Google Maps).
    • Practitioners (n). Each practitioner shows name, specialty, qualification, years of experience, a rating line ("No reviews yet", "4.5 / 5 — 12 reviews", or "from a single review") and the fee.
  3. "Book appointment" opens booking for that doctor at this branch. Tapping the practitioner's name opens their profile.
  4. Empty state: "No practitioners listed at this location yet." An unknown branch shows 404 on web, or "This clinic/hospital could not be found — it may have been unpublished." on mobile.
Mobile branch profile
Patient app (iPhone) — Branch profile: address, "Get directions ↗", and Practitioners (2) with qualification, experience, rating line ("5.0 / 5 — 2 reviews", "from a single review"), fee and Book appointment. Note the type label reads "Hospital" for a clinic, because that is how the organisation is registered in the demo data.

2.3 Practitioner profile and reviews (/practitioners/[practitionerId])#

  1. The profile loads from GET /api/v1/public/practitioners/{id}. It shows specialty, name, qualification, "N years experience", "Speaks …" and the About text.
  2. Practises at (n) lists each branch with its fee and a Book appointment button.
  3. Patient reviews load from GET /api/v1/practitioners/{id}/reviews, which needs no sign-in and returns published reviews only, newest first.
    • The summary shows "{avg} / 5" and the count.
    • With only one review the page says "One patient's experience, not a track record…".
    • The practice's reply appears under "Response from the practice".
    • Empty state: "No reviews yet for {name}. Only a patient whose visit is complete can leave one…"
    • Reviews never affect search ranking.

3. Booking#

There are three steps: Choose a time → Review and confirm → Booked. Both apps show "Step n of 3 · …" (for example "Step 1 of 3 · Choose a time").

Booking — choose a time
Patient web (desktop) — Step 1 of 3 · Choose a time: doctor card with fee, "Who is this appointment for?", the two-week date strip and, for today, the empty state "No more openings today. Pick another day from the strip above."
Mobile booking
Patient app (iPhone) — Step 1 of 3 · Choose a time: the same doctor card, "Who is this appointment for?" set to Myself, the date strip and Morning / Afternoon slots ready to tap.
  1. Signed-out guard.
    • Web: "Sign in to finish booking with {doctor}. We'll bring you straight back here." with a Sign in button carrying ?next=.
    • Mobile: "Sign in to book an appointment."
  2. Who is it for? This appears only if the patient has family members, loaded from GET /api/v1/patients/me/dependents. Choices are "Myself" or "{name} ({relationship})".
  3. Main issue (where it sits differs by app).
    • Both apps ask for it on step 2, after a time is held (see step 6). Step 1 has no main-issue field and the time slots can be tapped straight away.
  4. Choose a date → choose a time.
    • The date strip covers 14 days from today (IST).
    • Slots come from GET /api/v1/booking/slots?practitionerBranchId=…&fromDate=…&days=1, grouped into Morning, Afternoon and Evening. Times already passed are hidden.
    • Loading: "Loading available times…"
    • Empty: "No openings on this date." (web adds "Try another day — the strip above runs two weeks ahead."). Web shows "No more openings today." when every remaining slot has passed.
  5. Tap a time → slot hold.
    • The system calls POST /api/v1/booking/holds with an idempotency key. This creates an appointment in status Reserved (HELD) that expires in 10 minutes.
    • If the slot was just taken (HTTP 409), the server's message appears with Nearby alternatives to tap instead.
    • The web helper text reads "Choosing a time holds it for 10 minutes while you review."
  6. Review and confirm.
    • A banner reads "Slot reserved — confirm within" with an M:SS countdown that turns red in the last minute.
    • A summary shows When, Doctor, Where, Patient and Fee.
    • "What is the main issue?" (web: "This goes directly to the doctor as the starting chief complaint."; mobile: "The doctor sees this as the initial chief complaint."). Confirm booking stays disabled until 3 characters are entered, with the hint "Add the main issue above to confirm."
    • "Choose a different time" returns to step 1. The hold is not released; it simply expires.
    • If the countdown reaches zero, the patient returns to step 1 with "Your hold expired after 10 minutes — please choose a time again." The server also expires holds on its own.
  7. Confirm booking.
    • The system calls PATCH /api/v1/booking/appointments/{id}/confirm, which moves the appointment from HELD to BOOKED. The UI shows this as "Confirmed".
    • The appointment.confirmed email is queued.
    • The main issue is then saved as pre-visit symptoms with PUT /api/v1/appointments/{id}/pre-visit. If that save fails, the booking still stands and the patient sees "…confirmed, but the reason for visit could not be saved. Add it from My appointments."
    • If the hold has run out: "Could not confirm this booking — the hold may have expired."
  8. Booked.
    • The screen shows "Appointment confirmed", the summary, and View my appointments. On mobile this replaces the navigation stack.
    • Web only: Add to calendar downloads thehealint-appointment.ics. Mobile has no calendar export.
Booking — review and confirm
Patient web (desktop) — Step 2 of 3 · Review and confirm: the "Slot reserved — confirm within 9:59" banner, the When / Doctor / Where / Patient / Fee summary, the main-issue box, a greyed Confirm booking with "Add the main issue above to confirm." and "Choose a different time".
Booking — review and confirm at phone width
Patient web (phone width) — the same review step stacked in one column; the countdown banner and the disabled Confirm booking stay above the fold.

4. Pre-visit form#

  1. Where to find it:
    • On each Upcoming appointment card (web and mobile; hidden once the visit is "In consultation").
    • On the web visit page, under "Before your visit", while the visit has not started.
    • The link reads "Add symptoms, medicines or allergies before your visit".
  2. Open it. Existing answers load from GET /api/v1/appointments/{id}/pre-visit.
  3. Fill in Symptoms, Current medicines and Allergies → "Save".
    • The system calls PUT /api/v1/appointments/{id}/pre-visit. The patient sees "Saved."
    • The patient can save as many times as they like before the visit.
  4. Attach a file (web only).
    • "Attach a file" uploads an image or PDF with POST …/pre-visit/uploads.
    • Attachments are listed and open through a signed link. Mobile can view attachments but cannot upload them.
  5. Who sees it. Only the patient and the treating doctor (the doctor it is booked with, or a colleague covering with a reason) can read it; other doctors and all other staff get a 403. See Permissions & privacy.

5. Family members (dependents)#

  1. Family (/family) → "Add a family member".
    • Required: Full name, Relationship to you (free text), Date of birth, Biological sex.
    • Optional: Blood group, Height, Weight, Known allergies, Chronic conditions, Phone.
    • The system calls POST /api/v1/patients/me/dependents. The list reloads.
  2. Edit calls PATCH …/dependents/{id}.
  3. Remove asks first: "They will no longer appear when you book… If they have appointments on record… they cannot be removed." It then calls DELETE …/dependents/{id}. The server refuses to remove a dependent who has appointments.
  4. States:
    • Empty: "No family members yet." with an add button.
    • Error: "We could not load your family profiles." with Retry.
  5. Booking for a dependent works through the "Who is this appointment for?" choice (section 3). On web, appointment cards show "For {name}" and the visit page shows "For". Mobile cards do not show who the visit is for.
  6. Profile (web and mobile) also lists family members, with links to manage them.
Mobile family
Patient app (iPhone) — Family profiles: each dependent with relationship, age and phone (if any), Edit and Remove buttons, and "Add a family member".

6. Managing appointments#

My appointments (/appointments) loads GET /api/v1/booking/appointments/mine and GET /api/v1/reviews/mine. It has two sections:

  • Upcoming: open statuses, sorted soonest first.
    • On web, the appointment must also start today or later (IST).
    • Mobile applies the same rule.
  • Past: everything else, newest first.

Each card shows doctor, specialty, place, date · time · fee, and a status badge. Web adds Visit details.

Status labels the patient sees

System statusPatient label
HELDReserved
BOOKED, CONFIRMEDConfirmed
CHECKED_INChecked in
IN_QUEUEIn queue
IN_CONSULTATIONIn consultation
COMPLETEDCompleted
CANCELLEDCancelled
EXPIREDExpired
RESCHEDULEDRescheduled
NO_SHOWNo-show
Appointments
Patient web (desktop) — My appointments: the live queue card ("Token 1 · With the doctor · You're with the doctor now."), an Upcoming visit "In consultation" (no change buttons, no pre-visit link), and a Past "Completed" visit with Rate this visit.
Appointments at phone width
Patient web (phone width) — the same page stacked; Book another moves under the heading.
Mobile appointments
Patient app (iPhone) — My appointments: the queue card on top, then Upcoming cards with status, fee, Reschedule, Cancel and "Add symptoms, medicines or allergies before your visit". Cards do not say who the visit is for.

6.1 Reschedule#

  1. Upcoming card → "Reschedule".
    • Both apps show it only before the visit has started (Confirmed).
  2. A sheet opens: "Reschedule with {doctor}", with the date strip and time slots.
  3. Web: tap a time, then see "Move to {date · time}? Your current time (…) is released." and choose Confirm new time or Keep current. Mobile does the same: tapping a time shows "Move to {date, time}?" with the current time underneath, and nothing moves until Confirm new time.
  4. The system calls PATCH /api/v1/booking/appointments/{id}/reschedule.
    • The old booking becomes "Rescheduled" and a new one is created.
    • The appointment.rescheduled email is queued.
    • Web shows the toast "Moved to …".
    • Errors: web shows the server message, or "That time is no longer available — please pick another."; mobile always shows that fallback text.
Reschedule sheet
Patient web (desktop) — Reschedule sheet: "Reschedule with Dr. Arjun Reddy", date strip, slots, and "Move to Fri, 16 Oct · 9:00 am? Your current time (…) is released." with Confirm new time / Keep current. Behind it, the Confirmed card shows Check in on tomorrow's visit (web does not limit check-in to the day; see Gaps).
Reschedule sheet at phone width
Patient web (phone width) — the same sheet slides up from the bottom of the screen.

6.2 Cancel#

  1. Upcoming card → "Cancel appointment" (web) or "Cancel" (mobile).
  2. Dialog: "Cancel this appointment?", showing doctor, date and time, with an optional reason ("Shared with the clinic so they know why.").
  3. "Cancel appointment" calls PATCH …/{id}/cancel.
    • The status becomes "Cancelled", the slot is freed, and the appointment.cancelled email is queued.
    • Web shows the toast "Appointment with {doctor} cancelled".
    • "Never mind" closes the dialog.

The server applies no time cutoff to cancel or reschedule: any BOOKED or CONFIRMED appointment can be changed.

7. Visit day#

7.1 Check in from the phone#

  1. Upcoming card → "Check in". Web offers it on every Confirmed upcoming appointment, even one on a later day. Mobile offers "I've arrived — check in" only on the appointment's day.
  2. The system calls PATCH /api/v1/booking/appointments/{id}/check-in. This is the same endpoint reception uses. The appointment joins today's queue with a token number and becomes "In queue".
    • Web toast: "Checked in — you're in the queue".
    • Error: "Could not check in — please try again or ask reception."
  3. Reception can also check the patient in (see 03-front-desk.md).

7.2 Live queue status#

  • A card at the top of My appointments (and on the web visit page while the visit is in progress) polls GET /api/v1/queue/mine every 20 seconds. Nothing shows if there is no live token.
  • It shows "Token {n}" and a pill:
Queue statePillHeadline
WaitingChecked in"You're next." / "One person ahead of you." / "{n} people ahead of you."
CalledCalled"You're being called — please go in."
In consultationWith the doctor"You're with the doctor now."
  • While waiting, it adds "Estimated wait about {n} min" when the server provides an estimate.

7.3 Visit page (/appointments/[appointmentId], web only)#

  1. Open "Visit details" or the doctor's name.
    • The page loads the appointment from …/appointments/mine, plus its history (…/{id}/history), the branch, invoices, the patient's reviews, prescriptions and fulfilment orders.
    • If the appointment is not the patient's: "We couldn't find this visit — It may belong to another account."
  2. What the patient sees:
    • Header: date, doctor, specialty · place, and a status badge.
    • Progress stepper (for open or completed visits): Booked → Checked in → With the doctor → Done. Closed visits show a sentence instead, for example "This appointment was cancelled.", "This visit was marked as missed.", or "This reservation expired before it was confirmed."
    • When & where: When, Where (with address), For, Fee. Buttons: Get directions, Call the clinic (only when the branch has a phone number; the demo branches have none, so it is missing from the screenshots), and Add to calendar (open visits only).
    • Before your visit: the pre-visit form (not-yet-started visits only).
    • History: a timeline of status changes with reasons.
    • Once the doctor has started the consultation: Prescription, Pharmacy & lab orders, Bill, and a review prompt for completed visits the patient has not reviewed yet (section 8).
  3. The page has no change buttons. It says "To check in, reschedule or cancel, use My appointments."

Mobile has no visit page. Appointment cards cannot be tapped.

Visit — upcoming
Patient web (desktop) — Visit page for a Confirmed visit: the stepper on step 1 (Booked), Before your visit with the pre-visit link, History, When & where with Get directions and Add to calendar, and "To check in, reschedule or cancel, use My appointments."

8. After the visit#

When the doctor completes the consultation, the appointment becomes "Completed". The system then creates the prescription (if medicines were added), investigation requests, an optional follow-up and an invoice, and queues the prescription.ready and encounter.follow_up_reminder emails. See 02-doctor.md.

Visit — completed
Patient web (desktop) — Visit page for a Completed visit booked for a dependent ("For: Thanush Family Child"): all four steps ticked, Prescription with Order these medicines, Pharmacy & lab orders (lab "Results ready" with View report, pharmacy "Out for delivery"), Bill marked Paid, and History. No review prompt, because this visit was already reviewed.
Visit — completed at phone width
Patient web (phone width) — the same visit; the stepper turns vertical and When & where moves to the bottom.

8.1 Prescription#

  • Web visit page → Prescription.
    • Each medicine shows name, strength, dose · frequency · duration, and instructions. Order these medicines links to /fulfillment.
    • Empty: "Your prescription appears here once the doctor issues it." or, once completed, "No medicines were prescribed at this visit."
  • The web visit page also has Dose timetable, which opens the prescription page.
  • Records → Prescriptions lists every prescription. On web each has View & dose timetable, and timeline entries for a prescription have "View prescription & dose timetable". Mobile keeps View, which loads GET /api/v1/patients/me/prescriptions/{id}.
  • Prescription page (web, /records/prescriptions/[prescriptionId]):
    • Header "Prescription from doctor" with "Issued date", the specialty and place, and Order these medicines.
    • Medicines: each with Dose, How often (with a plain-words line such as "Twice a day — morning, night"), For (duration), route and instructions.
    • Daily timetable: a grid of Morning, Afternoon, Evening and Night per medicine with its dates. Lead: "When each medicine is taken in a day. Times follow the usual meaning of what your doctor wrote — BD is morning and night, TDS is morning, afternoon and night. If your doctor told you different times, follow them." Frequencies it can't read are listed under "Take exactly as written".
    • Day by day: Day 1 (the day it was prescribed) onward, with today highlighted.
    • Prescribed by: doctor, registration number and council, where, issued, and for whom, with See the visit. A side note says the timetable is a reading aid and the issued prescription is what counts.
    • Not found: "We couldn't find this prescription — It may belong to another account."
  • There is still no PDF or download on either app.
Prescription with dose timetable
Patient web (desktop) — a prescription from Dr. Meera Iyer for a dependent: two medicines (Paracetamol 500mg twice daily for 3 days, Omeprazole 20mg once daily for 5 days), the Daily timetable grid with the doses in the Morning and Night columns, Day by day with Day 5 marked "Today", and the Prescribed by card with See the visit.

8.2 Pharmacy and lab orders (/fulfillment, mobile: Pharmacy & labs)#

  1. Choose Pharmacy or Diagnostic lab (mobile: Pharmacy / Diagnostics).
  2. Pick the clinical source. This is a prescription or an investigation from GET /api/v1/patients/me/fulfillment-sources.
    • Empty (web): "No prescriptions available — A clinician must issue one during a completed consultation first."
  3. Send to:
    • The hospital or clinic's own pharmacy or lab, or another verified one.
    • Then choose the Facility, loaded from GET /api/v1/fulfillment/facilities.
  4. Service: Pick up / Home delivery (pharmacy) or Visit lab / Home sample collection (lab). Then a Contact phone (prefilled from the profile) and a Home address for home services.
  5. Tick the consent box. On web it reads "I authorize thehealint to share only this selected clinical order and the contact details needed for fulfilment with the selected verified facility."
  6. "Send order securely" (web) or "Send securely" (mobile) calls POST /api/v1/patients/me/fulfillment-orders. The order appears in the list.
  7. Orders list.
    • Each order shows a status pill, Pharmacy or Diagnostics, its items, Hospital-owned or External, and the service mode.
    • Cancel is offered while the order is Requested or Accepted, via PATCH …/fulfillment-orders/{id}/cancel.
    • Both apps use friendly, sentence-case status labels.
  8. Lab reports. When a lab attaches a result, the web visit page and the web Pharmacy & labs list show View report, which opens the lab report page (section 9). The file itself comes from a signed link through GET /api/v1/patients/me/documents/{id}/url.

The pharmacy and lab side is covered in 05-pharmacy-lab.md.

Fulfilment
Patient web (desktop) — Pharmacy & diagnostic orders: Pharmacy / Diagnostic lab switch, the new-order form (Prescription, Send to, Facility, Service, Contact phone prefilled from the profile), the consent tick box, and Your orders with a "Scheduled" lab order and a "Requested" pharmacy order that can still be cancelled.
Mobile orders
Patient app (iPhone) — Pharmacy & labs: Pharmacy / Diagnostics switch, the same form with a shorter consent line, a disabled "Send securely", and "No fulfilment orders yet." Contact phone is empty here because this demo patient has no mobile number on their profile.

8.3 Bill, invoice and payment#

  • Web visit page → Bill shows the invoice number, the total, and either "₹X due" or the settled status.
  • Records → Invoices (web and mobile) lists all invoices from GET /api/v1/invoices, each marked "₹X due" or "Paid".
  • Patients cannot pay in the app. The API has payment endpoints (POST /api/v1/payments/orders, pay-at-facility, and a Razorpay webhook), but neither app calls them. Payment is collected at the facility by billing staff (see 03-front-desk.md). The patient receives the payment emails listed in section 12.

8.4 Review#

  1. Past card (Completed and not yet reviewed) or web visit page → "Rate this visit".
  2. Pick 1 / 5 to 5 / 5, add an optional comment → "Submit review".
    • The system calls POST /api/v1/reviews. The server accepts only COMPLETED visits ("You can only review a completed visit.").
    • Reviews publish immediately. Platform admins can hide them afterwards (see 06-platform-admin.md).
  3. Outcomes:
    • Success: "Thank you — your review is now on {doctor}'s profile."
    • Duplicate (409): "You have already reviewed this visit."

9. Health records (/records, mobile: Health records)#

There are four tabs: Timeline · Documents · Prescriptions · Invoices. Each loads when first opened.

  1. Timeline comes from GET /api/v1/patients/me/timeline. It lists encounters, prescriptions and documents in date order.
    • Empty: "Nothing on your timeline yet."
  2. Documents come from GET /api/v1/patients/me/documents.
    • To add one: choose a category (Lab report, Imaging, Prescription, Discharge summary, Insurance, Vaccination, Other), enter a title, then Choose file (image or PDF).
    • This calls POST /api/v1/patients/me/documents?category=…&title=…. With no title: "Give the document a title before uploading."
    • View opens a signed link. Lab reports instead have View report, which opens the report page.
    • Empty: "No documents uploaded yet."
  3. Prescriptions lists each prescription with View & dose timetable (web; see section 8.1) or View (mobile).
  4. Invoices lists invoice number, total, and either the amount due or "Paid".

Neither app lets the patient delete or share a document.

Lab report page (web, /records/reports/[documentId]). Reached from View report on Documents, on the visit page's orders, or on Pharmacy & labs.

  • Header: "Lab report · date", the report title, the tests and the lab, with Download and Open in new tab.
  • The report shown inside the page, with the note "Report not showing, or only the first page? Use "Open in new tab" — some phones can't display a PDF inside a page."
  • About this report: Tests, Lab, Ordered, Scheduled, Report released, For, File.
  • Lab order: status and service pills, the lab, each test with its instructions, and a link to Pharmacy & labs.
  • Requested at: the doctor and visit time, with See the visit.
  • Not found: "We couldn't find this report", with Your documents.
Lab report viewer
Patient web (desktop) — a "Paediatric blood investigation report" for a dependent: Download and Open in new tab, the report shown inline, About this report, the Lab order ("Results ready", "Walk-in") and Requested at with See the visit.
Mobile records
Patient app (iPhone) — Health records, Timeline tab: Consultation, Prescription and Document entries in plain words, with the Documents, Prescriptions and Invoices tabs alongside.

10. Care navigation (AI), mobile only#

  1. Home → "Not sure? Describe your symptoms".
    • The screen is titled "Describe your symptoms".
    • A banner reads "AI-assisted, not a diagnosis. In an emergency, call your local emergency number immediately."
  2. Type symptoms → send.
    • The system calls POST /api/v1/care-navigation/query with the message, a session id, and the patient's location if available.
    • A conversation is limited to 3 turns.
  3. Possible outcomes:
    • Clarifying: the assistant asks a follow-up question.
    • Red-flagged: a red emergency card with guidance appears and the conversation ends.
    • Completed: a symptom summary, suggested specialties and nearby providers. Tapping a provider opens the branch profile. If none are found: "No nearby providers found for this yet — try manual search."
    • AI unavailable: "The AI assistant isn't available right now — please use manual search below to find care."
  4. "Start over" or "Search manually" when the conversation ends.

The red-flag and knowledge-base content is marked as a synthetic placeholder pending clinician review. Web has no care-navigation page.

Mobile care navigation
Patient app (iPhone) — Describe your symptoms, before the first message: the AI-assisted warning banner, the prompt text, the message box and "Prefer to search manually instead?".
  1. The screen loads GET /api/v1/consents (what can be consented to) and GET /api/v1/consents/mine (the patient's grants).

  2. "What you can control" shows one card per consent. The seeded consents (version 1, placeholder legal text) are:

    • clinical data processing
    • marketing communications
    • ABDM data sharing

    Each card shows the purpose, a Granted or Not granted pill, the scope, and "Version N · granted {date}". If a newer version exists it says so.

  3. "Give consent" calls POST /api/v1/consents/{key}/grant.

  4. "Withdraw" opens a dialog: "Providers will stop being able to rely on it from now on. This does not delete anything already recorded…", with an optional reason.

    • "Withdraw consent" calls POST /api/v1/consent-grants/{id}/revoke.
  5. "Previously" lists withdrawn and expired grants: "v1 · granted {date} · withdrawn".

Mobile consent
Patient app (iPhone) — Privacy and consent: under "What you can control", the ABDM card is Not granted with Give consent; the clinical-records card is Granted.

12. Profile, account security and notifications#

Profile (/profile, mobile: Profile)#

  1. The profile loads from GET /api/v1/me.
  2. Account details: Username, Full name, Mobile number and Email are all required.
  3. My health settings: Date of birth, Biological sex, Blood group, Height, Weight, Known allergies, Chronic conditions.
  4. "Save profile" calls PATCH /api/v1/me and shows "Saved".
    • On web the button stays disabled until the required fields are valid.
    • On mobile an invalid form does nothing, with no message.
  5. Family profiles shows a summary of each family member and links to Family.
Mobile profile
Patient app (iPhone) — Profile: Account details (Username, Full name, Mobile number and Email marked required) and My health settings (date of birth, sex, blood group, height, weight). Sign out is further down the page.

Account security#

  • Sign out: the web account menu, or the Sign out button at the bottom of Profile on mobile.
  • There is no password change, password reset, two-factor setup, session list, account deletion or data export for patients on either app.

Notifications#

Notifications are email only. The API's notification outbox sends email over SMTP. SMS (MSG91) is blocked on TRAI DLT registration, and push (Firebase) has no project configured; both fail closed. Neither app has an in-app inbox, notification bell or notification preferences.

TriggerEmail template
Booking confirmedappointment.confirmed — "Appointment confirmed with {doctor}"
Appointment cancelled (by patient or clinic)appointment.cancelled
Appointment rescheduledappointment.rescheduled
Consultation completed with medicinesprescription.ready — "Your prescription from {doctor} is ready"
Follow-up recommendedencounter.follow_up_reminder (held until the recommended date)
Payment received / collected at facility / pay-at-facility confirmed / refundedpayment.captured, payment.collected_at_facility, payment.pay_at_facility_confirmed, payment.refunded

Permissions & privacy#

  • Own records only. Patient endpoints (/patients/me/*, /booking/appointments/mine, /queue/mine, /reviews/mine, /invoices) are limited to the signed-in profile and their dependents by row-level security. Opening another account's visit shows "We couldn't find this visit".
  • Pre-visit information (symptoms, medicines, allergies, attachments) can be read by the patient and by the treating doctor only: the doctor the appointment is booked with, or a colleague who opened it as cover with a reason. Other doctors, reception, nurses, billing and clinic admins get a 403 and see "Only the treating doctor can see what the patient shared before the visit."
  • Clinical notes written by the doctor are not shown to the patient. The patient sees outcomes only: prescription, orders, reports and invoice.
  • Fulfilment sharing needs an explicit consent tick for each order. Only the selected order and contact details go to the chosen verified facility.
  • Consent grants and withdrawals are versioned and kept as history.
  • Reviews are public with no patient name shown, can be left only after a completed visit, and do not affect search ranking.
  • Dependents have no login. All of their data sits under the guardian's account.

Gaps & known limitations#

Sign-in and account

  1. No one-time-code sign-in, yet the error copy says "If you normally sign in with a code, use that instead" and "That code has expired…". Mobile still contains an unreachable Verify (code) screen.
  2. No password reset, password change, two-factor setup, account deletion or data export for patients.
  3. No consent step at sign-up or booking. Consent exists only on the Privacy screen.
  4. Some raw system values still reach users: care-navigation severity and specialty keys, and the branch type on web. (Fixed on mobile: the debug "API: ok" line is gone, and branch type, timeline record type, invoice status and order status now read in plain words.)
  5. Mobile profile save fails silently when a required field is invalid. The "Signed in as" name on Home does not update after saving.

Booking and appointments

  1. No check-in date check on the server or on web. Mobile offers "I've arrived — check in" only on the appointment's day, but web shows Check in on any Confirmed upcoming visit, and the API would place an early check-in in today's queue.
  2. No cancel or reschedule cutoff on the server, and no policy text in either app.
  3. Mobile offered Reschedule and Cancel too broadly — fixed: only before the visit starts.
  4. Mobile Upcoming was decided by status only — fixed: past days move to Past.
  5. "Choose a different time" does not release the hold. The slot stays reserved for up to 10 minutes.
  6. Booking page details rely on the link (web). Doctor name, clinic and fee come from URL parameters, so opening /book/[id] directly shows "Doctor" and no fee.
  7. Two status names share one label. BOOKED and CONFIRMED both show as "Confirmed", and a confirmed booking is stored as BOOKED.
  8. Mobile reschedule hides the server's error message.

Visit and after-visit

  1. Mobile has no visit page. There is no per-visit prescription, orders, bill, status history, directions, call or Add to calendar.
  2. No Add to calendar on mobile.
  3. No in-app payment on either app, even though payment endpoints exist. Invoices are view-only, with no line items (mobile) and no download.
  4. No prescription PDF or download.
  5. Pre-visit attachments cannot be uploaded on mobile. Doctors on web cannot see attachments in the consultation screen either; doctor-mobile can.
  6. Mobile fulfilment:
    • No success message after sending.
    • No empty-state text when there are no sources or facilities.
    • Prescription choices show only "{n} medicines".
  7. Mobile records:
    • An error never clears.
    • A failed tab spins forever.
    • Dates used device time — fixed: India time.
  8. No delete or share for uploaded documents.

Other

  1. Care navigation is mobile-only, and its clinical content is a synthetic placeholder.
    • It needs ANTHROPIC_API_KEY; without it every query returns "AI unavailable".
  2. Consent grants are recorded but never enforced. No other module checks them, so withdrawing "clinical data processing" changes nothing about access. ABDM appears only as a consent type; there is no ABDM integration.
  3. Pre-visit has no edit window. The server accepts edits even after the visit.
  4. Pre-visit uploads skip checks. They do not go through the malware scan or the file type/size limits that health-record uploads have.
  5. Some emails send blank doctor and clinic names. Several email payloads leave both fields empty.
  6. No reminder emails. Nothing goes out before an appointment, when a hold expires, or when the queue calls the patient.
  7. Email is the only notification channel. SMS and push are built but not configured, and there is no in-app notification centre or preference screen.
  8. No pull-to-refresh on mobile. Appointment lists reload only after the patient's own actions (the queue card polls every 20 seconds).

Region: time zone and currency (added Oct 2026)#

Every time and fee a patient sees belongs to the clinic: the API sends each appointment, search result, branch profile and practitioner affiliation with the clinic's currency and timeZone (the phone apps also receive utcOffsetMinutes, the clinic's offset from UTC at that moment, so they need no time-zone database). Web: clinicSettings(clinic) from @health-platform/ui formats money, dates and times; the booking page receives currency and tz in its link. Mobile: ClinicFormat in mobile_core. "Today", the date strip, the slot grid's morning/afternoon/evening and the check-in rule all use the clinic's calendar. Invoice amounts in Records and the consent and review dates still use the platform default (India) because those payloads do not carry the clinic yet.

Creating an account (web and app) says it means agreeing to the Terms and Privacy policy, linking to thehealint.com/terms and /privacy. The agreement is stated, not yet recorded per account.

PDF version

The same guide with all its screenshots, to print or share. (2.0 MB)

Download the PDF Open in a new tab

Loading the PDF viewer… If it does not appear, your browser cannot show PDFs inside a page: use Download the PDF.