warmbox/docs/05-primary-satellite-topology.md

120 lines
4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Primary & Satellite Topology
## Core principle
**Primaries** are the mailboxes whose reputation matters for cold outreach.
**Satellites** exist only to generate realistic, controlled engagement with primaries.
```
┌─────────────────┐
│ Primary │
│ hello@fillcare │
└────────┬────────┘
┌───────────────────┼───────────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│Satellite│ │Satellite│ │Satellite│
│ Gmail 1 │ │ Yahoo │ │ Live │
└─────────┘ └─────────┘ └─────────┘
```
## Traffic rules
| Direction | Allowed | Notes |
|-----------|---------|-------|
| Satellite → Primary | Yes | Main warmup send |
| Primary → Satellite | Yes | Reply to satellite (completes thread) |
| Satellite → Satellite | No | Wastes quota; looks unnatural |
| Primary → Primary | No | Never warm primaries against each other |
| Satellite → unrelated external | No | Only campaign-assigned primaries |
## Multi-primary support
One operator can run **N campaigns** concurrently:
```
Campaign A: primary=hello@fillcareapp.com ← satellites [gmail1, yahoo1, live1]
Campaign B: primary=sales@otherdomain.com ← satellites [gmail2, yahoo2]
```
Satellites may be **shared** across campaigns only if explicitly enabled (default: dedicated per primary to avoid cross-brand leakage).
## FillCare example setup
| Mailbox | Role | Provider |
|---------|------|----------|
| hello@fillcareapp.com | Primary | Google Workspace |
| personal@gmail.com | Satellite | Gmail |
| personal@yahoo.com | Satellite | Yahoo |
| personal@live.com | Satellite | Outlook |
| (+ 12 more) | Satellite | Mixed |
### Minimum viable pool
- 1 primary + **2 satellites** (technical minimum)
- Recommended: 1 primary + **46 satellites** for natural variety and reply distribution
## Satellite lifecycle
```mermaid
stateDiagram-v2
[*] --> Unassigned: Add mailbox
Unassigned --> Active: Assign to campaign
Active --> Paused: Operator pause
Paused --> Active: Resume
Active --> Error: Auth/IMAP failure
Error --> Active: Fix + test
Active --> Unassigned: Remove from campaign
```
## Add / remove operations
### Add satellite
1. `POST /mailboxes` with `role: satellite`
2. Test SMTP/IMAP
3. `POST /campaigns/:id/satellites` to assign
### Remove satellite
1. `DELETE /campaigns/:id/satellites/:mailboxId` — stops new sends
2. In-flight threads complete or timeout
3. Optional: `DELETE /mailboxes/:id` if fully removed
### Add primary
1. `POST /mailboxes` with `role: primary`
2. `POST /campaigns` with recipe + bounds
3. Assign satellites
4. Start campaign (`status: active`)
## Peer network (phase 3 — optional)
When enabled, additional engagement from vetted peer mailboxes:
| Aspect | Own satellites | Peer network |
|--------|----------------|--------------|
| Control | Full | Limited |
| ESP risk | Lower | Higher (pool quality) |
| Cost | User supplies accounts | Platform fee |
| Detection | User responsible | Platform must maintain pool health |
**Recommendation:** Ship own-satellite-only first. Peer network requires bounce monitoring, DNS validation, and pool rotation — significant ops burden.
## Dispatcher pairing (target logic)
```
for each campaign where status=active:
if today.sends < schedule.plannedSends:
satellite = pickWeighted(campaign.satellites)
primary = campaign.primaryMailbox
queueSend(from=satellite, to=primary)
```
Reply path (rescuer):
```
if shouldReply(campaign.replyRatePercent):
reply(from=primary, to=satellite, inReplyTo=original)
```