Engineering & deliveryField notes
Who skipped the credit check? Order fulfilment across five systems
8 min read

A customer calls on Thursday afternoon. He received 40 units of a component; he ordered 4. The delivery has already been installed, so the return will be expensive. And internally, sales support asks a second question: why did this order ship at all — hasn't that customer been on credit hold for two months?
Three hours later, the important part is clear. What is not clear is who skipped the credit check.
The pattern is typical for a mid-sized B2B distributor: around 180 people, roughly 40 million euro in revenue, technical components and machinery for industrial and trade customers across the DACH region. A web shop, an ERP, a separate warehouse management system, a shipping tool, a CRM, a finance system. Plus spreadsheets, shared mailboxes and a few colleagues who know how it really works.
The path of an order — and where it becomes invisible
The flow is unremarkable:
- The customer orders in the shop; the order lands in the shop database.
- A job or a person transfers it into the ERP. Status: "new".
- The warehouse checks availability, writes to the warehouse database and reports a status back.
- If everything fits, the goods are picked, packed and handed to the shipping system.
- The finance system issues the invoice.
- The CRM gets a note: "order delivered".
- When questions come up, five departments open five different systems.
Every step is clean on its own. What is missing is the bracket around them. Each system knows its own latest state; none knows the sequence. Between the systems sit interfaces that transfer statuses — not events with a reason, but values that overwrite the previous value.
That is why every uncomfortable question starts the same forensics: shop logs, ERP change history, warehouse transaction records, the mail archive, and finally somebody's private notes. The truth was nowhere, so it had to be renegotiated every time. We described the same pattern in a SaaS company in Who promised what? — that one is about commitments, this one about goods and money.
What the search costs when you extrapolate
Conservatively: three hours per disputed case, two to four cases a month, involving sales support, warehouse management, accounting and, in doubt, the managing director. That is several person-weeks a year that sell nothing and ship nothing.
The more expensive item sits right next to it. Management wants a new rule: above 15,000 euro in order value, a second approval is required, and international shipments should trigger an automatic customs check. In business terms, two sentences. In technical terms: schema changes in several databases, migration scripts, adjustments to the interfaces between shop, ERP, warehouse and shipping, and tests across all of them. Four to eight weeks — plus the residual risk that something stays inconsistent somewhere.
On top of that runs an observability stack that collects logs from five sources to reconstruct a picture that existed in full at the moment it happened and simply was not recorded. High availability and recovery are a collection of one-offs: replication here, a queue backup there, a restore script nobody has rehearsed in two years.
A lot of energy goes into systems that exist only because the actual truth lives nowhere central and immutable.
The knowledge keeper is not a people problem
The experienced clerk knows that for certain customers the credit check has to be triggered manually in the finance system before the warehouse starts. Technical sales knows which articles may only ship after internal release. Neither is written down properly anywhere.
When those people are on holiday, the process stalls — or it continues and produces exactly the Thursday afternoon case. This is not individual sloppiness. It is a business rule that never made it into a system, because there was no place it belonged. As long as only states are stored, "under this condition you must not proceed" has no natural home.
That is where modelling before code comes in: event modelling is first of all an adoption tool. The value is not the diagram; it is that sales, warehouse and accounting describe the same flow with the same words for the first time.
The same process on an event foundation
Now assume order fulfilment stands on an event sourcing and CQRS foundation. Everything that matters to the business is written as an immutable event:
OrderPlaced— line items, customer reference, delivery address, requested dateCreditCheckRequested,CreditCheckPassed,CreditCheckFailedStockReserved,StockReservationFailedPickingStarted,PickingCompleted,PackageCreatedShipmentDispatched— with tracking number and carrierInvoiceGenerated,DeliveryConfirmedByCustomer,ReturnInitiated
These events land in a central, append-only store. There is no leading "current order" table any more. The current state of an order is a projection — a view computed from the events, and there may be as many as you need: one for sales support, one for the warehouse, one for accounting.
On Thursday afternoon the question is no longer "where do we look?" but: show all events for order 45821 in chronological order. What becomes visible is that no CreditCheckPassed ever existed — the reservation happened anyway, because an interface job set the status without the check. The quantity also fails to match OrderPlaced. Forensics turns into a query instead of detective work.
What gets thinner:
- Business audit logs become unnecessary, because the event stream is the audit log. Technical logs for infrastructure and access remain — this does not replace those.
- Status synchronisation between systems largely disappears. Systems subscribe to the events they need and maintain their own projection.
- Recovery is not magically solved, but the problem narrows: one store to restore instead of five databases whose mutual consistency nobody can guarantee. Backups and rehearsed restores stay mandatory.
Why this is structural rather than merely tidier is laid out on the event sourcing page.
Why change gets cheaper
The rule "second approval above 15,000 euro, customs check for international shipments" is implemented like this:
- New event types and handlers are added:
SecondApprovalRequired,SecondApprovalGranted,CustomsCheckTriggered. - Existing events stay untouched. No migration of old orders.
- A new projection "orders awaiting second approval" appears, and the approver interface reads from it.
- Orders that ran before the rule change stay correct, because their history is not rewritten.
Instead of a rebuild across five systems, it is a new interpretation of the same history.
With one caveat worth knowing: this holds if the domain boundaries are right. If the order was modelled as one giant aggregate that mixes pricing, stock logic and shipping, the change is just as expensive as a schema migration — only with less familiar tooling. The cut decides, not the technology.
What this does not solve
Rules nobody says out loud stay invisible. If nobody mentions in the modelling workshop that three customers run a different credit check, it will not appear in any event either. The system forces the clarification into one place — it does not replace it.
Third-party systems stay third-party systems. ERP, finance and the carrier do not become event-sourced by wishful thinking. You need a translation layer at their boundary that turns their status messages into business events — and that layer has to be built and maintained. The stream ends where the foreign systems begin.
It is not a tool purchase. The expensive part is agreeing which events matter and what they are called. If you want to check whether the approach is worth it at all, the scope is discussed in event sourcing without fear.
The questions that follow
Retention. Completed processes may be archived, and snapshots shorten replay. The period follows business and accounting law, not convenience.
Permissions. Purchase prices and margins live in the same processes as delivery quantities. Who sees what is decided at the projection level, not in the interface — the same logic as multi-tenancy with Keycloak.
Personal data. Delivery addresses and contacts do not belong in the stream in raw form. Pseudonymisation or crypto-shredding resolves the conflict between immutability and the right to erasure; the first worked example covers it in detail.
Where to realistically start
Not with the whole of order fulfilment. Four to six weeks to the first stream in production is achievable if the scope is tight:
- Pick a domain where "what happened?" is asked regularly today and is expensive — order release and credit checks are the usual candidates.
- Model the events together: sales, warehouse, accounting and engineering at one table, on paper, before anything is built. That is what the event modelling sprint is for.
- Put one stream into production, with clean causation and correlation identifiers from day one. For implementation with a specialised event store there is the EventSourcingDB offer.
- Build a projection that answers a real question — the timeline of an order, not a dashboard.
- Mirror the read model back into ERP and CRM so teams stay where they work. The same incremental logic as modernising a monolith.
If the first thing to settle is whether the scope holds at all, an architecture second opinion is a cheaper entry point than a project.
What remains
This is not automation for its own sake. It is the reduction of friction that appears when operational reality and its representation in the systems drift apart. The history of what happened is recorded once, cleanly and immutably; current states, reports, approval workflows, the customer view and the audit are derived, replaceable views of it.
The check takes a minute: take the last complaint where you had to reconstruct what actually happened. How long did it take — and did you know, in the end, who decided?
← Back to insightsArticles on this topic
Engineering & deliveryNote
Bolt-on logging: where is the truth?
AI takes the burden of human vagueness off us. So why do we place a second vagueness — a log — next to our core processes?
Engineering & deliveryFoundation
Tenant separation that survives the security questionnaire
One forgotten filter is a reportable incident. Why isolation in application code is not evidence — and which models enterprise buyers accept.
Engineering & deliveryField notes
Tamper-proof logging: why database logs do not count in an audit
Almost every system logs. Audits still fail on the question of who changed what and when. The difference between a log and evidence — and what creates it.