Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
11 KiB
PRD — Workflow Wait Steps Productization
- Slug:
workflow-wait-steps-productization - Date:
2026-04-07 - Status: Draft
Summary
Productize the existing workflow wait primitive so workflow authors can naturally pause on business events and time. V1 should formalize and extend the existing event.wait node, add a sibling time.wait node, expose both as first-class steps in the workflow designer, and keep runtime matching event-driven rather than query- or polling-based.
Problem
The workflow system already supports event.wait in runtime, tests, and parts of the UI, but it is not a complete product surface. Authors cannot naturally build lifecycle workflows such as onboarding follow-up cadences because:
event.waitis partially implemented and not presented as a polished first-class step.- matching is limited to event name plus correlation key; there is no structured payload filter layer.
- there is no sibling
time.waitstep for “wait 2 days” or “wait until Monday at 9 AM.” - the current shape pushes users toward manual schedules and external orchestration for workflows that should stay inside the workflow engine.
For onboarding and customer-success workflows, this creates unnecessary composition overhead and makes otherwise natural automations awkward.
Goals
- Make
Wait for Eventa first-class workflow step built on the existing runtime primitive. - Support structured payload filters with a constrained operator set.
- Support entity-aware wait-filter value pickers where event fields provide presentation metadata.
- Add
Wait for Timefor duration- and absolute-time waits. - Keep the runtime model event-driven and deterministic.
- Preserve backward compatibility for existing
event.waitdefinitions. - Give workflow authors a clear designer experience, summaries, and validation for both wait types.
Non-goals
- No generic “wait until arbitrary database condition” engine.
- No polling-based entity rechecks.
- No nested boolean filter groups in v1.
- No matching inside arrays or collections in event payloads in v1.
- No “wait for N matching events” semantics in v1.
- No broad observability or metrics program beyond the existing workflow run/event surfaces.
Users and Primary Flows
Primary users:
- Workflow builders creating onboarding, customer-success, and operational automations
- Internal product and solutions teams validating real-world lifecycle workflows
Primary flows:
- Author selects
Wait for Event, picks an event from the catalog, sets a correlation key expression, adds payload filters, and continues the workflow when the first matching event arrives. - Author selects
Wait for Time, chooses either a duration or an until-expression, and resumes the workflow when the deadline is reached. - Author inspects run details and can clearly see what a run is waiting on, when it will timeout or resume, and what event resumed it.
UX / UI Notes
- Expose
Wait for EventandWait for Timedirectly in the workflow designer palette. - Keep them implemented as node-backed steps, not
control.*blocks. - Add curated config panels rather than relying only on the generic schema form.
Wait for Event fields:
EventCorrelation Key ExpressionPayload FiltersTimeoutAssign On Resume
Wait for Time fields:
Mode(DurationorUntil)DurationorUntil Expression- optional resume assignment only if clearly useful; otherwise omit in v1
Pipeline and run UI should show concise summaries:
- event name
- filter count
- timeout or scheduled resume time
Requirements
Functional Requirements
- The runtime must continue to support existing
event.waitdefinitions without requiring migration. - The shared workflow model must explicitly recognize
event.waitas a supported step type rather than relying on it only as an untyped generic node. event.waitconfig must support an optionalfiltersarray.- Supported filter operators in v1 must be:
=!=innot_inexistsnot_exists>>=<<=containsstarts_withends_with
- Filter evaluation must apply only to scalar payload fields in v1.
- Array literals on the right-hand side must be allowed for
inandnot_in. - All filter clauses must be ANDed in v1.
- Event ingestion must resume the first waiting run whose
eventName,correlationKey, tenant scope, and filters all match. event.waittimeout behavior must remain supported and compatible with existing timeout and try/catch handling.- A new
time.waitstep must be introduced. time.waitmust support waiting for a relative duration.time.waitmust support waiting until a computed or provided date/time value.- The worker/runtime scheduler must resume due
time.waitentries. - The workflow designer palette must expose both wait steps as first-class choices.
- The workflow designer must provide custom configuration UI for both wait steps.
- Designer summaries and run details must show useful wait metadata.
- Publish-time validation must cover invalid assignment paths and malformed wait configuration for both wait steps.
- Event-catalog-driven authoring must remain compatible with
event.wait, including event selection and schema-informed payload path authoring. - Event-backed wait filters must support field presentation metadata so eligible fields can render typed value pickers instead of raw text or JSON inputs.
- V1 wait-filter picker behavior must fall back cleanly when event fields do not provide picker metadata.
Non-functional Requirements
- Matching must stay event-driven and avoid broad polling loops.
- Wait resolution must remain tenant-scoped.
- The design must reuse existing workflow run wait persistence where practical.
- The change should avoid unnecessary schema churn; use existing
payloadandtimeout_atcolumns when possible.
Data / API / Integrations
Current relevant surfaces:
- Runtime wait persistence in workflowRunWaitModelV2.ts
- Runtime node registration in registerDefaultNodes.ts
- Publish validation in publishValidation.ts
- Event submission and wait resolution in workflow-runtime-v2-actions.ts
- Designer UI in WorkflowDesigner.tsx
Recommended persistence model:
- Keep using
workflow_run_waits - store event filters in
payload - store
time.waitmetadata inpayload - use a new
wait_typevalue such astimefor time waits - keep
timeout_atas the wake-up deadline fortime.waitand timeout deadline forevent.wait
Recommended event-wait runtime model:
- Event is submitted and recorded as today.
- Candidate waits are selected by
event_name,correlation_key, tenant, and wait type. - Candidates are evaluated in created order against filter clauses.
- The first matching wait is resolved and its run is resumed.
Recommended time-wait runtime model:
time.waitcomputes a due timestamp.- Runtime publishes a
timewait row withtimeout_at = due timestamp. - Worker picks up due time waits and resumes the run.
Recommended event-field authoring model:
- Keep structural field discovery in the event catalog payload schema.
- Add field-level presentation metadata for wait-filter authoring, for example schema annotations that describe:
- editor kind
- picker resource
- picker dependencies
- Use those annotations only for designer rendering; they must not change runtime event matching semantics.
Recommended wait-filter UI fallback order:
- Typed picker when event field metadata declares a supported picker resource.
- Enum dropdown when the schema declares
enum. - Primitive fallback by type:
- boolean toggle
- number input
- text input
Security / Permissions
- Reuse existing workflow permissions for read/manage/publish/admin.
- Do not expand secret-handling semantics.
- Continue to validate assignment paths and expression usage.
- Preserve tenant scoping when resolving waits from incoming events.
Observability
Use existing workflow run, wait, and event surfaces rather than introducing a new observability feature set. The main product requirement here is clarity:
- run details should show wait type, event name, correlation key, timeout/scheduled time, and resolution status
- event surfaces should continue to show matched run and wait information
Rollout / Migration
- Backward compatibility for existing
event.waitdefinitions is required. - Prefer no database migration if
filtersandtime.waitmetadata can live in the existingpayloadcolumn and time waits can use a newwait_type. - Roll out in phases:
- formalize shared typing and runtime schema
- extend
event.waitfilter matching - add
time.wait - finish designer productization
Open Questions
- Should
time.waitsupport assignment on resume in v1, or should that wait until a clearer use case appears? - Should
time.waitusewait_type='time'or reuse an existing type with different payload semantics?timeis cleaner. - Should the designer allow raw schema editing fallback for wait steps, or force the curated editor only?
- Should event field picker metadata live entirely in event schemas, or do we need a supplemental registry for event producers that cannot reasonably own UI annotations?
Acceptance Criteria (Definition of Done)
- Workflow authors can create a
Wait for Eventstep from the palette and configure event name, correlation key, filters, timeout, and resume assignments. - When event fields provide supported picker metadata, the wait-filter editor renders typed value controls such as status or entity pickers instead of only raw inputs.
- When event fields do not provide picker metadata, the wait-filter editor falls back to enum or primitive controls without blocking authoring.
- Event ingestion resumes the first waiting run whose event name, correlation key, tenant, and filters all match.
- Existing
event.waitworkflows continue to publish and execute. - Workflow authors can create a
Wait for Timestep from the palette and configure either a duration or an until-expression. - Due time waits resume successfully through the worker/runtime path.
- Publish validation and designer UI make invalid wait configuration understandable before runtime.
- Run and event detail surfaces show enough wait metadata for debugging without inspecting raw database rows.