Change logging (audit)
Any entity can capture an append-only change log of every insert, update and delete. Because the log is written by a database trigger, it captures every mutation path — form submit, row delete, LINQ, import, even raw SQL — inside the same transaction as the change itself. Nothing that touches the table escapes it.
Enabling it
Section titled “Enabling it”Set Logging="Enabled" on the entity. See
Entities → Logging.
<Entity Name="Invoice" SchemaName="Sales" PluralName="Invoices" Logging="Enabled"> <Fields> … </Fields></Entity>On the next model migration, AuditLogSqlHandlerService installs a per-entity
AFTER INSERT, UPDATE, DELETE trigger. Setting Logging="Disabled" (or removing the attribute) drops
the trigger on the next migration, so capture stops cleanly. The operation is idempotent and dual-dialect
(SQL Server + PostgreSQL).
What gets written
Section titled “What gets written”Each committed change becomes a row in [Genie].[AuditLog]:
| Column | Meaning |
|---|---|
SchemaName, TableName, RowId |
which record changed |
Operation |
I, U, or D |
ChangedById |
the actor — taken straight off the row’s own audit columns (CreatedById / UpdatedById), which the app stamps from @SessionUserId |
CompanyId |
the tenant, from the row |
ChangedAt |
timestamp (SYSDATETIMEOFFSET() / now()), falling back to the row’s audit timestamp |
OldValues, NewValues |
full before/after JSON images of the row |
- Insert logs
NewValuesonly; delete logsOldValuesonly; update logs both. - On update, only rows whose image actually changed are logged (the trigger compares the before/after JSON), so a no-op save writes nothing.
The IsDirty exclusion
Section titled “The IsDirty exclusion”The application-only IsDirty search flag (added by the search feature) is stripped
from both the logged JSON image and from change detection. That single exclusion is what lets the audit
trigger coexist with the Meilisearch-sync IsDirty trigger without conflict — a change that only flips
IsDirty produces no audit row, so there are no phantom entries and the two triggers never fight.