Skip to main content

Drafts

Draft workflow for safe report editing without affecting the production version.

Overview

Reports support a draft workflow that allows users to make changes without modifying the live report. Each user can have their own draft of a report. Drafts are temporary copies that can be committed (published) or discarded.

POST /api/reports/{id}/_edit

Create a draft copy of a report for editing.

Authentication: Required

Permissions: report:write

Path Parameters:

ParameterTypeDescription
idstringReport ID to create draft from

Response:

{
"id": "user:john.doe:sales-dashboard-draft",
"type": "dashboard",
"name": "Sales Dashboard",
"editingId": "team:sales-dashboard",
"ownerId": "user:john.doe",
"defn": {},
"createdAt": "2024-02-09T10:00:00Z",
"_links": {
"self": { "href": "/api/reports/user:john.doe:sales-dashboard-draft" },
"inf:original": { "href": "/api/reports/team:sales-dashboard" },
"inf:commit-draft": { "href": "/api/reports/team:sales-dashboard/draft/_commit" }
}
}

Status Code: 200 OK

Behavior:

  • If a draft already exists for this user and report, returns the existing draft
  • Creates a new draft with editingId pointing to the original report
  • Copies all report configuration including dataset references and snapshot settings
  • Draft is owned by the current user (not the original report owner)
  • Report drivers can customize draft creation via beforeCreateDraft hook

GET /api/reports/{id}/draft

Get the current user's draft of a report.

Authentication: Required

Path Parameters:

ParameterTypeDescription
idstringOriginal report ID

Response:

Returns the draft report (same structure as GET /api/reports/{id}), or 404 if no draft exists.

{
"id": "user:john.doe:sales-dashboard-draft",
"editingId": "team:sales-dashboard",
"type": "dashboard",
"name": "Sales Dashboard",
"ownerId": "user:john.doe",
"_links": {
"inf:original": { "href": "/api/reports/team:sales-dashboard" },
"inf:commit-draft": { "href": "/api/reports/team:sales-dashboard/draft/_commit" }
}
}

PUT /api/reports/{id}/draft

Create or update a draft (alternative to POST /_edit).

Authentication: Required

Permissions: report:write

Path Parameters:

ParameterTypeDescription
idstringOriginal report ID

Request Body:

{
"defn": {
"visuals": []
},
"templateId": "template-123",
"datasourceId": "mysql-prod",
"queryId": null,
"settings": {}
}

Optional Fields:

FieldTypeDescription
defnobjectReport definition
templateIdstringTemplate ID
datasourceIdstringDatasource ID
queryIdstringQuery ID
settingsobjectReport settings

Response:

Returns the created/updated draft with 201 Created status and Location header.

Notes:

  • Fields default to values from the original report
  • The name field is intentionally removed (cannot rename via draft PUT)
  • Report drivers can customize via beforeCreateDraft hook
  • Dataset references and snapshot settings are copied from the original

DELETE /api/reports/{id}/draft

Discard a draft without committing changes.

Authentication: Required

Permissions: report:write

Path Parameters:

ParameterTypeDescription
idstringOriginal report ID

Response:

204 No Content on success.

Behavior:

  • Deletes the draft report for the current user
  • Report drivers can perform cleanup via beforeDiscardDraft hook
  • Original report is unaffected

POST /api/reports/{id}/draft/_commit

Commit a draft, publishing changes to the original report.

Authentication: Required

Permissions: report:write

Path Parameters:

ParameterTypeDescription
idstringOriginal report ID

Response:

Returns the updated original report with committed changes.

{
"id": "team:sales-dashboard",
"type": "dashboard",
"name": "Sales Dashboard",
"defn": {},
"defnUpdatedAt": "2024-02-09T10:15:00Z",
"updatedAt": "2024-02-09T10:15:00Z"
}

Behavior:

  1. Standard fields committed: defn, datasourceId, templateId, queryId, settings, enableFilter
  2. Name updated conditionally: Only if draft name differs from original (allows Apps to rename via AI)
  3. Dataset references swapped: Draft's ReportDataset entries replace original's
  4. Timestamps updated: defnUpdatedAt set to commit time
  5. Draft deleted: After successful commit
  6. User settings cleared: All user-specific view settings are removed
  7. Activity logged: Creates reportUpdated activity entry
  8. Driver hooks: Report drivers can modify changes via afterCommitDraft hook
Transaction Safety

Draft commit operations run in a database transaction to ensure atomicity. If any step fails, all changes are rolled back.


Workflow Example

// 1. Create draft
POST /api/reports/team:sales-dashboard/_edit
// Returns: user:john.doe:sales-dashboard-draft

// 2. Make changes to draft
PUT /api/reports/user:john.doe:sales-dashboard-draft
{
"defn": {
"visuals": [/* updated visuals */]
}
}

// 3. Commit draft
POST /api/reports/team:sales-dashboard/draft/_commit
// Original report now has the changes

// OR: Discard draft
DELETE /api/reports/team:sales-dashboard/draft
// Changes are lost, original unchanged

Multi-User Drafts

  • Each user maintains their own independent draft of a report
  • Drafts are identified by editingId field pointing to the original
  • Only the draft owner can commit or discard their draft
  • Multiple users can have concurrent drafts of the same report
  • Last commit wins (no merge conflict resolution)