Skip to content

The health data we decided not to store

The client asked to save patients' answers on the server. I said no, explained why, and built the comparison they actually wanted without a single answer leaving the person's device.

Role
Designed and built end to end, alone
Client
Alnylam, on TTRacker (ttracker.com.br), a clinical monitoring platform for ATTR amyloidosis
Period
About a month, in 2026
Context
A rare disease, health data, and a stack I did not choose: the client's WordPress and the plugins they already had
What I personally did
requirements with the client, the seventeen instruments, the calculators, the comparison, the print layout, the accessibility, the tests, and the working flow I built to do all of it

The request

The client wanted to store patients' answers so a doctor could compare one consultation against the next. The need was real and the value was obvious. The way to get there was not.

Why I said no

Three things stacked up: this is health data, the platform is WordPress with the plugins they already owned, and LGPD had just changed what carelessness costs. I spent five years as a criminal lawyer before design, and that repertoire is why I raised the question before anyone asked me to. I did not give legal advice, I put the risk on the table early. Their own legal team reached the same conclusion later and turned the request down.

Two boxes side by side. On the left, the person's own device, holding the answers, the history of what was filled in and the delta between applications. On the right, the server, holding the pages and the seventeen instruments and not one answer. Between them there is no arrow: the amber marks the connection that was never built, with no answer posted, fetched or stored server-side. Below, the count of requests carrying patient answers is zero.
DIAGRAM · WHERE THE DATA LIVES

What I built instead

Saying no is half a job. The answers live on the person's own device, so a returning patient finds what they filled in before, with the delta between applications calculated for them. For anyone who clears their browser or switches phones, there is a path to write the previous result down and compare by hand. Same value, and the data never becomes someone else's problem. No request ever contains a patient's answers: nothing is posted, fetched or persisted server-side. For this flow, privacy is architectural: there is no code path that sends an answer to the server.

The TTRacker tracking table with three assessments of the same person on different dates. Each row carries the date, the BMI, the modified BMI, and two variation columns: against the previous assessment and against the current one. The most recent row is marked as current. All of this comparison is computed on the device, with no answer ever reaching the server.
SCREEN · THE COMPARISON, COMPUTED ON THE DEVICE

What shipped

Seventeen validated clinical instruments in Brazilian Portuguese, with calculators, history and comparison. A print layout made for the consultation itself, not for the screen. Access restricted to health professionals, as the category requires. Search optimization, because a rare disease platform that nobody finds helps nobody. And accessibility built in rather than checked at the end: the pages carry 287 ARIA attributes and ship with 33 automated regression tests, one of them dedicated to accessibility.

How a month was enough

One person, one month, someone else's tooling. That only worked because I built the working flow first: Claude Code and Codex, back when there was no MCP and almost nothing ready for WordPress. The skills I wrote for this project were the reason it moved at all, and they are the same habit that shows up in everything else here.

Limits and learning

The platform has usage data and it belongs to the client, so I am not publishing it. The disease is rare, so the audience is small by definition, and I would rather say that than dress it up. Local-only has costs of its own, and I would rather name them than pretend local means safe: the answers live in the browser storage of that one device, so clearing the browser erases them, switching phones leaves them behind, and a shared browser is a shared record. The manual comparison path is the mitigation designed for that; the rest is the declared price of not holding the data. The constraint that shaped everything was the stack: on tooling I chose myself, some of these decisions would have been easier. That is exactly why the case is here.