Skip to content

Content Versions & Activity

Overview

The versions system allows creating named snapshots of content items for branching and review workflows. A version stores a delta (JSON diff) from the main item and can be promoted to become the live content.

The activity log tracks all create/update/delete operations across all collections, providing a full audit trail.


Versions

Data Model

A version is tied to a specific collection + item pair and has a human-readable key (slug). Multiple versions can exist for the same item simultaneously.

odp_versions

ColumnTypeDescription
idUUID PK
keystring(64)Human-readable slug/name
namestring(255)Display name
collectionstring(255) FK → odp_collectionsCollection name
itemstring(255)Item primary key (as string)
hashstring(255)Hash of the delta content
date_createdtimestamp
date_updatedtimestamp
user_createdUUID FK → odp_users
user_updatedUUID FK → odp_users
deltatext (JSON)The content diff from the main item

Endpoints

POST /versions

Create a new version.

Auth required: Yes (permissions checked by service layer)

Request Body:

json
{
  "key": "draft-v2",
  "name": "Draft Version 2",
  "collection": "articles",
  "item": "item-uuid",
  "delta": {
    "title": "Updated Title",
    "body": "New body content"
  }
}
FieldTypeRequiredDescription
keystringYesUnique slug for this version within (collection, item)
namestringNoDisplay label
collectionstringYesCollection name
itemstringYesItem primary key
deltaobjectNoJSON object with field overrides

Response:

json
{
  "data": "new-version-uuid"
}

GET /versions

List versions with optional filtering.

Auth required: Yes

Query Parameters: Standard ODP query params (filter, sort, fields, limit, offset, meta).

Example Query:

GET /versions?filter[collection][_eq]=articles&filter[item][_eq]=article-uuid

Response:

json
{
  "data": [
    {
      "id": "version-uuid",
      "key": "draft-v2",
      "name": "Draft Version 2",
      "collection": "articles",
      "item": "article-uuid",
      "hash": "abc123...",
      "date_created": "2024-01-01T00:00:00.000Z",
      "date_updated": null,
      "user_created": "user-uuid",
      "user_updated": null,
      "delta": { "title": "Updated Title" }
    }
  ],
  "meta": { "total_count": 1 }
}

GET /versions/:id

Read a single version.

Response: Single version object.


PATCH /versions/:id

Update a version's metadata or delta.

Request Body:

json
{
  "name": "Renamed Draft",
  "delta": {
    "title": "Even More Updated Title"
  }
}

Response:

json
{
  "data": "version-uuid"
}

DELETE /versions/:id

Delete a version.

Response: 204 No Content


POST /versions/:id/promote

Promote a version to become the live content of the parent item.

Response: 204 No Content

Business Logic (implemented in VersionsService.promote):

  1. Reads the version record including delta
  2. Fetches the current live item from the collection
  3. Merges delta onto the current item data
  4. Updates the live item with the merged data
  5. Optionally deletes the version after promotion (implementation-dependent)

Activity Log

The activity log (odp_activity) records all data mutations across the system. It is append-only and can be queried to build an audit trail.

odp_activity

ColumnTypeDescription
idinteger PK (auto-increment)
actionstring(45)Action type (see below)
userUUID FK → odp_usersUser who performed the action
timestamptimestampWhen the action occurred
ipstring(50)Client IP
user_agenttextBrowser/client
collectionstring(255)Affected collection
itemstring(255)Affected item PK
originstring(255)Request origin header
impersonated_byUUIDIf impersonating, the real admin user

Common Action Types

ActionDescription
createItem created
updateItem updated
deleteItem deleted
loginUser logged in (via auth.login event)
logoutUser logged out
impersonation.startedImpersonation session started
impersonation.stoppedImpersonation session ended

Revisions

Each activity record can have associated revision data in odp_revisions:

odp_revisions

ColumnTypeDescription
idinteger PK
activityinteger FK → odp_activityParent activity (CASCADE delete)
collectionstring(255)Collection name
itemstring(255)Item primary key
datatext (JSON)Full snapshot after the change
deltatext (JSON)Only the changed fields
parentinteger FK → odp_revisionsParent revision
versionUUID FK → odp_versionsLinked version (if via promote)

Activity Endpoints

Activity endpoints are read-only. See the system server docs for the full CRUD route list. Activity is accessible at GET /activity and GET /activity/:id.

Example: Fetch recent login activity

GET /activity?filter[action][_eq]=login&sort=-timestamp&limit=20

ODP Internal API Documentation