Designing audit trails for legal document workflows
In notary and court systems, the record of who did what and when matters as much as the document. How to design complete, tamper-evident audit trails.

In legal document workflows, such as notarial deeds, court filings and powers of attorney, the document is only part of what needs to be trusted. Equally important is the record around it: who created it, who reviewed it, who signed it, which version they signed, and when. If that record is incomplete or can be altered, the system cannot be relied on when it matters most.
This article describes how we approach audit trails in systems of this kind.
What an audit trail must answer
A useful test is whether the trail can answer these questions for any document, years after the fact:
- Who performed the action, and in what role?
- What exactly happened: created, edited, viewed, signed, sent, registered?
- When did it happen, according to a reliable clock?
- Which version of the document was involved?
- On what authority: which case, mandate or approval allowed it?
- From where: which application, and for sensitive actions, which device or network?
If any of these cannot be answered, the design is not finished.
Record events, not states
Many systems store only the current state of a document: its status, last editor and last modified date. That is not an audit trail. We model each action as an event that is written once and never changed:
interface AuditEvent {
id: string; // unique event identifier
documentId: string;
documentVersion: number;
documentHash: string; // SHA-256 of the exact content acted on
action: 'created' | 'edited' | 'viewed' | 'signed' | 'registered';
actorId: string;
actorRole: string;
occurredAt: string; // ISO 8601, from a synchronised clock
context: Record<string, string>; // case number, approval, client app
previousHash: string; // hash of the previous event in the chain
hash: string; // hash of this event, including previousHash
}
The current state of a document can always be rebuilt from its events. The reverse is not true.
Make tampering detectable
An audit log stored in an ordinary database table can be edited by anyone with sufficient database access. Preventing every possible change is difficult; making changes detectable is achievable.
Each event above includes the hash of the previous one, forming a chain. Changing or deleting any past event breaks every hash that follows, which a routine verification job will detect. To protect the chain itself, we periodically record its latest hash somewhere the application cannot rewrite, such as write-once storage, or a timestamp from an independent time-stamping authority using the RFC 3161 protocol.
Link signatures to exact content
When a document is signed, the trail should show precisely what was signed. We store the hash of the signed file with the signature event, so that any later version can be compared against it.
In the EU, electronic signatures and trust services are governed by the eIDAS Regulation, which distinguishes simple, advanced and qualified electronic signatures. Legal workflows often require advanced or qualified signatures issued through a qualified trust service provider. The audit trail should record the signature level, the certificate used and the provider’s validation result, not just the fact that a signature exists.
Use a reliable clock
Timestamps are only as trustworthy as the clock behind them. All servers should synchronise time from a dependable source, and timestamps should be stored in UTC. For legally significant actions, such as signing or registration, a qualified time stamp from a trust service provider gives independent evidence of when the action took place.
Store the trail separately
The audit trail should not live alongside the data it describes with the same access rights. We keep it in a separate store, accessible to the application only through an append operation. Administrators of the main system should not be able to modify it, and access to read it should itself be logged.
Respect data protection
Audit trails contain personal data: names, roles, IP addresses and the documents people worked on. Under the GDPR, that data must still be minimised and protected.
- Record what is needed to account for an action, and no more.
- Restrict who can read the trail and log every access.
- Define retention periods that reflect the legal requirements for the records concerned.
Requests for erasure need careful handling. The GDPR provides an exception where processing is necessary to comply with a legal obligation, which often applies to notarial and court records. Where it does not apply, personal identifiers can be separated from the event chain and removed without breaking the chain’s integrity.
Make the trail usable
An audit trail that only engineers can read is of limited value. Notaries, court staff and auditors need a clear history view for each document, filters by person and date, and an export that includes the verification result for the chain. In practice, the quality of this view often determines whether the audit trail is trusted by the people who depend on it.
Test it like any other feature
We include the audit trail in automated tests: every user action must produce the expected event, and the verification job must fail when an event is altered. We also run the verification regularly in production and alert on any failure.
Summary
A well-designed audit trail is complete, append-only, tamper-evident, linked to exact document versions, based on reliable time, stored separately, compliant with data protection rules and readable by the people who need it. These requirements are easier to build in from the start than to add later, which is why we treat the audit trail as a core part of the design in every legal workflow we work on.
If you are planning or modernising a system for legal documents, we would be glad to discuss it. Write to us at contact@dritalabs.ai.

