diff --git a/CHANGELOG.md b/CHANGELOG.md index f280ebf..ea5550d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht - Recorder draft review panel with reorder/edit/skip controls before inserting recorded steps. - Autopilot plan diagnostics: overall confidence score, node-level insights, and fallback template options. - Contributor onboarding package: 10-minute tutorial, starter workflow file, and reusable docs templates. +- Real-world starter template pack (invoice approval, web scrape sync, CSV cleanup, email triage, health check alert). ### Changed - CI now includes browser smoke validation (`Web E2E Smoke`). diff --git a/README.md b/README.md index d21266e..7a1f164 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,21 @@ Use these guided demos to evaluate the platform quickly: - `docs/DEMOS.md#demo-3-document-understanding-and-clipboard-ai` - `docs/DEMOS.md#demo-4-workflow-builder-mvp-controls` - `docs/DEMOS.md#demo-5-recorder-draft-review-and-insert` +- `docs/DEMOS.md#demo-6-real-world-starter-pack` + +## Production Starter Templates +Use built-in templates as a fast path from idea to first successful run: + +- `invoice-intake-approval`: Parse invoice text, classify risk, branch to approval, and sync approved data. +- `web-scrape-api-sync`: Scrape table data from a page and push rows to an API endpoint. +- `csv-cleanup-validation`: Import CSV rows, normalize with AI, validate required fields, and branch bad records. +- `email-triage-ticket-create`: Classify inbound email priority, summarize content, then create a ticket. +- `scheduled-health-check-alert`: Run scheduled API checks, classify service state, and alert on degradation. + +Create from UI: +1. Open `Templates` in the left sidebar. +2. Select a starter template. +3. Click `Create Workflow`. ## Contributor Onboarding New contributors should start here: diff --git a/apps/server/src/lib/templates.test.ts b/apps/server/src/lib/templates.test.ts index addd6f7..2a09e69 100644 --- a/apps/server/src/lib/templates.test.ts +++ b/apps/server/src/lib/templates.test.ts @@ -4,20 +4,25 @@ import { getWorkflowTemplate, listWorkflowTemplates } from "./templates.js"; test("listWorkflowTemplates exposes curated templates", () => { const templates = listWorkflowTemplates(); - assert.equal(templates.length >= 7, true); + assert.equal(templates.length >= 12, true); + assert.equal(templates.some((template) => template.id === "invoice-intake-approval"), true); + assert.equal(templates.some((template) => template.id === "web-scrape-api-sync"), true); + assert.equal(templates.some((template) => template.id === "csv-cleanup-validation"), true); + assert.equal(templates.some((template) => template.id === "email-triage-ticket-create"), true); + assert.equal(templates.some((template) => template.id === "scheduled-health-check-alert"), true); assert.equal(templates.some((template) => template.id === "web-form-submit"), true); assert.equal(templates.some((template) => template.id === "web-table-scrape"), true); assert.equal(templates.some((template) => template.id === "conditional-routing"), true); assert.equal(templates.some((template) => template.id === "api-cleanup-sync"), true); assert.equal(templates.some((template) => template.id === "batch-loop-sync"), true); - const sample = templates.find((template) => template.id === "api-cleanup-sync"); + const sample = templates.find((template) => template.id === "invoice-intake-approval"); assert.equal(typeof sample?.difficulty, "string"); assert.equal(Array.isArray(sample?.tags), true); }); test("getWorkflowTemplate returns full definition for known template", () => { - const template = getWorkflowTemplate("api-cleanup-sync"); + const template = getWorkflowTemplate("web-scrape-api-sync"); assert.ok(template); - assert.equal(template?.name, "API Cleanup Sync"); + assert.equal(template?.name, "Web Scrape -> API Sync"); assert.equal(Array.isArray((template?.definition as any).nodes), true); }); diff --git a/apps/server/src/lib/templates.ts b/apps/server/src/lib/templates.ts index 5eae305..b14dfb3 100644 --- a/apps/server/src/lib/templates.ts +++ b/apps/server/src/lib/templates.ts @@ -16,6 +16,481 @@ const executionDefaults = { }; const templates: WorkflowTemplate[] = [ + { + id: "invoice-intake-approval", + name: "Invoice Intake + Approval", + description: "Extract invoice fields, validate risk, route high-value invoices to approval, then sync.", + category: "operations", + difficulty: "intermediate", + useCase: "Invoice capture and governance workflow with human oversight.", + tags: ["invoice", "document", "approval", "integration"], + definition: { + nodes: [ + { id: "start", type: "action", position: { x: 80, y: 80 }, data: { type: "start", label: "Start" } }, + { + id: "load-doc", + type: "action", + position: { x: 330, y: 80 }, + data: { + type: "set_variable", + label: "Set Invoice Text", + key: "invoiceRawText", + value: "Invoice Number: INV-1001\nVendor: Example AB\nTotal: 12850.00\nCurrency: USD\nDue Date: 2026-03-01" + } + }, + { + id: "understand", + type: "action", + position: { x: 580, y: 80 }, + data: { + type: "document_understanding", + label: "Extract Invoice Fields", + inputKey: "invoiceRawText", + outputKey: "invoiceDoc", + expectedFields: ["invoice_number", "vendor", "total", "due_date", "currency"] + } + }, + { + id: "normalize", + type: "action", + position: { x: 830, y: 80 }, + data: { + type: "transform_llm", + label: "Normalize Invoice Payload", + inputKey: "invoiceDoc", + outputKey: "invoicePayload", + strictJson: true + } + }, + { + id: "guard", + type: "action", + position: { x: 1080, y: 80 }, + data: { + type: "submit_guard", + label: "Validate Required Fields", + inputKey: "invoicePayload", + schema: { + type: "object", + required: ["invoice_number", "vendor", "total"], + properties: { + invoice_number: { type: "string", minLength: 1 }, + vendor: { type: "string", minLength: 1 }, + total: { type: "number" } + } + } + } + }, + { + id: "amount", + type: "action", + position: { x: 1330, y: 80 }, + data: { + type: "transform_llm", + label: "Extract Invoice Amount", + inputKey: "invoicePayload", + outputKey: "invoiceAmount", + strictJson: false, + prompt: "Return only the numeric invoice total as plain text." + } + }, + { + id: "branch", + type: "action", + position: { x: 1580, y: 80 }, + data: { + type: "conditional_branch", + label: "Amount > 10000?", + inputKey: "invoiceAmount", + operator: "gt", + right: 10000, + trueTarget: "approval", + falseTarget: "sync" + } + }, + { + id: "approval", + type: "action", + position: { x: 1830, y: 20 }, + data: { + type: "manual_approval", + label: "Manager Approval", + message: "Approve high-value invoice before sync." + } + }, + { + id: "sync", + type: "action", + position: { x: 1830, y: 140 }, + data: { + type: "integration_request", + label: "Sync to Finance System", + integrationId: "finance_api", + method: "POST", + path: "/invoices", + body: { + invoice: "{{invoicePayload}}" + }, + saveAs: "syncResponse" + } + } + ], + edges: [ + { id: "e1", source: "start", target: "load-doc" }, + { id: "e2", source: "load-doc", target: "understand" }, + { id: "e3", source: "understand", target: "normalize" }, + { id: "e4", source: "normalize", target: "guard" }, + { id: "e5", source: "guard", target: "amount" }, + { id: "e6", source: "amount", target: "branch" }, + { id: "e7", source: "branch", target: "approval" }, + { id: "e8", source: "branch", target: "sync" }, + { id: "e9", source: "approval", target: "sync" } + ], + execution: executionDefaults + } + }, + { + id: "web-scrape-api-sync", + name: "Web Scrape -> API Sync", + description: "Scrape rows from a portal, normalize to schema, and sync downstream API.", + category: "web", + difficulty: "intermediate", + useCase: "Move structured data from browser UI into backend systems.", + tags: ["scrape", "playwright", "api", "sync"], + definition: { + nodes: [ + { id: "start", type: "action", position: { x: 80, y: 80 }, data: { type: "start", label: "Start" } }, + { + id: "navigate", + type: "action", + position: { x: 330, y: 80 }, + data: { type: "playwright_navigate", label: "Open Source Portal", url: "https://example.com/reports/orders" } + }, + { + id: "extract", + type: "action", + position: { x: 580, y: 80 }, + data: { + type: "playwright_extract", + label: "Extract Table Data", + selector: "table tbody", + saveAs: "rawRows" + } + }, + { + id: "normalize", + type: "action", + position: { x: 830, y: 80 }, + data: { + type: "transform_llm", + label: "Normalize Rows", + inputKey: "rawRows", + outputKey: "cleanRows", + strictJson: true + } + }, + { + id: "guard", + type: "action", + position: { x: 1080, y: 80 }, + data: { + type: "submit_guard", + label: "Validate Row Shape", + inputKey: "cleanRows", + schema: { + type: "array", + minItems: 1 + } + } + }, + { + id: "sync", + type: "action", + position: { x: 1330, y: 80 }, + data: { + type: "http_request", + label: "POST Rows", + method: "POST", + url: "https://example.com/api/order-sync", + body: { rows: "{{cleanRows}}" }, + saveAs: "syncResult" + } + } + ], + edges: [ + { id: "e1", source: "start", target: "navigate" }, + { id: "e2", source: "navigate", target: "extract" }, + { id: "e3", source: "extract", target: "normalize" }, + { id: "e4", source: "normalize", target: "guard" }, + { id: "e5", source: "guard", target: "sync" } + ], + execution: executionDefaults + } + }, + { + id: "csv-cleanup-validation", + name: "CSV Cleanup + Validation", + description: "Import CSV rows, normalize records with AI, validate, and export to API.", + category: "data", + difficulty: "starter", + useCase: "Prepare spreadsheet exports for reliable downstream ingestion.", + tags: ["csv", "cleanup", "validation", "etl"], + definition: { + nodes: [ + { id: "start", type: "action", position: { x: 80, y: 80 }, data: { type: "start", label: "Start" } }, + { + id: "import", + type: "action", + position: { x: 330, y: 80 }, + data: { + type: "data_import_csv", + label: "Import CSV", + text: "id,email,total\n1,alice@example.com,120.50\n2,bob@example.com,94.00", + outputKey: "csvRows" + } + }, + { + id: "clean", + type: "action", + position: { x: 580, y: 80 }, + data: { + type: "transform_llm", + label: "Normalize CSV Rows", + inputKey: "csvRows", + outputKey: "normalizedRows", + strictJson: true + } + }, + { + id: "validate", + type: "action", + position: { x: 830, y: 80 }, + data: { + type: "submit_guard", + label: "Validate CSV Output", + inputKey: "normalizedRows", + schema: { + type: "array", + minItems: 1 + } + } + }, + { + id: "send", + type: "action", + position: { x: 1080, y: 80 }, + data: { + type: "http_request", + label: "Send to Import API", + method: "POST", + url: "https://example.com/api/csv-import", + body: { rows: "{{normalizedRows}}" }, + saveAs: "importResult" + } + } + ], + edges: [ + { id: "e1", source: "start", target: "import" }, + { id: "e2", source: "import", target: "clean" }, + { id: "e3", source: "clean", target: "validate" }, + { id: "e4", source: "validate", target: "send" } + ], + execution: executionDefaults + } + }, + { + id: "email-triage-ticket-create", + name: "Email Triage -> Ticket Create", + description: "Classify inbound email content, route urgent cases to approval, then create support ticket.", + category: "operations", + difficulty: "intermediate", + useCase: "Convert inbox workload into structured ticket operations.", + tags: ["email", "triage", "ticketing", "approval"], + definition: { + nodes: [ + { id: "start", type: "action", position: { x: 80, y: 80 }, data: { type: "start", label: "Start" } }, + { + id: "email", + type: "action", + position: { x: 330, y: 80 }, + data: { + type: "set_variable", + label: "Set Email Body", + key: "emailBody", + value: + "Subject: Unable to process payroll export\\nPriority: high\\nBody: payroll API returns 500 for 3 hours." + } + }, + { + id: "priority", + type: "action", + position: { x: 580, y: 80 }, + data: { + type: "transform_llm", + label: "Derive Ticket Priority", + inputKey: "emailBody", + outputKey: "ticketPriority", + strictJson: false, + prompt: "Return only one word priority: high, medium, or low." + } + }, + { + id: "summary", + type: "action", + position: { x: 830, y: 80 }, + data: { + type: "transform_llm", + label: "Summarize Issue", + inputKey: "emailBody", + outputKey: "ticketSummary", + strictJson: false, + prompt: "Return one short support ticket summary sentence." + } + }, + { + id: "branch", + type: "action", + position: { x: 1080, y: 80 }, + data: { + type: "conditional_branch", + label: "High Priority?", + inputKey: "ticketPriority", + operator: "eq", + right: "high", + trueTarget: "approval", + falseTarget: "ticket" + } + }, + { + id: "approval", + type: "action", + position: { x: 1330, y: 20 }, + data: { + type: "manual_approval", + label: "Ops Lead Approval", + message: "Approve high-priority ticket creation." + } + }, + { + id: "ticket", + type: "action", + position: { x: 1330, y: 140 }, + data: { + type: "integration_request", + label: "Create Ticket", + integrationId: "helpdesk_api", + method: "POST", + path: "/tickets", + body: { + summary: "{{ticketSummary}}", + priority: "{{ticketPriority}}", + details: "{{emailBody}}" + }, + saveAs: "ticketResponse" + } + } + ], + edges: [ + { id: "e1", source: "start", target: "email" }, + { id: "e2", source: "email", target: "priority" }, + { id: "e3", source: "priority", target: "summary" }, + { id: "e4", source: "summary", target: "branch" }, + { id: "e5", source: "branch", target: "approval" }, + { id: "e6", source: "branch", target: "ticket" }, + { id: "e7", source: "approval", target: "ticket" } + ], + execution: executionDefaults + } + }, + { + id: "scheduled-health-check-alert", + name: "Scheduled Health-Check + Alert", + description: "Run a health probe, score service state, and trigger alert webhook for degraded state.", + category: "operations", + difficulty: "starter", + useCase: "Operational monitoring workflow for scheduled execution.", + tags: ["health-check", "alerting", "ops", "schedule"], + definition: { + nodes: [ + { id: "start", type: "action", position: { x: 80, y: 80 }, data: { type: "start", label: "Start" } }, + { + id: "check", + type: "action", + position: { x: 330, y: 80 }, + data: { + type: "http_request", + label: "Call Health Endpoint", + method: "GET", + url: "https://example.com/health", + saveAs: "healthPayload" + } + }, + { + id: "classify", + type: "action", + position: { x: 580, y: 80 }, + data: { + type: "transform_llm", + label: "Classify Health State", + inputKey: "healthPayload", + outputKey: "healthState", + strictJson: false, + prompt: "Return only one word: healthy or degraded." + } + }, + { + id: "branch", + type: "action", + position: { x: 830, y: 80 }, + data: { + type: "conditional_branch", + label: "Degraded?", + inputKey: "healthState", + operator: "eq", + right: "degraded", + trueTarget: "alert", + falseTarget: "ok" + } + }, + { + id: "alert", + type: "action", + position: { x: 1080, y: 20 }, + data: { + type: "http_request", + label: "Send Alert", + method: "POST", + url: "https://example.com/webhooks/alerts", + body: { + service: "forgeflow", + status: "{{healthState}}", + payload: "{{healthPayload}}" + }, + saveAs: "alertResult" + } + }, + { + id: "ok", + type: "action", + position: { x: 1080, y: 140 }, + data: { + type: "set_variable", + label: "Mark Healthy", + key: "alertResult", + value: "no-alert-required" + } + } + ], + edges: [ + { id: "e1", source: "start", target: "check" }, + { id: "e2", source: "check", target: "classify" }, + { id: "e3", source: "classify", target: "branch" }, + { id: "e4", source: "branch", target: "alert" }, + { id: "e5", source: "branch", target: "ok" } + ], + execution: executionDefaults + } + }, { id: "web-form-submit", name: "Web Form Submit", diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index 154db19..7c34e06 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -60,6 +60,13 @@ Base URL (local): `http://localhost:8080` | POST | `/api/autopilot/plan` | `workflows:write` | Generate workflow draft definition from natural-language prompt | | POST | `/api/workflows/from-template` | `workflows:write` | Create workflow from template | +Built-in production starter template IDs: +- `invoice-intake-approval` +- `web-scrape-api-sync` +- `csv-cleanup-validation` +- `email-triage-ticket-create` +- `scheduled-health-check-alert` + ## 6. Document Intelligence and Orchestrator | Method | Path | Permission | Description | diff --git a/docs/DEMOS.md b/docs/DEMOS.md index c7969f3..e767361 100644 --- a/docs/DEMOS.md +++ b/docs/DEMOS.md @@ -77,6 +77,24 @@ Expected outcome: - Inserted nodes are linked in sequence with stable defaults. - The resulting flow is cleaner than raw event capture. +## Demo 6: Real-World Starter Pack +Goal: Prove production-leaning workflows can be launched in minutes. + +1. Open `Templates` and create workflows from: + - `Invoice Intake + Approval` + - `Web Scrape -> API Sync` + - `CSV Cleanup + Validation` + - `Email Triage -> Ticket Create` + - `Scheduled Health Check + Alert` +2. For each workflow, set integration URLs/credentials in inspector inputs. +3. Run each in `Test Run` mode with representative sample payloads. +4. Inspect branch behavior (approval paths, validation failures, degraded service alerts). + +Expected outcome: +- Teams can start from realistic baseline flows rather than empty canvas. +- Key automation patterns (ingest, transform, branch, sync, alert) are prewired. +- Contributors can extend templates without changing core runtime behavior. + ## Demo Assets - Template source: `apps/server/src/lib/templates.ts` - Node catalog: `apps/web/src/lib/nodeCatalog.ts` @@ -88,5 +106,6 @@ Expected outcome: - Demo 3: 4-5 minutes - Demo 4: 4-6 minutes - Demo 5: 4-6 minutes +- Demo 6: 8-10 minutes -Total: 23-30 minutes for a full product walkthrough. +Total: 31-40 minutes for a full product walkthrough. diff --git a/docs/README.md b/docs/README.md index 87c85d3..261ceb6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,6 +9,7 @@ This folder contains the long-form technical documentation for operators and con - [Deployment Guide](./DEPLOYMENT.md): local/prod deployment steps, hardening checklist, and Kubernetes starter manifests. - [Contributing Guide](./CONTRIBUTING.md): development setup, testing workflow, coding standards, and contribution process. - [Demo Guide](./DEMOS.md): repeatable walkthroughs for product capability demos. +- [Starter Templates](../apps/server/src/lib/templates.ts): built-in production workflow baselines. - [Contributor Onboarding](./ONBOARDING.md): fast path for first-time contributors. - [First Automation Tutorial](./tutorials/FIRST_AUTOMATION_10_MIN.md): a 10-minute path from setup to successful test run. - [Starter Workflow Example](./examples/workflows/first-automation.workflow.json): importable workflow file used in onboarding.