Workflow Versioning and Deprecation¶
Overview¶
Floh supports safe evolution of published workflows through versioning and deprecation. Instead of editing a live workflow in place (which would break the integrity of existing runs), users create a new draft version that can be modified independently. The previous version can then be deprecated to prevent new runs while allowing in-flight runs to complete.
Workflow Lifecycle¶
A workflow definition moves through these statuses:
| Status | Can edit? | Can start runs? | Purpose |
|---|---|---|---|
| draft | Yes | Yes (test runs) | Under development |
| active | No (create new version) | Yes | Production use |
| deprecated | No (create new version) | No | Superseded; existing runs continue |
Workflows can be soft-deleted at any status to remove them from the default list. Soft-deleted workflows can be restored or permanently deleted.
Workspace Writability¶
Every workflow lives in a workspace (a project row). Which workspaces a caller may write to determines where they can create, version, deprecate, or revert a workflow.
A caller may write to a workspace when any of the following holds:
- They hold
system:administer. - The workspace is Default (
DEFAULT_PROJECT_ID=00000000-0000-0000-0000-000000000001). - They own the workspace (
project.owner_idmatches their user id).
There is no workspace membership table — ownership is a single column, so a workspace someone else created is read-only to everyone but its owner and admins. Default exists precisely to give every workflow:create holder somewhere to author.
GET /api/projects returns a canWrite boolean per row that evaluates these same rules for the calling user, so the designer can pre-select a workspace the caller can actually save to and disable the ones they cannot. The server re-checks on every write regardless of what the client sent; canWrite is a UI affordance, not the authorization decision.
The reserved "Default" name¶
The name Default belongs to the seeded workspace and cannot be taken by another workspace or renamed away. This is enforced in three places:
POST /api/projectsandPUT /api/projects/:idreturn409when a name normalizes todefaulton any row other than the seeded one, and when the seeded row is renamed to anything else. Normalization is NFKC + trim + lowercase, so" DEFAULT "and the fullwidth"Default"are both rejected.- A partial unique index on
lower(btrim(name))(non-deleted rows only) blocks a duplicate that bypasses the route — soft-deleted rows are exempt so a deleted workspace never blocks the seeded one. - A CHECK constraint pins the seeded row's name.
Because both objects cover live rows only, a workspace soft-deleted before the reservation existed can still hold the name. POST /api/projects/:id/restore therefore runs the same guard and returns 409 rather than letting the restore trip the index. Such a workspace currently cannot be restored at all — there is no API path to rename a soft-deleted workspace, tracked in #1227.
Config import binds an incoming workspace named Default to DEFAULT_PROJECT_ID rather than inserting a second row.
Operator note: the migration that installs these objects runs a preflight over every live workspace using the application's normalization — broader than the index expression, so a fullwidth or tab-padded impostor is caught rather than silently left in place. It aborts, writing nothing, and lists the offending ids if any workspace other than the seeded one claims the name. Rename or soft-delete those rows, then re-run.
The same preflight canonicalizes the seeded workspace's name if a prior release left it as a variant spelling (default, " Default "), so editing that workspace does not start returning 409. If the seeded workspace was renamed to something unrelated, the migration aborts and asks you to rename it back rather than overwriting a deliberate choice.
Creating a New Version¶
When a workflow is active or deprecated, editing it directly is not allowed. Instead, users create a new version:
- From the workflow detail page, click New Version.
- A confirmation dialog explains that a new draft copy will be created and the original will remain unchanged.
- On confirmation, the system clones the workflow as a new draft with a link back to the source.
- The user is navigated to the designer to edit the new draft.
What gets copied¶
The new version is a complete clone of the source workflow, including:
- Name, description, and error strategy
- Trigger configuration
- All context variables
- All step definitions and transitions
- Project and workflow set assignment
The new version receives:
- A new unique ID
- Status set to
draft - Version number inherited from the source (incremented upon publish)
- A
sourceWorkflowIdreference back to the original
API¶
Requirements: workflow:create permission + a write grant on the destination workspace. The seeded Default workspace ships with an all-users write grant, so any workflow:create holder may create there. Other workspaces require ownership, system:administer, or an assigned write grant — see Workspace Access.
Response (201):
{
"message": "New draft version created",
"newWorkflow": { ... },
"sourceWorkflowId": "uuid-of-source"
}
Publishing and Deprecating the Previous Version¶
When publishing a new version that was created from an existing workflow, the system detects the sourceWorkflowId and prompts the user to deprecate the previous version.
Publish flow¶
- User clicks Publish on the draft workflow.
- The server validates the workflow graph (strict mode) and sets status to
active. - If the workflow has a
sourceWorkflowIdand the source workflow is stillactive, the frontend shows a prompt: "Would you like to deprecate the previous version?" - If the user confirms, a follow-up API call deprecates the source.
The publish endpoint also supports atomic deprecation via the request body:
Body (optional):
When deprecatePreviousVersionId is provided and the referenced workflow is active, it is automatically set to deprecated as part of the publish operation.
Deprecating a Workflow¶
Deprecation marks a workflow as superseded. Deprecated workflows:
- Cannot start new runs.
- Continue to serve existing in-flight runs normally.
- Can have new versions created from them.
- Can be deleted or (with confirmation) reverted to draft.
API¶
Requirements: workflow:update permission + a write grant on the workflow's workspace. Only active workflows can be deprecated. Default-hosted workflows are writable by any workflow:update holder via Default's all-users grant; other workspaces require ownership, system:administer, or an assigned write grant.
Response (200):
UI¶
The Deprecate button appears on active workflows in both the workflow detail page and the workflow list. A confirmation dialog explains the impact before proceeding.
Reverting to Draft¶
Reverting a published workflow to draft is a destructive action that should be avoided for production workflows. It is provided as a last resort for development and testing scenarios.
Safeguards¶
When reverting an active or deprecated workflow to draft:
- A warning dialog explains that existing workflow runs would lose integrity.
- The dialog advises that creating a new version is the preferred practice.
- The user must type the exact workflow name to confirm the action.
- The typed name is validated server-side before the revert proceeds.
API¶
Body (required):
If confirmationName does not match the workflow's name, the server returns 400:
Version Tracking¶
Each workflow definition has two fields for version tracking:
| Field | Type | Description |
|---|---|---|
version |
integer | Incremented each time a workflow is published |
sourceWorkflowId |
uuid (nullable) | References the workflow this version was cloned from |
The sourceWorkflowId creates a chain of versions that can be followed to trace the history of a workflow. The workflow detail page displays a "Previous Version" link when a source exists.
Database¶
The source_workflow_id column was added in migration 012_workflow_versioning:
ALTER TABLE workflow_definition
ADD COLUMN source_workflow_id VARCHAR(255) DEFAULT NULL;
ALTER TABLE workflow_definition
ADD CONSTRAINT fk_wf_source
FOREIGN KEY (source_workflow_id)
REFERENCES workflow_definition(id)
ON DELETE SET NULL;
The v_workflow_definition view includes this column.
Run Behavior by Status¶
| Workflow status | New runs | Existing runs |
|---|---|---|
| draft | Allowed (test runs) | Continue normally |
| active | Allowed | Continue normally |
| deprecated | Blocked (400 error) | Continue normally |
When a deprecated workflow is started, the API returns:
{
"statusCode": 400,
"message": "Deprecated workflows cannot start new runs. Create a new version instead."
}
Audit Logging¶
All versioning and deprecation operations are recorded in the audit log:
| Action | Description |
|---|---|
workflow.version_created |
New draft version cloned from a published workflow |
workflow.published |
Workflow published (draft → active) |
workflow.deprecated |
Workflow deprecated (active → deprecated) |
workflow.reverted_to_draft |
Workflow reverted to draft |
The workflow.version_created and workflow.deprecated entries include metadata linking the source and target versions.
UI Summary¶
Workflow Detail Page¶
| Status | Available Actions |
|---|---|
| draft | Test Run, Edit, Publish, Delete |
| active | Start Run, View Runs, New Version, Deprecate, Delete |
| deprecated | View Runs, New Version, Revert to Draft, Delete |
Workflow List Page¶
| Status | Row Actions |
|---|---|
| draft | Test Run, Edit, Publish, Delete |
| active | Start Run, New Version, Deprecate, Delete |
| deprecated | New Version, Delete |
The status filter dropdown includes Deprecated as an option. Deprecated workflows display with a red/danger status badge.
Recommended Practices¶
-
Never revert a production workflow to draft. Always create a new version instead. Reverting breaks the integrity of existing runs that reference the workflow's published state.
-
Deprecate the previous version when publishing a new one. This ensures users always start runs on the latest version.
-
Delete deprecated workflows once all their runs have completed, to keep the workflow list clean. Deleted workflows can be restored if needed.
-
Use version tracking to maintain an audit trail of how workflows have evolved over time.