# Task 019 — Sequences & Smart Outreach Engine

## Status: Implemented

## Overview

Transforms the platform from one-time email campaigns into multi-step B2B outreach (Sequences), while preserving Campaigns as broadcast sends.

## Key modules

| Module | Path |
|--------|------|
| Sequence models | `src/server/models/sequence*.ts`, `suppression-list.model.ts` |
| Sequence service | `src/server/services/sequence.service.ts` |
| Execution engine | `src/server/services/sequence-execution.service.ts` |
| Reply handling | `src/server/services/sequence-reply.service.ts` |
| Suppression | `src/server/services/suppression.service.ts` |
| UI | `/sequences`, `/sequences/new`, `/sequences/[id]`, `/sequences/[id]/edit` — `layout.tsx` AppShell |
| Cron | `POST /api/cron/run-sequences`, `POST /api/cron/sync-mailboxes` + `CronRunLog` |
| Admin cron | `/settings/cron`, `GET /api/admin/cron/logs`, manual trigger APIs |

## Segment member resolution

Sequence and campaign recipient generation use **`getAllDedupedSegmentMembers`** → **`dedupeSegmentMembersBatched`** / **`segment-dedup-accumulator`**:

- Channel filtering (`targetChannel=email`)
- `emailStatuses` multi-select from segment filters
- Email deduplication (normalize + priority winner)
- Suppression list check
- Duplicate enrollment prevention per active sequence

## Batch segment dedup (implemented)

`src/lib/segment-dedup-accumulator.ts` is wired into:

- `previewSegment` / `getSegmentMembers` — DB page batches → accumulator → server-side pagination
- `getAllDedupedSegmentMembers` — single batched pass for campaign/sequence recipient generation

Stats (`rawCount`, `uniqueCount`, `duplicatesRemoved`, email status counts) remain accurate; browser receives only the requested preview/members page.

## Cron setup (cPanel)

```bash
# Every 5 minutes — sequence steps
curl -X POST https://yourdomain.com/api/cron/run-sequences -H "x-cron-secret: YOUR_SECRET"

# Every 1–2 minutes — mailbox sync
curl -X POST https://yourdomain.com/api/cron/sync-mailboxes -H "x-cron-secret: YOUR_SECRET"
```

## Duplicate protection rules

| Context | Behavior |
|---------|----------|
| Campaign send | `email_send_history` window check via `emailPolicy` (`duplicateWindowDays`, `duplicateAction`: warn/skip/allow). Settings: `/settings/email-policy` |
| Sequence steps | No campaign duplicate block — follow-ups allowed |
| Sequence enrollment | Same `normalizedEmail` blocked in active sequence |
| Suppression list | Blocks all campaign + sequence sends |

## Docs

- `docs/23-sequences.md`
- `docs/24-cpanel-cron.md`
