Automations
Build cross-module workflows with the Visual Automation Builder — connect CRM, Finance, Projects, Support, and Recruiting with zero code.
Automations
The Automations module is Workestra's cross-module workflow engine. It lets you define if-this-then-that flows that span any combination of modules — trigger on a CRM deal, create a Finance invoice, notify a Support agent, and open a Project, all in one workflow.
This is not the same as Quick Rules (Settings → Quick Rules). Quick Rules are pre-configured on/off toggles. The Automations module is the full visual workflow builder where you can create custom multi-step flows.
Enabling Automations
The Visual Builder ships feature-flagged off. An admin enables it deployment-wide by setting two environment variables:
NEXT_PUBLIC_AUTOMATIONS_ENABLED=true
AUTOMATIONS_ENABLED=trueEffects of the flag:
| State | Sidebar entry | /automations* routes | Event dispatch |
|---|---|---|---|
| Off (default) | Hidden | Render a 404 | No-op — events don't fire any workflows |
| On | Visible | Render normally | Workflows fire on matching domain events |
The cron sweep always processes any already-queued workflow_executions rows, so a workflow that was mid-run when the flag flipped off still completes.
Where to Find It
Automations is a top-level module in the sidebar — not buried under Settings.
| Location | Path | Description |
|---|---|---|
| Workflows | /automations | List of all workspace workflows |
| Visual Editor | /automations/new | Create a new workflow |
| Edit Workflow | /automations/[id] | Edit an existing workflow |
| Templates | /automations/templates | Start from a pre-built template |
| Runs | /automations/runs | Cross-workflow execution history |
| Quick Rules | /settings/automations | Toggle pre-seeded simple rules (legacy surface) |
Core Concepts
Workflow
A workflow is a saved automation with three parts:
Trigger → (optional Conditions) → Actions[]| Component | What it is |
|---|---|
| Trigger | The event that starts the workflow |
| Conditions | Optional filters — the workflow only runs if all conditions are met |
| Actions | The steps that execute in order when triggered |
Status
| Status | Meaning |
|---|---|
| Draft | Saved but not active — won't fire on events |
| Active | Running — fires on every matching trigger |
| Paused | Temporarily stopped — can be re-activated |
| Archived | Hidden from the list — no longer fires |
Execution
When an active workflow matches a trigger, Workestra:
- Creates a
workflow_executionsrow in pending status. - Runs the actions in order, recording each step's outcome.
- Flips the execution to completed (or failed / paused depending on the workflow's error-handling strategy).
Runs are visible at /automations/runs with status, duration, and error details.
Available Triggers
Triggers are grouped by module. Wired triggers fire automatically when the corresponding domain event happens. Manual triggers fire only when you hit "Run now" or when the daily cron sweeps a matching scheduled workflow.
CRM
| Trigger | Fires When | Auto-fires? |
|---|---|---|
| Deal Created | A new deal is created | ✓ |
| Deal Stage Changes | An opportunity moves to a new pipeline stage | ✓ |
| Deal Closed Won | A deal is marked as Closed Won | ✓ |
| Contact Created | A new contact is added | ✓ |
Projects
| Trigger | Fires When | Auto-fires? |
|---|---|---|
| Task Status Changes | A task's status is updated | ✓ |
| Task Completed | A task is marked complete | ✓ |
Support
| Trigger | Fires When | Auto-fires? |
|---|---|---|
| Ticket Created | A new support ticket is opened | ✓ |
| Ticket Escalated | A ticket's priority is escalated | ✓ |
| Ticket Resolved | A ticket is marked resolved | ✓ |
Finance
| Trigger | Fires When | Auto-fires? |
|---|---|---|
| Invoice Paid | An invoice flips to paid status | ✓ |
| Invoice Refunded | A refund is processed | Manual only |
Recruiting
| Trigger | Fires When | Auto-fires? |
|---|---|---|
| Candidate Applied | A new application is submitted | ✓ |
| Candidate Stage Changes | A candidate moves to a different stage | ✓ |
Platform
| Trigger | Fires When | Auto-fires? |
|---|---|---|
| Email Sent | Any email is sent via Workestra | Manual only |
| Scheduled (Cron) | On a recurring schedule | Daily cron sweep |
| Webhook Received | A POST request is received on the workflow's URL | Manual only |
Available Actions
Actions execute in order. Each routes through a shared platform service — emails via sendEmail, notifications via notificationService, webhooks with HMAC signing, audit events via the audit log.
| Action | Module | What it does |
|---|---|---|
| Send Template Email | Platform | Send an email to a recipient via Resend |
| Send In-App Notification | Platform | Push a notification into a user's inbox |
| Call Webhook | Platform | POST a signed payload to an external URL (HMAC via WEBHOOK_SIGNING_SECRET) |
| Log Event | Platform | Write a custom event to the audit log |
| Wait / Delay | Platform | Pause for a set duration before the next action |
| Create Deal | CRM | Insert a new deal record |
| Update Deal | CRM | Update whitelisted fields (title, stage, status, value, currency, probability, notes) |
| Update Win Probability | CRM | Set the probability field on an opportunity (0–100) |
| Assign Owner | CRM / Projects / Support | Reassign the owner of a deal, contact, ticket, task, issue, or project |
| Flag as Stale | CRM | Record a stale_flagged event in the audit log |
| Create Ticket | Support | Open a new support ticket |
| Create Project | Projects | Open a new project |
| Close Sprint Cycle | Projects | Close the active sprint cycle |
| Create Invoice | Finance | Insert a draft invoice |
| Create Quotation | Finance | Insert a draft quotation |
| Notify ATS | Recruiting | Send a recruiting-team notification |
| Generate Document | Platform | Reserved — pending the shared document service |
Creating a Workflow
From Scratch
- Navigate to Automations in the sidebar.
- Click New Workflow.
- Give the workflow a name and optional description.
- Select a Trigger from the dropdown (searchable, grouped by module).
- Add one or more Actions from the left palette. Drag to reorder.
- Set a per-action Delay if you want a pause before it runs.
- Click Save — the workflow is saved as a Draft.
- Click Activate to make it live.
From a Template
- Navigate to Automations → Templates.
- Browse templates grouped by category (Sales, Marketing, Customer Success, Operations).
- Click Use Template — a real workflow is created in your workspace and the editor opens on it.
- Review and adjust the trigger and actions.
- Click Save then Activate.
Default Templates
Every workspace sees the same 20 system templates in /automations/templates. Pick one, click Use Template, the workflow is copied into your workspace as an editable draft. Every copy is yours to tweak — the original system template stays pristine.
Sales
| Template | What it does |
|---|---|
| Lead Welcome Email ★ | Sends a welcome email when a new contact is created |
| Deal Created → Slack Alert | Posts a signed webhook when a new deal lands |
| Deal Stage → Negotiation Nudge ★ | Notifies the sales manager and bumps win probability to 60% |
| Deal Won → Thank-You Email ★ | Sends a thank-you email and logs the win |
| Deal Won → Auto-Generate Invoice | Drafts an invoice pre-filled from the deal |
Customer Success
| Template | What it does |
|---|---|
| Customer Onboarding Kickoff ★ | Sends welcome email, assigns a CSM, logs the onboarding |
| Ticket Created → Auto-Acknowledge ★ | Sends an acknowledgement the moment a ticket opens |
| Ticket Resolved → CSAT Survey | Sends a satisfaction survey on resolution |
| New Contact → CSM Notification | Pings a CSM when a new contact is created |
Operations
| Template | What it does |
|---|---|
| Deal Won → Kickoff Project ★ | Opens a kickoff project and assigns a lead |
| Ticket Escalation → Ops PagerDuty | Notifies ops, logs escalation, pings a paging webhook |
| Task Completed → Audit Log | Writes an audit event every time a task is completed |
| Candidate Applied → Auto-Confirmation | Confirms the candidate and notifies the recruiter |
| Candidate Stage → Recruiter Alert | Pings recruiting when a candidate changes stage |
Marketing
| Template | What it does |
|---|---|
| Invoice Paid → Thank-You Email ★ | Sends a thank-you and logs the payment |
| Invoice Paid → Accounting Webhook | Forwards a signed webhook to an external accounting system |
| Invoice Refunded → Apology Email | Sends an apology and logs the refund |
Custom / Platform
| Template | What it does |
|---|---|
| Daily Digest (Scheduled) | Fires once per day and writes a digest event |
| Stale Deal Alert (Scheduled) | Flags stale deals daily and notifies the sales manager |
| External Webhook → Create Ticket | Opens a ticket from an incoming signed webhook |
★ = featured. Featured templates show at the top of the gallery.
Publishing your own templates
Workspace admins can publish custom workflows as templates via TemplatesService.publish(). They appear in the same gallery — scoped to your workspace only — next to the system defaults, marked with a Workspace badge. Use this to share recurring patterns with the rest of your team without duplicating each workflow manually.
Usage counts
Each time someone clicks Use Template for a given template, its usage_count bumps by 1. The gallery surfaces the count under each card so you can see which templates are most popular.
How system templates are managed. System defaults live in the workflow_templates table with workspace_id IS NULL. They're seeded by a Supabase migration, not by hardcoded TypeScript — so admins can update the catalog without a code deploy. The TypeScript side keeps a SYSTEM_TEMPLATE_SLUGS registry and a drift-check unit test so the two never diverge.
Run History
The Runs tab (/automations/runs) shows every execution in the workspace.
| Column | Meaning |
|---|---|
| Status icon | Pending / Running / Completed / Failed / Cancelled / Paused |
| Workflow | Name (links to the editor) |
| Started | Relative time |
| Duration | Total run time (ms → s → m → h) |
| Error | Inline error message when the run failed |
Filter by status using the tabs at the top. Click a row to jump to the workflow it came from.
Error Handling
Each workflow has an error-handling strategy set in the right-hand Workflow Settings panel:
| Strategy | Behaviour when an action fails |
|---|---|
| Continue on error (default) | Skip the failed action, keep executing subsequent ones |
| Retry on error | Retry the action up to 3× with backoff, then continue |
| Stop on error | Halt the run, mark execution failed |
Failures are captured in completed_actions[].error on the execution row, and surfaced inline on /automations/runs.
Security
- Workspace isolation — every workflow and execution is scoped by
workspace_idvia RLS. The stats view usessecurity_invoker=trueso it honours RLS of the base tables. - Role-gated deletes — only workspace owners and admins can delete workflows.
- Signed webhooks —
Call Webhookactions sign the payload with HMAC-SHA256 usingWEBHOOK_SIGNING_SECRET. The receiving server verifies via theX-Workestra-Signatureheader. - Defense-in-depth on the JSONB shape — CHECK constraints on
workflows.trigger/.actions/.conditionsreject malformed rows at the DB boundary. Application writes validate with Zod before the insert. - Executor whitelisting —
Update Dealonly accepts a fixed list of columns, so a workflow author cannot rewrite arbitrary fields.
Difference: Quick Rules vs. Workflows
| Feature | Quick Rules (/settings/automations) | Visual Workflows (/automations) |
|---|---|---|
| Complexity | Single trigger → single action | Multi-step, multi-action |
| Editing | Toggle on/off only | Full visual editor with React Flow canvas |
| Conditions | Not supported | Full condition logic |
| Scope | Pre-defined system rules | Fully custom |
| Storage | automation_rules table | workflows + workflow_executions tables |
| Best for | Common platform automations | Custom business logic |
Use Quick Rules for common patterns that ship pre-configured. Use Workflows for any custom logic specific to your business.
Architecture (For Developers)
Layers
UX: /automations/* pages → Thin shells over the module
Module: src/modules/automations/* → Services, hooks, schemas, components, events
Dispatch: src/modules/automations/events/dispatcher.ts → fireWorkflowEvent
Runner: src/modules/automations/events/runner.ts → runExecution + sweep
Cron: /api/cron/workflow-runner → Daily sweep of pending executions
Data: Supabase: workflows + workflow_executions + workflow_run_stats viewKey files
| File | Purpose |
|---|---|
src/modules/automations/lib/workflow-constants.ts | Single source of truth for the trigger + action catalog |
src/modules/automations/lib/trigger-mapper.ts | UI key ↔ stored trigger shape (handles legacy rows) |
src/modules/automations/lib/action-mapper.ts | UI key ↔ canonical action type |
src/modules/automations/lib/workflow-to-graph.ts | Stored workflow ↔ React Flow nodes/edges |
src/modules/automations/lib/workflow-templates.ts | Built-in template catalog |
src/modules/automations/lib/feature-flag.ts | isAutomationsEnabledClient / isAutomationsEnabledServer |
src/modules/automations/schemas/workflow-schema.ts | Zod schemas for reads/writes |
src/modules/automations/services/ | Workflows, executions, stats data access |
src/modules/automations/hooks/ | TanStack Query hooks (list / one / stats / executions + mutations) |
src/modules/automations/components/ | Canvas, palette, config panel, editor, list row, stats strip |
src/modules/automations/events/dispatcher.ts | fireWorkflowEvent, triggerWorkflowManually |
src/modules/automations/events/runner.ts | runExecution, sweepPendingExecutions |
src/modules/automations/events/executors.ts | 17 action executors wired to platform services |
src/modules/automations/events/dispatch-action.ts | Server action wrapper for client callers |
src/app/(dashboard)/automations/ | Pages (list, [id], templates, runs, layout gate) |
src/app/api/cron/workflow-runner/route.ts | Daily cron sweep |
supabase/migrations/20260424200000_automations_visual_builder.sql | Base tables |
supabase/migrations/20260424210000_automations_security_hardening.sql | Security hardening |
Supabase objects
| Object | Purpose |
|---|---|
workflows | Workflow definitions (trigger + conditions + actions as JSONB) |
workflow_executions | Immutable execution history + audit log |
workflow_run_stats | View with security_invoker=true — powers the 4-col stats strip |
seed_workspace_workflows(ws_id) | RPC — seeds the default onboarding workflow for new workspaces |
automation_rules | Separate system — Quick Rules (legacy surface) |
How domain events fire workflows
The dispatcher (fireWorkflowEvent) is called from the following paths. Each call is fire-and-forget and wrapped in try/catch — workflow dispatch never breaks the underlying mutation.
| Trigger key | Called from |
|---|---|
deal_created | DealService.createDeal |
deal_stage_change | DealService.moveDealToStage |
deal_closed_won | Same path when stage === "closed_won" |
contact_created | ContactService.createContact |
task_status_change | TaskService.updateIssueStatus |
task_completed | Same path when status === "done" |
ticket_created | TicketService.createTicket |
ticket_escalated | TicketService.escalateTicket |
ticket_resolved | TicketService.resolveTicket |
invoice_paid | PaymentService.refreshInvoicePaidAmount (server-only) |
candidate_applied | ApplicationService.createApplication |
candidate_stage_change | ApplicationService.updateApplicationStatus |
The in-process runner is called immediately after a dispatch for low latency. The daily cron at /api/cron/workflow-runner is the backstop for executions that crashed, were delayed, or need to resume after a Wait / Delay action.
Next Steps
- CRM Automations — CRM-specific Quick Rules
- Projects Automations — Project-level automation patterns
- API Reference — Trigger workflows via webhook from external systems