All checks were successful
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
331 lines
9.6 KiB
Markdown
331 lines
9.6 KiB
Markdown
# Demo Workflows — v0.3.6
|
|
|
|
Four example workflow packages that prove the engine works end-to-end.
|
|
Each is a self-contained `.pkg` archive installable via Admin > Packages.
|
|
|
|
## Feature Capability Matrix
|
|
|
|
| Feature | Bug Report | Onboarding | Content Approval | Webhook |
|
|
|---------|:----------:|:----------:|:----------------:|:-------:|
|
|
| Public entry (anonymous) | ✅ | | | |
|
|
| Progressive fieldsets | ✅ | ✅ | | |
|
|
| Branch rules (conditional routing) | ✅ | | | |
|
|
| Team assignment + claim | ✅ | | | |
|
|
| SLA timer | ✅ | | | |
|
|
| Starlark automated stage | | ✅ | | ✅ |
|
|
| db.insert (ext_data tables) | | ✅ | | ✅ |
|
|
| notifications.send | | ✅ | | |
|
|
| http.post (outbound webhook) | | | | ✅ |
|
|
| connections.get (credentials) | | | | ✅ |
|
|
| Signoff gate (required_role) | | ✅ | | |
|
|
| Multi-party signoff (quorum) | | | ✅ | |
|
|
| Rejection reroute | | ✅ | ✅ | |
|
|
| Review cycle (loop) | | | ✅ | |
|
|
|
|
---
|
|
|
|
## Package 1: Bug Report Triage
|
|
|
|
**Slug:** `bug-report-triage`
|
|
**Entry mode:** `public_link` — anyone with the link can submit
|
|
**Tier:** browser (no Starlark needed)
|
|
|
|
### Stage Flow
|
|
|
|
```
|
|
[submit] → [classify] → [fix-critical] → [verify]
|
|
public team ↘ [fix-normal] ↗ team
|
|
team
|
|
```
|
|
|
|
### Stages
|
|
|
|
| # | Name | Mode | Audience | Key Feature |
|
|
|---|------|------|----------|-------------|
|
|
| 0 | submit | form | public | 2 fieldsets: "Report Details" (email, summary, component, severity) + "Reproduction" (steps, expected, actual) |
|
|
| 1 | classify | form | team | Team reviews. Branch rules: severity=critical → fix-critical, else → fix-normal |
|
|
| 2 | fix-critical | form | team | Senior team queue. SLA: 3600s |
|
|
| 3 | fix-normal | form | team | Standard fix queue |
|
|
| 4 | verify | review | team | Verify fix, close out |
|
|
|
|
### Branch Rules (stage 1)
|
|
|
|
```json
|
|
[
|
|
{"field": "severity", "op": "eq", "value": "critical", "target_stage": "fix-critical"},
|
|
{"field": "severity", "op": "neq", "value": "critical", "target_stage": "fix-normal"}
|
|
]
|
|
```
|
|
|
|
### API Walkthrough
|
|
|
|
```bash
|
|
# 1. Start public instance (no auth required)
|
|
curl -X POST $BASE/api/v1/public/workflows/$WF_ID/start \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"data": {"reporter_email": "user@example.com", "summary": "Login broken", "component": "ui", "severity": "critical", "steps": "1. Click login", "expected": "Login page", "actual": "500 error"}}'
|
|
|
|
# Response includes entry_token for anonymous continuation
|
|
# {"id": "inst-xxx", "entry_token": "tok-yyy", ...}
|
|
|
|
# 2. Resume (check status)
|
|
curl $BASE/api/v1/public/workflows/resume/tok-yyy
|
|
|
|
# 3. Team member claims the classify assignment
|
|
curl -X POST $BASE/api/v1/teams/$TEAM/assignments/$ASSIGN_ID/claim \
|
|
-H "Authorization: Bearer $TOKEN"
|
|
|
|
# 4. Advance classify stage (triggers branch rule)
|
|
curl -X POST $BASE/api/v1/teams/$TEAM/instances/$INST/advance \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"data": {"severity": "critical", "notes": "Confirmed production issue"}}'
|
|
# → Routes to fix-critical (not fix-normal)
|
|
```
|
|
|
|
---
|
|
|
|
## Package 2: Employee Onboarding
|
|
|
|
**Slug:** `employee-onboarding`
|
|
**Entry mode:** `team_only`
|
|
**Tier:** starlark
|
|
**Permissions:** `db.write`, `notifications.send`
|
|
|
|
### Stage Flow
|
|
|
|
```
|
|
[new-hire-info] → [provision-accounts] → [manager-signoff] → [it-setup] → [welcome]
|
|
team automated (Starlark) review + signoff team automated
|
|
auto-advances reject → stage 0 auto-advances
|
|
```
|
|
|
|
### Stages
|
|
|
|
| # | Name | Mode | Audience | Key Feature |
|
|
|---|------|------|----------|-------------|
|
|
| 0 | new-hire-info | form | team | 2 fieldsets: "Personal Info" + "Access Requirements" |
|
|
| 1 | provision-accounts | automated | system | Starlark: db.insert provisioning records, notify HR |
|
|
| 2 | manager-signoff | review | team | 1 approval required, required_role: "manager", reject → new-hire-info |
|
|
| 3 | it-setup | form | team | IT confirms hardware + access |
|
|
| 4 | welcome | automated | system | Starlark: log completion, send welcome notification |
|
|
|
|
### Starlark Hooks
|
|
|
|
**`on_provision(ctx)`** — Automated provisioning:
|
|
|
|
```python
|
|
def on_provision(ctx):
|
|
data = ctx["stage_data"]
|
|
name = data.get("full_name", "unknown")
|
|
dept = data.get("department", "general")
|
|
|
|
# Record provision in ext_data table
|
|
db.insert("provisions", {
|
|
"employee_name": name,
|
|
"department": dept,
|
|
"needs_vpn": str(data.get("needs_vpn", False)),
|
|
"needs_admin": str(data.get("needs_admin", False)),
|
|
"equipment": data.get("equipment", "standard laptop"),
|
|
"status": "provisioned"
|
|
})
|
|
|
|
# Notify the HR user who started this workflow
|
|
notifications.send(
|
|
ctx["started_by"],
|
|
"Accounts provisioned for " + name,
|
|
"Department: " + dept + ". Ready for manager review."
|
|
)
|
|
|
|
return {"advance": True, "data": {
|
|
"provision_status": "complete",
|
|
"accounts": ["email", "vpn" if data.get("needs_vpn") else None, "admin" if data.get("needs_admin") else None]
|
|
}}
|
|
```
|
|
|
|
**`on_welcome(ctx)`** — Completion logging:
|
|
|
|
```python
|
|
def on_welcome(ctx):
|
|
data = ctx["stage_data"]
|
|
|
|
db.insert("onboarding_log", {
|
|
"employee_name": data.get("full_name", ""),
|
|
"department": data.get("department", ""),
|
|
"completed_by": ctx["started_by"],
|
|
"status": "complete"
|
|
})
|
|
|
|
notifications.send(
|
|
ctx["started_by"],
|
|
"Onboarding complete: " + data.get("full_name", ""),
|
|
"All stages finished. Welcome aboard!"
|
|
)
|
|
|
|
return {"advance": True, "data": {"onboarding_complete": True}}
|
|
```
|
|
|
|
### Signoff Gate (stage 2)
|
|
|
|
```json
|
|
{
|
|
"validation": {
|
|
"required_approvals": 1,
|
|
"required_role": "manager",
|
|
"reject_action": "new-hire-info"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Prerequisites
|
|
|
|
- Team must have a custom "manager" role (via Team Admin > Members > Team Roles)
|
|
- At least one team member with the "manager" role assigned
|
|
|
|
---
|
|
|
|
## Package 3: Content Approval
|
|
|
|
**Slug:** `content-approval`
|
|
**Entry mode:** `team_only`
|
|
**Tier:** browser
|
|
|
|
### Stage Flow
|
|
|
|
```
|
|
[draft] → [review] → [publish]
|
|
team team ↕ team
|
|
[revision]
|
|
team
|
|
```
|
|
|
|
### Stages
|
|
|
|
| # | Name | Mode | Audience | Key Feature |
|
|
|---|------|------|----------|-------------|
|
|
| 0 | draft | form | team | Author submits title, body, category |
|
|
| 1 | review | review | team | 2 approvals required. Reject → revision |
|
|
| 2 | revision | form | team | Author revises. Branch rule always routes back to review |
|
|
| 3 | publish | form | team | Final confirmation |
|
|
|
|
### Review Cycle
|
|
|
|
The rejection reroute creates a loop:
|
|
|
|
1. Author submits draft → enters review
|
|
2. Reviewer A approves, Reviewer B rejects → `reject_action: "revision"` routes to stage 2
|
|
3. Author revises → branch rule routes back to review (stage 1)
|
|
4. Both reviewers approve → advances to publish (stage 3)
|
|
|
|
### Signoff Gate (stage 1)
|
|
|
|
```json
|
|
{
|
|
"validation": {
|
|
"required_approvals": 2,
|
|
"reject_action": "revision"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Package 4: Webhook Notifier
|
|
|
|
**Slug:** `webhook-notifier`
|
|
**Entry mode:** `team_only`
|
|
**Tier:** starlark
|
|
**Permissions:** `api.http`, `connections.read`, `db.write`
|
|
|
|
### Stage Flow
|
|
|
|
```
|
|
[configure] → [fire-webhook] → [result]
|
|
team automated review
|
|
(http.post)
|
|
```
|
|
|
|
### Stages
|
|
|
|
| # | Name | Mode | Audience | Key Feature |
|
|
|---|------|------|----------|-------------|
|
|
| 0 | configure | form | team | URL + event name + payload |
|
|
| 1 | fire-webhook | automated | system | Starlark: http.post to webhook URL |
|
|
| 2 | result | review | team | Shows delivery status |
|
|
|
|
### Starlark Hook
|
|
|
|
**`on_fire(ctx)`** — Outbound HTTP:
|
|
|
|
```python
|
|
def on_fire(ctx):
|
|
data = ctx["stage_data"]
|
|
url = data.get("webhook_url", "")
|
|
|
|
# Fallback to configured connection
|
|
if not url:
|
|
conn = connections.get("webhook")
|
|
if conn:
|
|
url = conn.get("url", "")
|
|
|
|
if not url:
|
|
return {"error": "No webhook URL configured"}
|
|
|
|
payload = json.encode({
|
|
"event": data.get("event_name", "workflow.notify"),
|
|
"instance_id": ctx["instance_id"],
|
|
"workflow_id": ctx["workflow_id"],
|
|
"data": data
|
|
})
|
|
|
|
resp = http.post(url, body=payload, headers={
|
|
"Content-Type": "application/json",
|
|
"X-Armature-Event": data.get("event_name", "workflow.notify")
|
|
})
|
|
|
|
# Log the delivery
|
|
db.insert("webhook_log", {
|
|
"url": url,
|
|
"status_code": str(resp["status"]),
|
|
"event": data.get("event_name", ""),
|
|
"instance_id": ctx["instance_id"]
|
|
})
|
|
|
|
return {"advance": True, "data": {
|
|
"delivery_status": "delivered" if int(resp["status"]) < 400 else "failed",
|
|
"status_code": resp["status"],
|
|
"response_body": resp["body"][:500]
|
|
}}
|
|
```
|
|
|
|
---
|
|
|
|
## Demo Surface
|
|
|
|
A browser-tier surface (`workflow-demo`) auto-installed on first run. Provides:
|
|
|
|
- Workflow cards with feature badges and stage flow diagrams
|
|
- "Try It" buttons for interactive exploration
|
|
- Starlark code viewer showing hook source
|
|
- API curl examples for each operation
|
|
|
|
Can be uninstalled by admin like any other package.
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# Build all example packages
|
|
cd packages && ./build.sh bug-report-triage employee-onboarding content-approval webhook-notifier workflow-demo
|
|
|
|
# Install via admin API
|
|
for pkg in dist/bug-report-triage.pkg dist/employee-onboarding.pkg dist/content-approval.pkg dist/webhook-notifier.pkg dist/workflow-demo.pkg; do
|
|
curl -X POST $BASE/api/v1/admin/packages/install \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-F "file=@$pkg"
|
|
done
|
|
```
|
|
|
|
Or with bundled packages (v0.3.8+): just `docker compose up` — all examples are auto-installed.
|