Skip to main content
ThinkEx uses event sourcing to manage workspace state. Instead of directly modifying state, all changes are recorded as immutable events that can be replayed to reconstruct the workspace state at any point in time.

Event Sourcing Architecture

Workspace state is managed through an append-only event log. Each modification to a workspace generates an event that is appended to the log with an incrementing version number. The current state is reconstructed by replaying all events from the beginning (or from the latest snapshot).

Benefits

  • Complete History: Every change is recorded with timestamp and user information
  • Conflict Resolution: Built-in optimistic locking with version-based conflict detection
  • Undo/Redo: Natural support for time-travel and undo operations
  • Collaboration: Multiple users can work simultaneously with automatic conflict handling
  • Snapshots: Periodic snapshots optimize state reconstruction for workspaces with many events

Event Object

id
string
required
Unique identifier for the event (UUID)
type
string
required
Event type determining how the payload should be processed
payload
object
required
Event-specific data containing the changes to apply
timestamp
number
required
Unix timestamp (milliseconds) when the event was created
userId
string
required
ID of the user who created the event
userName
string
Name of the user who created the event
version
integer
required
Sequential version number for optimistic locking

Event Types

WORKSPACE_CREATED

Initializes a new workspace with basic metadata.
{
  "type": "WORKSPACE_CREATED",
  "payload": {
    "title": "My Workspace",
    "description": "Workspace description"
  }
}

WORKSPACE_SNAPSHOT

Sets the complete workspace state in a single event. Used for workspace creation with initial content or for periodic snapshots.
{
  "type": "WORKSPACE_SNAPSHOT",
  "payload": {
    "workspaceId": "550e8400-e29b-41d4-a716-446655440000",
    "globalTitle": "My Workspace",
    "items": []
  }
}

ITEM_CREATED

Creates a new item (canvas, text, flowchart, etc.) in the workspace.
{
  "type": "ITEM_CREATED",
  "payload": {
    "item": {
      "id": "item_123",
      "type": "canvas",
      "name": "New Canvas",
      "content": {},
      "folderId": null
    }
  }
}

ITEM_UPDATED

Updates properties of an existing item.
{
  "type": "ITEM_UPDATED",
  "payload": {
    "id": "item_123",
    "changes": {
      "name": "Updated Canvas Name",
      "content": { "nodes": [], "edges": [] }
    }
  }
}

ITEM_DELETED

Removes an item from the workspace.
{
  "type": "ITEM_DELETED",
  "payload": {
    "id": "item_123"
  }
}

Get Events

Retrieves all events for a workspace, optionally with the latest snapshot for efficient state reconstruction.
curl https://thinkex.app/api/workspaces/{id}/events \
  -H "Cookie: your-session-cookie"

Path Parameters

id
string
required
The workspace ID (UUID)

Response

Returns events after the latest snapshot (if one exists) and the snapshot itself.
events
array
required
Array of events ordered by version
version
integer
required
Current version number of the workspace (highest event version)
snapshot
object
Latest snapshot containing a complete state at a specific version
snapshot.version
integer
Version number at which the snapshot was taken
snapshot.state
object
Complete workspace state at the snapshot version
{
  "events": [
    {
      "id": "evt_123",
      "type": "ITEM_CREATED",
      "payload": {
        "item": {
          "id": "item_456",
          "type": "canvas",
          "name": "New Canvas",
          "content": {}
        }
      },
      "timestamp": 1705843200000,
      "userId": "user_123",
      "userName": "John Doe",
      "version": 5
    }
  ],
  "version": 5,
  "snapshot": {
    "version": 0,
    "state": {
      "workspaceId": "550e8400-e29b-41d4-a716-446655440000",
      "globalTitle": "My Workspace",
      "items": []
    }
  }
}
The response includes only events after the snapshot version. To reconstruct the full state, start with the snapshot state and apply all returned events in order.

Append Event

Appends a new event to the workspace event log with optimistic locking.
curl -X POST https://thinkex.app/api/workspaces/{id}/events \
  -H "Content-Type: application/json" \
  -H "Cookie: your-session-cookie" \
  -d '{
    "event": {
      "id": "evt_123",
      "type": "ITEM_CREATED",
      "payload": {
        "item": {
          "id": "item_456",
          "type": "canvas",
          "name": "New Canvas",
          "content": {}
        }
      },
      "timestamp": 1705843200000,
      "userId": "user_123",
      "userName": "John Doe"
    },
    "baseVersion": 4
  }'

Path Parameters

id
string
required
The workspace ID (UUID)

Request Body

event
object
required
The event to append
event.id
string
required
Unique event ID (UUID)
event.type
string
required
Event type (e.g., ITEM_CREATED, ITEM_UPDATED, ITEM_DELETED)
event.payload
object
required
Event-specific payload
event.timestamp
number
required
Unix timestamp in milliseconds
event.userId
string
required
ID of the user creating the event
event.userName
string
Name of the user creating the event
baseVersion
integer
required
The version number the client is based on. Used for optimistic locking

Success Response

Returned when the event is successfully appended with no conflicts.
{
  "success": true,
  "version": 5,
  "conflict": false
}

Conflict Response

Returned when another event was appended since baseVersion. Client must merge changes and retry.
{
  "conflict": true,
  "version": 6,
  "currentEvents": [
    {
      "id": "evt_other",
      "type": "ITEM_UPDATED",
      "payload": {
        "id": "item_789",
        "changes": { "name": "Updated Name" }
      },
      "timestamp": 1705843190000,
      "userId": "user_456",
      "userName": "Jane Doe"
    }
  ]
}
When a conflict occurs, currentEvents contains all events that were appended since baseVersion. The client should:
  1. Apply these events to their local state
  2. Re-generate their event based on the updated state
  3. Retry with the new baseVersion (returned as version)

Validation

The API automatically validates events to ensure data integrity:

Name Uniqueness

When creating or renaming items, the API checks that no item with the same name and type exists in the same folder.
Error Response
{
  "error": "A canvas named 'New Canvas' already exists in this folder"
}

Version Conflicts

The API uses optimistic locking to prevent lost updates. Always include the current version as baseVersion when appending events.

Snapshots

To optimize performance, ThinkEx automatically creates periodic snapshots of workspace state. Snapshots are created after a configurable number of events (default: every 100 events). Snapshots allow the API to return a base state without replaying thousands of events. The client only needs to apply events since the snapshot.
Snapshot creation is automatic and asynchronous. It does not affect event append performance.

Version History

ThinkEx supports reverting to previous versions using the event sourcing system. You can roll back to any previous state by reverting to a specific version number.

Build docs developers (and LLMs) love