Drafts & Versioning
Create and manage draft copies of datasets for safe editing without affecting production data.
Overview
Datasets support a draft workflow that allows users to:
- Create a personal draft copy of a dataset
- Make changes to the draft (fields, flow, settings) without affecting the production dataset
- Preview draft results
- Commit changes back to the production dataset or discard the draft
Each user can have their own draft of a dataset, enabling collaborative editing without conflicts.
POST /api/datasets/{id}/_edit
Create or retrieve a draft of a dataset for the current user.
Authentication: Required
Permission: dataset:write
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Dataset ID or slug |
Response:
Returns the user's draft dataset if it exists, or creates a new draft and returns it.
{
"id": "sales-2024-draft-user123",
"name": "Sales Data 2024 (Draft)",
"description": "Quarterly sales analysis",
"datasourceId": "mysql-prod",
"ownerId": "user:admin",
"parentId": "sales-2024",
"isDraft": true,
"query": "SELECT * FROM sales WHERE year = {{year}}",
"params": [
{
"name": "year",
"dataType": "number",
"defaultValue": 2024,
"required": true
}
],
"fields": [...],
"createdAt": "2024-02-08T15:00:00Z",
"updatedAt": "2024-02-08T15:00:00Z",
"_links": {
"self": { "href": "/api/datasets/sales-2024-draft-user123" },
"inf:parent": { "href": "/api/datasets/sales-2024" }
}
}
Behavior:
- If draft already exists for current user, returns existing draft
- If no draft exists, creates new draft as child of parent dataset
- Draft is created with current state of parent dataset
- Draft owner is always the current user
Use Case:
Call this endpoint when a user clicks "Edit" on a dataset to enter draft mode.
GET /api/datasets/{id}/draft
Get the draft dataset for the current user.
Authentication: Required
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Parent dataset ID or slug |
Response:
{
"id": "sales-2024-draft-user123",
"name": "Sales Data 2024 (Draft)",
"parentId": "sales-2024",
"isDraft": true,
"hasUserSettings": true,
"query": "SELECT * FROM sales WHERE year = {{year}}",
"fields": [...],
"createdAt": "2024-02-08T15:00:00Z",
"updatedAt": "2024-02-08T15:10:00Z"
}
Special Fields:
| Field | Type | Description |
|---|---|---|
hasUserSettings | boolean | Indicates if user has custom settings applied |
Status Codes:
200- Draft found404- No draft exists for current user
PUT /api/datasets/{id}/draft
Create a new draft with custom settings, replacing any existing draft.
Authentication: Required
Permission: dataset:write
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Parent dataset ID or slug |
Request Body:
| Field | Type | Description |
|---|---|---|
flow | array | Flow transformation steps |
queryId | string | Create from existing query |
settings | object | User-specific view settings |
Response:
Returns the newly created draft dataset.
Example Request:
{
"flow": [
{
"type": "filter",
"criteria": { "region": "West" }
},
{
"type": "sort",
"field": "amount",
"order": "desc"
}
],
"settings": {
"defaultView": "table",
"pageSize": 50
}
}
Behavior:
- Deletes any existing draft for current user
- Creates new draft with specified configuration
- Applies custom settings to draft
This endpoint will delete any existing draft for the current user before creating the new one. Unsaved changes will be lost.
DELETE /api/datasets/{id}/draft
Delete the draft dataset created by the current user.
Authentication: Required
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Parent dataset ID or slug |
Response:
204 No Content
Behavior:
- Looks up draft by parent dataset and current user
- Deletes draft if found
- Returns 404 if no draft exists
Use Case:
Call this endpoint when a user clicks "Cancel" or "Discard Draft" to exit draft mode without saving changes.
POST /api/datasets/{id}/draft/_commit
Commit/publish draft changes back to the main dataset.
Authentication: Required
Permission: dataset:write (on parent dataset)
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Parent dataset ID or slug |
Request Body:
| Field | Type | Default | Description |
|---|---|---|---|
clearAllUserSettings | boolean | true | Clear all user settings when committing |
Response:
{
"id": "sales-2024",
"name": "Sales Data 2024",
"description": "Quarterly sales analysis (Updated)",
"query": "SELECT * FROM sales WHERE year = {{year}} AND region = {{region}}",
"fields": [...],
"updatedAt": "2024-02-08T15:30:00Z"
}
Behavior:
- Copies draft configuration (query, flow, fields) to parent dataset
- Optionally clears all user-specific settings (default: true)
- Creates Activity record for notification
- Deletes the draft
- Returns updated parent dataset
Activity Notification:
The commit creates an Activity record of type dataset.draft.committed with:
{
"type": "dataset.draft.committed",
"userId": "user:admin",
"datasetId": "sales-2024",
"message": "Draft committed by Admin User",
"createdAt": "2024-02-08T15:30:00Z"
}
Use clearAllUserSettings: false if you want to preserve user-specific view preferences (column widths, sort orders, etc.) after publishing changes.
Draft Workflow Example
Complete workflow for editing a dataset:
// 1. Enter draft mode
const draft = await POST('/api/datasets/sales-2024/_edit');
// Returns existing draft or creates new one
// 2. Make changes to draft
await PUT(`/api/datasets/${draft.id}`, {
query: "SELECT * FROM sales WHERE year = {{year}} AND region = {{region}}",
params: [
{ name: "year", dataType: "number", defaultValue: 2024 },
{ name: "region", dataType: "string", defaultValue: "West" }
]
});
// 3. Preview draft results
const preview = await GET(`/api/datasets/${draft.id}/data?limit=100`);
// 4a. Commit changes (publish)
await POST('/api/datasets/sales-2024/draft/_commit', {
clearAllUserSettings: true
});
// OR
// 4b. Discard changes
await DELETE('/api/datasets/sales-2024/draft');
Best Practices
When to Use Drafts
- Complex changes - Multi-step changes to query, flow, or fields
- Testing - Preview results before affecting production
- Collaboration - Multiple users can work on separate drafts
- Safety - Revert changes easily without affecting others
When to Skip Drafts
- Simple updates - Name/description changes don't need drafts
- Data operations - Adding/deleting records (use data endpoints directly)
- Administrative changes - Ownership, sharing, tags
User Settings
User settings control personal view preferences like:
- Default visualization type
- Page size for tables
- Column visibility and order
- Sort preferences
- Filter presets
Set clearAllUserSettings: false when committing if you want to preserve these across draft publishes.
Each user can have their own draft of the same dataset. When one user commits their draft, other users' drafts remain intact but may become out of sync with the parent dataset.