All notes

Sep 2026 · 4 min read

Published

Build Log #10: A Number You Can't Click Through Isn't Trustworthy

AuthorKervintz Noel
Filed underAI Engineering · Claude Code · Building in Public · TypeScript
SeriesPart 10 of 11 · View the full case study

Up to this point the pipeline had a real parser, real deduplication, a real analytics engine, and a real Privacy Gateway — and no way to see any of it except a JSON response. This entry is the two screens that make the numbers visible: the Dashboard and Review.

Coverage comes before the totals, not after

The Dashboard's first element isn't a chart, it's a coverage bar: how many statements are actually included in the numbers below versus excluded, and why. A spending figure computed over an unknown slice of the data isn't a spending figure — it's a guess wearing a dollar sign — so it doesn't get to appear before the reader knows what it's built on.

Below that: net cash flow, spending, and top category as stat cards; a cash-flow chart and a spending breakdown, each with a "show as table" toggle so the numbers are never locked inside a chart only sighted users can read; recurring charges and top merchants; and an AI-generated summary, kept in its own visually separate card so it never gets mistaken for a computed figure.

A chart is a claim. If you can't click through the number to the rows behind it, the chart is decoration wearing the shape of evidence.

That click-through is the transaction drawer — opened by a URL parameter, not local component state, so it's linkable and survives a refresh no matter which screen opened it. Every clickable number on the Dashboard and every row in Review opens the same drawer.

Two corrections that weren't my first instinct

  1. 01The Dashboard's spending comparison uses the latest full calendar month against the one before it, not whatever the most recent period happens to be — comparing against a partial current month makes the percentage change meaningless.
  2. 02The "always categorize this merchant" action in Review never fires silently. The button spells out both the merchant and the category it's about to apply, every time, so nothing changes because someone clicked fast.

Review itself is one inbox for three things that need a human: possible duplicates, transactions needing a category, and statements that failed or came back unsupported. The sidebar's badge count is the same number the screen shows — no separate query that could quietly drift out of sync.

One bug, caught by actually using the app instead of trusting the tests: every new endpoint returned 404 during manual verification. The code was fine — a stale backend process from an earlier session was still bound to the port, answering with old routes. Killing it and starting fresh fixed it in seconds, but it's a good reminder that a green test suite and a working manual session are two different claims.


Next

Accounts and Settings — the last two screens in build-plan #9, and the one holding real API keys.

I write these as I go. You can follow along here or on Hashnode, where I'll start cross-posting.

All notes