Skip to content

CDX Integration

This page maps the current workflow packages in CDX to the runtime, storage, template, feature, protocol, and editor surfaces.

Server Runtime

A production service wires four things:

  1. A WorkflowStorage implementation.
  2. A WorkflowTypeResolver.
  3. ExecutionMode.production.
  4. Workflow definitions loaded into the engine memory cache.
dart
import 'package:cdx_workflow_templates/cdx_workflow_templates.dart';
import 'package:supabase/supabase.dart';
import 'package:vyuh_workflow_engine/vyuh_workflow_engine.dart';
import 'package:vyuh_workflow_storage_supabase/vyuh_workflow_storage_supabase.dart';

final approvalTemplate = ApprovalTemplate(
  domains: [equipmentApprovalDomain, materialApprovalDomain],
);

final context = RegistryTypeResolver(
  descriptors: [
    DefaultWorkflowDescriptor(),
    approvalTemplate.buildDescriptor(),
  ],
);

final storage = SupabaseStorage(
  client: SupabaseClient(url, serviceRoleKey),
  config: const SupabaseStorageConfig(schema: 'elog'),
);

final engine = WorkflowEngine(
  context: context,
  storage: storage,
  executionMode: ExecutionMode.production,
);

await engine.initialize();

final storedApproval = await engine.storage.workflows.getByCode(
  approvalTemplate.workflowCode,
);
if (storedApproval == null) {
  throw StateError('Missing seeded approval workflow definition.');
}
engine.loadWorkflowDefinition(storedApproval);

For local tests, replace SupabaseStorage with InMemoryStorage(). If you need a local seed, create the template definition through storage.workflows.create(approvalTemplate.buildDefinition()) before loading it.

Canonical Approval Template

cdx_workflow_templates currently provides the canonical shared approval workflow.

ConceptCurrent contract
ApprovalTemplateA WorkflowTemplate that bundles the canonical approval definition and descriptor.
ApprovalWorkflow.codeStable workflow code: approval.
ApprovalWorkflow.buildDefinition()Emits canonical JSON for seeding. Runtime should load the stored definition, not rebuild it as mutable application state.
ApprovalWorkflow.buildDescriptor(...)Registers approval service-task and user-task executors.
ApprovalDomainPer-domain typed slots for item/config/decision JSON, chain resolution, outcome effects, and optional refreshItem.
item_schema_typeDispatch key in ApprovalWorkflowInput.toJson() used to select the correct ApprovalDomain.

The approval graph is versioned in ApprovalWorkflow.buildDefinition(). Version 4 includes failure-port routing to on_failed, revision-loop nodes, and stable enum-backed node/port IDs from cdx_workflow_types.

Approval Input

Start approval instances with the typed input envelope from cdx_workflow_types:

dart
final input = ApprovalWorkflowInput(
  item: item,
  config: approvalConfig,
  submittedBy: userId,
  submittedAt: DateTime.now().toUtc(),
  correlationId: item.id,
);

final instance = await engine.startWorkflow(
  workflowCode: ApprovalWorkflow.code,
  input: input.toJson(),
  correlationId: item.id,
  userId: userId,
);

The top-level item_schema_type is required. Dispatcher executors use it to select the registered domain before they deserialize the item, config, or decision payload.

Supabase Storage

vyuh_workflow_storage_supabase implements WorkflowStorage.

Default configuration:

dart
const SupabaseStorageConfig(
  schema: 'elog',
  definitionsTable: 'workflows',
  instancesTable: 'workflow_instances',
  userTasksTable: 'workflow_user_tasks',
  eventsTable: 'workflow_events',
);

The adapter verifies all four tables during initialize(). It does not create tables and it does not perform type resolution. Stored workflow rows are WorkflowDefinition data; the engine converts them into executable Workflow objects through its resolver.

Feature Inbox

cdx_feature_workflows is the Flutter/Vyuh inbox surface for workflow user tasks. It exports:

  • WorkflowActionBar, driven by server-provided List<UserTaskAction>.
  • WorkflowStatusCard for entity workflow status.
  • Inbox row/detail helper widgets.
  • WorkflowActivityTimelineView and labels.
  • entityWorkflowDataFromTask for a first-pass task-to-status projection.
  • CdxFeatureWorkflowsPlugin and feature.

Task actions are resolved server-side through UserTaskActionResolverRegistry and serialized on the task projection. The Flutter action bar switches on the sealed UserTaskAction subtype to render icons, severity, and labels; it does not infer approval semantics from schema strings.

Protocol Client

vyuh_workflow_protocol wraps engine interaction in typed messages:

  • Commands: start, signal, cancel, fail, retry, state, subscribe, unsubscribe, pause/resume.
  • Responses: command success/error/state envelopes.
  • Events: workflow events, engine errors, heartbeat.
  • Transports: WorkflowTransport plus InProcessTransport.

Use WorkflowProtocolClient when a client or editor should not call WorkflowEngine directly:

dart
final transport = InProcessTransport(engine: engine);
final client = WorkflowProtocolClient(transport: transport);
await client.connect();

final instance = await client.startWorkflow(
  workflowCode: 'approval',
  input: approvalInput.toJson(),
);

await client.sendSignal(
  workflowInstanceId: instance.id,
  node: 'approval_decision',
  port: 'approve',
  payload: {'output': decision.toJson()},
);

Visual Editor

vyuh_workflow_editor is Flutter-only. It exports the node editor SDK with workflow-specific hides, plus workflow models, controllers, validation, widgets, registry helpers, and run mode.

Typical embedding:

dart
WorkflowEditor(
  environments: [
    SimulationEnvironment(
      storageAdapter: InMemoryStorage(),
    ),
    DatabaseEnvironment(
      id: 'elog',
      name: 'ELog',
      storageAdapter: storage,
      descriptors: [approvalTemplate.buildDescriptor()],
      authConfig: authConfig,
    ),
  ],
  initialEnvironment: 'simulation',
)

Important editor behavior:

  • SimulationEnvironment uses SimulationDeserializationContext, InMemoryStorage, passthrough task execution, and manual decision points.
  • DatabaseEnvironment uses real storage and descriptors, but editor execution mode is still simulation so users can drive branches, timers, subflows, and multi-output tasks manually.
  • EditorContext creates an in-process WorkflowEngine, wraps it in InProcessTransport, and exposes a WorkflowProtocolClient.
  • The editor library is loaded from storage.workflows.list(activeOnly: true) and converted to WorkflowDocument.

Keep The Layers Separate

LayerOwns
EngineExecution, tokens, effects, events, repositories, type resolution.
Supabase storageTable-backed repository implementations only.
CDX typesShared wire contracts and action/result/status models.
CDX templatesCanonical workflow definitions and descriptor/executor bundles.
CDX feature workflowsFlutter inbox/status/timeline widgets.
ProtocolClient/transport command and event API.
EditorVisual authoring, validation, library loading, and simulation.