Symphony Apps Development logo — teal interlocking S monogram beside the studio wordmark
All writing

Build note: a permissions audit trail a regulator actually accepted

A financial services client needed an audit trail that would satisfy an external reviewer, not just a table of who-did-what. The distinction changed the design.

Category
Case notes
Reading time
7 min
Published
28 Jul 2026
Topics
Case study, Engineering, Data

The client's initial request was an audit log. What they actually needed, once we understood who would eventually be reading it, was something a regulator's reviewer could use to reconstruct a decision months after the fact without asking anyone on the team what it meant.

The gap between a log and an audit trail

A log records that something happened. An audit trail a reviewer accepts has to record who, under what permission, on whose authority, with what data visible to them at the time, and why the system allowed it — and it has to be tamper-evident, because the reviewer's job is partly to ask whether the record could have been altered after the fact.

What we built beyond the obvious table

  • Permission state at the time of the action, not looked up against current permissions — a user's access changes over time, and a reviewer needs to know what they could see when they acted, not what they can see today.
  • An append-only store with cryptographic chaining between entries, so that altering a past entry would be detectable rather than merely against policy.
  • Denied actions logged with the same detail as permitted ones, because a reviewer investigating a concern is often as interested in what was correctly blocked as in what went through.
  • Human-readable narrative generation from the raw log, turning a sequence of structured entries into a plain-English account of what happened in a given window, because a raw table of rows was not something a non-technical reviewer could use unassisted.

Where a model helped and where it explicitly did not

We used a model to generate the human-readable narrative from structured log entries, which it does well because the underlying facts are already correct and fixed — it is a summarisation task, not a judgement task. We did not let anything model-generated decide what counted as a permission violation or influence the structured record itself; that logic is deterministic, reviewed, and tested against specific scenarios agreed with the client's compliance team in advance.

An audit trail's value is almost entirely in the parts nobody wants to build: tamper evidence, denied-action logging, and permission state as it was, not as it is now.

The actual test of success

The client's external reviewer accepted the trail on first submission, which the client told us was not the norm for their previous systems. The specific things called out as good were the denied-action logging and the tamper-evidence, both of which had been the parts easiest to deprioritise under time pressure and the ones we had insisted on keeping in scope regardless.

What we would build the same way again

Involving the eventual reviewer's stated requirements, even secondhand through the client's compliance team, before writing a line of the schema. Retrofitting tamper evidence onto an existing append-only table is possible; designing it in from the first migration is considerably cheaper.

Tell us what you’re trying to ship

A first call is thirty minutes and costs nothing. Bring the problem, not a spec — working out what to build is the part we are good at.

Or email office@symphonyapps.ro. We reply within one business day, in English or Romanian.