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:
| Parameter | Type | Description |
|---|---|---|
id | string | Report 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
editingIdpointing 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
beforeCreateDrafthook
GET /api/reports/{id}/draft
Get the current user's draft of a report.
Authentication: Required
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Original 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:
| Parameter | Type | Description |
|---|---|---|
id | string | Original report ID |
Request Body:
{
"defn": {
"visuals": []
},
"templateId": "template-123",
"datasourceId": "mysql-prod",
"queryId": null,
"settings": {}
}
Optional Fields:
| Field | Type | Description |
|---|---|---|
defn | object | Report definition |
templateId | string | Template ID |
datasourceId | string | Datasource ID |
queryId | string | Query ID |
settings | object | Report settings |
Response:
Returns the created/updated draft with 201 Created status and Location header.
Notes:
- Fields default to values from the original report
- The
namefield is intentionally removed (cannot rename via draft PUT) - Report drivers can customize via
beforeCreateDrafthook - 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:
| Parameter | Type | Description |
|---|---|---|
id | string | Original report ID |
Response:
204 No Content on success.
Behavior:
- Deletes the draft report for the current user
- Report drivers can perform cleanup via
beforeDiscardDrafthook - 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:
| Parameter | Type | Description |
|---|---|---|
id | string | Original 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:
- Standard fields committed:
defn,datasourceId,templateId,queryId,settings,enableFilter - Name updated conditionally: Only if draft name differs from original (allows Apps to rename via AI)
- Dataset references swapped: Draft's
ReportDatasetentries replace original's - Timestamps updated:
defnUpdatedAtset to commit time - Draft deleted: After successful commit
- User settings cleared: All user-specific view settings are removed
- Activity logged: Creates
reportUpdatedactivity entry - Driver hooks: Report drivers can modify changes via
afterCommitDrafthook
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
editingIdfield 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)