Brooke / roles.sales — Campaign & Sequence System Design
internal prototype · canonical JSON + Dreamborn Forge HTML
internal generated
design_doc · markdown

Brooke / roles.sales — Campaign & Sequence System Design

Brooke / roles.sales — Campaign & Sequence System Design Date: 2026 04 29 Status: Approved for planning Overview A campaign and sequence system for the B2BEA / RedKey sales motion. Contacts are enrolled in campaigns by the roles.sales agent (Brooke) after Justin gates the initial routing. Each campaign has its own sequence of timed touchpoints (email + Linke...

Brooke / roles.sales — Campaign & Sequence System Design

Date: 2026-04-29 Status: Approved for planning

---

Overview

A campaign and sequence system for the B2BEA / RedKey sales motion. Contacts are enrolled in campaigns by the roles.sales agent (Brooke) after Justin gates the initial routing. Each campaign has its own sequence of timed touchpoints (email + LinkedIn). When a contact exits a campaign, the campaign's on_exit map determines the next campaign automatically — Justin only gates the first handoff.

---

The Full Pipeline

`` Tara (roles.bdr) finds prospect → books meeting → meeting_booked task dispatched to roles.exec (Justin) → Justin reviews handoff, specifies campaign(s): "vendor_membership_close" → task dispatched to roles.sales → roles.sales enrolls contact in specified campaign(s), step 1 → Engine fires execute_sequence_step tasks as next_send_at arrives → roles.sales drafts each touch → staged_drafts → Justin approves → sends → reply received → roles.sales classifies → continue or exit → exit: on_exit map routes to next campaign automatically ``

---

BDR Campaigns (Tara / roles.bdr)

| Slug | Type | Client | Purpose | |---|---|---|---| | b2bea_world | event | b2bea | Outreach for B2B eCommerce World event | | b2bea_membership | membership | b2bea | Vendor membership outreach | | dreamborn | platform | dreamborn | DreamBorn platform outreach |

Sales Campaigns (Brooke / roles.sales)

| Slug | Type | Client | Purpose | |---|---|---|---| | b2bea_membership_close | membership | b2bea | Post-meeting close sequence |

Customer Success Campaigns

| Slug | Type | Client | Purpose | |---|---|---|---| | b2bea_membership_cs | onboarding | b2bea | Post-close member onboarding |

on_exit Chains

`` b2bea_membership (BDR) → meeting → Justin gates → b2bea_membership_close b2bea_membership_close → converted → b2bea_membership_cs b2bea_membership_close → no_engagement → null (close the loop) b2bea_membership_close → rejected → null (close the loop) b2bea_world (BDR) → registered → null (no sales sequence for event) dreamborn (BDR) → meeting → Justin gates → no sales campaign yet ``

---

`campaigns` table

``sql id uuid primary key slug text unique not null -- e.g. 'b2bea_membership_close' name text not null client_id text not null type text not null -- event | membership | platform | onboarding owner_role text not null -- roles.bdr | roles.sales | roles.cs status text not null default 'active' -- active | paused | archived on_exit jsonb not null default '{}' -- shape: { "converted": "<slug|null>", "no_engagement": "<slug|null>", "rejected": "<slug|null>" } created_at timestamptz not null default now() ``

`campaign_sequences` table

Each row is one step in a campaign's sequence.

``sql id uuid primary key campaign_id uuid not null references campaigns(id) step_number int not null -- 1-based, per campaign delay_days int not null -- days from enrollment (step 1 = day 0) channel text not null -- email | linkedin content_type text not null -- follow_up | proof | boss_arming | campaign_visibility -- personal_visibility | marketing_relief | close | exit template_instructions text not null -- what to write — not the copy itself unique (campaign_id, step_number) ``

`campaign_contacts` table

One row per contact per campaign enrollment. Each enrollment starts fresh at step 1.

``sql id uuid primary key contact_id text not null -- Attio contact record ID campaign_id uuid not null references campaigns(id) client_id text not null status text not null default 'active' -- active | converted | rejected | timed_out current_step int not null default 1 next_send_at timestamptz -- when to fire the next step enrolled_at timestamptz not null default now() exited_at timestamptz exit_reason text goal text -- awareness | pipeline | credibility | marketing_relief notes text -- from Justin's exec gate routing decision -- partial unique: only one ACTIVE enrollment per contact per campaign -- exited enrollments are preserved as history and do not block re-enrollment -- create unique index campaign_contacts_active_uniq on campaign_contacts (contact_id, campaign_id) where status = 'active' ``

`sales_send_queue` table

Individual outbound items queued for execution.

``sql id uuid primary key client_id text not null contact_id text not null campaign_id uuid not null references campaigns(id) step_number int not null channel text not null -- email | linkedin staged_draft_id uuid -- FK to staged_drafts once drafted scheduled_at timestamptz not null sent_at timestamptz status text not null default 'pending' -- pending | drafted | approved | sent | failed error text created_at timestamptz not null default now() ``

---

roles.sales Task Types

| Task type | Trigger | What roles.sales does | |---|---|---| | enroll_contact | Justin's exec gate approval | Creates campaign_contacts row(s), sets step 1, calculates first next_send_at | | execute_sequence_step | Engine when next_send_at arrives | Drafts the touch for current step, writes to staged_drafts, advances current_step, sets next next_send_at | | process_reply | Inbound reply received (deferred — reply detection mechanism TBD) | Classifies intent, updates Attio activity, continues sequence or triggers exit | | exit_contact | Exit condition met | Sets campaign_contacts.status, follows on_exit map to enroll in next campaign |

---