Skip to content

feat(api): complete the v2 workflows resource with versions and CRUD - #6184

Merged
TheodoreSpeaks merged 4 commits into
improvement/v2-endpointsfrom
feat/v2-workflow-versions
Aug 2, 2026
Merged

feat(api): complete the v2 workflows resource with versions and CRUD#6184
TheodoreSpeaks merged 4 commits into
improvement/v2-endpointsfrom
feat/v2-workflow-versions

Conversation

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator

Summary

  • v2 workflows had 9 routes covering only execution and deployment — you could run and deploy a workflow you couldn't manage, and rollback existed with no way to enumerate what to roll back to
  • Adds GET /api/v2/workflows/[id]/versions (cursor-paginated, newest first) and GET .../versions/[version] (version + the workflow state it pins)
  • Adds POST /api/v2/workflows, PATCH /api/v2/workflows/[id], DELETE /api/v2/workflows/[id]
  • All six are wrappers — they delegate to performCreateWorkflow/performUpdateWorkflow/performDeleteWorkflow and listWorkflowVersions/getWorkflowDeploymentVersion. No new domain logic

Notes on three judgment calls:

  • Versions are cursor-paginated, not returned whole. Nothing prunes workflow_deployment_version — one row per deploy, forever. The cursor keys on the version number. listWorkflowVersions itself is still unpaginated, so the route bounds the response, not the DB read; the rows carry no state blob so they're small, but that helper wants a limit argument eventually
  • assertWorkflowMutable is called in the routes. performUpdateWorkflow/performDeleteWorkflow don't assert internally (unlike the deploy family), so this matches what the internal PUT/DELETE handlers already do. Locked workflow returns 423
  • Access failures on [id] routes are masked as 404, matching the existing GET — the caller never names a workspace, so a 403 would confirm the workflow exists somewhere they can't reach. Create returns a real 403 since the caller supplied the workspaceId
  • deployments/[version]/revert is deliberately not ported: it overwrites the editor draft, which is an editor concern whose public analogue is export/import. rollback already covers version activation

Path is named versions, not deployments, to match the existing rollback verb. Public projection drops the raw createdBy user id — deployedBy already carries the name. sortOrder/locked/forkSyncExcluded stay off the public surface.

Type of Change

  • New feature

Testing

  • 4 new route.test.ts files, 69 tests passing across app/api/v2/workflows + lib/workflows/orchestration — gate-off, invalid body, access denied, rate limited, happy path per route, plus locked-workflow 423 on PATCH and DELETE, 409 name collision, and last-workflow-in-workspace 400
  • bun run check:api-validation:strict, check:openapi, type-check, lint:check all pass
  • Full pre-ship audit suite (boundaries, utils, zustand-v5, react-query, client-boundary, bare-icons, icon-paths, realtime-prune, skills, agent-stream-docs) passes; no generator drift
  • BASELINE.totalRoutes/zodRoutes bumped 1046 → 1048 for the two new route.ts files

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Adds version listing/detail plus create, update, and delete to the v2
workflows surface, which previously covered only execution and deployment.

- GET /api/v2/workflows/[id]/versions — cursor-paginated, newest first
- GET /api/v2/workflows/[id]/versions/[version] — version + pinned state
- POST /api/v2/workflows, PATCH and DELETE /api/v2/workflows/[id]

All six delegate to the existing orchestration and persistence helpers;
no new domain logic.
@vercel

vercel Bot commented Aug 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview Aug 2, 2026 5:25am

Request Review

@cursor

cursor Bot commented Aug 2, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Expands the public API for workflow lifecycle and version inspection, including auth masking and archive semantics, but reuses existing orchestration and persistence rather than new business rules.

Overview
Completes the public v2 workflows surface so callers can manage workflows—not only list, run, and deploy them—and discover deployment versions before using rollback.

New routes: POST /api/v2/workflows (create empty workflow), PATCH / DELETE on /api/v2/workflows/{id} (metadata move/rename/archive to Recently Deleted), GET .../versions (cursor-paginated, newest first), and GET .../versions/{version} (version metadata plus pinned graph state). OpenAPI (openapi-v2-workflows.json) and Zod contracts in lib/api/contracts/v2/workflows.ts are updated to match.

Handlers are thin wrappers around existing performCreateWorkflow / performUpdateWorkflow / performDeleteWorkflow and listWorkflowVersions / getWorkflowDeploymentVersion. listWorkflowVersions now accepts limit and afterVersion for keyset paging; version list cursors encode the version number and invalid cursors return 400 instead of a silent empty page.

Auth / errors: [id] routes mask workspace access denial as 404 (same as existing GET). Create returns real 403 when the caller supplies workspaceId. Folder checks run assertFolderInWorkspace before assertFolderMutable so foreign folders cannot be distinguished by lock status. Locked workflow/folder → 423; name collision → 409; last workflow in workspace → 400.

Rate-limit labels workflow-versions and workflow-version-detail are added in v1 middleware; API validation baseline bumps to 1048 routes. Route tests cover gate-off, validation, rate limits, happy paths, and the cases above.

Reviewed by Cursor Bugbot for commit a155729. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR completes the public v2 workflow-management surface and adds deployment-version inspection.

  • Adds workflow create, update, and archive endpoints.
  • Adds cursor-paginated version listing and individual version retrieval.
  • Extends public contracts, OpenAPI documentation, persistence helpers, validation checks, and route coverage.
  • Orders folder containment checks before lock-state checks and validates decoded version cursors.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the prior folder-state disclosure is prevented by checking workspace containment before lock state, and malformed decoded version cursors are now rejected.

Important Files Changed

Filename Overview
apps/sim/app/api/v2/workflows/route.ts Adds workflow creation with write authorization, containment-before-lock validation, orchestration delegation, and public response projection.
apps/sim/app/api/v2/workflows/[id]/route.ts Adds metadata update and archive handlers with masked authorization failures and mutability enforcement.
apps/sim/app/api/v2/workflows/[id]/versions/route.ts Adds bounded keyset pagination for deployment versions and rejects decoded cursors without a positive integer version.
apps/sim/app/api/v2/workflows/[id]/versions/[version]/route.ts Adds authorized retrieval of a deployment version and its pinned workflow state.
apps/sim/lib/workflows/persistence/utils.ts Extends deployment-version persistence reads with bounded version-keyset pagination.
apps/sim/lib/api/contracts/v2/workflows.ts Defines request and response contracts for workflow CRUD and version resources.
apps/docs/openapi-v2-workflows.json Documents the expanded v2 workflow CRUD and deployment-version API surface.

Sequence Diagram

sequenceDiagram
  participant Client
  participant Route as v2 Workflow Route
  participant Auth as Access Control
  participant Domain as Workflow Orchestration
  participant DB as Persistence
  Client->>Route: CRUD or version request
  Route->>Auth: Rate limit, feature gate, workspace access
  Auth-->>Route: Authorized
  alt Create or move into folder
    Route->>Auth: Verify folder containment
    Route->>Auth: Verify workflow/folder mutability
  end
  alt Workflow mutation
    Route->>Domain: Create, update, or archive
    Domain->>DB: Validate and persist
    DB-->>Domain: Workflow result
    Domain-->>Route: Public workflow projection
  else Version inspection
    Route->>DB: List versions or fetch pinned state
    DB-->>Route: Deployment-version data
  end
  Route-->>Client: v2 response envelope
Loading

Reviews (4): Last reviewed commit: "Merge remote-tracking branch 'origin/imp..." | Re-trigger Greptile

Comment thread apps/sim/app/api/v2/workflows/route.ts
Comment thread apps/sim/app/api/v2/workflows/[id]/versions/route.ts
…d version cursors

assertFolderMutable walks a folder's ancestor chain without filtering on
workspace, so inspecting it before containment let a caller tell a locked
folder in someone else's workspace (423) from a nonexistent one (400).
Create and update now assert containment first, matching the ordering
import-workflow.ts already uses.

A version cursor that decodes to JSON without a numeric version filtered
every row out and returned an empty page with nextCursor null, which reads
as a clean end-of-list. Malformed cursors are now a 400.
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit c86d2fc. Configure here.

listWorkflowVersions read every version row and the route filtered and
sliced the result in memory, so the response was bounded but the query
was not. It now takes optional limit/afterVersion, turning the cursor
into a real keyset query; the route asks for limit + 1 and only trims
the has-more probe. Both params are optional, so the internal, v1 admin,
and copilot callers are unchanged.

Also restores the untouched GET handler in [id]/route.ts to its original
formatting — collapsing its signature had re-indented the whole body and
buried the actual additions in whitespace churn.
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit a745600. Configure here.

…eat/v2-workflow-versions

# Conflicts:
#	apps/sim/app/api/v2/workflows/route.test.ts
#	apps/sim/app/api/v2/workflows/route.ts
#	apps/sim/lib/api/contracts/v2/workflows.ts
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit a155729. Configure here.

@TheodoreSpeaks
TheodoreSpeaks merged commit ca1dad8 into improvement/v2-endpoints Aug 2, 2026
5 checks passed
@TheodoreSpeaks
TheodoreSpeaks deleted the feat/v2-workflow-versions branch August 2, 2026 05:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant