# Workflow Builder Tasks

The **Workflow Builder** module lets administrators design workflows without touching code. Open it from the dashboard to drag step types into a canvas and define their order.

## UI Layout

- **Steps palette** – lists available steps from the `workflow_step_types` table.
- **Canvas** – drop area where steps are arranged sequentially.
- **Properties** – shows workflow metadata and a JSON editor for the selected step.

Steps are loaded from the API as shown in the builder script:
```javascript
const res = await fetch('../api/workflow_step_types');
if (res.ok) stepTypes = await res.json();
```
This populates the palette with draggable items.

## Available Step Types

The system ships with these step handlers:

- `start`
- `add_calendar_event`
- `alert`
- `assign_items`
- `check_signoff`
- `condition`
- `create_leave_request`
- `create_ohs_medical`
- `query_budget`
- `create_task`
- `document_approval`
- `email`
- `http_request`
- `notify_exit_departments`
- `notify_manager`
- `open_form`
- `open_modal`
- `request_feedback`
- `review_approval`
- `save_hiring_documents`
- `save_record`
- `schedule_services`
- `send_welcome`
- `sms`
- `trigger_api`
- `update_attendance`
- `update_clearance_steps`
- `update_ohs_incident`
- `update_status`
- `query_records`
- `for_each_record`
- `wait_approval`

The `start` step represents the entry point of a workflow. Its configuration now includes a
`triggerType` that determines how the workflow is launched. When saved the builder creates the
corresponding records in `workflow_event_triggers` or `workflow_api_triggers` so the server can
emit the configured `trigger_event` automatically.

### Start Trigger Options

- **Form** – choose one or more forms and operations such as **Save**, **Edit** or **Delete**.
  When a matching submission occurs the `FormSubmissionsController` fires an event like
  `form.{form_id}.updated` which starts the workflow. Selecting multiple forms inserts
  additional rows in `workflow_triggers` so the workflow runs for each form.
  ```json
  {
    "type": "start",
    "triggerType": "Form",
    "formIds": [3, 5],
    "operations": ["save", "edit"]
  }
  ```
- **Database** – watch a table for inserts, updates or deletes. `GenericController` checks the
  `workflow_event_triggers` table after each operation and emits the workflow event when the
  conditions match.
  ```json
  {
    "type": "start",
    "triggerType": "Database",
    "table": "time_clocks",
    "operations": ["insert", "update"]
  }
  ```
- **Button** – link to a record in `ui_actions`. Clicking the button posts to
  `/api/ui_actions/trigger/{id}` which calls `WorkflowEngine->emit()` with the action's
  `workflow_event` value.
- **API** – generates a token stored in `workflow_api_triggers`. Sending a request to the new
  `/api/webhook/{token}` endpoint with the allowed method triggers the workflow. Example:
  ```bash
  curl -X POST https://example.com/api/webhook/abc123 -d '{"id":5}'
  ```
- **Custom** – manually enter any event name. Use this when another module or custom code calls
  `WorkflowEngine::trigger()` directly.

### Condition Step

The `condition` step evaluates one or more rules against the workflow
context. Click the step in the canvas and use the **Properties** panel to
add rules with the `field`, `operator` and `value` inputs. Each rule may
optionally specify a `setting` name to pull the comparison value from
`SettingsService`.
Example rule:
```json
{ "field": "status", "operator": "==", "setting": "desired_status" }
```
All rules must pass for the step to succeed. The result is stored in the
`condition_result` context property for later steps to use.

### Query Records and For Each Record

The `query_records` step pulls rows from a table using a simple `where`
object or raw SQL clause. The results are stored in the context under
`context_key`. The `for_each_record` step iterates over that array and
executes a nested list of steps for every row.

```json
[
  { "type": "query_records", "table": "alerts", "where": { "status": "open" }, "context_key": "alerts" },
  {
    "type": "for_each_record",
    "list_key": "alerts",
    "steps": [
      { "type": "email", "to": "{email}", "message": "Alert {id} requires action" }
    ]
  }
]
```

This combination reads all open alerts and sends a notification for each one.

## Adding New Steps

1. Create a class under `api/services/workflow_steps` that implements `WorkflowStepInterface`:
```php
interface WorkflowStepInterface
{
    public function execute(array &$context): void;
}
```
2. Insert a new record into `workflow_step_types` describing the step and its builder metadata:
```sql
INSERT INTO workflow_step_types (type, description, metadata) VALUES
  ('my_step', 'Custom description', '{"field":"value"}');
```
3. Update the builder metadata so the palette shows the new type and any configuration fields.

After these changes the builder will load the new step and the engine will instantiate the class when a workflow executes it.

## Connecting Steps and Conditions

Drag from the small handle on the right side of a step to another step's
left handle to create a connection. jsPlumb renders the link and the
builder stores it in the workflow definition.

Click any connection line to edit its conditions in the **Properties**
panel. Press **Add Condition** to define a `field`, comparison
`operator` and `value`. Multiple conditions are combined using `AND`
logic.

When saved, connections become entries under `definition.transitions`:

```json
{
  "definition": {
    "steps": [ ... ],
    "transitions": [
      {
        "fromId": "step1",
        "toId": "step2",
        "conditions": [
          { "field": "status", "operator": "==", "value": "open" }
        ]
      }
    ]
  }
}
```

Each transition object stores the source step ID, target step ID and an
optional list of conditions.

## Investigator Module

The `Investigators` modal lists users belonging to the `Investigators` group. Submitting the
**Investigator** form triggers the `investigator.created` workflow which assigns the new
user to that group and sends a notification.
