Skip to content
Lethra

Four regimes, one API surface

Retention rules differ by jurisdiction and change over time. Putting that behind a declared regime keeps it out of partner code, and makes the schedule an auditable artefact rather than a scattered assumption.

Lethra Technologies · · 5 min read
productapi-designarchitecture

A platform operating across German, Austrian and Swiss users is dealing with three different retention frameworks, and if it handles erasure requests it is dealing with a fourth thing that interacts with all of them.

The naive way to absorb that is in application code. A function that takes a document type and a country and returns a date. It works, briefly, and then it becomes the most quietly dangerous file in the codebase — because it encodes legal parameters in a place where nobody reviews them, nobody versions them meaningfully, and nobody notices when they go stale.

We took a different approach, and the reasoning is worth setting out because it is the part of the product most likely to be dismissed as configuration.

What a regime is in our model

A regime is a named, versioned schedule for what happens to a deposit over time.

A partner declares the regime when storing a document. Four ship at launch: GoBD-DE, BAO-AT, OR-CH, and GDPR-Art17. The API accepts the name; the engine owns everything behind it.

What that means concretely is that the partner's integration contains a string, not a calculation. There is no date arithmetic in partner code, no table of durations to keep current, no conditional logic that has to be revisited when something changes. The parameters live in one place, in one system, under one review process.

Why this matters more than it looks

Retention parameters are not stable. They are set by legislation, they differ by record class within a single framework, and they change — sometimes with a transition period, sometimes with an effective date that catches people out.

When those parameters are scattered through application code across several partners, a change means finding every place it was encoded, in every codebase, and hoping nobody duplicated the logic into a script. When they sit behind a named regime, a change is one versioned update in one engine, and every deposit that declared that regime is on the new schedule with a recorded reason.

That is the operational argument. The evidential argument is stronger.

A partner who has to demonstrate their retention behaviour to an outside party is in a much better position saying deposits of this class were stored under this named, versioned regime, and here is the engine's definition of it than reconstructing an argument from application code and a git history. The regime becomes an artefact somebody can be shown. Scattered arithmetic does not.

What the engine actually does

Three things, and the third is where the design earns its keep.

It computes the schedule. Given a regime and a storage date, it determines when the retention window closes. This is the boring part and it is the part people assume is the whole thing.

It drives the scheduler. A worker scans for deposits whose window has closed and hands each to the forget path, which destroys the key and issues the certificate. Retention is not a flag that something checks on read — it is an active process that acts on its own.

And it holds a pause. Any partner can suspend scheduled forgetting for their deposits, which matters for the case where preservation has been required beyond the normal schedule. This is the feature that makes the automation safe: without it, a correctly functioning scheduler would destroy material that had become subject to a hold, and would do so precisely on time. Automation without an override is a liability wearing the costume of reliability.

The tension we do not claim to have resolved

The fourth regime is not like the other three, and pretending otherwise would be dishonest.

Three of them are schedules — a document goes in, a clock runs, the window closes. The fourth is a request-driven path: an individual asks for erasure and something has to happen in response.

Those two things can point in opposite directions for the same document. A deposit under a retention schedule and subject to an erasure request has two claims on it that do not obviously reconcile, and the reconciliation is not a technical question. It is a question about who is responsible for the decision.

Our position is narrow and we hold it consistently. The partner is the controller. We are the processor. We act on the partner's instruction, and the instruction is explicit — a forget call names its mode, so the record shows what was requested and on what basis. We do not adjudicate between competing obligations, we do not advise on which prevails, and we do not offer a setting that quietly picks a side.

What we provide is that whichever way the partner resolves it, the outcome is evidenced. If the deposit is forgotten, there is a certificate naming the mode. If it is preserved, the pause is on record with a timestamp. Both are auditable, which is the most useful thing a processor can contribute to a decision that is not theirs to make.

Anyone selling a resolution to this tension is selling something we are not.

Why the API surface stays constant

The four primitives — store, log, retrieve, forget — behave identically regardless of regime. The regime changes the schedule, not the interface.

That constancy is deliberate and it is what makes the abstraction worth having. A partner integrating for one jurisdiction has already integrated for all four; expanding to a new market changes a string in a request. A partner reading their own code a year later does not need to know which regimes are in play to understand what the code does.

It also keeps our own surface honest. A regime that needed its own endpoint would be a sign the abstraction had failed — that the thing we called a parameter was actually a different product wearing the same name.

Adding regimes

The design anticipates more. A regime is a definition plus a schedule plus a test suite, and adding one does not touch the primitives, the storage path, the signing design, or any partner's integration.

What it does require is getting the parameters right, which is not an engineering problem and is not one we solve by ourselves. Each regime we add is reviewed by someone qualified in that jurisdiction before it ships, and that review is the long pole rather than the code.

We would rather ship four regimes we can stand behind than a dozen assembled from public summaries.