Skip to content

Audit trail

Accounts keeps an append-only audit trail. Mutating requests across the document, ledger, banking and platform surfaces are recorded after they succeed, so the ledger of record comes with a record of who touched it.

  • A generic hook writes an entry after every successful create, update or delete on a mapped business record — the object types in the table below. Posts, sends, voids, reversals and imports are recorded as what they are rather than flattened into a generic update.
  • Flows whose meaning the generic hook cannot infer record themselves explicitly: logins and logouts, and approval actions (submit, approve, reject, recall).
  • Each entry carries the action type, the object type and id, the acting user and the time, and can capture before/after values.
  • Reads are not logged, and neither is inbox housekeeping (notifications and their preferences). Three surfaces are off the map as well: exchange rates, file attachments and workflow definitions change without leaving a row.

The vocabulary is a fixed list, checked by the database:

Area Object types
Sales Estimate, sales order, invoice, customer payment, credit note, retainer invoice, credit refund
Purchasing Bill, vendor payment, vendor credit, purchase order, expense
Ledger Journal entry, GL account, fiscal period, tax code, budget
Banking Bank account, bank transaction, bank statement line, bank rule, bank reconciliation
Runs and engines Fixed asset and asset type, recurring invoice, recurring transaction, dunning policy and run, FX revaluation run, revenue-recognition rule and schedule
Masters Contact, contact person, item, price list, payment term, cost center, department, branch, project, time entry, common master
Platform Role, approval process, custom field, validation rule, form, auto-number config
Account User — sign-in, sign-out, profile edits, password and avatar changes

Common master covers the generic typed lookups (countries, states, cities, designations, units of measure and the rest) added with the Common Masters engine. Deactivating one is recorded as an update, not a delete — the record changed, it did not die.

Bank reconciliations are audited across their whole lifecycle: opening one is a create, discarding it a delete, completing and reopening it updates — so the month-end sign-off, and any later reversal of it, both leave a row.

  • Successful sign-ins and sign-outs are logged explicitly, with the session and the originating IP and user agent.
  • A profile edit records the fields that actually changed, before and after. A password change records that it happened and how many other sessions it signed out; a change refused because the current password was wrong is recorded too, marked as a failure.
  • Failed sign-ins are counted on the account rather than logged as audit rows. After five consecutive failures the account locks for fifteen minutes and further attempts are refused; both thresholds are deployment settings (LOGIN_MAX_ATTEMPTS, LOGIN_LOCKOUT_MINUTES).
  • The lock is checked before the password, so a locked account cannot be probed even with the right credentials. A successful sign-in clears the counter and the lock.
  • The trail is queryable read-only: filter by a single record’s history (object type + id), by user, by action type, or by date range, newest first.
  • There is no write, edit or delete route for the log: it is append-only by design.