---
title: "A Paid Charge Row Sat in client_charges While the Page Showed Zero"
canonical: https://dxdev.com/blog/hardcoded-state-hides-feature/
datePublished: 2026-08-31
---
The payment cleared at 18:16:03 UTC. Stripe fired `payment_intent.succeeded`, `invoice.payment_succeeded` and `checkout.session.completed`, all three, on schedule. The webhook endpoint reported `enabled`, subscribed to all six events the route handles. The row landed in `client_charges`: paid, "Website Bundle and Event Updates," bound to a subscription and a customer's card. Every system said yes. The staff page built to show a brewery client's first payment said: "Your first payment will appear here once it goes through."

As far as that page was concerned, nothing had gone through. It had never loaded a payment in its life.

## Ruling out the plumbing

Before touching code, we checked what could be broken, cheapest check first. We started with Stripe's event log, because if the charge never fired, nothing downstream matters. It fired. Next was the webhook, since a disabled or misconfigured endpoint means Stripe tried and nobody heard it. It was live and subscribed.

Then we went to the database. We queried `client_charges` with the tenant's own row-level security context instead of an admin bypass, so elevated access couldn't hide a real gap. The row was there, correctly priced, correctly linked to the plan.

Three systems gave three confirmations, and the page still showed nothing. That left one place: the page itself.

## An array with nothing in it

Staff check a business with a URL that carries `?as=<id>`. That routes through `StaffPreview`, which is a different component from the real `/plan` a signed-in customer hits. In `StaffPreview`, the payment history prop is `history={[]}`, a literal. A comment explains why: the loader that fetches real history needs tenant context the staff view doesn't carry. The card on file and the next charge date are both hardcoded to `null`.

`PlanView` takes that empty array and does what an empty array should make it do. It renders its empty state, the same line a brand-new signup with zero charges would see. The component was correct. The input was fake.

When someone asks "shouldn't this be clickable and show details," the obvious guess is a missing feature. The feature existed. It had been fed a stub since the day it shipped. The stub sat through every review of the billing rewrite, because an empty payment history looks exactly like a customer with no payments yet.

## Reading our own diff for a bug that wasn't there

While we were building the real fetch, the deploy failed. We spent maybe forty minutes on it.

The failure wasn't ours. It predated our branch by two merged commits that had never actually shipped. They had been reporting green while sitting behind a gate that was red the whole time. The gate was a query the delete-business confirmation runs to show a record count before it lets someone delete a tenant. A table that query depends on had been dropped during the billing rewrite and never replaced.

So two unrelated commits had been stuck, unshipped, for however long that gate had been failing. In production, clicking delete on a business was throwing an error, and nobody had noticed because nobody had tried to delete a business since the rewrite landed. The forty minutes bought us nothing. The real cost was those two stuck commits and a broken admin action sitting live with nothing pointing at it.

## The fix

The fix needed no new access path. Postgres already had a policy on `client_charges`, `client_charges_platform_read`, defined as `FOR SELECT USING (app_platform_active())`, which grants platform staff read access. `StaffPreview` just wasn't using it. The same `requirePlatformRead` call that already loads plan data for the staff view now loads payment history too. No new door, just using the one that was already unlocked.

Payments load now. Each one opens to its billing period, card and receipt.

We shipped it without loading the finished page ourselves to look at it. The diagnostic checked everything except the one thing a diagnostic like this exists to confirm.

A staff page has one job, which is showing what a customer's account actually looks like. A stub on that page agrees with whatever you already believe. It doesn't fail loud. It shows an empty account forever, until someone asks why the first real payment in the system didn't count. And in the same incident, a deploy gate that had been red the whole time was holding back two commits and hiding a broken admin action, so it's worth confirming your gates are actually passing.
