← back to journal
ProductionJun 4, 20261 min

The receipt that kept rewriting itself

arc: wrong amount on a receipt with no error anywhere → receipts were rebuilt on every download → we were asking what the fees are, not what they were

a parent downloaded a fee receipt and the amount was wrong.

the payment was correct. the database was correct. nothing crashed and there were no errors in the logs. that combination is what made it confusing for a while.

it turned out our receipts were being built fresh on every download. so a receipt always showed today's data about a payment from the past. a school changed its fee structure mid year, and every old receipt silently recalculated itself against the new structure.

the receipt was not lying about the data. it was answering the wrong question. we were asking what do the fees look like. we should have been asking what did the fees look like when the money changed hands.

so the fix is to freeze the moment. the instant a payment succeeds we snapshot it. the facts go into one column as JSON, the frozen numbers and names and the real date. the rendered PDF goes into another column as raw bytes. on download we hand back the saved file instead of building a new one.

parent payssnapshotrender oncereceipt_datathe frozen factsreceipt_pdfthe exact byteson downloadhand back those exact bytesnothing is rebuilt
the download path never reaches the live tables — so a fee structure that changes next term cannot reach back into last term’s receipt.

honest bit, i did not understand BYTEA at first. i thought it was something for text. it is not, it is for any raw binary data, which here is the actual PDF bytes. i shipped my first version half understanding it and only really got it later.

a receipt is a fact, not a query.

Day 4 — what actually gets frozen: receipt_data JSONB holds the frozen facts, receipt_pdf BYTEA holds the file itself, live fees changed but the receipt did not

day 4 — what actually gets frozen

#buildinpublic #softwareengineering #startup #maahitatechnologies

Send this as proof →Share on LinkedIn