Flow Studio Integration
Flow Studio is the workflow engine that drives WorkDesk's task inbox. When a workflow reaches a HIL (Human-in-the-Loop) node, Flow Studio suspends execution and writes a task record that WorkDesk detects and displays. When the employee acts, WorkDesk resumes the workflow via the Flow Studio resume API.
Integration Direction
The Flow Studio integration is bidirectional: Bidirectional
- Flow Studio → WorkDesk: HIL node suspension creates a record in
Process_HILTasksthat WorkDesk's sync service detects. - WorkDesk → Flow Studio: Employee action (approve/submit/acknowledge) triggers WorkDesk to POST to the Flow Studio resume API, resuming the suspended workflow execution.
How Flow Studio Creates HIL Tasks
When a workflow execution reaches a HIL node in Flow Studio, the process engine:
HIL Node Reached
The Flow Studio process engine evaluates the HIL node. Actor assignment is resolved — either a specific userId, a role, or a dynamic expression that evaluates to a user at runtime.
Execution Suspended
The execution is moved to status = "suspended". The engine serializes the current data context (all workflow variables) and saves it alongside the task record.
Process_HILTasks Record Written
A row is inserted into Process_HILTasks with the task type, assigned actor, form ID (if form task), initial values (from data context), due date, and execution ID.
WorkDesk Detects Task
HILTaskSyncService detects the new row, creates a WorkDesk task record, and publishes an EdgeStream event to notify the assigned user's browser.
Process_HILTasks Schema
The Process_HILTasks table is the handoff point between Flow Studio and WorkDesk. WorkDesk reads from this table but never writes to it — only the Flow Studio process engine writes HIL task records.
| Column | Type | Description |
|---|---|---|
Id | uniqueidentifier | Primary key — HIL task ID |
ExecutionId | uniqueidentifier | FK to the suspended workflow execution |
TenantId | uniqueidentifier | Tenant isolation |
NodeId | nvarchar(100) | The HIL node's ID in the workflow graph |
TaskType | nvarchar(50) | approval | form | review |
AssignedActorId | uniqueidentifier | User ID of the assigned employee |
FormId | nvarchar(100) | Atlas Form ID (form tasks only; null for approval/review) |
InitialValues | nvarchar(max) | JSON map of field → value from the workflow data context |
ReviewContent | nvarchar(max) | JSON content for review tasks (null for approval/form) |
Title | nvarchar(500) | Human-readable task title from HIL node config |
DueAt | datetime2 | Optional deadline from HIL node config |
CreatedAt | datetime2 | When the task was created (execution suspended) |
Status | nvarchar(50) | pending | claimed | completed |
CompletedAt | datetime2 | When WorkDesk posted the resume response |
HILTaskSyncService
WorkDesk's backend service that monitors Process_HILTasks and creates corresponding WorkDesk task records:
// HILTaskSyncService.cs — simplified polling loop
public class HILTaskSyncService : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var newHilTasks = await _hilTaskRepo.GetNewTasksSinceAsync(
_lastSyncCursor,
tenantIds: _tenantRegistry.ActiveTenantIds,
ct: stoppingToken);
foreach (var hilTask in newHilTasks)
{
// Create WorkDesk task record
var workdeskTask = new WorkDeskTask
{
Id = Guid.NewGuid(),
HilTaskId = hilTask.Id,
ExecutionId = hilTask.ExecutionId,
ActorId = hilTask.AssignedActorId,
TenantId = hilTask.TenantId,
Type = hilTask.TaskType,
Title = hilTask.Title,
FormId = hilTask.FormId,
InitialValues = hilTask.InitialValues,
ReviewContent = hilTask.ReviewContent,
DueAt = hilTask.DueAt,
Status = TaskStatus.Pending,
CreatedAt = DateTime.UtcNow
};
await _workdeskTaskRepo.InsertAsync(workdeskTask, stoppingToken);
// Notify the user via EdgeStream
await _edgeStream.PublishAsync(
topic: $"tasks.{hilTask.AssignedActorId}",
payload: new TaskAssignedEvent { Task = workdeskTask },
ct: stoppingToken);
}
_lastSyncCursor = newHilTasks.LastOrDefault()?.CreatedAt ?? _lastSyncCursor;
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken); // poll every 5s
}
}
}
The current HILTaskSyncService uses a 5-second polling loop against Process_HILTasks. This is intentional — it avoids tight coupling between the Flow Studio process engine and WorkDesk. The maximum task visibility delay is 5 seconds, which is acceptable for HIL workflows.
Resume API — WorkDesk to Flow Studio
When an employee completes a task in WorkDesk, the frontend calls the WorkDesk backend which in turn calls the Flow Studio resume API:
// WorkDesk Backend — Resume workflow after HIL task completion
POST /api/executions/{executionId}/resume
Authorization: Bearer {service-token} // machine-to-machine token
Content-Type: application/json
// Request body — approval task
{
"nodeId": "hil-approval-node-1",
"decision": "approved", // "approved" | "rejected"
"comment": "Looks good, approved.", // optional
"actorId": "user-guid-here"
}
// Request body — form task
{
"nodeId": "hil-form-node-2",
"formData": { // submitted form field values
"expenseAmount": 1200.00,
"category": "travel",
"description": "Q2 conference travel"
},
"actorId": "user-guid-here"
}
// Request body — review task
{
"nodeId": "hil-review-node-3",
"acknowledged": true,
"actorId": "user-guid-here"
}
// Response — 200 OK
{
"executionId": "exec-guid",
"status": "running", // execution resumed and is now running
"resumedAt": "2026-05-25T14:32:00Z"
}
What Happens After Resume
WorkDesk Receives Employee Action
Employee submits approval/form/review in WorkDesk UI. WorkDesk backend validates the payload and marks the WorkDesk task as completed.
Flow Studio Resume Called
WorkDesk backend POSTs to POST /api/executions/{id}/resume with the decision payload. The service-to-service call uses a machine-to-machine JWT.
Execution Resumes
Flow Studio injects the employee's response into the workflow data context. Conditional branches (e.g., "if approved → next node, if rejected → notify manager") are evaluated and the workflow continues.
Process_HILTasks Updated
Flow Studio marks the Process_HILTasks row as status = "completed" with a CompletedAt timestamp. WorkDesk reflects this in the task history view.
Workflow Continues or Ends
Execution proceeds through subsequent nodes (automated steps, further HIL nodes, or terminal nodes). The execution status in WorkDesk history updates in real-time via EdgeStream.
Execution History Linkage
WorkDesk's workflow history view links directly to Flow Studio's execution records. An employee can see:
- All executions they triggered (initiator view)
- All executions they participated in as a HIL respondent (participant view)
- The Observer Panel — a read-only drill-down into execution status, node list, and logs — powered by Flow Studio's execution detail API
// WorkDesk calls Flow Studio execution detail API for Observer Panel
GET /api/executions/{executionId}
Authorization: Bearer {userToken}
// Response includes
{
"executionId": "...",
"workflowName": "Expense Approval Flow",
"status": "running",
"startedAt": "...",
"nodes": [
{ "nodeId": "node-1", "name": "Start", "status": "completed", "duration": 12 },
{ "nodeId": "hil-1", "name": "Manager Approval", "status": "completed", "duration": 86400 },
{ "nodeId": "node-3", "name": "Send Notification", "status": "running", "duration": null }
],
"dataContext": { ... }, // only visible to workflow owner
"hilTasks": [ ... ] // HIL tasks associated with this execution
}
Error Handling
| Error Scenario | Behavior |
|---|---|
| Resume API returns 404 (execution not found) | WorkDesk shows error: "This workflow execution no longer exists — it may have been cancelled or expired" |
| Resume API returns 409 (already resumed) | WorkDesk shows: "Another user already completed this task" — task marked read-only |
| Resume API timeout (>30s) | WorkDesk retries once after 5s; if second attempt fails, shows manual retry button |
| HILTaskSyncService can't reach Process_HILTasks DB | Sync pauses; resumes automatically when connectivity is restored; no task loss (cursor-based sync) |
| Machine-to-machine token expired | WorkDesk backend refreshes service token from Passport on next request; transparent to user |