Audit trail & e-signatures
Changes are appended, never edited. Signatures say what they mean.
Changes to quality records land in an audit trail the database will not let anyone edit or delete: who, when, which record, and the value before and after. At every sign-off point in the app, the signer re-enters an e-signature PIN, and the signature records its meaning.
Anatomy of an entry
One entry, taken apart
A real update to a nonconformance in the demo tenant, drawn as the audit log draws it. Each numbered part is a column on the audit row.
Update
NC-1227
by Astrid Lindqvist29 Sept 2026, 18:56
Changed Description on NC-1227:
Before: Cosmetic defect above acceptance limit on Type I Borosilicate Vial 2R lot V2R-2478 Detected during routine operations at Uppsala Manufacturing. Immediate assessment performed and the affected material identified.
After: Cosmetic defect above acceptance limit on Type I Borosilicate Vial 2R lot V2R-2478 Detected during routine operations at Uppsala Manufacturing. Immediate assessment performed and the affected material identified. Update: 100% visual re-inspection of the 2,000-unit AQL sample found 41 units with airlines and 6 with stones (limit: 0 critical, 10 major); the defects cluster on two mould numbers (M07, M12), which points to the supplier forming line rather than transport damage.
ip_addresscompany_idWhat happened
actionCreate, update or delete, or a named step such as Close, Cancel or Approve when a status change maps to one.
Which record
entity_type · entity_idThe record type and the record, shown by its number and linked to the record itself.
Who
performed_byThe signed-in user whose session made the change. When a scheduled job changes a record, the entry is kept and reads “System”.
When
performed_atThe server’s clock when the entry is written, just after the change commits. Never the user’s device clock.
Before and after
old_value_json · new_value_jsonThe tracked fields as they were and as they became. For a nonconformance that is status, title, description, owner, site and department.
Where from
ip_addressStored on every entry. It is not drawn in this view, but it goes into the CSV export and the printed record.
How the entry gets written
The record changes
From a screen, the API or a scheduled job. The table carries its own audit trigger.
The entry is queued with it
The trigger queues the entry inside the same database transaction, so a change that rolls back leaves no entry behind.
Database refusesThe worker writes it
Just after the change commits. Ids in the values are resolved to readable names where it can, and secrets such as passwords are redacted.
It can only be read
An update or delete on an audit entry is refused by a trigger on the audit table.
Database refuses
Append-only, stated exactly
Entries are added and never altered. The audit table refuses every update and every delete, whoever sends it.
Is the trail hash-chained?
No. Entries are not cryptographically chained to one another, and we do not call the trail tamper-proof. What protects them is the database refusing any update or delete on the audit table, and the absence of any edit screen or write API for it. Signatures carry their own SHA-256 hash of the signing context, which is a separate thing.
Anatomy of a signature
Prove it is you, say what you mean, and it is written against one record
Approving a document, closing a CAPA or nonconformance, disposing of a retain sample, recording a calibration and approving a log entry all open the same signature step.
Step 1: Re-authenticate
The app asks the signer for their e-signature PIN, a secret separate from their login password. Being signed in is not enough to sign.
- Five wrong PINs lock PIN signing for that user for 15 minutes
- The signature service can also verify a password or a Google or Microsoft token
Server refusesStep 2: State the meaning
The signature records what it asserts, in its own column, set by the action being signed: closing an NC signs Closed, a disposal signs Disposed, a calibration signs Performed.
Meanings in use
- Approved
- Rejected
- Reviewed
- Verified
- Closed
- Cancelled
- Disposed
- Performed
Step 3: Write the row
One row in the signature ledger: the signer, the meaning, the time, the IP address and browser, and a SHA-256 hash of that signing context. It names exactly one thing it was given for.
- The hash covers the signing context, not the record’s content
- The signature row is itself audited: signer, meaning, time, hash and subject
- Revoking a signature marks it revoked with a reason; the trail records the revoke
Step 4: See it on the record
The record’s audit history shows the approval. Printed records carry an Approvals & Signatures block, built from those approval entries: action, signer, date and IP.
- The printout appends the record’s recent audit history
- A copy printed by someone without audit-trail access says the block was withheld, so it is never mistaken for an unsigned record
signatures- Signer
user_id - Meaning
meaning - Signed at
signed_at - From
ip_address · user_agent - Hash
payload_hash - Revocation
is_revoked · revoked_reason
Exactly one subject
- nc_id
- capa_id
- change_request_id
- quality_event_id
- specification_id
- sampling_plan_id
- retain_sample_id
- equipment_id
- record_id
- field_record_revision_id
- assignment_instance_id
- task_instance_id
- workflow_instance_step_id
Straight answers
What auditors and IT ask first
What does this do for 21 CFR Part 11?
It supplies technical controls that Part 11 addresses for audit trails and electronic signatures: an append-only trail with before-and-after values, and signatures with re-authentication, a recorded meaning and the signer’s identity on the record. Whether your system meets Part 11 depends on how you validate and operate it. Software alone cannot make that claim for you.
Are reads logged?
No. The trail records changes (creates, updates and deletes) on the tables that carry an audit trigger. Opening or viewing a record is not an audit event.
Is every field of every table in the trail?
No. Each audited table tracks a configured set of fields, the ones that matter for that record, and ignores housekeeping timestamps. Secrets such as passwords, tokens and assessment answer keys are redacted: the trail shows that they changed, not their values.
Is every action signed, with a reason for change?
No. Signatures are taken at defined sign-off points such as approvals, closures, disposals, calibrations and log entry reviews. Ordinary edits are captured in the audit trail with their before-and-after values rather than a mandatory reason for change.
Can a signature be deleted?
There is no delete action for signatures. A signature can be revoked by its signer or the company owner, with a written reason; the row stays, marked revoked, and the revoke is written to the audit trail. The signatures table does not carry the database trigger that the audit table does, so we describe only the audit trail as append-only.
The rules
What the trail and the ledger refuse
- Edit or delete an audit entry
- A trigger on the audit table refuses every update and delete. There is no edit screen for the trail.
- Database refuses
- Write an audit entry by hand
- The app’s GraphQL API exposes no insert, update or delete on the audit table. Entries come from the audit triggers.
- Server refuses
- A signature that names no record, or two
- A check on the signatures table requires exactly one subject column to be set on every row.
- Database refuses
- Who reads and exports the trail
- Reading the audit trail and exporting a record’s history to CSV are separate permissions you grant by role.
- You configure