Skip to content

Process Designer

openwcs-docs-agent edited this page Jun 18, 2026 · 23 revisions

Process Designer

The process designer lets a non-developer build a configurable handheld operator process (goods-in, packing, stock check, an ad-hoc move) as a versioned definition, assign one version as active for a process type, and have the handheld PWA run it. It complements, and does not replace, the Flowable BPMN process-engine, which stays for heavy backend orchestration.

It is backed by the process-designer service (Java, port 8097, own process_designer schema), introduced in Phase 1, extended in Phase 2 (version management, JSON import/export, step skip conditions, more curated tasks, instance monitoring) and completed in Phase 3 (a sandboxed scripting escape hatch and design-time AI task-assist). A later increment added scan verification (the verify block on text/number input screens — see Scan verification below). The feature is now complete (spec: docs/process-designer-spec.md in the repo). See Services for the one-line summary.

Base path note. The process designer lives under /api/process-designer/**, deliberately not /api/process/** (the Flowable process-engine owns that prefix). The two engines coexist.

What a process is

A process is a versioned JSON flow of four kinds of steps:

  • Screens: what the operator sees. Six screen types ship: text, number, date, acknowledge, yes/no, choice. Each can validate input, bind to a scanner, and write its result into a named field on the process data object.
  • Tasks: calls into the rest of the WCS (see the curated library below). A task reads from the data object, runs, and merges named outputs back.
  • Compute (no-code, client-evaluated): an ordered set of { var, expr } rows the handheld evaluates in sequence against the data object, writing each result into the named variable before following next/transitions. No screen is rendered; no server call is made; no checkpoint is created. Use compute steps to derive flags and values (e.g. match = qty == expected) for downstream branching.
  • Decision (no-code, client-evaluated router): an ordered list of if/elseif rules (each a when condition + a to target step) plus an optional else/default next. No screen is rendered; no server call is made; nothing is written to the data object. The runtime evaluates the rules top-to-bottom and routes to the first match, or falls back to next. Use decision steps to split a flow into multiple branches.

Steps connect with transitions; branch conditions decide the next step from the data collected so far. A step can also carry a skip condition (skipWhen, Phase 2): when it evaluates true, the runtime skips that step (the same restricted grammar as a transition condition). Compute steps are processed like skip-resolution — the handheld evaluates their set rows and advances without rendering a screen, so transitions/next see the freshly computed values. Decision steps are similar pass-through steps: they evaluate their ordered when rules and route to the first match (or next), but write nothing — no screen, no server call, no data mutation. A data object carries values across the whole run, and screen titles / prompts can interpolate {{placeholder}} values from it (placeholders resolve to codes via the catalog, never raw UUIDs).

How to design a process

  1. Open Engineering → Process Designer (/process-design, ADMIN / SUPERVISOR). The permission is PROCESS_DESIGN_EDIT.
  2. The designer opens to a definitions table: one row per process key, showing its title, key, status, active version number, and total version count. Click a row to open that process in the editor; click + New process to start a blank draft. A ← Processes back button in the editor toolbar returns to this table; if there are unsaved changes a styled confirmation dialog (not a native browser alert) asks whether to discard them.
  3. The editor is a WYSIWYG layout with a flow pane, a live handheld preview, a properties panel, and a version-management pane. The flow pane shows the visual node-canvas — the single authoritative flow editor:
    • The canvas is a zoomable visual node-canvas (powered by React Flow). Each step appears as a draggable node showing the step ID, type icon, step-type description, and status badges (start, verify, task, script, compute, or orphan). Nodes are draggable even on read-only (ACTIVE/ARCHIVED) versions — node position is pure layout and non-behavioural; the position is persisted only when the version is an editable draft. Drag from a node's right-hand connector to another node to create a link; the first link out of a node becomes its next, any further link becomes a new branch transition. Click a dashed branch edge's label to edit the when condition inline (unknown variables and syntax errors are flagged immediately). Canvas edges use orthogonal (90-degree) routing (smooth-step with rounded corners) rather than bezier curves, making flow paths easier to follow on dense graphs. Loop-back edges (a step whose link points to an ancestor) are rendered as animated amber arrows. Orphan nodes (not reachable from start) have a dashed border and a warning badge. Node positions are auto-laid out on first open (BFS left-to-right, tighter spacing) and persisted in the definition so the layout survives reloads. Select a node to drive the properties panel and the live preview; hover or select a node to reveal a ▶ Set as start button (top-left, shown only for non-start nodes) and a red × delete button in the top-right corner (circular, shown on hover/selection for all editable nodes). A mini-map in the canvas corner aids navigation. The layout shows a wide canvas column on the left with the preview and properties panel stacked on the right.
    • A "Data object" button at the bottom of the flow pane (labelled { } Data object (N)) opens the data-object dialog.
    • The toolbar groups the process identity (title, key, icon, status) on the left and a compact action cluster on the right: Validate, Simulate, Save, and Publish are primary buttons; Duplicate, Export, and Import are tucked into a More ▾ overflow menu to keep the bar uncluttered. When the open version is not editable (ACTIVE or ARCHIVED), an Edit as draft button appears next to the read-only badge; clicking it duplicates the current version to a new DRAFT so the editor unlocks immediately.
    • a LIVE handheld preview that renders the selected screen exactly as the operator will see it (it reuses the very same ProcessScreenView component the runtime uses, so what you see is what runs),
    • a properties panel for the selected step (the data-object editor lives in its own dialog, see above),
    • a version-management pane (Phase 2) listing drafts / active / archived versions (only a DRAFT is editable), with duplicate / clone and JSON export / import controls.
  4. Add screens, tasks, compute, and decision steps, set transitions, branch conditions and step skip conditions ("Skip this step when…"), and bind screens to the data object. The task picker is driven by the live server task catalog (GET /api/process-designer/tasks) and is a searchable combobox — type to filter across task label, type ID, and description. Each task in the catalog carries a one-sentence description of what it does and when to use it; each input and output carries a hint explaining what to map into it or what the value means. Both are shown in the guided task configuration dialog. Screen steps show an "Edit screen" button beside the live mockup when selected; clicking it opens a two-step guided dialog: ① Basics — the step name (renames the step id, updating every next/branch reference automatically; blank or colliding names are rejected), header text, and detail text (with {{var}} placeholder insert chips); ② Capture & validation — the fields relevant to that screen type: write-to variable, scan-binding toggle, and validation builder for text/number/date inputs; question write-to variable and answer options for yes/no or choice screens; confirm-button label and optional required checkbox for acknowledge screens. The properties panel for a screen step shows a compact one-line summary (type · what it writes · scan binding on/off · verify on/off) and the skip-when field only — the full config lives in the dialog. Task and compute steps show an "Edit task…" button on the mockup card when selected; clicking it opens the guided task configuration dialog. Decision steps show an "Edit decision…" button; clicking it opens the decision dialog — an ordered list of if/elseif rule rows (each with a condition input and a target-step picker, with up/down/remove controls) plus an "Otherwise / else go to" picker for the default target. Rules are evaluated in order; the first matching when wins. A Step name field at the top of the dialog allows renaming the step's id (updates every next/branch reference automatically; a blank or colliding name is rejected). Below the name field the dialog steps through kind selection and input/output mapping. For a compute step, the dialog shows an ordered table of variable = expression rows with inline syntax validation; it also flags rows whose target variable is not declared in the data object or whose expression references an undeclared variable, and the Done button is disabled until every row is valid (declared target + a syntactically correct expression over declared variables only). Branch condition (when) fields and the "Skip this step when…" (skipWhen) field carry the same live check: if the expression is syntactically valid but references an undeclared variable, an inline warning appears immediately (⚠ Unknown variable(s): …) prompting the designer to add the variable in the data-object dialog before publishing.
  5. Use Simulate to walk the flow in the preview without touching real data.
  6. Validate, then Publish.

(For the no-code compute step that derives values and decisions without a task, see Compute steps below.)

Version management, import and export (Phase 2)

  • Duplicate / clone: POST /defs/{key}/{version}/duplicate copies any version into a new DRAFT, so you can iterate from a published version without disturbing it.
  • Export: GET /defs/{key}/{version} returns the full definition JSON; the designer offers it as a download.
  • Import: POST /defs/import creates a new DRAFT from a full definition JSON (an upload in the designer). Together, export + import move a process between environments (dev → test → prod).

Drafts, active versions, and publishing

  • Every edit happens on a DRAFT version. Editing a non-draft is rejected.
  • Publish first validates the definition (step reachability, no dangling transitions, every writeTo / task reference resolves, a valid start, and Phase 2: no unreachable steps, no skippable step without an onward path, well-formed branch and skipWhen conditions — validated by a recursive-descent ConditionParser with no eval, so a malformed condition is rejected with 422 — and every identifier referenced in a transition when or skipWhen condition must be a declared data-object variable (ExpressionParser.identifiers cross-checks; null is treated as a literal and never flagged; 422 if any reference is undeclared) — task steps that supply every required input per the live catalog, no duplicate step ids, and compute steps whose set is non-empty with every var declared in the data schema and every expr valid per the expression grammar with all referenced variables also declared in the data schemaExpressionParser validates syntax and ExpressionParser.identifiers cross-checks variable references server-side, 422 on either failure — and decision steps that have at least one transition or a next (an empty decision with neither is a dead end, rejected with 422), with every when valid and referencing only declared variables and every to/next an existing step). If anything is wrong you get the list of problems back and nothing changes.
  • On success, publish flips the draft to ACTIVE and archives the prior active version atomically (there is always exactly one ACTIVE version per process key). Versions auto-increment per key.
  • Instances that are already running are pinned to the definition they started on, so publishing a new version never disrupts an in-flight operator.

The handheld runtime

The runtime is client-driven. On the handheld:

  • The operator menu (the big-tile PWA menu) lists the active configurable processes as tiles, alongside the curated built-in screens.
  • Tapping a tile runs it at /process/:key. The client walks the screens locally, evaluates branch conditions, step skip conditions, and any compute steps (variable assignments) with a safe TypeScript interpreter (no round-trip per screen).
  • It posts to the server only at task steps (checkpoints). Screen, compute, and decision steps are fully offline. Checkpoints are offline-queued: a screen flow keeps working through a Wi-Fi blip, and the run holds at a task until connectivity returns.
  • Checkpoints are idempotent per (instance, step), so a device swap or a retry resumes cleanly without re-running a task's side effects.

Running a process needs PROCESS_DESIGN_VIEW (granted to all shipped roles).

Curated tasks, not arbitrary code

A process cannot run arbitrary Java. Task steps choose from a curated server-side task library, a fixed registry with no API to author new task types. Each task calls an existing WCS endpoint and forwards the operator's identity (X-Auth-*), so the same RBAC and warehouse scope apply as if the operator called it directly:

Task Calls
inventory.move POST /api/flow/moves
slotting.putaway POST /api/slotting/decant/putaway
picking.confirm POST /api/orders/pick-tasks/{id}/confirm
inventory.lookup GET /api/inventory/availability (by locationId) or GET /api/inventory/handling-units/{huId}/contents (by huId; sums the SKU's lines on the HU); falls back to warehouse-wide availability when neither is supplied. warehouseId is auto-injected from the running instance.
txlog.post POST /api/txlog/events
host.confirm (Phase 2) POST /api/host/inventory/adjustments
inventory.adjust (Phase 2) POST /api/txlog/events (a StockAdjusted event)
counting.capture (Phase 2) POST /api/counting/tasks/{taskId}/lines/{lineId}/station-count
order.lookup (Phase 2) GET /api/orders/{id}

A failing task surfaces the error and does not advance the instance.

warehouseId auto-injection. All curated tasks (except script) automatically receive the running instance's warehouseId without the designer mapping it. An explicit input mapping still wins. This means the operator never has to scan a warehouse, and task inputs like inventory.lookup only need the operator-visible identifiers (skuId, locationId or huId).

Compute steps (expression grammar)

The expression grammar used by a compute step's set[].expr is a superset of the condition grammar that adds arithmetic:

  • identifiers, number, string ('…'/"…"), and boolean (true/false) literals
  • arithmetic: +, -, *, / with unary minus and parentheses
  • comparisons: ==, !=, <>, <, <=, >, >=
  • boolean: and / or / not

No function calls, no member access. Examples: qty == expected or qty == prevCount, expected - qty. The server validates every expr with ExpressionParser at publish (422 on a parse error); additionally, every variable name an expression references must be declared in the data objectExpressionParser.identifiers extracts the referenced identifiers and the validator cross-checks them against the schema (422 if any is missing). The designer mirrors both validations inline: a syntax error is flagged immediately, and an undeclared target variable or expression variable is highlighted with a suggested fix ("Add it in Data object"). The task dialog's Done button is disabled until all rows pass both checks.

Decision steps (if/elseif/else)

A decision step (type: "decision") is a no-code, client-evaluated router/gateway: it renders no screen, makes no server call, and writes nothing to the data object. The runtime evaluates its ordered transitions (each a { when, to } rule — same condition grammar as a transition when) top-to-bottom; the first matching rule's to is the next step. If no rule matches the step follows its next (the else/default target); if neither exists, the instance ends.

{ "type": "decision",
  "transitions": [
    { "when": "qty < expected", "to": "tooLow" },
    { "when": "qty > expected", "to": "tooHigh" }
  ],
  "next": "done"
}

Use decision steps to branch a flow without touching the data object. They complement compute steps: derive a flag with a compute step, then branch on it with a decision step.

Publish validation: a decision step must have at least one transition or a next — an empty decision with neither is a dead end (422). Every when expression must parse and reference only declared data-object variables. Every to and next must be an existing step id.

Scan verification

A screen's format checks (regex / maxLength / mustEqual) only check the shape of an entered value. Verification confirms the code actually exists in master data and pulls its linked ids, so a later task that needs a UUID gets it. Text and Number input screens can carry an optional Verify block:

"config": {
  "header": "Scan location",
  "writeTo": "locationCode",
  "verify": {
    "kind": "location",                   // barcode | sku | location | skuScan | order | asn
    "write": {                            // write path -> data-object variable
      "id":   "locationId",               // scalar: the resolved UUID
      "code": "locationCode",
      "purpose": "locationPurpose",       // location scalars: purpose, locationType, status
      "location": "locationObj",          // object whole key: stores the full nested object (type: object)
      "location.locationType": "locType"  // dotted sub-field: stores one property of the object
    },                                    // SKU-like also supports objects: sku (skuId/code/description/status),
                                          //   uom (uomId/code/factor/baseUnit), plus dotted paths e.g. uom.factor
    "onNotFound": { "mode": "reprompt" }  // or { "mode": "goto", "step": "<stepId>" }
  }
}
  • kind picks what to resolve. The designer's kind picker is server-driven by capabilities.verifyKinds (["barcode","sku","location","skuScan","order","asn"]):
    • barcode (a scanned barcode resolved to a SKU + UOMs + attribute-schema graph, master-data),
    • sku (a SKU code, master-data),
    • location (a location code, master-data),
    • skuScan (combined: tries the value as a product barcode first; if no match, tries it as a SKU code; a barcode pins its UOM, a single-UOM SKU auto-picks, a multi-UOM SKU triggers a UOM picker the operator uses before the step advances),
    • order (an outbound order / picksheet barcode, resolved against order-management),
    • asn (an inbound order / ASN barcode, resolved against order-management; a flow can branch on the resolved orderType).
  • write maps resolved field paths into declared data-object variables. A path is a scalar key (id, code, …), an object whole key (stores the entire resolved object as an object-typed variable), or a dotted sub-field (uom.factor, sku.code, location.locationType, stores one property of the nested object). Valid paths differ by kind (served via capabilities.verifyFields): location has scalars id, code, purpose, locationType, status plus object location (sub-fields locationId, code, locationType, purpose, status); barcode / sku / skuScan have scalars id, code, name, uomCode, schemaCategory plus object sku (skuId, code, description, status) and object uom (uomId, code, factor, baseUnit); order has scalars id, code (order reference), status, orderType, customerRef, lineCount plus object order; asn has the same scalar set (code is the ASN reference) plus object asn. id is the resolved UUID; uom reflects the matched or auto-resolved unit of measure (for skuScan, the operator-chosen UOM). A dotted path on a scalar field, or an unknown sub-field, fails 422 at publish.
  • onNotFound is re-prompt (clear and ask again) or go to a step. A goto target must exist and counts toward reachability, so the validator never flags it as unreachable.

In the designer, an "Edit screen" button appears beside the live mockup whenever any screen step is selected (opens the guided screen-configuration dialog described above). For scan-capable text or number input screens a "Verify flow" button additionally appears when the server advertises at least one verifyKind. Clicking it opens a step-by-step guided dialog: ① pick the scan kind, ② map the per-kind resolved fields to data-object variables (the field rows are driven by capabilities.verifyFields so a location shows Purpose / Location type / Status, a SKU shows Description / Unit of measure / Attribute category, an order/ASN shows Status / Order type / Customer reference / Line count: scalar fields appear as single combobox rows; object fields (UOM, SKU, Location, Order, ASN) appear as a grouped block with a "store whole object" combobox at the top and indented sub-field rows below; the two are independent, so the designer can store the whole object and/or individual sub-properties into different variables), ③ choose the not-found behaviour. Switching kind in step ① drops any write mappings whose path is not valid for the new kind. When verification is already configured, the button reads "Edit verify flow" and a small "Verification on" label appears beside it; a "Turn off verification" action inside the dialog removes the verify block. The properties panel no longer carries the verify checkbox; it stays focused on the screen's own input fields.

On the curated-API path (no raw SQL). The runtime posts POST /api/process-designer/verify {warehouseId, kind, code} (PROCESS_DESIGN_VIEW), which proxies the read-only resolve endpoints (master-data for barcode / sku / location / skuScan, order-management GET /api/orders/resolve for order / asn) with the operator's forwarded identity (so the downstream RBAC + warehouse scope apply) and returns a normalised {found, ambiguous, id, code, name, uomCode, schemaCategory, matchedAs, uoms, needsUomChoice, detail, fields}. fields carries the per-kind resolved values: scalar fields are plain strings; object fields (sku, uom, location, order, asn) hold nested {subKey → value} maps. A dotted write path (e.g. uom.factor) drills into the nested map; a whole-object key (e.g. uom) stores the entire map. The runtime reads fields first, falling back to the legacy top-level scalars for older servers. The skuScan-specific fields: matchedAs signals whether a "barcode" or "sku" code path fired; uoms is the SKU's full unit list [{code, baseUnit}]; needsUomChoice is true when the SKU has more than one UOM and the runtime must prompt. The resolve endpoints return 200 with found:false on a miss (never 404), so a flow branches instead of erroring; a downstream failure surfaces as 502. Verification reuses the same repositories the card / order reads use, so RBAC + audit + service boundaries stay intact.

At runtime, on submit the client resolves: offline holds ("verification needs a connection"); found:false re-prompts or routes per onNotFound; found:true merges the write mappings into the data object and continues; ambiguous:true (a value spanning more than one SKU) shows a subtle note. For skuScan when needsUomChoice:true the normal screen is replaced by a UOM picker (a full-screen button list of the SKU's units of measure, each labelled with its code, the base unit tagged) and the step only advances once the operator selects one; the chosen code is written into the variable mapped to uomCode. Simulate mode resolves locally with no backend (a "simulate not found" toggle). Publish validates the block: a valid kind, every write key (or its object root) a known per-kind resolved field whose target is a declared variable (an invalid key for the chosen kind fails 422), and a goto step that exists.

The master-data base url is OPENWCS_MASTER_DATA_BASE_URL (openwcs.process-designer.master-data-base-url); the order/asn kinds use openwcs.process-designer.orders-base-url.

Sandboxed scripting (Phase 3, controlled escape hatch)

For logic the curated library does not cover, Phase 3 adds a built-in script task type. The step config is { "script": "<js>", "outputs": [{ "name": "..." }] }. The snippet runs server-side in a locked-down GraalJS sandbox:

  • No host access whatsoever: allowAllAccess(false), HostAccess.NONE, no host class lookup or loading, no native, no threads, no process, no IO (IOAccess.NONE), no environment, PolyglotAccess.NONE. It is interpreted guest JavaScript, never compiled to host JVM bytecode.
  • Hard limits: a statement limit (default 100000), a watchdog wall-clock timeout (default 2000 ms), and an output size cap (default 65536 bytes), all tunable via openwcs.process-designer.scripting.{statement-limit,timeout-ms,max-output-bytes}.
  • The script sees only a deep-frozen, read-only data global (the process data object) and returns an object whose fields become the declared outputs.

Governance is defense in depth. A script step can be saved or published only when both:

  1. the config flag openwcs.process-designer.scripting.enabled is on (env OPENWCS_PROCESS_SCRIPTING_ENABLED, default false), else 422; and
  2. the caller holds the new PROCESS_SCRIPT_AUTHOR permission (granted to ADMIN only), else 403.

Each script is parse-validated in the sandbox at publish (a malformed snippet is rejected with 422). The script step code editor in the designer is shown only when scripting is enabled and the caller may author scripts.

AI task-assist (Phase 3, design-time only, never auto-deploys)

The designer can ask an assistant to describe a task in plain language: POST /api/process-designer/assist/task with {description, variables:[{name,type}]} returns {kind:"curated"|"script"|"none", taskType?, inputs?, outputs?, script?, rationale, confidence} (gated by PROCESS_DESIGN_EDIT). It uses the Anthropic Java SDK (default model claude-haiku-4-5, key from the ANTHROPIC_API_KEY env), grounded with the live task catalog plus the available variables, and either:

  • maps the description to an existing curated task type with variable mappings (kind:"curated"), which you Apply; or
  • drafts a sandboxed JS snippet (kind:"script") for a human to review and Insert as a script step, clearly labelled "AI draft, for your review".

The suggestion is never saved, compiled, or executed by the server, and nothing is deployed automatically. AI text → compiled Java → a live server is permanently out of scope by design. Absent an Anthropic key, /assist/task returns 503 and the service still starts.

Capabilities

GET /api/process-designer/capabilities{scriptingEnabled, aiAssistEnabled, canAuthorScript, verifyKinds, verifyFields} (gated by PROCESS_DESIGN_VIEW) tells the designer whether to show the script editor and the AI assist panel, which scan-verify kinds the Verify picker offers (["barcode","sku","location","skuScan","order","asn"]), and the per-kind resolvable field catalog (verifyFields, scalar fields and object fields with drill-down sub-fields) that drives the step-by-step Verify dialog's field rows in step 2.

New compose env on process-designer: OPENWCS_PROCESS_SCRIPTING_ENABLED (default false), ANTHROPIC_API_KEY (opt-in), OPENWCS_PROCESS_ASSIST_MODEL.

Instance monitoring (Phase 2)

A read-only desktop Process instances screen (Engineering, ADMIN / SUPERVISOR, route /process-instances) lists process instances newest-first with a detail pane (the data object, the current step, and the step trail). It is backed by GET /api/process-designer/instances?processKey=&status=&warehouseId=&limit= (summaries) plus the existing GET /api/process-designer/instances/{id} (detail).

Seeded example processes

Two ACTIVE processes ship via Flyway so the feature is demoable end to end out of the box.

Stock Check (stock-check)

The service seeds an ACTIVE Stock Check process: scan location → scan SKU → count → txlog.post records a StockCounted event → acknowledge. It is a worked example of screens + a curated task in one flow.

Its data object contains the following fields:

Variable Type Purpose
location location Resolved location (typed)
sku sku Resolved SKU (typed)
qty number Counted quantity
skuBarcode string Raw barcode value scanned for the SKU
LocationCode string Location code as scanned
LocationBarcode string Raw barcode value scanned for the location
HUBarcode string Handling-unit barcode as scanned
HUCode string Handling-unit code as scanned

The five string variables (skuBarcode, LocationCode, LocationBarcode, HUBarcode, HUCode) capture the literal scanned codes before and alongside the resolution performed by the verify block; they are available to downstream tasks and {{placeholder}} text. Fresh installs receive them via the V1 seed; existing installations pick them up via the idempotent V3 migration.

Stock Count — reference (stock-count-ref)

A richer reference process that exercises the full designer toolkit end to end: verify, lookup, compute, and decision. Its own process key (stock-count-ref) means it never clobbers stock-check or a user's drafts. It ships as V4 Flyway migration and is idempotent on re-run.

Flow: scan + verify a location → scan + verify a SKU (skuScan) → inventory.lookup expected on-hand → operator enters counted quantity → compute a match flag → decision that posts the count when matched or loops back to the count screen for a recount.

The recount tolerance in the compute step is: match = qty == expectedQty or qty == prevCount — a count that equals either the system expected quantity or the previous count (confirming recount) is treated as a match. The compute step also advances prevCount = qty each pass through the loop so the tolerance remains meaningful across multiple recounts.

Its data object contains the following fields:

Variable Type Purpose
locationScan string Raw location barcode/code as scanned
locationId location Resolved location UUID (via verify kind: location)
locationCode string Resolved location code (used in downstream {{locationCode}} placeholders)
skuScan string Raw SKU barcode/code as scanned
skuId sku Resolved SKU UUID (via verify kind: skuScan)
uom string Matched unit of measure code
expectedQty number Expected on-hand from inventory.lookup
qty number Operator-entered counted quantity
prevCount number Quantity from the previous count pass (for recount tolerance)
match boolean Computed flag: true when qty == expectedQty or qty == prevCount
eventId string Event ID returned by txlog.post on a successful count

Internationalisation

The designer and runtime are translated for German, French, Spanish, and Chinese (see Internationalisation).

See Mobile Process Designer for the full design-detail reference (model, screen-step config, API surface), Services for the service summary, Security for the identity-forwarding model, and Transport Overview / Slotting and Replenishment for the endpoints the curated tasks drive.

Clone this wiki locally