Feat v0.3.5 settings icd clone (#19)
All checks were successful
All checks were successful
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #19.
This commit is contained in:
330
docs/DEMO-WORKFLOWS.md
Normal file
330
docs/DEMO-WORKFLOWS.md
Normal file
@@ -0,0 +1,330 @@
|
||||
# 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-Switchboard-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.
|
||||
Reference in New Issue
Block a user