Template: customer onboarding (Operations)
Document information
- Canonical URL:
/docs/12_workflows/40_template-customer-onboarding - Version:
2026-10-02 - Tags:
operations,processflow,template,guides
Copyable ProcessFlow pattern for a customer onboarding journey that feeds My Work. This is documentation for tenant admins and Trace — it does not insert demo requests into employee queues. Clone the steps in ProcessFlow, connect real integrations, then run with real or sandbox input you choose.
Outcome
An employee sees a My Work card, understands why they are involved, Approves a real gate, and the process writes back to CRM. Failures open an Exception card with Retry when input was stored.
Process shape
| Step | Kind | Operations write |
|---|---|---|
| 1. Intake | Automatic | updateProgress — journey_beat: received |
| 2. Enrich from CRM | Automatic | updateProgress — checks + system_refs |
| 3. AI document skim (optional) | AI-assisted | updateProgress with ai_summary |
| 4. Credit / risk decision | Human approval | openApproval with human_request_id |
| 5. Activate in CRM | Automatic | updateProgress — journey_beat: systems |
| 6. Failure handler | Exception | openException |
| 7. Finish | Automatic | complete |
Set process category to business.
Stable identity
const external_id = `crm-onboarding-${customer_id}`;
Reuse the same external_id on every upsert so My Work updates one card.
Step sketches
Progress after enrich
await tf.operations.updateProgress({
external_id,
subject: `Onboard ${customer_name}`,
party: customer_name,
process_name: "Customer onboarding",
status: "open",
attention: "info",
journey_beat: "in_process",
journey_stage_label: "Documents checked",
checks: [
{ label: "Company registration", state: "verified" },
{ label: "Credit pack", state: "pending" }
],
system_refs: [{ system: "CRM", label: "Account", external_ref: customer_id }]
});
Open approval (after human-input pause)
await tf.operations.openApproval({
external_id,
subject: `Approve onboarding for ${customer_name}`,
party: customer_name,
process_name: "Customer onboarding",
human_request_id: String(pending_human_request_id),
why_visible: "You own customer activation for this region.",
consequence: "Approving activates the account in CRM and continues provisioning.",
required_action: "Confirm credit pack and approve or reject.",
journey_beat: "in_process",
journey_stage_label: "Activation decision",
actor_hint: "person"
});
Exception
await tf.operations.openException({
external_id,
subject: `Onboarding blocked for ${customer_name}`,
process_name: "Customer onboarding",
required_action: "Fix the CRM write error, then Retry or Pass to Delivery.",
why_visible: "Activation failed in CRM after approval.",
journey_beat: "systems"
});
Complete
await tf.operations.complete({
external_id,
subject: `Onboarded ${customer_name}`,
process_name: "Customer onboarding"
});
Verify before go-live
tf.operations.validate({ … attention: "approval", human_request_id: "…" })→approve_buttons_would_show: true- Run once with a test account; open My Work as the intended owner
- Confirm Approve resumes the process and CRM updates
- Force a failure path and confirm Exception copy (no raw stack on the primary panel)