Automation Engine
The Automation Engine enables podcast hosts to create automated workflows triggered by events (booking confirmed, episode published) or time-based schedules (24 hours before recording). It features a visual step-based workflow builder (click a step type to add it; the layout is derived, not dragged), a magic tag system for dynamic content, and reliable execution via Cloudflare Workers and Queues.
Quick Links
| Document | Description |
|---|---|
| Architecture | System design, data flow, and component interactions |
| Queue Producers | Event emission and time-based scheduling (app-side) |
| Database Schema | Tables, enums, RLS policies, and relationships |
| API Reference | All automation API endpoints |
| Magic Tags | Dynamic content replacement system |
| Workflow Builder | Visual UI components and state management |
| Scheduler Worker | Cron-based job scheduler |
| Executor Worker | Queue-based action executor |
Architecture Overview
Key Concepts
Automation Rules
An automation rule defines what triggers the automation and what actions to perform. Each rule belongs to a podcast and contains:
- Trigger Type: The event or time-based condition (e.g.,
booking.confirmed,time.before_recording) - Trigger Config: Additional configuration (e.g., delay amount for time-based triggers)
- Workflow Data: JSON structure of nodes and connections from the visual builder
- Actions: One or more actions to execute (email, webhook, field update)
Execution Flow
- Event Emission: When a triggering event occurs (booking confirmed, episode published), the system calls
emitAutomationEvent() - Rule Matching: The scheduler finds all enabled rules matching the trigger type for that podcast
- Job Creation: For time-based triggers, jobs are scheduled; for event triggers, executions are created immediately
- Queue Processing: The executor worker processes executions from the queue
- Action Execution: Each action (email, webhook, field update) is executed with magic tag replacement
- Result Recording: Success/failure status and results are recorded in
automation_executions
Magic Tags
Magic tags like {guest_first_name} and {recording_date} are placeholders replaced with actual values at execution time. See Magic Tags for the complete reference.
File Structure
src/
├── api/routes/automations/
│ ├── index.ts # Route aggregator
│ ├── templates.ts # Template CRUD endpoints
│ ├── rules.ts # Rule CRUD + toggle + manual trigger
│ ├── executions.ts # Execution history + retry + stats
│ └── scheduled-jobs.ts # Scheduled job management
├── lib/
│ ├── automation/
│ │ ├── index.ts # Module exports (magic tags, scheduler)
│ │ ├── magic-tags.ts # Tag definitions and categories (29 tags)
│ │ ├── tag-parser.ts # Tag extraction and replacement
│ │ ├── events.ts # Event emission producers (import directly)
│ │ ├── scheduler.ts # Time-based job scheduling producers
│ │ └── __tests__/ # Unit tests (123 tests)
│ ├── stores/automation/
│ │ ├── index.ts # Store exports
│ │ ├── workflow.svelte.ts # Workflow state (nodes, connections)
│ │ ├── canvas.svelte.ts # Canvas state (pan, zoom)
│ │ └── history.svelte.ts # Undo/redo state
│ ├── components/automation/
│ │ ├── automation-list-item.svelte # List view row component
│ │ ├── view-switcher.svelte # Grid/list toggle
│ │ ├── TemplateEditorModal.svelte
│ │ ├── TestAutomationDialog.svelte # Manual trigger testing UI
│ │ ├── MagicTagInserter.svelte
│ │ └── workflow/
│ │ ├── WorkflowBuilder.svelte
│ │ ├── WorkflowCanvas.svelte
│ │ ├── WorkflowTopBar.svelte # Name/save controls
│ │ ├── NodePalette.svelte
│ │ ├── NodeConfigPanel.svelte
│ │ ├── NodeConnection.svelte
│ │ ├── nodes/
│ │ │ └── WorkflowNode.svelte
│ │ └── config/
│ │ ├── TriggerConfig.svelte
│ │ ├── ActionEmailConfig.svelte
│ │ ├── ActionWebhookConfig.svelte
│ │ ├── ActionFieldUpdateConfig.svelte
│ │ ├── ConditionConfig.svelte
│ │ └── DelayConfig.svelte
│ └── types/
│ └── automation.types.ts # All TypeScript types
├── routes/(app)/p/[slug]/
│ ├── automations/
│ │ ├── +page.svelte # Automations list
│ │ ├── +page.server.ts # Server-side data loading
│ │ ├── new/+page.svelte # Create automation
│ │ ├── [id]/+page.svelte # Edit automation
│ │ └── history/
│ │ ├── +page.svelte # Execution history view
│ │ └── +page.server.ts # History data loading
│ └── templates/
│ └── +page.svelte # Template management
workers/
├── automation-scheduler/
│ ├── wrangler.toml
│ └── src/index.ts # Cron + HTTP handlers
└── automation-executor/
├── wrangler.toml
└── src/
├── index.ts # Queue + HTTP handlers
├── types/
│ └── env.ts # Environment bindings
└── executors/
├── email.ts
├── webhook.ts
└── field-update.ts
supabase/migrations/
└── 20260107164436_automation_engine.sqlEnvironment Variables
Main Application
Required in wrangler.toml or environment:
| Variable | Description |
|---|---|
SUPABASE_URL | Supabase project URL |
SUPABASE_SERVICE_ROLE_KEY | Service role key for admin access |
Workers
Both workers require:
| Variable | Description |
|---|---|
HYPERDRIVE | Hyperdrive binding for database connection |
SUPABASE_URL | Supabase project URL |
SUPABASE_SERVICE_ROLE_KEY | Service role key |
RESEND_API_KEY | Resend API key (executor only) |
AUTOMATION_QUEUE | Queue binding (scheduler → executor) |
Testing
Run automation tests:
pnpm test src/lib/automation --runCurrent coverage: 123 tests across 4 test files:
src/lib/automation/__tests__/magic-tags.test.ts- Tag definitions and utilitiessrc/lib/automation/__tests__/tag-parser.test.ts- Tag extraction, validation, replacementsrc/lib/automation/__tests__/scheduler.test.ts- Time-based job scheduling (32 tests)src/lib/automation/__tests__/events.test.ts- Event emission and rule matching
Common Tasks
Adding a New Trigger Type
- Add to
AutomationTriggerTypeenum inautomation.types.ts - Add label in
TRIGGER_TYPE_LABELSconstant - Add to
TriggerConfig.svelteoptions - Add event emission in the appropriate route/worker
There is deliberately no per-trigger tag-scoping function. getMagicTagsForTrigger() used to fill that role but had no production caller, and its hardcoded claim that every booking.* trigger carries episode context stopped being true when general booking links shipped (#295 item 1). Tags that cannot resolve for a given trigger render empty via the zero-fill contract instead.
Adding a New Action Type
- Add to
AutomationActionTypeenum inautomation.types.ts - Add label in
ACTION_TYPE_LABELSconstant - Create config component in
workflow/config/ - Add to
NodeConfigPanel.svelterouting - Add to
NodePalette.sveltenode types - Create executor in
workers/automation-executor/src/executors/ - Add to executor worker action routing
Adding a New Magic Tag
- Add definition to
MAGIC_TAGSarray inmagic-tags.ts - Add to appropriate category
- Add context population in
tag-parser.ts→buildMagicTagContext() - Add to
events.ts→buildFullContext()if from new data source - Add test case in
magic-tags.test.ts
Version History
| Date | Change | Author |
|---|---|---|
| 2026-01-07 | Initial automation engine implementation | Development Team |
| 2026-01-13 | Documentation audit - file structure updated, new components documented | Development Team |
| 2026-01-16 | Documentation update - corrected test count (123 tests), updated tag count (29 tags) | Claude Code |