The patient who never signs in: how MedSync shares a live schedule with someone who has no account
Here's the requirement that sounded simple and wasn't: the person actually taking the medication should never have to remember a password.
MedSync has two kinds of users on opposite ends of a phone screen — a caretaker managing someone's medications, appointments, and stock, and a patient who just needs to see "what do I take, and when." In practice, that patient is very often someone elderly, sometimes not especially comfortable with a smartphone to begin with, and absolutely never going to successfully recover a forgotten password over a support email. Any login screen at all was already the wrong design for who this app is actually for.
So the patient side of MedSync has no email, no password, and no account in the sense anyone would normally mean it. And yet a patient's phone still needs to see live, private medical data — someone else's medications, someone else's appointments — safely, and stay showing it correctly for months without that person ever "logging in" again. That combination is the whole architecture problem this post is about.
A code instead of a login
Setup works the other way round from a normal app: the caretaker generates a 6-digit code from their own dashboard, good for ten minutes, and reads it out to the patient once — over the phone, in person, however. The patient opens MedSync, taps "I am the patient," types the six digits into a numpad, and that's the entire signup. No name to type, no email to verify, no password to invent and immediately forget.
Behind that numpad, the patient's phone gets a real Supabase auth session — just an anonymous one, created the instant the code is accepted. It's a genuine identity as far as the database is concerned, with its own ID, its own auth token, everything Row-Level Security needs to work. It's just not attached to an email address anywhere, because nobody was ever going to ask this person to remember one.
One row decides what an anonymous stranger can see
An anonymous auth ID by itself means nothing — it's just a random identity with no data attached. The moment the pairing code is verified, the app writes exactly one row into a table called patient_sessions, linking that anonymous ID to a specific patient, and that patient to a specific caretaker. Every table that holds anything private — medications, consultations, medical reports, the stock changelog — has a Row-Level Security policy that all resolves the same question the same way: does a patient_sessions row exist connecting the person asking to the patient this data belongs to? If yes, they see it. If no, the database never returns the row in the first place, regardless of what the app's own code assumed or forgot to check.
That's a decision I'd make the same way again on any project like this: the permission logic isn't scattered across every screen that happens to query medications — it lives in exactly one place, enforced by the database itself, for every request, including ones I haven't written yet. A new screen built eight sessions from now, by an AI with zero memory of this decision, inherits the same protection automatically, just by querying the table normally.
It also means re-pairing is a genuine, deliberate trade-off rather than an edge case I patched around. patient_sessions has a unique constraint on the patient, and pairing overwrites whatever was there — so if a patient gets a new phone, generating a fresh code and pairing again silently signs the old device out. I built it that way on purpose: a lost or replaced phone needing to reclaim access without calling support felt more important than guarding against two devices staying paired forever. It's the kind of call that's obvious once you say it out loud and easy to get backwards if you don't think about who's actually holding the phone.
The problem that only shows up days later
Anonymous Supabase sessions expire like any other session. That's fine for someone opening an app daily. It is not fine for the actual audience here: an elderly patient who might not touch their phone for four or five days at a stretch, whose caretaker set this whole thing up for them precisely because they weren't going to manage it themselves. The first version of MedSync handled an expired session honestly and unhelpfully — it sent them back to the pairing screen. Which meant a 6-digit numpad, and a phone call to their caretaker asking for a code, for someone who had no idea what a "pairing code" was the first time and had even less reason to remember the phrase five days later.
The fix is a second value stored alongside the pairing session: a permanent_token, a UUID that lives on the patient's own record and gets saved to the phone once, at pairing time, completely separately from the session that expires. When the app opens and finds no live Supabase session but does find a stored token, it quietly signs in anonymously again, calls a database function with that token, and gets the exact same patient_sessions row rebuilt — same patient, same caretaker, same access — before the patient has seen a single screen. No numpad. No phone call. As far as they're concerned, nothing ever happened; the app just opened, like it always does.
What "no account" actually bought
The takeaway isn't really about anonymous auth as a technique. It's that the right amount of security for a system is defined by who has to actually operate it, not by what's easiest to implement. A password would have been less code and a more "normal" auth flow. It also would have quietly locked out the one person this entire app exists for, the first time they forgot it — which, for this particular audience, was never going to be a matter of if.
Next up: the part of this project that has nothing to do with the database — how thirty-plus AI coding sessions, spread out over months, still add up to a caretaker app that looks like one person designed every screen, instead of drifting a little further from itself each time.
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 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.

What building two other apps first taught me before I started MedSync
Two finished apps bought me proven patterns. They didn't buy me a pass on double-checking the one number that actually mattered.