Skip to content

Beyond Innovation. Beyond Limits. Into Impact.

Language
Appearance

The receipt you cannot delete

German fiscal law requires every till transaction to be signed and kept for ten years. There is no delete. That one sentence decided more of the database than any product requirement did.

Author
Published
Reading time
4min

Most compliance work is paperwork that sits beside the software. German point-of-sale law is not that. It reaches into the schema and rearranges it.

The rule is short. Every transaction at a till must be signed by a certified technical security device — a TSE — and the signed record must survive ten years, available to the tax authority in a prescribed export format whenever they ask for it.

Read it again with an engineer's eye. There is no delete.

What "no delete" does to a design

Consider something ordinary: a test transaction. Every system has a staging mode, and every developer has at some point run a test order through production to see whether it works.

Do that here and the test order is in the fiscal record for a decade. Not awkward — permanent. It cannot be removed, because the whole point of the device is that nothing can be removed.

So "test and live are separate" stops being a convention and becomes a structure. In this build a till device declares its environment as either test or live, and a CHECK constraint plus a partial unique index make only one live device at a time a guarantee the database enforces. Not a rule in a runbook. Not a habit. A thing the database will refuse to let you do.

That is the difference the ten years makes. Normally you write the constraint that catches the bug. Here you write the constraint that catches the decade.

Compose from the specification, not from memory

The fiscal payload has a schema, and that schema is published. The client here composes it from the specification the API itself serves rather than from anyone's recollection of what the fields were called.

This sounds pedantic until you notice the alternative: a developer reading the spec once, writing what they remember, and shipping it. It passes the tests, because the tests were written from the same memory. It fails at the audit, years later, in a way nobody can now reconstruct.

The details that only production teaches you

Here is one worth the price of admission.

The signature timestamp comes back from the device in the format the security module declares — and that is a property of the module, not a constant of the standard. The one in this build reports unixTime: epoch seconds, as a number. A differently configured one may well send an ISO string.

So the code accepts both. Nobody designs that in advance. You learn it the first time a receipt is stamped with a date in 1970, and then you write down why in the file, so the next person does not helpfully simplify it back.

Write for the auditor, not for the test suite

The export carries the security module's certificate and public key. Not because the format demands a field be filled, but so an auditor can verify the signatures offline, against trusted roots, without asking the system under audit to vouch for itself.

Leave it out and checking a signature means trusting the very thing being checked. The format allows it. The point of the exercise does not.

That principle shapes the export as a whole. It is a bundle of sixteen tables in the order the authority lists them — master data, then the daily closing, then the individual records — and when it cannot be assembled, it says why. An unfrozen VAT rate, an unmapped tax code, a missing tax number: each becomes a recorded problem on the result rather than an exception somewhere up the stack. The caller's job is to log the failed attempt, not to crash on it. An export that fails silently is worse than one that fails.

Why this is not only a German problem

We do the same work for Egypt's e-invoicing and for ZATCA in Saudi Arabia. The formats differ, the authorities differ, the deadlines differ.

The discipline does not. Wherever the record outlives the software that produced it, the record is the product — and the code that writes it should be legible to someone who will read it years from now, in an argument, without you in the room to explain.

Talk to us about a compliance-critical build

All posts

On this page

Where does this leave your system?

A post can explain how something works; it cannot say what that means for the system you already run. Thirty minutes with an engineer, not a salesperson, and no follow-up sequence.