Dashboard authoring and promotion

Use this workflow when a dashboard change must move from a safe project draft to a production deployment. It defines the ownership, environment, source-control, and lifecycle boundaries for file, UI, and agent authors. The browser builder, headless authoring API, and dashboard-authoring agent tools all use the same draft, revision, authorization, and promotion rules.

An unpublished draft is visible to its author and users with authorized editing access. Draft status keeps it out of published dashboard delivery; it does not restrict access to the author alone.

Before you begin

Choose a permanent development boundary and a production boundary. Use separate LeapView instances for development and production; each instance is permanently bound to one environment and one active project generation. This workflow does not create temporary environments.

Boundary choice Isolation Cost and operations Decision
Separate development and production instances Strongest: distinct instance identities, targets, credentials, storage, and failure domains Higher infrastructure and operator cost; promotion crosses an explicit target boundary Preferred for production isolation

Create separate credentials for development and production. A recommended permission model is:

Principal Development Production
Author Edit private drafts, preview, and publish on the development instance No edit, publish, or deploy grant on the production instance
QA/verifier Read and test the development publication with representative grants Read-only verification when assigned
Production deploy service account No access unless a separate, explicitly scoped account is needed Deploy the approved full project; no interactive authoring
Viewer Read only Read only
Operator Administer the instance and recover it Administer the instance and recover it; use a separately audited identity

Use distinct development and production service principals. Target identity and credentials provide the first boundary; project-resource grants remain the second.

Understand ownership and status

Dashboards are project assets whether their visibility is private, restricted, or organization-wide. The interactive builder must select a governed semantic model from that project graph. Semantic-model usage, visibility counts, and publication state remain observable and governable in catalog, audit, and access surfaces.

File-authored, UI-authored, and agent-authored are origins. Origin is provenance, not ownership: it must not decide who can edit, publish, or deploy. Access and RBAC grant those actions to principals over a project and its assets. Anonymous publication is a separate, explicit publication capability; it does not transfer dashboard ownership or authoring rights.

Treat common UI badges as projections of these separate facts:

Badge or concept Meaning Does not mean
Private / Restricted / Organization The dashboard's project visibility A different owner or a different semantic model
Draft A mutable project draft that can be edited by an authorized principal A production deployment or an immutable version
Published A selected immutable dashboard revision is available through the project publication path That the project is deployed to production
Archived The dashboard lifecycle no longer accepts normal publication That its historical revision or deployment evidence was deleted
File / UI / Agent How the current authored content entered LeapView Who owns the asset or who may deploy it

The lifecycle layers are intentionally different:

  1. A draft is the mutable project-owned editing record. Saving or applying edits may point it at a new revision.
  2. A dashboard revision is an immutable, complete copy of one dashboard document. Publishing selects a revision; it does not mutate one that has already been published.
  3. Compiled serving-state generations are immutable full-project deployments for an environment. Each includes the compiled project graph, semantic, dashboard, access, policy, connection, and managed-data decisions needed to serve requests.
  4. A DuckLake data snapshot is an analytical consistency and retention boundary used by runtime queries. It is not a dashboard revision, a draft fork, or a customer-facing dashboard version.

Do not use a data snapshot, virtual schema, or automatic fork of an underlying model as a dashboard authoring mechanism.

Follow the normal change flow

  1. Fork or copy the published dashboard into a private draft. Keep the published dashboard stable while the change is being developed.
  2. Iterate in the draft. UI, file, and agent edits are equivalent origins. Select and reuse the existing governed semantic model for dashboard-only work; do not fork the model automatically.
  3. Validate and preview. Validate the project and inspect the draft with the author's effective grants. Check query results, filters, empty and failure states, layout, and accessibility. Use the existing dashboard creation guide for resource details and develop, review, and publish for CLI gates.
  4. Publish to development. Publish the draft on the development instance. Have QA exercise the published result with representative viewer and row-policy identities.
  5. Export canonical YAML. The export is the reviewable project representation. If Git is enabled, commit it to the user's repository and review the change through the user's Git provider. Merge only after the project and dashboard checks pass.
  6. Deploy the full project to production. A dedicated production, project-scoped deploy service account or CLI deploys the approved merged project. The production deployment is atomic across the resources in that project.

For a dashboard-only change, reuse the already approved semantic model and deploy the dashboard change with that model reference. If model, semantic-model, access-policy, or dashboard changes must move together, validate and QA the complete project in development, then deploy that same full project to production. Do not suggest snapshots, virtual schemas, or automatic model forks to avoid coordinating those changes.

Use the browser dashboard builder

Open the authenticated edit route:

GET /dashboards/{dashboard}/edit

The route requires dashboard edit access. It resolves the repository's current draft pointer and exact retained revision on the server, then streams a typed builder projection. The page shows the governed semantic-model fields, pages, visuals, source origin, visibility, lifecycle, revision number, save state, diagnostics, and source evidence. It never accepts a client-supplied document as authority.

An authenticated owner with current dashboard.update authority may permanently discard their own private draft that has never been published. Ownership alone is insufficient. This owner policy does not grant dashboard.delete, change built-in roles, or allow archiving published dashboards. API credentials still require explicit dashboard.delete authority within their permission ceiling. Delete is checked again against current authorization and durable lifecycle state when the command executes or replays.

The browser builder is a closed command surface. Each row below is a browser command emitted by the current builder and translated by the server into a typed authoring payload. The last column is part of the contract: values not listed as editable remain unchanged when that command is applied, or are intentionally code-only.

Browser surface Command Browser-editable properties Preserved or code-only properties
Dashboard appearance update_appearance Dashboard icon and color Dashboard title, description, slug, semantic model, visibility, pages, visuals, and advanced appearance metadata remain unchanged or code-only
Dashboard visibility set_visibility private or organization visibility Dashboard document, lifecycle revision history, and restricted/access policy details remain server-owned or code-only
Dashboard metadata update_dashboard_metadata Dashboard title and description Slug, semantic model, visibility, icon/color, pages, visuals, and advanced metadata remain unchanged or code-only
Publish publish The exact current draft revision selected by the browser Draft bytes, revision history, publication evidence, and serving deployment remain server-owned; publish does not deploy a full project
Archive archive Dashboard lifecycle state Retained revisions, authored source, and evidence remain preserved; archive does not delete the document
Delete delete The current private draft dashboard Dashboard content and retained revisions are permanently removed; only audit and idempotency evidence remain; published or restricted dashboards cannot be deleted
Add page add_page Page title and optional page ID The server allocates missing IDs; description, grid, components, and advanced page metadata use canonical defaults or remain code-only
Rename page rename_page Page title Page ID, description, grid, components, and page bindings remain unchanged; description is code-only here
Page metadata update_page_metadata Page description; the current title is carried to preserve it Page ID, grid, components, bindings, and advanced page metadata remain unchanged or code-only
Duplicate page duplicate_page Source page and optional duplicate title or ID The server clones authored content and allocates collision-free visual/component IDs; the source page remains unchanged
Reorder page move_page Page order index Page identity, title, description, grid, components, and visual definitions remain unchanged
Page grid update_page_layout Columns, row height, gap, and padding Page title, description, components, canvas geometry, and visual/filter properties remain unchanged or code-only
Remove page remove_page The selected page Other pages, dashboard metadata, visual definitions not removed by canonical cleanup, and revision history remain preserved
Add visual add_visual Target page, visual type, title, and optional governed field plus role The server allocates IDs and canonical query/presentation defaults; arbitrary query expressions, advanced presentation, and interactions are code-only
Change visual type set_visual_type Target visual and visual type The server resolves compatible governed bindings; unsupported query-family options and advanced presentation settings remain code-only or are reset by the target family
Duplicate visual duplicate_visual Source visual, optional title, and optional IDs The server clones the authored definition and allocates collision-free IDs; source visual fields, formatting, filters, and interactions remain unchanged
Remove visual remove_visual Selected visual placement/definition Other visuals, page layout, filters, interactions, and dashboard metadata remain unchanged
Move or resize components set_placements Selected page component positions and spans Visual queries, formatting, filter definitions, interactions, and all untouched component placements remain unchanged
Add governed field assign_field Target visual, semantic field ID, and metric, dimension, or detail role The active semantic model validates the field; arbitrary physical fields, expressions, query options, and presentation remain code-only
Remove governed field remove_field Target visual, field ID, and role Remaining field selections, query family, formatting, filters, and interactions remain unchanged; required scalar bindings cannot be removed
Reorder governed field move_field Field order within a compatible role Cross-role conversion, semantic meaning, query expressions, and physical bindings remain server-governed or code-only
Visual query options set_visual_query_options Selected field alias, temporal grain, bounded sort, and result limit Semantic field identity, query family, calculations, filters, interactions, and unexposed query options remain unchanged or code-only
Visual formatting update_visual_format Visual title, title visibility, and catalog-provided renderer-neutral format options Query/semantic selections, interactions, and presentation options not exposed by the catalog remain unchanged or code-only
Add report filter add_filter Governed dimension, label, option dataset, and control type Filter defaults, operators, targets, advanced option settings, and physical expressions use canonical defaults or remain code-only
Add filter slicer add_slicer Governed dimension, label, option dataset, control type, and target page The server atomically creates the filter and page component with generated IDs; defaults, operators, targets, and advanced filter settings remain code-only
Update filter update_filter Label, description, option dataset, control type, required, reader-editable, and URL parameter Authored defaults, operators, targets, and advanced option settings are deliberately preserved
Set filter scope set_filter_scope Report/page scope and optional visual targets Filter defaults, operators, reader-editable policy, and advanced options remain unchanged
Remove report filter remove_filter Selected filter definition Other filters, visuals, pages, and dashboard metadata remain unchanged; canonical cleanup handles its placements
Place existing filter add_filter_component Target page, filter ID, and optional component ID Filter definition and its defaults/options remain unchanged; the server allocates missing component IDs
Remove filter slicer remove_filter_component Selected page component The underlying filter definition, defaults, targets, and other placements remain unchanged
Set visual interaction target set_interaction_target Source visual, target visual, and filter, highlight, or none effect Existing governed mappings and unsupported/spatial interaction forms remain server-owned or code-only
Header metadata update_header_metadata Selected header title and description Header ID, placement, kind, page identity, and unsupported header properties remain unchanged or code-only
Undo or redo exact revision restore_revision Exact retained target revision selected by browser history Restore appends a new revision; the target and intervening revisions remain retained, and no implicit “latest” lookup is allowed

Field assignment is validated against the active governed semantic model before the edit is appended. The browser also has local-only controls (theme, canvas zoom, pane collapse, field search, and selection); they do not create authoring revisions. Preview, export, and Make a copy are links or read operations, not builder commands. The server accepts a few additional typed actions for headless/API callers, including set_filter_targets and rename_visual; they are not browser actions today. Arbitrary YAML patches, model edits, and properties marked code-only above require the project authoring guides or the headless/agent surfaces.

Every builder mutation carries the dashboard ID, draft ID, and a complete expected revision token (revisionId, number, and contentHash). The browser supplies a request ID (X-Request-ID, with Idempotency-Key as a fallback); the authenticated principal is the actor. A successful intent appends one immutable revision, increments the revision number, updates the draft pointer, and leaves an already published revision unchanged. Replaying the same command identity and fingerprint returns the recorded result without appending a second revision. A token that is no longer current returns a stale-revision conflict; reload the current draft and submit the intent again.

Preview, publish, and export exactly what was reviewed

The Preview link identifies one exact draft revision. It includes the draft ID, page ID, revision ID, revision number, and content hash; there is no implicit “latest” revision. The browser route is:

GET /dashboards/{dashboard}/preview?draft={draft}&page={page}&revisionId={id}&revisionNumber={number}&revisionContentHash={hash}

Preview compiles that retained document against the active governed runtime and returns the definition, page patch, semantic-model/runtime identity, exact serving identity (projectId, environment, and generationId), and DuckLake snapshot evidence. Preview does not change the draft, publish the dashboard, deploy a serving generation, or mutate data.

Publish is a typed command against the same complete expected revision. LeapView compiles the draft with its governed semantic model, stores the compiled revision and publication evidence, and moves the dashboard lifecycle to published. Publishing does not deploy a full project to production; use the development publication and full-project promotion gates described above.

Export YAML downloads the canonical authored source without changing lifecycle state:

GET /dashboards/{dashboard}/export.yaml

The export is reviewable project YAML. A retained project source resolves the current lifecycle draft by its dashboard ID; an active project source is the serving artifact with serving-state/path evidence. Neither export turns a compiled artifact into a fabricated authoring revision.

Use the headless dashboard-authoring API

The generated API is rooted at /api/v1/projects/{project}/authoring. Authenticate with a scoped principal and use IDs returned by the catalog; do not infer identity from titles. The generated OpenAPI contract is authoritative for field types and status codes.

Method and path Purpose and access
GET /api/v1/projects/{project}/authoring/catalog List governed dashboard identities (RESOURCE_READ).
GET /api/v1/projects/{project}/authoring/dashboards/{dashboard} Read one dashboard summary (RESOURCE_READ).
GET /api/v1/projects/{project}/authoring/dashboards/{dashboard}/draft Read the current private draft, lifecycle pointer, document, and exact revision (RESOURCE_EDIT).
GET /api/v1/projects/{project}/authoring/dashboards/{dashboard}/drafts/{draft}/revisions/{revision} Read that exact current draft revision (RESOURCE_EDIT); the draft and revision path values must match.
GET /api/v1/projects/{project}/authoring/dashboards/{dashboard}/revisions/{revision} Read that exact published revision (RESOURCE_READ); this path never means “latest draft.”
POST /api/v1/projects/{project}/authoring/drafts Create one named private draft.
POST /api/v1/projects/{project}/authoring/commands Apply one closed command: one builder intent, publish, or archive.
POST /api/v1/projects/{project}/authoring/forks Fork a retained project source into a new private draft.
POST /api/v1/projects/{project}/authoring/dashboards/{dashboard}/drafts/{draft}/preview Preview one exact revision and page.
GET /api/v1/projects/{project}/authoring/sources/{kind}/{dashboard}/export Export canonical YAML for the project source kind.

POST /drafts, POST /commands, and POST /forks require an Idempotency-Key header (1–200 characters). The key is an operation-idempotency identity, separate from actor and tool-call provenance, and is audited with the authenticated actor; it is not a repository or Git authority. For create and fork, the same key with the same normalized payload durably replays the original draft/result; the same key with a changed payload is a conflict; a different key creates a new draft. Command retries likewise replay only when the same key is reused with the same request fingerprint. Preview, reads, and export do not require an idempotency key.

Command requests must name the exact dashboardId, draftId, and expectedRevision token:

{
  "kind": "addVisual",
  "dashboardId": "revenue",
  "draftId": "draft-7",
  "expectedRevision": {
    "revisionId": "revision-12",
    "number": 12,
    "contentHash": "sha256:..."
  },
  "addVisual": {
    "pageId": "overview",
    "type": "bar",
    "title": "Revenue by month"
  }
}

The discriminated command union accepts exactly one payload for its kind: metadata, setVisibility, addPage, addVisual, assignField, upsertPage, removePage, upsertVisual, removeVisual, setLayout, setFilters, setInteraction, publish, or archive. Every successful edit returns the new immutable revision token and the repository-authoritative lifecycle pointer. A stale token is a 409 conflict; read the current draft and reconcile rather than dropping the token or defaulting to a newer revision. Preview requests repeat the complete token in their body, and responses include the same revision plus runtime and snapshot evidence.

Use dashboard-authoring agent tools

The dashboard-authoring subset of built-in chat and MCP contains these twelve tools:

list_dashboards
get_dashboard
get_dashboard_draft
create_dashboard_draft
execute_dashboard_command
fork_dashboard
preview_dashboard_draft
export_dashboard_yaml
set_dashboard_visibility
add_dashboard_page
add_dashboard_visual
assign_dashboard_field

The first three read the governed catalog or exact private draft. create_dashboard_draft and fork_dashboard create private drafts. The four intent tools apply the same visibility, add-page, add-visual, and assign-field union used by the browser. execute_dashboard_command is reserved for exact-revision publish and archive; preview_dashboard_draft requires an exact revision and page; and export_dashboard_yaml returns canonical YAML. Catalog, query, and documentation tools remain separate integration surfaces.

Agent inputs deliberately omit actor and provenance fields. The server binds origin: agent, the authenticated principal as actorId, the active conversation as conversationId, and the tool invocation ID as toolCallId; a model cannot spoof any of them. Agent calls use the invocation ID for both their operation idempotency key and actual tool-call identity. Agent tools enforce the project scope, object privilege, governed semantic-model check, and exact revision token before applying a mutation. Create and fork replay a durable result for the same invocation ID and normalized payload, conflict on a changed payload, and create a new draft for a different invocation ID; intent and lifecycle command retries follow command-ID/fingerprint replay rules. MCP writes are advertised as non-idempotent because MCP assigns a fresh server tool-call ID for each request; durable replay requires an agent caller to reuse the original invocation identity.

Choose a create, fork, or promotion flow

Situation Recommended flow
New dashboard with an existing governed semantic model Create a private draft in the active project, use the four bounded intents, preview the exact latest revision, publish on the development instance, then export and promote the full project.
Change to an existing published project dashboard Fork the exact published project revision into a new private draft; keep the source unchanged, iterate, preview, publish in development, and promote the reviewed project.
Only an active project artifact is available Fork the project source into a private draft. Record its serving-state/path evidence, understand that it has no authoring revision token, and continue editing the retained project source when one is available.
Dashboard and model, policy, or semantic changes must move together Validate and QA one complete project on the development instance, export the canonical YAML, and deploy that same full project atomically to the production instance.

The create/fork operation never deploys, publishes a serving generation, mutates the semantic model, creates a data snapshot, or makes a temporary schema. Git is an optional review and evidence integration after export; LeapView has no native Git integration and no repository authority. The server remains authoritative for lifecycle, authorization, revisions, and deployment targets.

Update existing copies of Visual Showcase

The shared dashboards/dashboards/visual-showcase.yaml defines Purchase period as a dateRange control on purchase_timestamp. The browser displays Start and End dates as MM/DD/YYYY, and the timestamp range includes the full selected end date. The filter retains its purchase_time ID, existing targets, and unfiltered default. Its canvas component also retains its existing ID so references remain stable. Relative-period controls remain available for other filters and dashboards.

No database schema or automatic saved-dashboard migration is required. The rollout depends on how the dashboard is stored:

  • Shared project dashboard: deploy the updated project source through the normal candidate/publication workflow. Viewers and new drafts forked from that generation receive the date-range definition. Updating the application binary alone does not deploy project YAML.
  • Existing saved drafts or separately published copies: their documents are retained revisions, so the shared-source update does not rewrite them. To adopt this change, edit that copy's purchase_time filter to use label Purchase period and control dateRange, update its description, and clear any old relative-period default. Keep its field, ID, targets, and other customizations. Validate and preview the resulting revision, then publish it explicitly if the copy should be shared. Starting a new draft from the updated shared dashboard is another option.
  • Existing viewer sessions: filter state belongs to a serving generation. A new generation uses its own session state; an old rolling-period selection is not converted into an absolute date range. Choose the desired Start and End dates after opening the updated dashboard.

This is an explicit content update for existing saved copies, not a bulk rewrite: an automatic conversion could replace a deliberately chosen rolling-period filter or overwrite user edits.

Use Git when it helps review

Git is highly recommended, but opt-in. LeapView has no native Git integration, pull-request workflow, or merge automation. A mature integration exports canonical YAML, lets the user's Git provider handle branches and review, and invokes LeapView's CLI or API from a dedicated project-scoped deploy service account after merge.

Repository, ref, and commit metadata may be recorded as evidence and provenance. They are not a server-enforced “managed by Git” authority: the server still validates the project, authorization, candidate, and deployment target. Without Git, use the same draft, preview, development publication, and full-project production gates with an explicitly authorized publisher or service account.

Validate the promotion

Before production deployment, confirm that:

  • the draft and published revision belong to the intended project and use the intended governed semantic model;
  • the development and production instances are separate, permanent environment boundaries;
  • dashboard visibility (private, restricted, or organization), access grants, row and column policies, and anonymous publication settings are intentional;
  • QA verified the development publication with representative viewer identities;
  • the exported YAML, source revision (when Git is used), plan, and deploy service-account identity are retained as evidence; and
  • coordinated model, semantic, policy, and dashboard changes are present in one full-project candidate.

Verify the result

After production activation, verify the serving-state generation and exercise one representative dashboard page, filter path, and table or query window. Check that the expected dashboard revision is published, visibility counts remain visible to authorized operators, and access policies still hold for viewers. A failed validation or activation leaves the previous valid generation serving; use the governed rollback operation rather than editing active files or deleting data snapshots.

Troubleshooting

Symptom Corrective action
An author can see or edit production assets Remove the author's production-instance role or credential; do not rely on naming alone.
A draft edit changes the published dashboard Confirm the author copied the published asset into a private draft and published a new revision only after review.
Git metadata is present but the server accepts an unintended source Review the canonical YAML, candidate digest, target identity, and permissions. Repository/ref metadata is evidence, not authority.
A model and dashboard disagree after promotion Treat them as one coordinated full-project change, revalidate in development, and redeploy the complete candidate.
A data snapshot is mistaken for a dashboard version Inspect the dashboard revision and serving-state generation separately; snapshots only describe analytical runtime consistency.

Next steps

Read Projects and environments for resource boundaries, API conventions for headless retry and error handling, Use the agent tool catalog for agent transport details, Targets and environments for target safeguards, and Dashboard authoring patterns for maintainable dashboard structure.