Who opened which patient record, and a log the database refuses to edit

By Abhishek Dogra, Founder, ElaiorLast verified

Most clinic software keeps a log. Few say what that log is worth on the day somebody wants a line out of it. In Elaior the answer is not a policy and not a permission: the trail is one Postgres table, and the database itself refuses to change a row in it.

What the database actually refuses

RAISE EXCEPTION 'AuditLog is append-only';

CREATE TRIGGER audit_log_append_only
  BEFORE UPDATE OR DELETE ON "AuditLog"
  FOR EACH ROW EXECUTE FUNCTION forbid_audit_log_mutation();

A trigger rather than a permission, and the migration says why: "on a managed Postgres the application connects as the TABLE OWNER, so REVOKE is toothless and a trigger is the only thing that holds for every role". So the refusal binds the application's own privileged connection, the one every handler holds.

One exemption exists, and in code that ships in the server binary the demo wipe is its only caller: a session setting scoped to a single transaction, so it dies with that transaction on a commit and on a rollback alike. Turning the trigger off at table level was rejected in writing, because that is a global switch: while it is off every other connection can delete too, and a wipe that dies partway leaves the protection off with nothing to notice.

Database, guarded write, or display only

Three different strengths of promise, and only the first rows are a guarantee the database keeps on its own.

What a row carries

Opening one named record is an event too

Most audit trails record writes. The line here is drawn at opening or downloading one named record. Nine read events are filed from ten hook sites: the print routes for a prescription, an invoice, a bill and a register; the blob routes for an attachment, a vault document and the clinic logo; the portal's own two document reads; and patient.history.

What this mechanism does not cover

This section is the reason to believe the rest. Every item is in the code, or is an absence in it.

None of that is comfortable to publish for a product with no customers yet. It is here because a mechanism is worth something only when its edges are written beside it.