Sequence and task models

SequenceTemplate

Table sequence_templates.

Field Type Notes

subscriptionId

String @db.Uuid

name

String

goal, description

String?

Also fed to the AI writer

callCampaignDefault, emailCampaignDefault, smsCampaignDefault

Boolean

Marks this as the default template for that campaign kind

type

SequenceType

onboarding, re_engagement, not_connected_outreach

isActive

Boolean

default true

Index: subscriptionId. Relations: steps, contactSequences.

SequenceTemplateStep

Table sequence_template_steps.

Field Type Notes

templateId

String @db.Uuid

onDelete: Cascade

stepIndex

Int

Unique per template

channel

SequenceStepChannel

email, call_task, sms, wait, data_gate, crm_task, crm_event

delayHours

Int

The delay amount for wait steps

delayUnit

String

"hours" or "minutes"; only meaningful for wait

timeoutHours

Int?

How long a rep has on a call_task

name, description, instructions, expectedOutcome

String?

Human and AI context

emailTone

String?

warm, direct, social_proof, urgency, breakup

emailSubjectHint

String?

Hint to the AI writer; also used as the subject fallback

smsTemplate

String?

isAiGenerated

Boolean

default true

fixedEmailId

String? @db.Uuid

A fixed EmailVariation when not AI-generated

Data gate fields

Field Type Notes

gateBigqueryView

String?

e.g. outreach_app.contacts; must expose a hubspotcontactid column

gateConditions

Json?

[{ field, operator, value }] — the current shape

gateMatchMode

String

"all" (AND) or "any" (OR); default "all"

gateField, gateOperator, gateValue

String?

Deprecated single-condition form, still read

trueBranchStepIndex, falseBranchStepIndex

Int?

Branch targets

gateRetryDelayHours

Int?

When set, a failure waits and re-checks instead of branching

gateMaxRetries

Int?

Cap on re-checks; null = unbounded

CRM fields

Field Type Notes

crmTaskType

String?

call, email, follow_up

crmTaskDescription

String?

Task body

crmTaskDueHours

Int?

Due-date offset from execution time

extraConfigs

Json?

For crm_event: { event_type, body }, validated by CrmEventConfigSchema

Unique: (templateId, stepIndex). Index: templateId.

ContactSequence

Table contact_sequences. One contact’s enrollment.

Field Type Notes

subscriptionId, contactId, templateId

String @db.Uuid

status

SequenceStatus

default pending

currentStepIndex

Int

default 0

nextStepAt

DateTime? @db.Timestamptz(6)

executionId

String?

The Inngest run id driving this enrollment; shared by all its step logs

campaignTargetId, emailCampaignTargetId, campaignId

String? @db.Uuid

What triggered the enrollment

startedAt, completedAt, abandonedAt

DateTime? @db.Timestamptz(6)

Indexes: contactId, (status, nextStepAt) for the scheduler, executionId, subscriptionId, campaignId, campaignTargetId, emailCampaignTargetId.

"One active sequence per contact" is enforced in application code (SequenceExecutionService.enrollContact), not by a unique constraint. A (contactId, status) unique index would wrongly prevent a contact from having several completed or paused enrollments.

ContactSequenceStep

Table contact_sequence_steps. One row per executed step.

Field Type Notes

sequenceId

String @db.Uuid

templateStepId

String? @db.Uuid

onDelete: SetNull — editing a template severs the link but keeps the log

executionId

String?

Mirrors ContactSequence.executionId

status

String

pending, executed, skipped, failed

gateRetryCount

Int

Re-check count for gate steps

callId, emailId, followUpTaskId, activityId

String? @db.Uuid

Whatever the step produced

executedAt

DateTime? @db.Timestamptz(6)

outcome

String?

replied, opened, connected, no_answer, no_reply, or a channel-specific string such as email:<id>

response

Json?

Full execution payload — provider ids, CRM event body, gate evaluation. One row per execution, never overwritten

Indexes: sequenceId, executionId, templateStepId, callId, emailId, followUpTaskId, activityId.

SalesRep

Table sales_reps. Workspace-scoped human seller identity.

Field Type Notes

subscriptionId

String @db.Uuid

profileId

String? @db.Uuid

Optional — a rep can exist before having a login

name, email

String

hubspotOwnerId

String?

Assigns tasks and contacts in HubSpot

nooksUserId

String?

Attributes Nooks calls and assigns sequences

activeListId

String?

HubSpot active list backing the rep’s sequences

hubspotCallSegmentId

String?

HubSpot call segment for call attribution

isActive

Boolean

default true

Unique: (subscriptionId, email). Indexes: subscriptionId, profileId, hubspotOwnerId, nooksUserId.

Relations: subscription, profile, followUpTasks, calls.

FollowUpTask

Table follow_up_tasks.

Field Type Notes

subscriptionId

String @db.Uuid

salesRepId

String @db.Uuid

Assignee

contactId

String @db.Uuid

The lead

campaignTargetId, contactSequenceId

String? @db.Uuid

What created the task

type

FollowUpTaskType

call (default), email, sequence_enrollment

status

FollowUpTaskStatus

pending (default), in_progress, completed, skipped, failed

hubspotTaskId, nooksTaskId, nooksSequenceStateId

String?

Nullable — a workspace may run only one integration

hubspotSyncStatus, nooksSyncStatus

String?

pending, synced, failed

escalationStage

Int

0 → 1 → 2 → 3 = failed

inngestRunId

String?

Stored so a completed task can cancel its own pending escalation

lastEscalatedAt

DateTime?

dueAt, completedAt

DateTime? @db.Timestamptz(6)

lastHubspotSyncAt, lastNooksSyncAt

DateTime? @db.Timestamptz(6)

notes

String?

Indexes: subscriptionId, salesRepId, contactId, campaignTargetId, status, dueAt, hubspotTaskId, nooksTaskId.

Relations: subscription, salesRep, contact, campaignTarget, contactSequence, activities, contactSequenceSteps.