Skip to content
How it works

Audit trail

The audit trail (labeled “Audit trail” in the interface) is an immutable record of every significant change: who made it, when (in UTC), what it was before and after, and — where required — why. Nothing in the journal can be edited or deleted; you can only append new records. This is the foundation of study-data reproducibility; the journal is designed for the requirements of 21 CFR Part 11 and EU Annex 11.

0:000:00
Reading the audit trail with before/after detail and a hash-chain check

Append-only and the hash chain in plain terms

Section titled “Append-only and the hash chain in plain terms”

Two guarantees make the trail trustworthy:

  • Append-only. Journal records cannot be changed or deleted through the application: the database runtime role has no permission to modify the journal or to disable the protection. A schema owner or a DBMS superuser can technically drop the triggers — but not undetectably: the hash chain and the anchors in previously issued inspection packets will diverge. Correcting an error is always a new record on top of the old one, never a substitution of the old one.
  • Hash chain (cryptographic linking). Each record carries a “fingerprint” (hash) whose computation includes the fingerprint of the previous record. The records are linked into a continuous chain. If someone tries to change, delete, or insert a record in the middle, the fingerprints stop matching, and verification detects it immediately.

Saving a single value is not one operation but a fixed chain of reactions, carried out in full within one transaction: either all of it goes through, or nothing changes at all. The audit write is a mandatory link in this chain, not a separate “log afterwards”.

  1. Permission check (PBAC). Do you hold the permission to write to this field and its scope? If not, the write is refused and the value does not change.

  2. Lock check. Are the field or its scope locked? Under a hard lock a write is impossible.

  3. Rule gates. You cannot write to a computed (derived) field, nor to a field hidden by a skip-logic condition.

  4. Value validation. Type, range, and code-list membership — per the field definition.

  5. Reason for Change (RfC). Editing an already-saved value requires a reason; an initial entry does not.

  6. Writing the value. The value is saved with an optimistic version check and a reset of dependent axes: SDV, medical review, and coding return to their initial state, and a completed form moves back to “in progress”.

  7. Audit write. audit.append() — in the same transaction as the data change itself.

  8. Signature invalidation. Every signature that covered this value automatically becomes invalid.

  9. Rule engine. Derivations are recomputed in a cascade (actor — the system), then the edit checks run: block rolls back the entire write, query opens an auto-query.

  10. Event publication. Events go into the transactional outbox; subscribers (modules) receive them via a background worker — only after the transaction commits.

All changes to data, metadata, configuration, access, and work objects are audited, along with a closed list of privileged reads. Ordinary reads are not audited (otherwise the journal would drown in noise).

Category Example actions
Clinical data entering and editing a value, clearing it, marking “not done”, creating a subject, changing its status, creating a visit, completing a form
Metadata (design) creating and publishing a design version, editing a form or an edit check in a draft, approving a translation
Work objects opening/answering/closing a query, applying and invalidating a signature, placing and releasing a lock
Access granting and revoking grants, creating and assigning roles, overriding an SoD conflict
Configuration changing a setting, syncing a module with the delivery (including its permission changes), enabling/disabling a module
Privileged reads an unblinded read of a blinded value, launching an export, exporting the audit trail itself

Each journal record describes one action with a set of fields (in the interface — columns and row details):

Field What it shows
Occurred at (UTC) the moment of the action in universal time; the local representation is for convenience only
Actor who did it: a user, a module, or the system
Role the user’s role at the moment of the action — a snapshot, not the current role (EMA 2023 §6.2.1)
Organization the user’s organization at the moment of the action — likewise a snapshot; older records show “not recorded”
Action what happened (for example, “data saved”, “signature applied”)
Entity which object it acted on (a value, a form, a subject, a grant…)
Scope the scope path: study → site → subject → form → field
Before / After the canonical values of exactly the fields that changed (not the whole record)
Reason the Reason for Change text, where it is required
Module if a module performed the action — which one
Caused by if the action is an automatic reaction (for example, a signature reset), a reference to the originating event

Role and organization are a snapshot at the moment of the action: the role may later change or the user may leave, yet the record still shows who they were when they acted. The user’s organization is set by the administrator in the user card (Administration → Users); it lands in every subsequent audit record. Older records, made before the snapshot existed, show “not recorded” — nothing is backfilled.

X7 Insight distinguishes a first entry from an edit of an already-saved value:

  • First entry (the field was empty) does not require a reason — this aligns with the ALCOA principle of “contemporaneous” recording.
  • Any change to a saved value, including clearing it, requires a reason. Without a reason the system will not save the edit. The interface shows a dialog with a free-text field and a per-study configurable list of common reasons.

A reason is also required for: releasing a lock, clearing an SDV mark, cancelling and reopening a query, rejecting a query answer, overriding an SoD conflict, and emergency unblinding. For how this looks during data entry, see Data entry.

The same viewer opens at different levels; the level determines which records you see (and requires the corresponding audit.read permission in that scope):

Four levels of the trail — from the journal of the entire organization to the history of a single form.
  • Tenant — the Admin → Audit section: the journal of the entire organization.
  • Study — the Audit tab inside a study: only its records.
  • Subject and form — the same viewer opened from a subject or form page: the history of one participant or one form.

Filters above the table: the period “From (UTC)” — “To (UTC)”, Actor, Action, and Entity type. Columns: Occurred at (UTC), Actor, Action, Entity, and Scope. Clicking a row reveals the “Before / After”, “Reason”, “Module”, and “Caused by” details.

Step by step — see the guide Export the audit trail.

Above the table sit three buttons: Export XLSX, Print PDF and CSV for verification. Each builds a server-side document — with exactly the screen’s current filters (site, subject, period, user, action):

  • XLSX — a register for humans: the first sheet “About this export” (filters, cut, who built it and when, the system), then the journal with before/after in words, role and organization;
  • PDF — the same picture as a printable PDF/A copy (landscape page, the table header repeats);
  • CSV — a dynamic file for independent verification: human-readable columns plus every field of the hash-chain link, from which the record’s fingerprint is recomputed without access to the system.

The buttons are shown to holders of both the audit-read and the run-exports rights; a view-only auditor reads the trail on screen. Every build lands in the Exports journal with its checksum, and every download is audited. How server-built documents work — Documents and certified copies.

Integrity verification (verify hash-chain)

Section titled “Integrity verification (verify hash-chain)”

Step by step — see the guide Verify the audit chain.

The Verify trail integrity button triggers a recomputation of the whole chain from the start. The permission to run it is audit.verify. The result:

  • Chain intact — “N records verified”. No record has been changed, deleted, or inserted in the middle.
  • Chain broken — the sequence number (seq) of the first broken record is reported. Verification catches content edits, record deletion, insertion in the middle (a gap in the numbering), and substitution of a reason.

An additional layer of protection is anchoring: on every inspection packet build X7 Insight records the “head” of the chain (its current fingerprint) as a separate entry and puts the full anchor list into the packet. The packet itself is the external write-once medium: placing it into your own WORM or eTMF store gives you a dated copy against which the live chain is later verified. This makes it possible to prove integrity even if you assume that someone with database access recomputed the entire chain. How often anchoring happens is set by your packet-building procedure.