Skip to content
bitzorcas
中EN

Guide

Migration, Start-at-Node, and Legacy Import

Choosing migration paths, mapping, preflight, current non-transactional/non-idempotent limits, batch recovery, applicant transfer, and acceptance runbook.

Last updated

Workflow has two distinct migration paths. StartAtNode executes a node through the current engine. ImportInstance directly reconstructs an old instance, executions, tasks, and one import activity. The first fits process adoption; the second fits in-flight legacy migration.

1. Choose a path

NeedOperation
Existing business record continues at a new-definition nodeStartAtNode
Existing completed record gets a completed processStartAtNode(autoComplete=true)
Preserve old assignee and task creation timeImportInstance
Move current applicant after staff departureTransferApplicant / TransferAllByUser
Repair a running instance to another nodeResetToNode with strict Manage permission

2. StartAtNode

It resolves the active definition, validates target node, creates instance and start activity, and either executes the target node or marks the instance completed.

Reconstruct matter intake at partner review
Result<IProcessInstance> migrated =
await migration.StartAtNodeAsync(
// The business key must reconcile one-to-one with the legacy case record.
"matter-intake-approval",
legacyMatter.MatterNo,
"MatterIntake",
legacyMatter.ApplicantId,
currentTenantId,
legacyMatter.OfficeId,
"partner-review",
autoComplete: false,
// Validate required names and value types before this write path.
mappedVariables,
"Legacy migration batch 2026-08",
cancellationToken);

Although comments say preceding nodes are marked skipped/completed, current code writes one Start activity pointing to the target; it does not create a record for every skipped node. There is no source idempotency key.

3. Import request

The request carries source system and ID, definition key, tenant and office, business identity, starter, current node, FlowState, Status, variables, active tasks, and original start time.

Legacy import request
{
"sourceSystem": "legacy-oa",
"sourceInstanceId": "WF-2021-00981",
"definitionKey": "matter-intake-approval",
"tenantId": "tenant-a",
"officeId": "shanghai",
"businessKey": "(2026)HU-ZH Case No. 0981",
"businessType": "MatterIntake",
"starterId": "1001",
"currentNodeId": "partner-review",
"currentNodeName": "Lead partner review",
"flowState": "BW",
"status": "Running",
"variables": { "disputeAmount": 1850000 },
"activeTasks": [
{
"nodeId": "partner-review",
"nodeName": "Lead partner review",
"assigneeId": "2008",
"taskStatus": "Pending",
"createTime": "2026-06-20T02:00:00Z"
}
],
"originalStartTime": "2026-06-18T08:00:00Z"
}

The HTTP command is authorized, but TenantId is taken from the request object rather than CurrentUser. Cross-tenant import needs explicit platform authorization and audit. The import command also implements ILicensedMigrationRequest, so commercial in-flight migration passes through the Runtime License gate — an unlicensed deployment cannot reach this entry point.

4. Definition selection defect

ManagementService lists definitions and selects versions[0], without using deployment binding or explicit sorting. Import can pin the wrong version. Require DefinitionId/version and validate every target node. Candidate refresh has the same version-selection issue.

5. Non-transactional write

Import saves instance, then each execution and task, then the activity record without BeginTransaction.

PersistenceManagementServiceMigration clientPersistenceManagementServiceMigration clientloop[active tasks]failure can leave partial stateImportInstanceSave instanceSave executionSave taskSave import activity

Put one item in one transaction and add a unique tenant+sourceSystem+sourceInstanceId import record.

6. Missing preflight

Current import does not validate current/task nodes, assignee tenancy, consistent statuses, existing business process, variable policy, or duplicate source ID. Invalid status text silently falls back to Running/Pending.

A dry-run report should classify blocking errors and signed warnings before writes.

7. Batch import

ImportInstancesBatch runs sequentially, wraps item failures in a successful batch Result, and reports transient progress. It has no durable checkpoint, pause/resume, or failure export.

Persist a batch manifest containing source snapshot checksum, mapping version, operator/approver, and item source ID to status/new ID/error. Restart only unfinished items and replay success from idempotency records.

8. Applicant transfer

TransferApplicant permits the current applicant or Manage authorization and transactionally updates applicant plus trail. TransferAllByUser iterates active instances and returns per-item failures; it is not all-or-nothing.

9. Safe runbook

  1. Snapshot and freeze legacy workflow writes.
  2. Run a small dry-run and approve mappings.
  3. Record every source-to-new identity.
  4. Stop at the first unexpected partial state.
  5. Clean only records tagged to the audited batch.
  6. Reconcile business key, task count, assignee, state, and trail.
  7. Complete a sample task in the new engine.
  8. Rehearse rollback before production.

10. Acceptance

  • source count equals success plus explicit failure;
  • one source maps to one new instance;
  • definition version is correct;
  • every pending task is visible and operable by the intended user;
  • no cross-tenant visibility;
  • process continues after sample completion;
  • timer, notification, and cache state is rebuilt;
  • replay creates no duplicates;
  • rollback is tested.

11. Source checks

Terminal window
rg -n "ImportInstanceAsync|SaveInstanceAsync|SaveExecutionAsync|SaveTaskAsync" src/Framework/BitzOrcas.Workflow/BitzOrcas.Workflow.Engine/Services/ManagementService.cs
rg -n "SourceInstanceId|BeginTransactionAsync|versions\[0\]" src/Framework/BitzOrcas.Workflow src/Platform/Workflow -g '*.cs'

Definitions themselves come from the Workflow Migrator, which reads BitzOrcas or Saury legacy tables into JSON DSL. Import on this page is complementary: publish a definition first, then import in-flight instances.

Next: notification pipeline

100%

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