# Audit trail

An entity keeps no history of its changes unless you ask. Give it an
`audit:` section and it keeps a history of every change: who made it,
when, through which action and request, and each changed field's value
before and after. `retention:` says how long each entry is kept:

```jadpo
// domains/billing/entities/invoice.jadpo
entity Invoice {
    ...
    audit: {
        retention: {
            after: config.audit_retention
        }
    }
}
```

- Each entry is written in the same transaction as the change, in the
  same store, so a change can't happen without its entry.
- "Who" is the principal, the signed-in caller. For schedules and
  subscribers it is the application, together with the request that
  emitted the event, so a change made later is traced back to the click
  that caused it.
- Fields marked `personal:` are stored as keyed hashes, as they are in
  logs ([Marking personal fields](marking-personal-fields.md)).
  The history shows that an email changed, not what it was. Server-only
  fields are left out.
- `Invoice.history(invoice_id)` is a generated query returning a page of
  entries. It needs the `read` grant on the record, and fields the caller
  can't read are left out.
- Entries are deleted when their retention ends, and with their record
  when it is erased. The permissions report lists which entities are
  audited.

The audit trail records changes to data. Who exported or erased a
person, and who read sensitive fields, is kept as log events instead
([Access records](access-records.md)).

## Sending audit entries elsewhere

When something subscribes to the built-in `AuditEntryRecorded` event, or
`publishing` names it, each entry is also emitted as that event, in the
same transaction, and travels through the outbox like any event
([Delivery: at least once, safe to repeat](delivery-at-least-once-safe-to-repeat.md)).
A SIEM or log archive receives it through `publishing`. With nothing
listening the event is never emitted. The database stays the record of
truth; the event is a copy, carrying the same hashed personal fields.
