Ulric
Book a call

Eugene, Oregon · one person, whole builds

Insights

Notes from the studio.

Building in public: what I'm making, what broke, and what I'd do differently.

Custom mental health web apps whose answers never leave the device

What a practice gets when it buys one of these is a tool that holds nothing. No row, no account, no export, and therefore no retention schedule to write, no breach plan to rehearse and no deletion request to route through a person three years from now. That is a storage decision, made before any screen is designed, and it decides most of what comes after it. It also has a limit worth being precise about, because the page a tool sits on is a separate question from the tool.

What a therapy practice website should never ask for

The federal definition of individually identifiable health information covers anything a provider receives that relates to a person's mental health or condition and can be tied back to them. Not diagnosis, not treatment: condition. So the website for my own counseling practice never asked for a history, never held a calendar and never took a card. Every other decision on it followed from that one word.

One engine, three client sites: the fork per client model

Three live sites share one CMS engine and share nothing at runtime: separate repositories, separate keys, separate databases, separate hosting accounts. The bill for that isolation arrives every time I fix something in the engine, because a fix lands in one copy and has to be carried to the rest. Here is the ritual, the path a real security fix took, and the four ways the sweep has quietly failed on me.

28,000 listings on one map with MapLibre and no API bill

Every active listing in the state lands on one map, drawn by MapLibre GL JS on ordinary shared hosting, with nothing metering the page loads. One version-stamped GeoJSON off the sync cron feeds the pins, and a self-hosted PMTiles archive is measured and staged to answer for the basemap the free hosted style is drawing today. Measured numbers, the compliance furniture, and the version pin that a release note forced.

Graph RAG vs vector RAG: when the graph earns its keep

Vector retrieval answers the question of what resembles this text, while a graph answers what is connected to it, and the two fail on different questions. The benchmarks say the difference is large on relational questions and close to nothing on lookups, which makes this an accounting decision rather than an architecture debate. What each one costs, the hybrid I actually run, and how to decide before you buy an index.