Medtech · Mobile
Anamna
A patient app for a clinic: appointments, test results and reminders on one screen. The work underneath that screen was proving a patient is the person the record belongs to, and deciding what a notification is allowed to say.
- Role
- Product design, mobile development, backend
- Timeline
- 6 months
- Stack
- React Native · Expo · Node.js
What changed
- 1 account
- instead of three. Booking, results and reminders were three separate logins, and one of them was handed over on a slip of paper at the desk.
- 44%
- of bookings made by patients themselves in the app by the end of the first year. Through the website before launch it was 17%; the rest came by phone.
- 12 minutes
- worst case from a result being signed off in the laboratory to the notification. Patients used to find out it was ready by calling to ask.
- 800 → 510
- status calls a week — is my result ready, what time am I due. One patient in three uses the app, but the people who called most were the ones who come most often.
What did not change is the share of appointments that do not happen: 11.8% before launch, 11.2% a year later. That gap sits inside the year-to-year swing, and we are not going to book it to the app. What did change is the warning: around 1,400 appointments a year are now cancelled in the app more than a day ahead, where cancelling used to mean getting through by phone in office hours. About half of the freed slots were filled again — a day’s notice is not enough for every speciality.
Before
A patient kept three accounts — one for booking, one for results, one for reminders — and still missed appointments. Booking lived in the clinic’s system, results on the laboratory’s portal behind a login handed over on a slip of paper, and reminders arrived as texts nobody could answer: cancelling meant getting through by phone during office hours.
- Three logins for one person. To the clinic’s system he was a record with a surname and a date of birth; to the laboratory, an order number on a printed slip; to the mailing list, a phone number.
- Of 2,600 calls a week, some 800 were not about booking at all but about status: is my result ready, and what time am I due.
- Cancelling took a phone call in office hours. The clinic learned a patient was not coming when the appointment was due to start, and the slot was simply lost.
What we built
One app over three systems: booking from the clinic’s system, results from an outside laboratory, reminders — and the match between a patient and a medical record, without which none of it can be shown.
Notifications that give nothing away: the text is assembled on the server from a closed set of templates, and the tests a doctor has to explain never reach the app at all.
Published to the App Store and Google Play under the clinic’s own account: the stores do not take an app handling medical data from a contractor.
Outcome
In the first year 18,000 patients used the app — roughly one in three of everyone who came to the clinic that year. Booking and results ended up in the same place as the reminder, and what gets shown to whom is decided on the server against the consents, not by the screen.
The client
A private multi-speciality clinic: four sites in one city, a hundred and thirty doctors, adults and children. Around ninety thousand appointments a year, spread across roughly fifty-five thousand different patients.
Roughly every second appointment ends in a lab order: samples are taken at the clinic and processed by an outside laboratory — about nine hundred orders a week. The card index holds two hundred and ten thousand records, fifty-five thousand of them opened at least once in the last year. Nine call-centre operators take around two thousand six hundred calls a week.
The brief
- What the client asked for
- A patient portal, but in the phone. The website already had one and almost nobody used it; they wanted an app where a patient sees appointments, results and reminders. The deadline was the opening of the fourth site.
- What the brief turned into
- The screen turned out to be a consequence rather than the job. Three systems knew the same person in three different ways — a record with a surname and a date of birth, an order number on a slip, a phone number on a list — and nothing proved they were one person. Until that is settled, showing someone their results means showing them somebody’s results. So the first two months went not into screens but into two questions: who is this patient, and what exactly did they agree to.
Why the obvious route was closed
Medical data does not allow the usual order of build first, lock down later. Every constraint here either sits inside somebody else’s system or is written into law, and every one of them shows in the architecture.
- The clinic’s system
- The schedule and the medical record live in an off-the-shelf system maintained by its vendor. It faces outward through a single gateway and offers a limited set of calls: a free slot can be taken and a taken slot released, but a slot cannot be created, a doctor cannot be moved and an appointment cannot be made longer. The app inherits that — rescheduling means releasing one slot and taking another.
- The laboratory is outside
- Samples are taken at the clinic and processed by an outside laboratory running its own system. It hands finished work over in batches every ten minutes, not as an event per result. So instant is not on the table: up to twelve minutes pass between a result being signed off and a notification arriving, and promising less would be untrue.
- The lock screen
- A push is readable without unlocking the phone, and the phone is not always in one pair of hands. That makes the notification text medical data in itself: a hormone panel named on a lock screen tells more about a person than they agreed to tell. The same goes for an appointment reminder — the doctor’s speciality is one line too many.
- Consent and the guardian
- Consent is not a checkbox at sign-up but a state: it is given, re-confirmed when the wording changes, and withdrawn. A parent gives it for a child, and at the age where a patient becomes the owner of their own data, the parent’s access has to close by itself rather than on somebody’s memory. Withdrawal switches the app off but does not delete the medical record: the retention period is not the clinic’s to set, and the app says so plainly.
- Data does not leave the perimeter
- Not into analytics, not into crash reports, not through a third-party push relay. That constraint took half of the usual toolkit out of the project and settled where the backend lives: inside the clinic’s perimeter, next to its own system, rather than wherever suited us.
How the work ran
- 01
Discovery
4 weeksFor two weeks the call-centre operators tagged every call with a topic: 2,600 calls a week, of which about 800 were is my result ready and what time am I due. In parallel, the clinic’s lawyer and the head of the laboratory worked through what the app may show and what a doctor has to explain in person. The output was not mockups but a list of what the app would not do.
- 02
Identity and consent
5 weeksSign-in by code, matching a patient to a medical record, the come-to-the-desk-with-ID branch, consent versions, an access log. Almost no screens yet: until there is an answer to who this patient is, every screen shows somebody else’s data.
- 03
Booking
4 weeksThe schedule, free slots, cancelling and rescheduling, reminders a day and two hours ahead. This is where it turned out that cancelling matters more than booking: you can book by phone, but you cannot cancel at nine in the evening.
- 04
Results and notifications
6 weeksIngesting the laboratory batches, the doctor-delivers flag, notification templates, sending straight to APNs and FCM. The long part was not the code but the wording: the head of the laboratory and the lawyer read every notification, and eight of the sixteen came back to be rewritten.
- 05
Trial, stores and rollout
7 weeksThree weeks with clinic staff and their families — sixty people — then two sites, then the other two. The first App Store submission was rejected: the developer account was ours, and the stores expect an app handling medical data to be published by the medical organisation itself. The account was moved to the clinic, and the reviewer was given a demo patient with an invented record, because real test results cannot be handed to review.
Technical decisions
The stack answers one condition — two platforms, six months, medical data. React Native and Expo give one app on both platforms; Node.js sits between it and two systems belonging to other people, and deliberately keeps no copy of a medical record.
A phone number opens the app, not the record
The SMS code proves control of a number, and nothing more. Matching a patient to a medical record is a separate step: phone, surname, first name and date of birth all have to agree, and no second candidate may exist in the index. Anything short of that sends the patient to the desk with an ID. In the first year 94% of everyone who signed up matched automatically; around 1,100 people were sent to the desk.
Consent as a state, not a checkbox
A consent record carries the wording it was given against, a date, how it was collected and how long it runs; a withdrawal is a record of the same kind, not the deletion of the previous one. A parent’s access to a child’s record is opened on a written request at the desk and closes on its own the day the child becomes the owner of their own data. Beside it sits an access log: who opened my results now has an answer, and our own support access is in there too.
A notification that gives nothing away
The text is assembled on the server from a closed set of templates, with exactly three substitutions: time, site and order number. No template holds a test name, a diagnosis or a doctor’s speciality — not as an agreement never to fill them in, but because there is nothing to fill in. Pushes go straight to APNs and FCM: expo-notifications will happily relay through Expo’s own service, which is markedly simpler, but the notification text would then travel through somebody else’s servers.
Some results the app never shows
The laboratory flags the tests a doctor is meant to explain. Those never reach the app at all: the notification says a result is ready and an appointment is needed, and offers to book one. The cut-off sits on the server rather than in the interface — the app never receives the file, so it cannot show it by mistake.
One app on two platforms, and what it cost
Two mobile developers and six months for iOS and Android: natively that means doubling the team or shipping the platforms one after the other. React Native answers that, and Expo covers builds and over-the-air updates — a bug in the reminder time zone was fixed within a day, without waiting for review. Two things were paid for it: Expo’s push service goes unused, and storing a result file had to be written as a native module, because the ready-made wrappers put it in a directory the system backup picks up.
A backend that holds no medical record
Node.js fetches the schedule and the results from the clinic’s system and the laboratory on request. It keeps only what the app cannot run without: the link between a patient and a record, consents, device tokens and the access log. The reason is plain — a copy of a medical record is a second place it can leak from. There is a cache, and it is named: the list of upcoming appointments lives five minutes, or the screen would take seconds to open. The result file is never cached; its link lives two minutes and works once.
What stayed outside the scope
Some of it was left out deliberately; some of it ran into something other than code.
Payment. Appointments are paid at the desk or by invoice; online payment and insurance handling did not go into the app — that is a separate perimeter and a separate contract.
Remote appointments. A chat with a doctor and video consultations were asked for and deferred: a remote appointment has its own identification, its own entry in the record and its own storage rules, and it does not get bolted onto booking.
Duplicate records. Discovery found around 3,400 people holding two records, opened at different sites. The app does not merge them: merging records is a decision for a doctor and the front desk, not for software, so a patient sees the record they are matched to.
Readings patients take themselves — blood pressure, glucose, weight. Left out at this stage: whatever a person enters has to be looked at by someone, and until it is settled who, the app would be promising monitoring that does not exist.
People without a smartphone. 18,000 patients out of 55,000 also means the other 37,000 still call. The call centre was not cut back, and half of all bookings still come by voice.
In progress: a second laboratory with an export format of its own, and working out why only about two thirds of the 1,100 people the app sent to the front desk actually went.
More projects
Fintech
Splitta
Instalments for online stores: buyer checks, a payment schedule and refunds — on real payments from day one.
7 weeks
from first call to production
Next.js · Node.js · Docker
Manufacturing
Naryado
A furniture plant where order, schedule and shipment travel under one number, and five systems already in place exchange data through the loop instead of spreadsheets.
5 systems
running on a single order number
Python · PostgreSQL · Redis
Contact
Send a description of the task
A reply with the scope, the timeline and a budget estimate comes within 24 hours.
The first call is 30 minutes, with no commitment on your side.