Mobile Apps

Native iOS · SwiftUI

Three native iPhone apps, three different jobs, one build discipline — a coding-session companion, a reconstitution tracker, and a field-services driver app, all out of the same SwiftUI monorepo.

Halcyon Driver job detail screen with directions, call, access notes, load details and a photo evidence chain
The challenge

Driving and reviewing coding sessions meant sitting at the desk they ran on — away from it, there was no way to check a session's status or browse what it had produced.

Peptide reconstitution tracking lived across notes and spreadsheets — dose math worked out by hand each time, no record of which injection site was used or when.

Halcyon Clearance's drivers ran their day off a phone with no purpose-built app — no single place for the day's jobs, directions, access notes, or the photo evidence a finished job needs.

One constraint sat under all three: the person building them works on Windows, and Apple's tooling does not. Every build has to leave the machine it was written on.

What was built, and why it was built that way

Operator Console — a native SwiftUI companion, built for iPhone and shipped to TestFlight on the phone. A session list shows every coding session with its live status, and a Library tab opens the same artifact store the desktop tooling writes to, so a session's output is checkable from a phone.

VialKit — a native reconstitution calculator and tracker. A dose calculator, vial inventory with concentration and shelf-life, dose history with an adherence heatmap, and injection-site rotation — a body map that shows a suggested next site and how long each site has rested.

Halcyon Driver — a native driver app for the field, built as a release build and installed straight onto a real iPhone. A job list split into Today, Coming up and Done; one tap for directions or a call; access notes, load details, and a structured before/after photo-evidence chain that closes a job out properly.

The driver app's evidence chain is the piece that had to be right. A job photo is taken in a yard on one bar of signal, at a moment that will not come back, by someone who has already moved on — so the shutter writes to disk first and the network happens afterwards, on its own schedule. The outbox behind it is a plain file written atomically rather than a database: a handful of records with a single reader has no migration story and no store to corrupt. It sits in the phone's application storage, out of the Files app, encrypted while the phone is locked but deliberately not so tightly that an upload already in flight is killed by the screen going off.

That app is also a guest on someone else's backend, and MAST built it that way on purpose. The rules deployed on the business's own database — not the brief, not a diagram — are the specification: they fix the photo phases by name, allow no job state after completed, and reject a location field outright. Against an allowlist like that, a design that disagrees does not degrade gracefully, it is refused. So the contract was read off the live rules before a screen was drawn.

A driver build that carries no credentials for the real business runs on obviously-fake data behind a banner the user cannot swipe away. That is what lets a build be proven to run and render on a machine holding no credentials for a real trading business — and the banner does not close, because the entire risk of shipping sample data is somebody believing it.

VialKit's dose calculations are exact decimals end to end — floating point only ever appears at the storage and display edges. Every figure in its engine is written as an exact decimal, and a gate scans that engine for numeric constants nobody has signed off — a rule that exists because an independent checker planted one in the codebase's own idiom and walked it straight past an earlier version of the same gate.

The pipeline underneath is the same for all three. Sources are authored on Windows and shipped over SSH to a Mac that exists only to build, sign and install; the project files are generated from one manifest rather than hand-edited, so nothing drifts between apps; and a half-delivered archive fails loudly instead of quietly building yesterday's code.

Screenshot walk-through

What it actually looks like, running.

Operator Console session list showing several projects and their live/idle status
Operator Console — every coding session at a glance, status and all, from a phone.
VialKit site rotation screen with a body map, a suggested next injection site, and a rest interval
VialKit — a body map suggests the next site, and the rest interval is set by the person using it, not asserted as fact.
Halcyon Driver job list split into Today, Coming up and Done, showing a sample-data banner
Halcyon Driver's job list — today's run in order, with a build clearly labelled as sample data, not real jobs.
What it meant

Three different problems, the same build discipline underneath — one SwiftUI monorepo, one Windows-author/Mac-build pipeline, three app shapes each honest about what it is: VialKit makes no medical claim, and a Halcyon Driver build running on sample data says so on the screen itself, not in a README nobody reads.

Each app reaches the person who needs it exactly where they are — the console on a phone away from the desk, the tracker at the point of drawing up a dose, the driver app in the cab between jobs.

The habit that keeps them honest is how a change is proved. Layout claims are read out of the running app's own accessibility tree rather than judged from a screenshot — one build reported that all ten keys of a row fitted, and the dump put the last key well off the side of a 402-point screen. A screenshot would have agreed with the build.

The stack
Swift / SwiftUIXcodeGen monorepoSwiftDataFirebase REST (no SDK)Decimal-precision calculator coreDurable on-device evidence outboxWindows-authored, Mac-built

Half an hour to see what an exacting fit looks like for your business.

Start a conversation
MAST
consulting
MAST Consulting · Applied AI for real workflows
matt@mastconsult.co.uk · MAST Consulting is a sole trader.