05 · Auditability · 2025 · Work

Audit Log

Middleware sitting in front of every save that records which fields changed, what they changed from and to, and who changed them.

ON SAVESaveAudit middlewareDIFFS CHANGED FIELDSOPT-IN PER ENTITYEntity tableAudit logIDS ONLYON READKEPT TWO QUARTERSAudit logResolve IDsLOOKUP AT READ TIMEChange historyFROM → TO · WHOCHEAP TO WRITE · RESOLVED ON READ

The problem

Operations managers wanted to know who had changed a rate or a stop. When a bad rate cost money, there was no way to find out which agent was responsible, or whether a system had made the change at all.

What was built

A lightweight middleware layered into the save path that records field-level changes per entity type.

◆Writes store IDs only, so the save path stays fast; the expensive lookup work happens at read time instead, when someone is actually asking.
◆Records which fields changed with their before-and-after values, the user or system responsible, and the entity affected.
◆Retains two quarters of history before purging - comfortably past the ~60 days managers typically need.
◆Opt-in per entity, so only the tables that need auditing carry the overhead.
◆Result: any change, good or bad, traces back to the agent who made it or to the system that made it on their behalf.

What I'd do differently

It was originally opt-out, until one forgotten table multiplied our storage footprint by ten. We switched to opt-in, and that is where I would start next time. I would also design auditing into the entities up front instead of hand-writing storage, lookup, and display logic separately for each one - and compress the logs, which today sit as raw uncompressed JSON.