Medical documents, parsed into structured data
MedQT is a live health-records app from SkyClad Ventures in Dubai. I joined as a founding developer in September 2025 and work on the iOS app. A scanned document goes up through a presigned-URL pipeline gated by App Attest, OCR pulls labs, medications and imaging findings out of it as typed fields, and what comes back is a record the whole family can share.
View on the App StoreOverview
MedQT is built by Amelay MedTech, and I work on it as one of the founding developers. On the iOS side it is a repository layer over async/await with SwiftUI feature modules on top, and UIKit bridged in where the platform still needs it.
The document path is the spine of the app. A capture is uploaded through a presigned URL with a SHA256 check, OCR starts server-side, and the client polls a seven-state job machine on a cancellable Task until the extraction finishes or the plan quota stops it. No timers, no Combine, just a loop that cancels cleanly when the screen goes away.
Everything else hangs off the record that comes back: a role-based Family Circle, reminders that mirror into Apple Reminders and Calendar through EventKit, symptom tracking with trend charts, and a patient ID card issued as a signed PKPass. App Attest guards the upload endpoints, CryptoKit and libsodium handle encryption, and OneSignal drives push and cold-start deep links.
Tech stack
- Swift
- SwiftUI
- async/await
- EventKit
- PassKit
- App Attest
- CryptoKit
- libsodium
- LocalAuthentication
- OneSignal
- RevenueCat
- Sentry
Inside the app
Live captures from the build. The app ships light and dark appearances, so these follow whichever one this site is set to.
Records, grouped into folders with upload and AI scan quotas. Family Circle: members, roles, and who added what. Home screen widgets for the day’s appointments and medications.
On the App Store
The product
Medical history is usually spread across a drawer of paper and a camera roll of half-legible photos. Four features carry the app’s answer to that.
Records, the part everything else hangs off
A record here isn’t a folder of images. Scanning a lab report gives you typed fields for the test name, value, unit, reference range and date, plus any medications and imaging findings on the page. The document becomes searchable data instead of a picture of data. Records group into folders, and the header carries the two numbers that actually constrain someone: how many uploads and how many AI scans their plan allows this month.
OCR on a phone photo of a printout is never clean, so nothing gets committed silently. Extracted values land in an editable review step first. The app proposes, the patient confirms.
Family Circle, because patients rarely manage alone
The person who needs a record is often not the person it belongs to. A parent keeps track of a child’s vaccinations, an adult child keeps track of a parent’s medications. Family Circle models that with four roles: owner, co-manager, caregiver and dependent. Each carries its own permissions, and a dependent is someone being cared for rather than someone you send an invite to.
Invitations go out by phone number or email through the same endpoint. Membership changes come back as push events that invalidate the circle and trigger a fresh fetch, so a caregiver accepting on their phone updates the owner’s screen without either of them reloading anything.
Reminders that live where you already look
A medication reminder is worthless if it only fires inside an app you open twice a week. Reminders are created in MedQT and scheduled server-side with full RFC 5545 recurrence, then mirrored onto the device through EventKit. A medication becomes an EKReminder in Apple Reminders and an appointment becomes an EKEvent in Calendar, so they turn up on the Lock Screen and the Watch, in the place someone already looks.
When OCR reads a prescription it suggests the reminders that follow from it, each with a confidence score to accept or reject. The app never quietly fills someone’s calendar on its own.
Symptoms, the data no document holds
A lab report captures one moment. How someone actually felt between visits never makes it onto paper, and that part of a history usually gets reconstructed badly from memory in the doctor’s office. Symptom entries record severity over time and chart the trend, so you walk into an appointment with a shape instead of a guess.
What I found interesting on the iOS side
Three bits of the iOS work that were more involved than they look from the outside.
Mirroring reminders into EventKit, dose by dose
EventKit recurrence cannot express “three times a day” inside a single EKReminder. So a medication gets mirrored as one EKReminder per dose, each with an absolute alarm computed from that dose’s time. An appointment is the easy case: one EKEvent with a relative “X before start” alarm.
Editing is the hard part. On every change the stored identifiers get paired against the new dose list, so matched pairs are updated in place, extras are created and orphans are deleted. The count in Apple Reminders always matches the backend. Changing a reminder from a medication to an appointment moves it between stores completely, which means removing the old item from Reminders before writing the new one to Calendar. The whole sync is best effort and sits behind a user toggle. If access is refused or a write fails, the backend reminder carries on untouched.
A patient ID card that lives in Apple Wallet
The emergency ID is a real PKPass, not a screenshot of one. The app builds the payload from the patient’s record (blood type, allergies, active medications, emergency contact) plus a scannable QR that resolves to their emergency profile. A pass has to be cryptographically signed by the issuer, so signing happens server-side. The app requests one, gets the signed .pkpass back, and hands it to PKAddPassesViewController so the user confirms the add themselves.
Invalidation turned out to matter more than issuance. Medical facts change, and a stale pass sitting in someone’s Wallet is worse than no pass at all, so updates get pushed to the pass instead of leaving whatever was true on the day it was added.
Proving the request came from a real build
Health documents are the last thing you want flowing through an endpoint anyone can hit. The upload and OCR path is gated with App Attest, using a Curve25519 key attested at install and then a per-request assertion, so the backend can tell a genuine unmodified build apart from a replayed or repackaged one.
Uploads go through presigned URLs with SHA256 verification, sensitive fields are encrypted with CryptoKit and libsodium, and the vault sits behind Face ID with a passcode fallback. None of it shows up in the UI, which is more or less the point.









