Audit trail

The record that answers “why?” two years later

When a borrower disputes a decision or an examiner asks how a loan came to be approved, the value of a lending system is measured entirely by what it can reconstruct.

Immutability

Append-only, enforced at the model layer

Update, updateMany, findOneAndUpdate, delete and deleteMany are all blocked on the audit collection. A correction is a new entry that supersedes an old one; the original stays exactly as written.

  • Mutation operations rejected before they reach the database
  • In production the database user should hold insert and find rights only
  • A correction never destroys the record it corrects
  • Retention covers the life of the relationship and the statutory period after it

What each entry carries

Nine fields, on every single entry

  • Action

    What happened, from a fixed enumeration — not a free-text description that varies by developer.

  • Actor and role

    Who did it, and the role they held at the time. System jobs are recorded as the system actor.

  • Entity

    The type and identifier of the thing that changed, so a full history is one query away.

  • Reason

    Mandatory on rejections, cancellations and defaults. The write fails without one.

  • Purpose

    Mandatory on any read of borrower personal data, from a closed list of lawful purposes.

  • Ruleset version

    Which version of the regulatory constants was in force, so old decisions stay interpretable.

  • Changes

    A shallow before-and-after of the fields that moved. Personal values appear as hashes.

  • Request context

    Request id, IP and user agent — one id ties a support ticket to the events behind it.

  • Timestamp

    Server-assigned. A client cannot set or influence it.

Privacy inside the trail

A complete record that does not itself leak data

An audit log full of names and citizenship numbers becomes the most sensitive table in the system and the hardest thing to show anyone. Khepee stores personal values in the trail as hashes.

  • Personal fields reduced to a stable hash before the entry is written
  • A change is still provable — the hash differs — without exposing the value
  • The trail can be shown to an examiner without a redaction exercise
  • Log output is separately redacted as a second line of defence
[redacted]

Coverage

Every write path, without exception

Coverage is verified mechanically rather than by discipline: an automated check flags any service that writes to the database without also calling the audit service.

  • Tenancy changes, product configuration and staff management
  • Every application state transition, with its reason
  • KYC submissions and verification decisions
  • Disbursement instructions and confirmations, and every repayment
  • Every login, logout, token refresh and detected token reuse
  • Every personal-data read and every bulk export

Failure behaviour

What happens if the audit write itself fails

A deliberate design decision worth stating: a failure to audit does not roll back a legitimate business action mid-request. It logs at fatal severity, which should page someone, because a silent gap in the trail is a reporting problem.

  • The business action completes; the failure is escalated rather than swallowed
  • Logged at fatal severity so it reaches an alert, not just a file
  • A missing purpose on a personal-data read is the exception — that throws
  • Gaps are detectable, because the request id sequence is reconstructable

Reporting

Your regulatory extract comes from here

Management reporting and the NRB extract are both derived from this trail, which is why they agree with each other and with what actually happened.

  • No parallel reporting store to fall out of step
  • Indexes built for the queries reporting actually makes
  • Reports regenerable for a past period, and they will match
  • Every export itself audited, with the actor and purpose
NRB

Coming soon

Inspect the trail with your auditor

It is designed to be shown to someone external without a rehearsal. We are happy to prove that.