Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
5.7 KiB
DESIGN-0.35.0 — Workflow Product
Transforms the workflow engine from a linear stage-runner into a product-grade automation tool. Seven changesets covering conditional routing, AI-triggered routing, data pipeline hooks, progressive forms, conditional fields, structured review, and a monitoring dashboard.
Depends on: v0.34.0 (Data Portability), v0.31.2 (Team Workflows), v0.29.0 (Starlark Sandbox).
Schema Changes
Migrations modified in-place (DB rebuild required):
005_channels.sql — add stage_entered_at (PG: TIMESTAMPTZ,
SQLite: TEXT). Tracks when the current stage was entered for SLA
computation. Also add index idx_channels_workflow_active on
(workflow_id, workflow_status) for monitoring queries.
018_workflows.sql — add sla_seconds INTEGER to workflow_stages.
Add review_comments (PG: JSONB DEFAULT '[]', SQLite: TEXT DEFAULT '[]') to workflow_assignments.
No new migration files. No new tables.
Conditional Routing Engine
File: server/workflow/routing.go
The existing advance logic hardcoded nextStage = currentStage + 1.
The routing engine replaces this with condition evaluation:
- Parse
transition_rules.conditions[]from the departing stage - Evaluate each condition against accumulated
stage_data - First match → resolve
target_stage(by name or ordinal) - No match → fallback to
ordinal + 1
Expression format: {field, op, value, target_stage}. Operators:
eq, neq, gt, lt, gte, lte, in, contains, exists,
not_exists. Loose equality via fmt.Sprintf("%v") comparison.
Numeric comparison extracts float64 from both sides.
Wiring: ResolveNextStage() called in all 4 advance sites:
handler (workflow_instances.go), tool (tools/workflow.go), forms
auto-advance (workflow_forms.go), Starlark module
(sandbox/workflow_module.go).
Backward compatible: no conditions = ordinal + 1.
AI-Triggered Routing
Tool: workflow_route — persona calls with {target_stage, reason}.
Uses ResolveStageByName() (case-insensitive). Records decision in
stage_data._route_history_latest. Allows forward and backward jumps
(loop stages for iterative correction).
Starlark: workflow.route(channel_id, target_stage, reason) for
extension-driven escalation patterns. Requires workflow.access.
on_advance Hook
File: server/handlers/workflow_hooks.go
Fires synchronously after AdvanceWorkflowStage succeeds. Configured
per-stage in transition_rules.on_advance: {package_id, entry_point}.
Hook receives: {stage_data, previous_stage, current_stage, channel_id}.
Returns: {stage_data: {...}} (enriched), None (no change), or
{error: "msg"} (logged, not rolled back — future: rollback support).
The existing http Starlark module (v0.29.1) is available in hooks,
enabling external API enrichment without new infrastructure.
Progressive Forms
Model: TypedFormTemplate.Fieldsets []FormFieldset — optional
array of {label, fields[]}. When present, top-level fields is
replaced by flattened fieldset fields in ParseTypedFormTemplate().
Frontend: workflow.html renders one fieldset at a time with
step indicator, next/back navigation. All fields submitted together
on the final step.
Conditional Fields
Model: FormField.Condition *FieldCondition — {when, op, value}.
Operators: eq (default), neq, in, exists.
Server-side: ValidateFormData() calls evaluateFieldCondition()
before each field. Hidden fields are skipped (no required check, no
type validation).
Client-side: workflow.html attaches change/input listeners
to source fields. Target fields toggle cond-hidden CSS class.
Structured Review
Review comments: review_comments JSONB on workflow_assignments.
POST /workflow-assignments/:id/comment appends {text, user_id, created_at}. GET /workflow-assignments/:id returns full assignment.
Review surface: Side-by-side layout in workflow.html — left panel
shows structured stage_data table (internal _-prefixed keys hidden),
right panel has comment textarea + approve/reject buttons. Keyboard
shortcuts: Ctrl+Enter approve, Ctrl+Shift+Enter reject.
Monitoring Dashboard
File: server/handlers/workflow_monitor.go
Endpoints:
GET /admin/workflows/monitor/instances— all active instancesGET /admin/workflows/monitor/funnel/:id— stage countsGET /admin/workflows/monitor/stale?threshold_hours=NGET /teams/:teamId/workflows/monitor/instances— team-scoped
SLA computation: stage_entered_at + sla_seconds vs NOW().
Returned as sla_remaining_seconds (negative = breached) and
sla_breached boolean. Computed at query time, not stored.
Store: New ListByType(ctx, "workflow") method on ChannelStore
(both PG and SQLite). Monitoring queries iterate active channels,
joining workflow definitions and stage metadata.
Frontend: src/js/workflow-monitor.js — auto-refresh every 30s,
SLA color indicators (green > 50%, yellow > 20%, red), stale instance
alert section.
Workflow Branding
WorkflowPageData.BrandingJSON passes the workflow's branding JSON
to the visitor template. Applied as:
--accentCSS custom property (fromaccent_color)- Logo image in header (from
logo_url) - Tagline text below header (from
tagline)
Previously branding was only on the landing page; now also on the active workflow surface.
New Files
| File | Purpose |
|---|---|
server/workflow/routing.go |
Conditional routing engine |
server/handlers/workflow_hooks.go |
on_advance hook dispatch |
server/handlers/workflow_monitor.go |
Monitoring dashboard |
src/js/workflow-monitor.js |
Admin monitoring frontend |
packages/icd-test-runner/js/crud/workflow-product.js |
E2E tests |