Case study 11 · Identity and documents
Invoices frozen at issue and coupons that pay out only once
Three products had to store when a record was created apart from when it became valid. On the customs system, none of 50,000 invoices changed after issue.
Customs invoicing: validated on 50,000 invoices
none of which changed after issue
The story in 5 steps
Stack
- Node.js
- PostgreSQL
- Kotlin
- Fabric.js
01 · Context
A customs authority needed invoices that could never change after issue.
A customs authority needed invoices that could never change after issue. Remittance terminals had to print coupons while offline without risking a double payout, and a meeting platform needed a whiteboard that people could still work with after the meeting ended.
The three products were unrelated and built in different years, but each needed the same answer: the stored data had to distinguish a record that exists from a record that is binding.
02 · Could not change
Every system that issues documents eventually has to decide what an old document shows after its template changes, and most decide too late.
Every system that issues documents eventually has to decide what an old document shows after its template changes, and most decide too late.
Templates change: a layout is corrected, a legal notice updated or a logo replaced. Then someone opens a document issued two years ago and sees this year's template, with this year's legal text, on a record that was signed under different terms.
No error is raised when a template change alters an old document, and from that point the archive no longer shows what was actually issued.
Creation and validity can drift apart in other systems too: a coupon printed with no network, or a whiteboard that only exists as a screenshot.
03 · What I did
Customs invoicing (2020). The customs authority required that an issued invoice never change.
Customs invoicing (2020). The customs authority required that an issued invoice never change. So at the moment of issue, the document was rendered and stored as immutable HTML, and later template edits touched nothing already issued.
The system kept the definition of a document separate from the issued document, so the template could keep evolving while the history stayed intact. The frozen output also no longer depended on the rendering code staying correct in the future. Had documents been rendered on demand, any change to that code would have retroactively altered every old document.
Remittance terminals (2022). A recipient collected cash at a filling station using a coupon code. The terminal had to keep working when the network was down, but a coupon that paid out twice was the one failure that cost real money.
The terminal printed each coupon as not yet valid, because a coupon that could not be used yet was an acceptable price for never paying one out twice. A coupon became valid when the system said so: automatically when the connection came back, or manually through an operator, who was alerted that an unactivated coupon existed. The system knew which coupons had been printed and were not yet valid, so none of them could be lost without anyone noticing.
Meeting platform (2023). The whiteboard was saved as structured objects instead of a flat image, so every stroke, shape and piece of text kept its own properties. After the meeting, people could reload the board and keep editing it.
04 · Result
In all three products the record stayed intact through the event that usually breaks it: a template change, a lost connection or the end of a session.
In all three products the record stayed intact through the event that usually breaks it: a template change, a lost connection or the end of a session.
- Customs invoicing: validated on 50,000 invoices, none of which changed after issue
05 · Differently
On the customs system, freezing the issued document was correct but incomplete, because the template itself was never versioned.
On the customs system, freezing the issued document was correct but incomplete, because the template itself was never versioned. No issued invoice could change, but there was no record of which template version produced it, or of who changed the template and when. The snapshot answered the urgent question and left the audit question open. I would version the templates from the start and point each issued document at the version that produced it.
Related services
The services that draw on this work.
- MobileHardware integration in React NativeA coupon printed on a POS terminal’s thermal printer at a filling station. It cannot be cashed until the system recognizes it.
- Regulated and sensitive systemsFintech developmentCustoms invoicing, remittance terminals and a meetings platform, each built to keep the moment a document is created apart from the moment it becomes valid.
- MobileOffline-first appsRemittance terminals that keep printing coupons without a network. A coupon becomes valid only when the system confirms it, either automatically once the connection returns or through an operator.
- Backend, data and integrationsPayment integrationsCoupons for collecting a remittance, printed at a terminal even when it has no network. A coupon becomes valid only when the system confirms it, so none can be paid out twice.
- Regulated and sensitive systemsGovernment documents and audit trailsCustoms invoices saved as immutable HTML when issued. Editing the template later can’t alter an invoice that has already gone out.
- Regulated and sensitive systemsInvoicing and customs systemsCustoms invoicing that renders each invoice once, at the moment of issue, and stores it as immutable HTML. We validated it on 50,000 invoices, and none changed after issue.
Related writing
Posts that came out of this project.
Case study 11
Working on a similar problem? We reply within one business day.
The first call takes 30 minutes, and you’re under no obligation.