Workflow history and archive
Each workflow insert and each version change captures its definition in the same PostgreSQL transaction. The snapshot holds name, trigger, conditions, ordered actions, enabled, dry-run, bound author and role ceiling, and capture time. The author is the definition's created_by, which may differ from the person stopping or archiving it. Updates to snapshots are refused by a database trigger. History has no application update or delete endpoint. Workflow deletion cascades by tenant FK; this feature exposes no hard delete.
Existing workflows get one snapshot at their current version, marked backfilled. Earlier definitions are unknown and cannot be recovered. Settings outside the workflow row, including schedule and inbound-hook configuration, are not versioned.
History lists newest versions first with integer version cursors, author id, time, backfill provenance and changed fields compared with the preceding known snapshot. View shows the full saved definition. The History panel compares it with the current workflow, including changes at each action position.
Restore requires the currently observed expectedVersion. It sends the saved name, trigger, conditions, actions and dry-run through the same authenticated PATCH endpoint as an edit. It retains the current enabled state, creates a new version, revalidates references and authority, binds revisions, cancels waits and audits normally. Deleted references, stale versions and other edit refusals are returned unchanged. Restoring the current version returns 409 already_current. Archived workflows must be unarchived before editing or restoring.
Duplicate creates Copy of <name> (maximum 120 characters) stopped in dry run. It copies no agent execution grants or remote approval receipts. It uses normal creation validation and counts toward the limit.
Archive checks expectedVersion under the organization automation lock, stops the workflow, timestamps archived_at and increments the version. It cancels waiting runs with workflow_archived and recalls queued remote steps after commit. In-flight remote work cannot be recalled. Archived workflows retain readable version and run history and reject PATCH and enable with 409 workflow_archived. PostgreSQL forbids an archived row from being enabled, including through raw SQL.
The default workflow list excludes archived rows. ?archived=true selects the archived list. Only unarchived workflows count toward the 100-workflow limit. Unarchive requires a free slot and expectedVersion and leaves the workflow stopped, creating another version.
Read operations require crm:read; mutations require crm:edit. The existing automation flag-first 404, tenant gates and credential rules apply. UI write controls are hidden without crm:edit. MCP tools are automation_versions, automation_version_get, automation_version_restore, automation_duplicate, automation_archive and automation_unarchive; their responses mark returned data untrusted. Runner keys are excluded from registration and refused by the CRM route-family gate.
History routes register inside automationRoutes, MCP tools inside the existing automation gate, and the UI on each workflow row. Migration 13627 installs snapshots and archive state.
Database trigger behavior: https://www.postgresql.org/docs/current/sql-createtrigger.html . In-process routing: https://github.com/fastify/fastify/blob/main/docs/Guides/Testing.md . Consulted 2026-10-22.