Skip to content

Drip automations / sequences (visual workflow editor + runner) #77

Description

@JuansesDev

Problem

SendDock today supports three send patterns: transactional (single /send), batch with per-recipient variables, and broadcast (one email to a segment). What it does not support is the most important pattern in modern email marketing: automated sequences triggered by subscriber events.

Examples that are currently impossible:

  • Welcome series: 4 emails over 14 days after signup
  • Onboarding course: 1 lesson per day for 7 days
  • Re-engagement: if no opens in 60 days, send "we miss you" → wait 7 days → if still no open, unsubscribe
  • Abandoned-form / abandoned-purchase: trigger via API when an external event fires
  • Post-event follow-up: 3 emails after webinar attendance

This is the single feature most cited when reviewers compare email tools. Mailchimp Customer Journeys, ConvertKit Visual Automations, EmailOctopus Workflows, Mautic Campaigns — all platforms competing in marketing automation have this. Without it, SendDock loses every "marketing-platform" evaluation by default.

This is the largest single piece of work in the roadmap. It deserves dedicated scoping, not a "later" bucket.

Proposal

A visual workflow editor plus a server-side runner that walks subscribers through a directed graph of steps.

Data model

CREATE TABLE automations (
    id UUID PRIMARY KEY,
    project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    name VARCHAR(255) NOT NULL,
    status VARCHAR(20) NOT NULL DEFAULT 'draft',   -- draft | active | paused
    trigger JSONB NOT NULL,                         -- { type: 'subscriber.created' | 'tag.added' | 'custom_field.changed' | 'api', config: {...} }
    graph JSONB NOT NULL,                           -- nodes + edges
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE automation_runs (
    id UUID PRIMARY KEY,
    automation_id UUID NOT NULL REFERENCES automations(id) ON DELETE CASCADE,
    subscriber_id UUID NOT NULL REFERENCES subscribers(id) ON DELETE CASCADE,
    current_node_id VARCHAR(64) NOT NULL,
    state VARCHAR(20) NOT NULL,                     -- running | waiting | completed | exited | failed
    next_run_at TIMESTAMPTZ,                        -- when state=waiting, queue picks it up at this time
    history JSONB NOT NULL DEFAULT '[]',
    started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    completed_at TIMESTAMPTZ,
    UNIQUE(automation_id, subscriber_id)            -- a subscriber is in an automation at most once
);

CREATE INDEX idx_automation_runs_next ON automation_runs(state, next_run_at) WHERE state = 'waiting';

Triggers (entry points)

  • subscriber.created — when a sub is added (via form, API, import, manual)
  • tag.added — when a specific tag is applied
  • tag.removed
  • custom_field.changed — when a field matches a condition (plan_tier = pro)
  • api — external trigger via POST /api/v1/projects/{id}/automations/{aid}/trigger { email: ... } (this is what enables abandoned-cart, webinar-attended, etc.)
  • segment.entered (later phase, requires segments from Subscriber tags and segmentation #40)

Node types

Node Behavior
Send email Send a specific template, using subscriber's variables + custom fields
Wait Pause for N minutes / hours / days / weeks
Wait until time of day Pause until next occurrence of HH:MM (subscriber's timezone if custom.timezone exists, else project default)
Branch (if/else) Split on: opened last email, clicked last email, has tag, custom field matches, was active in last N days
Add tag Apply a tag to the subscriber
Remove tag Remove a tag
Set custom field Update a custom field value
Exit Remove subscriber from this automation
Goal Marks a goal node; subscribers reaching it count toward conversion (for analytics)

Runner

  • Background worker polls automation_runs WHERE state = 'waiting' AND next_run_at <= NOW(), advances each one node-by-node until it hits a wait/branch/exit
  • Uses Redis for distributed locks on a run (multi-worker safe)
  • A subscriber can be in multiple distinct automations simultaneously, but at most once in the same automation
  • Subscriber's status = unsubscribed or status = bounced immediately exits all active runs

UI

  • New section Project → Automations with list of automations and their stats (active subs, completed, conversion rate to goal)
  • Visual editor using React Flow / Vue Flow style (drag-and-drop nodes, connect edges, configure each node in a side panel)
  • Activate / Pause toggle per automation
  • Run history per subscriber (see which node they're on, when they entered, what happened)

Why this is a multi-version effort

This is not a v0.7 feature. Realistic scoping:

  • Phase 1 (v0.9?): Linear sequences only (trigger → send → wait → send → wait → send → exit), no branches, single trigger type (subscriber.created). Ships welcome series and onboarding courses.
  • Phase 2 (v1.0?): Branches, all trigger types, all node types, full editor.
  • Phase 3 (v1.x): Goal tracking, analytics dashboard per automation, A/B branches.

The phasing matters because Phase 1 alone covers ~60% of demand and is shippable in 4-6 weeks; Phase 2 takes longer.

Acceptance criteria (Phase 1)

  • automations and automation_runs tables migrated
  • subscriber.created trigger functional
  • Node types: send email, wait (duration), exit
  • Visual editor for linear flows
  • Activate / pause toggle
  • Subscriber automatically exits if they unsubscribe or bounce
  • API to inspect runs for a subscriber

Acceptance criteria (Phase 2)

  • Remaining triggers (tag, custom field, api)
  • Branch node with all conditions listed above
  • All remaining node types
  • Per-automation analytics: entered / completed / exited counts, conversion to goal

Tier

Pro — automation is the headline Pro feature for marketing-platform positioning. Self-host Pro license unlocks it; included by default in Cloud Starter and above.

Blocked by

Metadata

Metadata

Assignees

No one assigned

    Labels

    backendenhancementNew feature or requestfrontendproPro-tier feature (gated by license)roadmapPlanned for a future release

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions