What building two other apps first taught me before I started MedSync
MedSync is the third app I've built this way, not the first. By the time I started it, I already had a working caching strategy from a budgeting app and an AsyncStorage pattern for passing data between screens from a sports scheduler, both proven against real usage, not just my own testing. Starting the third app with two finished ones behind me sounds like it should mean everything gets easier. Some of it did. Some of it needed rethinking specifically because a medication app is not a budgeting app, and getting a number wrong here doesn't mean an inconvenient dinner-table conversation — it means someone finds out they're out of blood pressure medication by running out.
What carried over cleanly
The data-loading pattern MedSync uses everywhere — cache the last known result, show it instantly on navigation, quietly refetch in the background — isn't something I redesigned. It's the same useQuery plus useFocusEffect shape I'd already leaned on for a previous app, and it's exactly the kind of decision that's genuinely safer to reuse than to reinvent: it had already been exercised across dozens of screens and real navigation patterns before MedSync's first screen existed. Same story for the AsyncStorage handoff trick that lets a pushed screen — adding a new medicine, adding a new doctor — hand a value back to the screen that opened it, since Expo Router itself has no built-in way to do that. Both patterns showed up in MedSync's very first sessions, not because I was being lazy, but because a data-loading strategy that's already survived contact with real users is worth more than a fresh one that merely looks reasonable.
What I didn't carry over on purpose
What I refused to reuse was the level of trust I'd put in a single formula living in a single place. In a budgeting app, if a total is wrong for a day before someone notices, the cost is confusion. In MedSync, the number on this screen — days of medication remaining — is the number a caretaker is actually relying on to know whether to reorder a prescription before their parent runs out. That number has to be exactly, provably the same whether it's read off the caretaker's own stock tab or off the patient's phone, because those are two different people, on two different screens, sometimes days apart, both trusting it to mean the same thing.
It does — both screenshots on this post show the same medicine, same patient, same moment: 29 tablets, "Good," 29 days remaining, whether you're looking at the caretaker's app or the patient's. That's not a coincidence I'm proud of because it's clever. It's one formula — initial stock, plus every restock, minus every dose actually marked taken, times how many units per dose — computed the same way regardless of which screen is asking, so there's no second version of the math anywhere left to quietly disagree with the first.
The bug that proved the formula wasn't as settled as I thought
Getting there took a real bug, not a hypothetical one. MedSync lets a caretaker link multiple medication courses to one shared medicine record — a patient restarting the same prescription after a gap, say. Early on, each course computed its own remaining stock independently off that same medicine's starting count, which meant a medicine linked to two courses got counted twice: once per course, both claiming the same physical tablets. The stock tab would show plausible, confident numbers that were simply wrong the moment more than one course pointed at the same bottle.
The fix was to stop computing stock per course and instead pool every course sharing a medicine into one number, computed once, assigned to whichever course is actually active. What actually stung was that fixing it once didn't fix it everywhere. The pooling logic had to land separately in the caretaker's own stock tab, in the dashboard's low-stock alert banner, and in the patient's read-only stock screen — three different queries, built in three different sessions, each one independently capable of getting this wrong again if a future change touched one without touching the other two. Porting a fix between two sibling apps taught me that a lesson doesn't travel with the code by default. This taught me the same lesson can fail to travel between two screens in the same app, a few files apart, if nothing forces them to share one answer.
The honest takeaway
Two finished apps bought me real, provable-safe patterns — a caching strategy and a cross-screen data trick I didn't have to re-earn the hard way a third time. They didn't buy me a pass on treating a healthcare number with more suspicion than a budgeting one, and they didn't automatically protect the one formula that mattered most just because I'd been careful about formulas before. That protection came from writing the rule down in the one place every session is required to read first — a single stock calculation, applied identically everywhere it's computed, checked against the same live numbers on both sides of the app before I called it done. The pattern-reuse made MedSync faster to build. It was never going to make it safe to build carelessly, and a medication app is exactly the kind of project where that difference actually matters.
More in this series

Why I built MedSync — and why it's a website, not an app
My mom asked if she'd already taken her medicine that day. I didn't know — and Google Play almost stopped me from fixing that.

The patient who never signs in: how MedSync shares a live schedule with someone who has no account
The person taking the medication was never going to manage a password. Here's what replaced the login screen instead.

The back button rule: what actually keeps a 30-screen app looking like one app
Color tokens are the easy 20%. Here's what actually kept thirty-plus screens looking like one app.

The medication that showed up a day late — but only for patients in the wrong timezone
It passed every test I ran myself, and was wrong for anyone testing it at the wrong hour, in the wrong timezone.