Health Data on a Public Page

Blog post #67


Alma has had sore feet for a while. Last year Edwin had headaches on and off for a period, and then they stopped. At the time I wanted a record of when they came and what the day had looked like, and I did not have one. The health wiki I wrote about in post #64 is where that record should live. On Tuesday I asked Claude to build the diary part.

What shipped

A symptom log in the wiki. One markdown table, one row per person, track and day: date, who, track, a level from 0 to 3, a note. Tracks are things worth following over time. Mine are stomach, nosebleeds and a wart I have had for a long time. Alma’s is feet. Edwin’s is headache, currently empty. Zero days get logged too, because a pattern needs the quiet days as much as the bad ones.

I dictate in the chat. “Stomach was a 2, Alma complained about her foot after gym.” Claude writes the raw file, adds the rows, updates the article for that track, commits, opens a pull request and merges it. The rules went into the project’s instructions file, so any session can do it.

A scheduled task that asks. Every evening at half past eight, Claude Code opens a session, reads the day’s log, sends a notification and asks one question: how was the stomach today, and how is everyone else. When I answer it logs, commits and republishes the page. It has run twice. Wednesday got zeros for three of us, which is the first real baseline I have. Thursday morning both kids woke up with sore throats.

A private page. The log is compiled into a small calendar: a month grid with one chip per person and track, coloured by level, eight weeks of track rows underneath, and the whole log as a table. It is published as a Claude artifact, which is private by default and can be shared with one person. That is the right shape for something two parents look at.

What’s unclear or broken

My first idea was the family calendar we already have on Vercel, a static page with our events and the kids’ weekly schedules. I asked Claude to show the symptom rows there as a health layer, one chip per day, coloured by severity. It took one session. It looked good. It was deployed to production before I remembered that the calendar has no login. Anyone with the address could open it. Alma’s feet and my stomach were on the open web, next to the children’s weekly schedule.

I noticed a few messages later and asked for it to come down. The layer is still in the code with an empty data list. The export script no longer writes to the calendar repository, and the wiki’s instructions now say the health data never goes there, so a future session does not repeat the mistake. But I had asked for it, watched it happen, and read the summary that said “deployed”, and the problem did not register until the next message.

The second thing I found out that evening was that the calendar had no GitHub remote. Every commit was on my laptop only. I was sure it had been set up. It had not. It is a private repository now.

Decisions made

The calendar gets a login. That should have been true from the beginning, and the health scare made it unavoidable.

Google sign-in, with an allowlist of two email addresses. The site stays static. A small edge middleware checks a signed cookie on every request and sends everything else to a login page, and three serverless functions handle the round trip to Google. The OAuth app stays in Google’s testing mode, which means only the listed test users can sign in at all. For a family of two adults that is exactly the restriction I want.

The health data stays out of the calendar even now that it is locked. The calendar is logistics. The diary is medical. They have different readers and different consequences if they leak.

Tooling & process

The Google Cloud console is a wall of buttons, and I got as far as the consent screen before handing over. Claude drove the rest in my Chrome: test users, client, redirect address. When the client was created the console showed the secret once, in a dialog, and I did not copy it before the next navigation closed it. Google no longer lets you view a secret after that. Adding a new one is two clicks, and this time I copied it.

The plan was to keep the secret in 1Password and let the CLI read it into Vercel. The CLI integration timed out on authorization twice, so I pasted it into Vercel’s dashboard myself. The secret never went through the chat.

The test was Claude clicking through the login in my own browser: account chooser, consent, calendar. It works. Caroline opens the same address as before and picks her account.

Two loose ends. The Google console still shows a warning that the OAuth configuration is incomplete, while every field I can find is filled in. And the evening question only fires while the Claude desktop app is open; if it is closed at half past eight, it runs on next launch. So far that has been fine. I will find out whether it stays fine.


— Stefan