go-auditGo Audit
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

ColumnPostgreSQLMySQLSQLiteDescription
idBIGSERIAL PKBIGINT UNSIGNED PKINTEGERAuto-increment primary key
entity_typeVARCHAR(100)VARCHAR(100)TEXTTable / model name
entity_idVARCHAR(100)VARCHAR(100)TEXTRecord identifier (JSON for compound PKs)
actionVARCHAR(20)VARCHAR(20)TEXTcreate, update, delete, soft_delete, restore
old_valuesJSONBJSONTEXTValues before change (nullable)
new_valuesJSONBJSONTEXTValues after change (nullable)
user_idVARCHAR(100)VARCHAR(100)TEXTWho made the change
user_typeVARCHAR(50)VARCHAR(50)TEXTuser, admin, system, …
metadataJSONBJSONTEXTExtra context (IP, reason, …)
transaction_idVARCHAR(100)VARCHAR(100)TEXTGroups related operations
created_atTIMESTAMPTZTIMESTAMPDATETIMEWhen 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"
}

On this page