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.
| Field | Description |
|---|---|
createdAt | ISO timestamp set on creation. |
updatedAt | ISO timestamp updated on every write. |
createdBy | ID of the user who created the document. |
updatedBy | ID 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
| Field | Description |
|---|---|
entity | Slug of the collection affected. |
entityId | ID of the document affected. |
action | create, update, or delete. |
userId | ID of the user who performed the action. |
userCollection | Auth collection the user belongs to (e.g. __admins). |
userEmail | Email of the acting user at the time of the action. |
changes | JSON diff — on update, an object of { field: { old, new } } pairs. |
snapshot | Full document copy at the time of the action. |
timestamp | ISO 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
__auditcollection is hidden in the Admin UI sidebar by default. Surface it by referencing the slug explicitly in your config withadmin: { hidden: false }. - Diffs are computed as a shallow comparison. Nested objects are compared by JSON serialisation.