# SMS Sequences v2 - Stage-Based + Randomized Timing

> Enhancement to v1 | Est: 6-8 hours | Depends on v1 being complete

**Created:** Jan 19, 2026
**Status:** ✅ COMPLETE - Deployed Jan 19, 2026
**Prerequisite:** v1 basic sequences working ✅

---

## What v1 Builds

- Basic sequence processor (fixed timing)
- Enrollment API
- Auto-pause on reply
- 2 sequences: "Worker Outreach" + "Contractor Outreach"

## What v2 Adds

1. **Stage-based sequences** - Different sequence per funnel stage
2. **Randomized timing** - Human-like variability in send times
3. **Auto-enrollment on stage change** - When lead moves to new stage, enroll in appropriate sequence
4. **Smart send windows** - Morning/lunch/knock-off optimization

---

## 1. Stage-Based Sequences

### Worker Sequences (7 stages that need nurturing)

| Stage | Sequence Name | Goal | Steps |
|-------|---------------|------|-------|
| `not_signed_up` | Worker Intro | Get signup | 3 SMS |
| `signed_up` | Complete Profile | Finish profile | 2 SMS |
| `profile_complete` | Connect Stripe | Setup payments | 2 SMS |
| `stripe_ready` | Get Job Ready | Upload docs | 2 SMS |
| `job_ready` | Start Applying | Apply for jobs | 2 SMS |
| `working` | Check-In | Satisfaction + referrals | 1 SMS |
| `proven` | Referral Ask | Get worker referrals | 2 SMS |

### Contractor Sequences (5 stages)

| Stage | Sequence Name | Goal | Steps |
|-------|---------------|------|-------|
| `not_signed_up` | Contractor Intro | Get signup | 3 SMS |
| `signed_up` | Complete Profile | Finish profile | 2 SMS |
| `profile_complete` | Post First Job | Create job listing | 2 SMS |
| `hired` | Satisfaction Check | Review + referrals | 1 SMS |
| `active` | Referral Ask | Get contractor referrals | 2 SMS |

### Total: 12 sequences, ~24 SMS templates

---

## 2. Randomized Timing

### Schema Changes

```sql
-- Replace fixed delay_hours with ranges
ALTER TABLE sequence_steps
ADD COLUMN IF NOT EXISTS delay_days_min INTEGER DEFAULT 0,
ADD COLUMN IF NOT EXISTS delay_days_max INTEGER DEFAULT 0,
ADD COLUMN IF NOT EXISTS send_window VARCHAR(20) DEFAULT 'any';

-- send_window values: 'morning', 'lunch', 'knockoff', 'any'
```

### Send Windows (AEST)

| Window | Time Range | Best For |
|--------|------------|----------|
| `morning` | 6:00-7:30am | Before site starts |
| `lunch` | 12:00-1:00pm | Lunch break |
| `knockoff` | 3:00-6:00pm | After work |
| `any` | 8:00am-6:00pm | General business hours |

### Processor Logic Change

**v1 (fixed):**
```javascript
next_step_at = now + step.delay_hours
```

**v2 (randomized):**
```javascript
// Random day within range
const delayDays = randomInt(step.delay_days_min, step.delay_days_max);

// Random time within window
const sendTime = getRandomTimeInWindow(step.send_window);

// Combine
next_step_at = addDays(now, delayDays) + sendTime;
```

### Example: Worker Intro Sequence

| Step | Day Range | Window | Message |
|------|-----------|--------|---------|
| 1 | 0-0 | knockoff | Intro + signup link |
| 2 | 2-4 | morning | Value prop, no link |
| 3 | 5-8 | knockoff | Last chance + link |

So messages could go:
- Day 0 at 4:23pm
- Day 3 at 6:47am
- Day 7 at 5:12pm

Feels human, not robotic.

---

## 3. Auto-Enrollment on Stage Change

### Trigger: Stage Transition

When `stageCalculator.js` detects a stage change:

```javascript
// In stageCalculator.js or a new stageTransition handler

async function onStageChange(leadId, oldStage, newStage, leadType) {
  // 1. Pause any active enrollment for old stage
  await pauseEnrollmentsForLead(leadId, 'stage_changed');

  // 2. Find sequence for new stage + lead type
  const sequence = await findSequenceForStage(newStage, leadType);

  // 3. Auto-enroll if sequence exists and lead not opted out
  if (sequence && !lead.sequence_opted_out) {
    await enrollLead(sequence.id, leadId, 'auto_stage_change');
  }
}
```

### Opt-Out Flag

```sql
ALTER TABLE leads
ADD COLUMN IF NOT EXISTS sequence_opted_out BOOLEAN DEFAULT FALSE;
```

Reps can disable auto-sequences for specific leads.

---

## 4. Sequence Templates by Stage

### Worker: not_signed_up (Intro)

**Step 1 - Day 0, knockoff:**
> Hey {first_name}, Rocky from RateRight. We connect tradies with work - only 9.9% when you get paid. Check us out: rateright.com.au/signup

**Step 2 - Day 2-4, morning:**
> Hey {first_name}, still looking for {trade} work? We've got jobs coming through in your area.

**Step 3 - Day 5-8, knockoff:**
> Last one from me {first_name}. If you're sorted, no dramas. We're here when you need work: rateright.com.au/signup

---

### Worker: signed_up (Complete Profile)

**Step 1 - Day 1-2, morning:**
> Hey {first_name}, saw you signed up - legend! Just need to finish your profile to start seeing jobs. Takes 2 mins.

**Step 2 - Day 4-6, knockoff:**
> Hey {first_name}, your profile's almost done. Once complete you'll see {trade} jobs in your area straight away.

---

### Worker: profile_complete (Connect Stripe)

**Step 1 - Day 1-2, lunch:**
> Hey {first_name}, profile's looking good! Last step - connect Stripe so you can get paid. Only takes a minute.

**Step 2 - Day 4-5, knockoff:**
> Hey {first_name}, quick reminder - connect your Stripe and you're ready to start earning. No fees until you get paid.

---

### Worker: stripe_ready (Get Job Ready)

**Step 1 - Day 1-2, morning:**
> Hey {first_name}, you're almost job-ready! Just need your white card and a few docs. Then you can start applying.

**Step 2 - Day 3-5, knockoff:**
> Hey {first_name}, upload your docs and you'll be first in line for {trade} jobs. Heaps coming through.

---

### Worker: job_ready (Start Applying)

**Step 1 - Day 1-2, morning:**
> Hey {first_name}, you're job-ready! Check the app - there's {trade} work available now. Apply and we'll connect you.

**Step 2 - Day 4-6, knockoff:**
> Hey {first_name}, seen any jobs you like? Apply for a few and we'll get you working.

---

### Worker: working (Check-In)

**Step 1 - Day 3-5, lunch:**
> Hey {first_name}, how's the job going? Let us know if you need anything. And if you know other tradies looking for work, send them our way!

---

### Worker: proven (Referral Ask)

**Step 1 - Day 2-3, knockoff:**
> Hey {first_name}, legend work on that last job! Know any other {trade}s looking for work? We're always after good blokes.

**Step 2 - Day 7-10, morning:**
> Hey {first_name}, just checking - any mates need work? Send them to rateright.com.au/signup and we'll look after them.

---

### Contractor: not_signed_up (Intro)

**Step 1 - Day 0, knockoff:**
> Hey {first_name}, Rocky from RateRight. We supply quality tradies to builders - FREE to use. Worth a look: rateright.com.au/signup

**Step 2 - Day 2-4, morning:**
> Hey {first_name}, need any crew for upcoming jobs? We've got good {trade}s ready to go.

**Step 3 - Day 5-8, knockoff:**
> Last check-in {first_name}. If you're all staffed up, no dramas. We're here when you need crew: rateright.com.au/signup

---

### Contractor: signed_up (Complete Profile)

**Step 1 - Day 1-2, morning:**
> Hey {first_name}, saw you signed up - good stuff! Finish your company profile and you can start posting jobs.

**Step 2 - Day 4-6, knockoff:**
> Hey {first_name}, your profile's almost done. Complete it and you'll have access to quality {trade}s straight away.

---

### Contractor: profile_complete (Post First Job)

**Step 1 - Day 1-2, lunch:**
> Hey {first_name}, profile's done! Ready to find crew? Post your first job and we'll match you with quality tradies.

**Step 2 - Day 4-5, knockoff:**
> Hey {first_name}, got any jobs coming up? Post them and we'll send you the right blokes. Free to post.

---

### Contractor: hired (Satisfaction Check)

**Step 1 - Day 2-3, knockoff:**
> Hey {first_name}, how'd that hire go? Let us know if the tradie worked out. And if you need more crew, we've got plenty.

---

### Contractor: active (Referral Ask)

**Step 1 - Day 3-5, morning:**
> Hey {first_name}, glad the crew's working out! Know any other builders who need tradies? Send them our way.

**Step 2 - Day 10-14, knockoff:**
> Hey {first_name}, any builder mates struggling to find good crew? We're always looking after contractors who refer others.

---

## 5. Migration & Seed Data

### Migration: sequence_v2_enhancements.sql

```sql
-- Add stage and lead_type to sequences
ALTER TABLE sequences
ADD COLUMN IF NOT EXISTS stage VARCHAR(50),
ADD COLUMN IF NOT EXISTS lead_type VARCHAR(20);

-- Add randomization columns to steps
ALTER TABLE sequence_steps
ADD COLUMN IF NOT EXISTS delay_days_min INTEGER DEFAULT 0,
ADD COLUMN IF NOT EXISTS delay_days_max INTEGER DEFAULT 0,
ADD COLUMN IF NOT EXISTS send_window VARCHAR(20) DEFAULT 'any';

-- Backfill existing: convert delay_hours to delay_days_min/max
UPDATE sequence_steps
SET delay_days_min = FLOOR(delay_hours / 24),
    delay_days_max = FLOOR(delay_hours / 24)
WHERE delay_days_min IS NULL;

-- Add opt-out flag to leads
ALTER TABLE leads
ADD COLUMN IF NOT EXISTS sequence_opted_out BOOLEAN DEFAULT FALSE;

-- Index for finding sequence by stage
CREATE INDEX IF NOT EXISTS idx_sequences_stage_type
ON sequences(stage, lead_type) WHERE is_active = TRUE;
```

### Seed: 12 sequences + 24 templates

See templates above. Create via seed migration or admin UI.

---

## 6. Implementation Steps

| Step | Task | Hours |
|------|------|-------|
| 6.1 | Schema migration (add columns) | 0.5 |
| 6.2 | Update processor for randomized timing | 1.5 |
| 6.3 | Add auto-enrollment on stage change | 1.5 |
| 6.4 | Create 12 sequences + 24 templates | 2 |
| 6.5 | Add opt-out toggle in lead profile | 0.5 |
| 6.6 | Testing all stage transitions | 1.5 |
| **Total** | | **7.5 hours** |

---

## 7. Files to Modify

```
supabase/migrations/YYYYMMDD_sequence_v2_enhancements.sql
src/jobs/sequenceProcessor.js (randomized timing)
src/services/stageCalculator.js (trigger auto-enrollment)
src/routes/sequences.js (add stage filter)
admin/src/pages/LeadProfile.jsx (opt-out toggle)
```

---

## 8. Testing Checklist

- [x] Manual enrollment still works
- [x] Auto-enrollment triggers on stage change
- [x] Old enrollment pauses when stage changes
- [x] Randomized timing produces varied send times
- [x] Send windows respected (morning/lunch/knockoff)
- [x] Opt-out flag prevents auto-enrollment
- [x] All 12 sequences send correctly

---

## Summary

| v1 | v2 |
|----|----|
| 2 sequences (worker/contractor) | 12 sequences (per stage) |
| Fixed timing (day 0, 3, 7) | Randomized (day ranges + windows) |
| Manual enrollment only | Auto-enroll on stage change |
| ~6 templates | ~24 templates |

**v2 makes sequences feel human, not robotic, and matches the lead's journey.**

---

*Ready to build after v1 is tested and working.*
