Dyrecteddyrected
Guides

Audit Trail

Track who changed what and when — automatic system metadata plus optional full activity logging.

Dyrected tracks document lifecycle through two complementary layers: system metadata that is always on, and activity logs that you opt into per collection.


System metadata (always on)

Every collection automatically gets the following fields. You do not need to declare them — Dyrected injects them when it loads your config.

FieldDescription
createdAtISO timestamp set on creation.
updatedAtISO timestamp updated on every write.
createdByID of the user who created the document.
updatedByID of the user who last modified the document.

These fields are read-only and hidden in the Admin UI. They are populated from the signed-in user's JWT (JSON Web Token — the signed session token from login) on every POST (create) and PATCH (update).


Activity logging (audit: true)

For a complete change history — including document snapshots (a full copy of the document at the moment of the change) and field-level diffs — enable audit logging on any collection:

const posts = defineCollection({
  slug: 'posts',
  audit: true,
  fields: [
    { name: 'title', label: 'Title', type: 'text' },
    { name: 'body', label: 'Body',  type: 'richText' },
  ],
})

Every create, update, and delete operation on that collection writes an entry to the built-in __audit collection.

What gets logged

FieldDescription
entitySlug of the collection affected.
entityIdID of the document affected.
actioncreate, update, or delete.
userIdID of the user who performed the action.
userCollectionAuth collection the user belongs to (e.g. __admins).
userEmailEmail of the acting user at the time of the action.
changesJSON diff — on update, an object of { field: { old, new } } pairs.
snapshotFull document copy at the time of the action.
timestampISO timestamp of the action.

Example entry for an update:

{
  "entity": "posts",
  "entityId": "abc123",
  "action": "update",
  "userId": "user_01",
  "userEmail": "[email protected]",
  "changes": {
    "title": { "old": "Hello World", "new": "Hello Dyrected" }
  },
  "snapshot": {
    "id": "abc123",
    "title": "Hello Dyrected",
    "body": "..."
  },
  "timestamp": "2026-05-11T10:23:00.000Z"
}

Querying audit logs

The __audit collection is queryable via the standard collection API:

// Fetch the change history for a specific document
const logs = await client.collection('__audit').find({
  where: {
    entity:   { equals: 'posts' },
    entityId: { equals: 'abc123' },
  },
  sort: '-timestamp',
})

Notes

  • Audit logging never blocks the primary write. If logging fails, the error is recorded to the server console but the original request succeeds.
  • The __audit collection is hidden in the Admin UI sidebar by default. Surface it by referencing the slug explicitly in your config with admin: { hidden: false }.
  • Diffs are computed as a shallow comparison. Nested objects are compared by JSON serialisation.

On this page