Schema
audit_logs Table
Schema and examples for the data audit log table.
The audit_logs table records every create, update, and delete
captured by an ORM adapter (plus manual RecordDataChange calls).
Table name is configurable via DataAudit.Table; the default is
audit_logs.
Schema
| Column | PostgreSQL | MySQL | SQLite | Description |
|---|---|---|---|---|
id | BIGSERIAL PK | BIGINT UNSIGNED PK | INTEGER | Auto-increment primary key |
entity_type | VARCHAR(100) | VARCHAR(100) | TEXT | Table / model name |
entity_id | VARCHAR(100) | VARCHAR(100) | TEXT | Record identifier (JSON for compound PKs) |
action | VARCHAR(20) | VARCHAR(20) | TEXT | create, update, delete, soft_delete, restore |
old_values | JSONB | JSON | TEXT | Values before change (nullable) |
new_values | JSONB | JSON | TEXT | Values after change (nullable) |
user_id | VARCHAR(100) | VARCHAR(100) | TEXT | Who made the change |
user_type | VARCHAR(50) | VARCHAR(50) | TEXT | user, admin, system, … |
metadata | JSONB | JSON | TEXT | Extra context (IP, reason, …) |
transaction_id | VARCHAR(100) | VARCHAR(100) | TEXT | Groups related operations |
created_at | TIMESTAMPTZ | TIMESTAMP | DATETIME | When the change occurred |
Indexes
All dialects create these indexes:
idx_<table>_entity (entity_type, entity_id)
idx_<table>_user (user_id, created_at)
idx_<table>_action (action)
idx_<table>_created (created_at)
idx_<table>_transaction (transaction_id)PostgreSQL additionally creates:
idx_<table>_old_values USING GIN (old_values)
idx_<table>_new_values USING GIN (new_values)MySQL declares its indexes inline in the CREATE TABLE statement;
SQLite and PostgreSQL use separate CREATE INDEX statements.
Go Struct
type AuditLog struct {
ID uint64 `json:"id"`
EntityType string `json:"entity_type"`
EntityID string `json:"entity_id"`
Action string `json:"action"`
OldValues json.RawMessage `json:"old_values,omitempty"`
NewValues json.RawMessage `json:"new_values,omitempty"`
UserID string `json:"user_id"`
UserType string `json:"user_type,omitempty"`
Metadata json.RawMessage `json:"metadata,omitempty"`
TransactionID string `json:"transaction_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
}OldValues, NewValues, and Metadata are json.RawMessage so you
can decode them into whatever shape your application expects.
Example Records
Create
{
"entity_type": "users",
"entity_id": "42",
"action": "create",
"old_values": null,
"new_values": { "name": "Ada", "email": "ada@example.com" },
"user_id": "admin-1",
"user_type": "admin",
"created_at": "2026-04-13T09:00:00Z"
}Update — only changed fields are stored:
{
"entity_type": "users",
"entity_id": "42",
"action": "update",
"old_values": { "email": "ada@example.com" },
"new_values": { "email": "ada.l@example.com" },
"user_id": "admin-1",
"created_at": "2026-04-13T09:05:00Z"
}Soft delete — GORM + gorm.DeletedAt:
{
"entity_type": "users",
"entity_id": "42",
"action": "soft_delete",
"old_values": { "name": "Ada", "email": "ada.l@example.com", "deleted_at": null },
"new_values": { "deleted_at": "2026-04-13T09:10:00Z" },
"user_id": "admin-1",
"created_at": "2026-04-13T09:10:00Z"
}Delete — hard delete:
{
"entity_type": "users",
"entity_id": "42",
"action": "delete",
"old_values": { "name": "Ada", "email": "ada.l@example.com" },
"new_values": null,
"user_id": "admin-1",
"created_at": "2026-04-13T09:10:00Z"
}