Skip to content
bitzorcas
中EN

Guide

Visual workflow designer

Current guide to the full-page designer, server schema, AOT business metadata, draft revisions, form-field policy, simulation paths, version scope, and permissions.

Last updated

The Web application now includes a full-page workflow designer, so authors do not have to maintain the entire JSON document by hand. The canvas remains an editor: the server is authoritative for node capabilities, business metadata, draft revisions, validation, and publication. A browser crash-recovery snapshot has no publication authority and cannot replace the database draft.

1. Designer data flow

YesNo

designer-schema

Canvas + property panel

AOT business metadata

Revisioned draft

Server validation

Server simulation

No error issues?

Immutable definition + deployment

The designer consumes @bitz/platform-sdk. Node types, field widgets, enum values, catalog data sources, and expression contexts come from backend contracts. Frontend models project those contracts into editable controls.

2. Current endpoints

Method and routePurposePermission
GET /api/workflow/definitions/designer-schemaJSON Schema, seven node types, and field metadatadefinition read
GET /api/workflow/metadata/bindable-entitiesBindable business entitiesworkflow.metadata.read or implication
GET /api/workflow/metadata/entities/{entityName}/flow-fieldsFlowScope field catalogworkflow.metadata.read or implication
GET/PUT/DELETE /api/workflow/definitions/{key}/draftRead, save, or discard draftsread / update / delete
POST /api/workflow/definitions/{key}/draft/validateValidate an exact saved revisionverify
POST /api/workflow/definitions/{key}/draft/simulateSimulate an exact revision with variablesuse
POST /api/workflow/definitions/{key}/draft/publishValidate, create an immutable version, and update deploymentpublish
GET /api/workflow/definitions/{key}/versionsVersion-dock listread
GET /api/workflow/definitions/versions/{definitionId}Read an immutable versionread plus authoring scope

workflow.definition.manage implies create, update, delete, publish, verify, and use, but deliberately does not imply read. workflow.definition.create implies update so a create-only role can save a revision-zero draft. A complete author role should still receive read plus the intended write capabilities explicitly.

3. Server-driven schema

WorkflowDesignerSchema returns the authoritative JSON Schema, registered node types, participant resolvers, service-task handlers, expression built-ins, timer actions, and listener types. A configuration field may declare:

  • ValueType, Required, Description, Section, and Order;
  • a Widget such as participantBuilder, multiInstanceBuilder, rollbackBuilder, formFieldBuilder, dataScopeBuilder, timerBuilder, or listenerBuilder;
  • EnumValues, nested Properties, and array ItemSchema;
  • DataSource and ExpressionContext.

The service-task handler catalog may currently be empty. Show that state and retain controlled input rather than inventing implementations. Older clients may ignore new metadata, but a client-side node allowlist is never a publication security boundary.

4. AOT business metadata

Bindable entities do not come from runtime reflection. WorkflowBusinessMetadataProjector reads compile-time EntityMetaModel entries emitted for [BitzWorkflow(processKey)] and returns EntityName, ProcessKey, DisplayName, and Category, ordered by type short name.

The field catalog exposes only columns with a FlowScope display name. It may also include Group, IsReadOnly, FieldDataType, DataSourceKey, IsRequired, and MaxLength. Missing metadata, an unknown entity, or an empty catalog produces an empty list rather than a 500.

Declare a business aggregate for designer binding
// ① ProcessKey becomes the stable definition key suggested by the designer.
[BitzWorkflow("matter-intake", DisplayName = "Matter intake approval", Category = "Litigation")]
public sealed class MatterIntake : TenantAggregateRoot<string>
{
// ② Only fields explicitly marked for FlowScope enter the form-field catalog.
[BitzFlowScope("Disputed amount", Group = "Case facts", IsReadOnly = true)]
public decimal DisputeAmount { get; private set; }
}

Check the current BitzWorkflowAttribute and BitzFlowScopeAttribute definitions for exact parameter names. Rebuild and regenerate contracts after metadata changes. Runtime reflection does not hot-discover them.

5. businessBinding DSL

A definition root can contain:

Business binding and task field policy
{
"key": "matter-intake-approval",
"businessBinding": { "entityName": "MatterIntake" },
"nodes": [
{
"id": "partner",
"type": "userTask",
"name": "Lead partner approval",
"formFields": [
{ "fieldName": "DisputeAmount", "visibility": "readOnly" },
{ "fieldName": "ApprovalComment", "visibility": "editable" }
]
}
],
"edges": []
}

EntityName is the compile-time catalog’s type short name. When the designer changes a binding, it preserves unknown extension properties under businessBinding; clearing EntityName removes the whole binding object.

6. Actual formFields boundary

formFields is a per-UserTask field-policy matrix. The designer combines existing DSL entries with the FlowScope catalog. It currently supports only editable, readOnly, and hidden; requiredness comes from the FlowScope metadata IsRequired value and is not part of the formFields DSL.

When metadata is available, the Validator checks EntityName and fieldName, but unknown items are warnings and do not block publication. This supports old definitions and version-skewed deployments; it does not create a universal runtime form engine. The owning business UI must consume and enforce the policy, and an unknown field must fail safely without bypassing owner field authorization.

7. Drafts and optimistic concurrency

A save contains Key, Name, JsonDefinition, optional BaseDefinitionId, ExpectedRevision, and DesignerStateJson. Creation uses revision 0. Every update submits the most recently returned Revision. The server checks the key, name, JSON root and embedded key, base-version visibility, and designer-state limits before saving.

If two tabs edit concurrently, the later save does not overwrite a newer revision; it receives a revision conflict. Prompt the author to reload or merge manually rather than forcing a local snapshot over server state.

8. Browser crash recovery

The frontend stores a dirty draft and canvas state as a local recovery snapshot. It exists only for a browser crash or accidental close:

  • its storage key currently contains tenant and definition key, but no user identifier; two users sharing one browser profile in the same tenant can overwrite or see the same recovery snapshot;
  • parse failure or snapshot-version mismatch discards it, and an older baseline is not offered after the server Revision advances;
  • a recovered draft still saves against the server Revision;
  • tokens, permission decisions, trusted TenantId, and publication state never enter the snapshot.

Shared workstations must therefore use separate operating-system accounts or browser profiles and clear recovery data at logout. The current implementation has neither time-based expiry nor user ID in the key; deployments that permit shared browser profiles should close both isolation gaps first.

9. Authoritative validation

ValidateWorkflowDefinitionDraft first reloads the authoritative draft by Key and ExpectedRevision and then calls the engine. Publication repeats the same validation. If any Error issue exists, it returns structured Validation with Published=false and neither creates a version nor changes a deployment.

Core checks cover node IDs, dangling edges, self-loops, start and end, ingress and egress, gateway conditions, participants, and reachability. Unknown business bindings and form fields are Warnings. Task switches, timer actions, and static expression types still need business-specific tests.

10. Simulation path

Simulation now returns PathNodeIds and VisitedEdgeRefs, which the frontend uses to highlight the canvas. It does not write the database, invoke listeners, or create tasks. It stops at a UserTask and has a maximum depth of 100.

Exclusive and inclusive preview select only the first matching edge, and parallel preview displays only the first path. A green highlight proves this input’s preview, not parallel joins, human task concurrency, or persisted execution.

11. Version dock and tenant scope

A Host author uses the PLATFORM scope; a tenant author uses the effective TenantId. The version list checks the authoring scope first. A tenant with no local version falls back to platform defaults, while Host never falls back to an arbitrary tenant version.

A DefinitionId lookup applies visibility again: Host sees only PLATFORM; a tenant sees its own and PLATFORM baseline versions; a foreign version becomes NotFound to prevent ID probing. Forking from a version applies the same base-version ownership check.

12. Publication semantics

The designer uses /draft/publish. It verifies the revision, runs authoritative validation, creates or reuses an immutable version, validates DefinitionId, Version, and Checksum, and updates the tenant/office deployment only when the binding changed.

The repository still has the direct management endpoint POST /api/workflow/definitions/. That older path requires compilable JSON but does not run the designer’s complete validation step. Automation that calls it must invoke /validate first; new UI should prefer the draft-publication flow.

13. Frontend permissions and errors

Gate buttons by the same actions as the server: save with update/create, validate with verify, simulate with use, publish with publish, and delete with delete. The ability to edit does not imply permission to validate or simulate.

Use NodeId and EdgeRef to locate validation issues on the canvas and distinguish Warning from Error. Network failure, a 409 revision conflict, and a 403 authorization denial must not collapse into one generic “save failed” message because their safe recovery actions differ.

14. Verification commands

Terminal window
# ① Backend: schema, AOT metadata, draft actions, authoring scope, and paths.
dotnet test tests/BitzOrcas.Unit.Tests \
--filter "FullyQualifiedName~WorkflowBusinessMetadata|FullyQualifiedName~DefinitionSimulator"
dotnet test tests/BitzOrcas.Application.Tests \
--filter FullyQualifiedName~Workflow
# ② Frontend: recovery, builders, path highlighting, and full-page routing.
cd frontend
yarn workspace @bitz/app test workflow-designer-recovery workflow-builder-models workflow-definition-runtime navigation-contract

15. Release checklist

  • Unknown schema and widget values degrade safely.
  • AOT metadata exposes only owner-declared entities and fields.
  • Positive and negative tests cover create/update/read/verify/use/publish/delete combinations.
  • Cross-tenant DefinitionId and Host PLATFORM version-list regressions are locked down.
  • Crash snapshots contain no credentials; shared-browser deployments separately verify user isolation and expiry cleanup.
  • Errors block publication; every Warning has an explicit accept-or-fix record.
  • Simulation remains preview evidence; real execution covers both ORMs, concurrency, and recovery.

Definition DSL · Deployment and versioning · API reference

100%

Scroll or use controls to zoom · drag when enlarged · double-click for 100% / 200%