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.
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
#buildinpublic #softwareengineering #startup #maahitatechnologies