-
-
Notifications
You must be signed in to change notification settings - Fork 0
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). The feature is now complete through Phase 3 (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.
A process is a versioned JSON flow of two 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.
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). 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).
- Open Engineering → Process Designer (
/process-design, ADMIN / SUPERVISOR). The permission isPROCESS_DESIGN_EDIT. - The screen is a WYSIWYG three-pane layout:
- a flow list of the steps,
- a LIVE handheld preview that renders the selected screen exactly as the operator will see it (it reuses the very same
ProcessScreenViewcomponent the runtime uses, so what you see is what runs), - a properties panel for the selected step plus a data-object panel for the fields the flow reads and writes,
- a version-management pane (Phase 2) listing drafts / active / archived versions (only a DRAFT is editable), with duplicate / clone and JSON export / import controls.
- Add screens and tasks, 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), so it always lists the real available task types and their inputs / outputs. - Use Simulate to walk the flow in the preview without touching real data.
- Validate, then Publish.
-
Duplicate / clone:
POST /defs/{key}/{version}/duplicatecopies 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/importcreates a new DRAFT from a full definition JSON (an upload in the designer). Together, export + import move a process between environments (dev → test → prod).
- 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 andskipWhenconditions — validated by a recursive-descentConditionParserwith noeval, so a malformed condition is rejected with 422 — task steps that supply every required input per the live catalog, and no duplicate step ids). 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 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 and evaluates branch conditions and step skip conditions with a safe TypeScript interpreter (no round-trip per screen). - It posts to the server only at task steps (checkpoints). 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).
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 |
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.
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:
-
kindpicks what to resolve:barcode(a scanned barcode → SKU + UOMs + attribute-schema graph),sku(a SKU code),location(a location code). The designer's kind picker is server-driven bycapabilities.verifyKinds(["barcode","sku","location"]). -
writemaps the normalised resolved fields (id,code,name,uomCode,schemaCategory) into declared data-object variables.idis the resolved UUID. -
onNotFoundis re-prompt (clear and ask again) or go to a step. Agototarget must exist and counts toward reachability, so the validator never flags it as unreachable.
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 master-data resolve endpoints with the operator's forwarded identity (so master-data RBAC + warehouse scope apply) and returns a normalised {found, ambiguous, id, code, name, uomCode, schemaCategory, detail}. 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 master-data repositories the SKU / location card 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. Simulate mode resolves locally with no backend (a "simulate not found" toggle). Publish validates the block: a valid kind, every write key a known resolved field whose target is a declared variable, and a goto step that exists.
The proxy's master-data base url is OPENWCS_MASTER_DATA_BASE_URL (openwcs.process-designer.master-data-base-url).
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
dataglobal (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:
- the config flag
openwcs.process-designer.scripting.enabledis on (envOPENWCS_PROCESS_SCRIPTING_ENABLED, default false), else 422; and - the caller holds the new
PROCESS_SCRIPT_AUTHORpermission (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.
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 ascriptstep, 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.
GET /api/process-designer/capabilities → {scriptingEnabled, aiAssistEnabled, canAuthorScript, verifyKinds} (gated by PROCESS_DESIGN_VIEW) tells the designer whether to show the script editor and the AI assist panel, and which scan-verify kinds the Verify picker offers.
New compose env on process-designer: OPENWCS_PROCESS_SCRIPTING_ENABLED (default false), ANTHROPIC_API_KEY (opt-in), OPENWCS_PROCESS_ASSIST_MODEL.
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).
The service seeds an ACTIVE Stock Check process out of the box: 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.
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.
openWCS — open-source Warehouse Control System · summarized from build.md & docs/AS-BUILT.md (the repo docs are authoritative).
Design
Flows
- Inbound and Inventory
- Slotting and Replenishment
- Goods-to-Person Stations
- Outbound Flow
- Equipment Integration
- Transport Overview
- Process Designer
- Mobile Process Designer
- Hardware Visualisation
- Host Integration
Reporting & Dashboards
Operations