# 33 — AI Lead Nurture Engine (24/7 Auto-Response)

**Status:** Phase 2.5 — Tier 1 (High priority, post-geographic extraction, requires instruction 03 AI layer)

**Inspiration:** Luxury Presence AI Lead Nurture Specialist. 25+ touchpoints per lead, 50%+ response rates, always-on engagement.

**Purpose:** Create an intelligent, self-hosted AI-powered lead nurture system that responds instantly to inbound inquiries (email, SMS, web form), learns lead preferences, adapts communication cadence, and intelligently hands off to humans when the lead is transaction-ready.

**Dependencies:** Instruction 03 (Ollama + FastAPI proxy), instruction 18 (MLS integration for market context), instruction 19 (SMS via Twilio), email.php and drips.php must be live.

**Scope:** 6 new database tables, 13 API endpoints, 3 cron jobs, Fair Housing audit integration, real-time temperature scoring.

---

## OVERVIEW

### The Problem

Currently, inbound leads (web forms, emails, SMS) trigger manual outreach or static drip campaigns. Response time is 2–24 hours. Leads are not segmented by intent or channel preference. Follow-up cadence is rigid. Handoff to agents is reactive.

Result: Lost leads, slow speed-to-lead, low engagement.

### The Solution

**Instant, intelligent, 24/7 nurture:**
1. Lead inquires → AI generates personalized response within 60 seconds
2. AI learns lead preferences (budget, neighborhoods, timeline, deal-breakers)
3. AI selects optimal channel and cadence based on engagement history
4. AI calculates real-time lead temperature (hot/warm/cold)
5. When lead is transaction-ready → AI alerts agent with summary + talking points
6. All AI output passes Fair Housing audit before sending

**Result:** 25+ touchpoints per lead, 50%+ response rate, zero leads left behind.

### Key Features

#### 1. Instant Response (60 seconds)
- Form submission, email, or SMS arrives
- AI generates personalized response using self-hosted LLM (instruction 03)
- Message matches agent's brand voice (via personality config in tenants table)
- Response uses lead's name, references their stated needs
- Sent immediately via email, SMS, or in-app message
- Logged in `ai_nurture_messages` with full thread context

#### 2. Multi-Channel Engagement
- **Email:** Primary channel. AI generates subject line + body. Sent via email.php SMTP.
- **SMS:** Secondary. AI generates concise SMS copy (160 chars optimized). Sent via Twilio (instruction 19).
- **In-app messaging:** If lead has app account, push notification + in-app message.
- AI learns which channel the lead responds fastest on. Biases future outreach accordingly.

#### 3. Conversation Intelligence
- Every message (inbound + outbound) logged in `ai_nurture_messages` with `conversation_thread_id`
- AI extracts structured intent from lead responses:
  - Budget range (e.g., "$1.5M–$3M" → stored as min/max in `ai_nurture_preferences`)
  - Neighborhoods (e.g., "Carmel, Pebble Beach" → stored as array)
  - Timeline (e.g., "looking within 6 months" → stored as deadline)
  - Must-haves (e.g., "ocean view, guest house" → stored as JSON)
  - Deal-breakers (e.g., "no HOA" → stored as JSON)
  - Preferred communication style (frequency, tone, channels)
  - Open house interest, showing preferences
- Extracted preferences updated in real-time as conversation grows

#### 4. Adaptive Touchpoint Cadence
- **Default sequence:** Immediate response → Day 1 follow-up → Day 3 value-add → Day 7 check-in → Weekly thereafter
- AI adjusts cadence based on:
  - Lead's response speed (fast responders → shorter intervals)
  - Engagement level (high engagement → more frequent)
  - Interaction timing (sent at times when lead is most responsive)
  - Channel preference (email vs. SMS)
- Configurable per-agent (via admin UI): min/max days between touches, max touches before human handoff
- `ai_nurture_scheduler` cron job checks pending touches every 5 minutes

#### 5. Handoff to Human
- AI detects transaction-ready triggers:
  - Lead asks to schedule showing
  - Lead mentions specific timeline ("looking to close in 60 days")
  - Lead asks about pricing, financing, closing
  - Lead engagement score exceeds configurable threshold (default 75)
  - Agent manually triggers handoff (e.g., "I'm ready to take this one")
- Creates entry in `ai_nurture_handoffs` with:
  - Full conversation thread
  - Extracted preferences + intent
  - Recommended talking points
  - Lead temperature + engagement score
  - Best time to contact (learned from prior messages)
- Sends priority notification to agent (in-app alert + email)
- Agent marks handoff complete → conversation continues with human, but AI tracks metrics

#### 6. Lead Temperature Scoring
- Real-time scoring (0–100 scale) based on:
  - **Response speed:** <1 hour = +15 pts, 1–4h = +10, 4–24h = +5
  - **Question specificity:** Generic ("When can I see homes?") = +5, specific ("Do you have ocean-view condos under $2M?") = +15
  - **Engagement frequency:** Replies to 80%+ of touchpoints = +20, 50–80% = +10, <50% = +5
  - **Property behavior:** Viewed 10+ listings = +10, clicked listing links = +5
  - **Interaction diversity:** Engaged via 2+ channels = +10
  - **Recency decay:** Last interaction >7 days ago = -5, >30 days = -15
- Classification:
  - **Hot (75–100):** Ready for showing, call immediately
  - **Warm (50–74):** Engaged, nurture actively
  - **Cold (<50):** Early-stage, education focus
- `ai_nurture_temperature` cron recalculates hourly
- Displayed in agent dashboard and handoff queue

#### 7. Fair Housing Compliance
- **Before sending any AI-generated message:**
  - Passes through Fair Housing audit (extends email.php logic)
  - Checks for steering (e.g., "I only show this to X demographic" — BLOCKED)
  - Checks for protected class language (race, religion, national origin, disability, familial status, sex, sexual orientation, gender identity — BLOCKED)
  - Checks for discriminatory patterns (e.g., only showing lead "safe" neighborhoods — FLAGGED)
  - Flags for human review if any risk detected
  - Logs all audits in `ai_nurture_messages.audit_log` (JSON)
- Non-compliant messages do NOT send. Alert goes to compliance officer (admin with Fair Housing role).
- Compliant messages get `audit_passed = true` before SMTP/Twilio send.

#### 8. Performance Analytics
- Real-time dashboard showing:
  - **Response metrics:** Avg response time (AI vs. human), response rate, first-touch open rate
  - **Engagement metrics:** Touches per lead, touches to first showing, touches to contract
  - **Conversion metrics:** Lead-to-appointment conversion rate, appointment-to-showing, showing-to-offer
  - **Efficiency metrics:** AI-assisted vs. full-manual nurture (time saved, cost/lead)
  - **Channel effectiveness:** Email open rate, SMS response rate, in-app engagement
  - **Comparison:** AI-nurtured vs. drip-campaign-only (control group)
  - **Cohort analysis:** By source (web form, email, SMS), by agent, by property type
- Exportable reports (CSV) with monthly trends

#### 9. Tenant Configuration
- Per-tenant settings (stored in `ai_nurture_configs`):
  - **Enable/disable** auto-response per lead source (enable for web forms, disable for existing clients)
  - **Business hours:** AI tone/cadence varies by time of day (can suppress late-night sends)
  - **Max AI touches before human:** Default 5, configurable
  - **Brand voice:** Agent personality settings (formal, casual, luxury-focused, market-expert tone)
  - **Channel preferences:** Which channels enabled (email, SMS, in-app)
  - **Cadence overrides:** Custom sequences per property type or price range
  - **Handoff threshold:** Lead temperature trigger for automatic handoff
- Configurable via admin UI (new "AI Nurture Settings" panel)

#### 10. Integration Points
- **email.php:** Use existing `sendEmail()` for AI-generated nurture emails. Log to both `email_messages` and `ai_nurture_messages`.
- **sms.php (instruction 19):** Use Twilio client to send AI-generated SMS. Log to `ai_nurture_messages`.
- **admin.php:** Extend to create leads from inbound inquiries. Update `clients` with extracted preferences when AI learns them.
- **drips.php:** AI nurture can supplement or replace drip campaigns. Lead in AI nurture doesn't also get duplicate drip emails.
- **lead-scoring.js:** Real-time temperature updates trigger UI refresh in agent dashboard.
- **daily-action-feed.js:** Handoff notifications appear as priority tasks.
- **ai_inference.php (instruction 03):** Call to generate nurture messages. Prompt includes agent voice style + lead context.

---

## DATABASE SCHEMA

### 1. `ai_nurture_conversations`
Tracks one conversation thread per lead (across all channels).

```sql
CREATE TABLE IF NOT EXISTS ai_nurture_conversations (
    id INT AUTO_INCREMENT PRIMARY KEY,
    tenant_id INT DEFAULT NULL,
    client_id INT NOT NULL,
    source VARCHAR(50) NOT NULL, -- 'web_form', 'email', 'sms', 'call'
    agent_id INT NOT NULL,
    started_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_message_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    temperature_score INT DEFAULT 0, -- 0-100
    status VARCHAR(50) DEFAULT 'active', -- 'active', 'paused', 'closed', 'handed_off'
    handoff_requested_at TIMESTAMP DEFAULT NULL,
    closed_at TIMESTAMP DEFAULT NULL,
    closed_reason VARCHAR(255) DEFAULT NULL, -- 'converted_to_deal', 'no_longer_interested', 'agent_closed'
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
    FOREIGN KEY (client_id) REFERENCES clients(id) ON DELETE CASCADE,
    FOREIGN KEY (agent_id) REFERENCES admins(id) ON DELETE CASCADE,
    INDEX (tenant_id, agent_id),
    INDEX (status, temperature_score),
    INDEX (last_message_at)
);
```

### 2. `ai_nurture_messages`
Individual messages in the conversation (inbound + outbound).

```sql
CREATE TABLE IF NOT EXISTS ai_nurture_messages (
    id INT AUTO_INCREMENT PRIMARY KEY,
    tenant_id INT DEFAULT NULL,
    conversation_id INT NOT NULL,
    direction VARCHAR(20) NOT NULL, -- 'inbound', 'outbound'
    channel VARCHAR(50) NOT NULL, -- 'email', 'sms', 'in_app', 'phone_note'
    from_email VARCHAR(255) DEFAULT NULL,
    to_email VARCHAR(255) DEFAULT NULL,
    from_phone VARCHAR(20) DEFAULT NULL,
    to_phone VARCHAR(20) DEFAULT NULL,
    subject VARCHAR(255) DEFAULT NULL, -- email only
    body LONGTEXT NOT NULL,
    ai_generated BOOLEAN DEFAULT FALSE,
    ai_model VARCHAR(100) DEFAULT NULL, -- 'llama-3.3-70b', 'mistral-7b'
    fair_housing_audit LONGTEXT DEFAULT NULL, -- JSON: {passed: bool, flags: [...], reviewed_by: admin_id, reviewed_at: timestamp}
    audit_passed BOOLEAN DEFAULT FALSE,
    extracted_intent LONGTEXT DEFAULT NULL, -- JSON: {budget_min, budget_max, neighborhoods: [], timeline, must_haves, deal_breakers}
    sent_at TIMESTAMP DEFAULT NULL,
    delivered_at TIMESTAMP DEFAULT NULL,
    read_at TIMESTAMP DEFAULT NULL,
    response_time_seconds INT DEFAULT NULL, -- if inbound
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
    FOREIGN KEY (conversation_id) REFERENCES ai_nurture_conversations(id) ON DELETE CASCADE,
    INDEX (tenant_id, conversation_id, created_at),
    INDEX (ai_generated, audit_passed),
    INDEX (sent_at)
);
```

### 3. `ai_nurture_preferences`
Extracted lead preferences (denormalized for fast access).

```sql
CREATE TABLE IF NOT EXISTS ai_nurture_preferences (
    id INT AUTO_INCREMENT PRIMARY KEY,
    tenant_id INT DEFAULT NULL,
    client_id INT NOT NULL,
    budget_min INT DEFAULT NULL,
    budget_max INT DEFAULT NULL,
    neighborhoods JSON DEFAULT NULL, -- ["Carmel", "Pebble Beach"]
    property_types JSON DEFAULT NULL, -- ["SFR", "Condo"]
    beds_min INT DEFAULT NULL,
    baths_min INT DEFAULT NULL,
    sqft_min INT DEFAULT NULL,
    timeline_months INT DEFAULT NULL, -- 6, 12, etc
    must_haves JSON DEFAULT NULL, -- {ocean_view: true, guest_house: true, ...}
    deal_breakers JSON DEFAULT NULL, -- {no_hoa: true, ...}
    preferred_channels JSON DEFAULT NULL, -- ["email", "sms"]
    best_contact_time_hour INT DEFAULT NULL, -- 9-17 range
    communication_frequency VARCHAR(50) DEFAULT 'adaptive', -- 'daily', 'weekly', 'adaptive'
    communication_tone VARCHAR(50) DEFAULT 'neutral', -- 'formal', 'casual', 'luxury_focused'
    last_preference_update TIMESTAMP DEFAULT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
    FOREIGN KEY (client_id) REFERENCES clients(id) ON DELETE CASCADE,
    INDEX (tenant_id, client_id)
);
```

### 4. `ai_nurture_handoffs`
Lead handoff requests with context for agent.

```sql
CREATE TABLE IF NOT EXISTS ai_nurture_handoffs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    tenant_id INT DEFAULT NULL,
    conversation_id INT NOT NULL,
    client_id INT NOT NULL,
    agent_id INT NOT NULL,
    handoff_initiated_by VARCHAR(50) DEFAULT 'ai', -- 'ai', 'agent', 'manual'
    temperature_score_at_handoff INT DEFAULT NULL,
    conversation_summary LONGTEXT DEFAULT NULL,
    extracted_preferences LONGTEXT DEFAULT NULL, -- JSON copy of ai_nurture_preferences
    recommended_talking_points LONGTEXT DEFAULT NULL, -- JSON: [{point, reason}, ...]
    best_time_to_contact_hour INT DEFAULT NULL,
    last_contact_at TIMESTAMP DEFAULT NULL,
    agent_notified_at TIMESTAMP DEFAULT NULL,
    agent_acknowledged_at TIMESTAMP DEFAULT NULL,
    status VARCHAR(50) DEFAULT 'pending', -- 'pending', 'acknowledged', 'completed', 'snoozed'
    completed_at TIMESTAMP DEFAULT NULL,
    outcome VARCHAR(255) DEFAULT NULL, -- 'scheduled_showing', 'scheduled_consultation', 'sent_info', 'no_response'
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
    FOREIGN KEY (conversation_id) REFERENCES ai_nurture_conversations(id) ON DELETE CASCADE,
    FOREIGN KEY (client_id) REFERENCES clients(id) ON DELETE CASCADE,
    FOREIGN KEY (agent_id) REFERENCES admins(id) ON DELETE CASCADE,
    INDEX (tenant_id, agent_id, status),
    INDEX (temperature_score_at_handoff)
);
```

### 5. `ai_nurture_configs`
Per-tenant configuration for auto-response behavior.

```sql
CREATE TABLE IF NOT EXISTS ai_nurture_configs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    tenant_id INT NOT NULL,
    admin_id INT DEFAULT NULL,
    enabled BOOLEAN DEFAULT TRUE,
    enable_by_source JSON DEFAULT NULL, -- {web_form: true, email: true, sms: false}
    max_ai_touches_before_handoff INT DEFAULT 5,
    business_hours_start INT DEFAULT 9, -- hour 0-23
    business_hours_end INT DEFAULT 17,
    suppress_after_hours BOOLEAN DEFAULT FALSE,
    suppress_weekends BOOLEAN DEFAULT FALSE,
    brand_voice VARCHAR(50) DEFAULT 'neutral', -- 'formal', 'casual', 'luxury_focused', 'market_expert'
    channels_enabled JSON DEFAULT NULL, -- {email: true, sms: true, in_app: true}
    temperature_handoff_threshold INT DEFAULT 75, -- auto-handoff when score exceeds
    enable_auto_handoff BOOLEAN DEFAULT TRUE,
    cadence_sequence JSON DEFAULT NULL, -- [{day: 0, action: 'immediate_response'}, {day: 1, action: 'follow_up'}, ...]
    fairhousing_audit_strict BOOLEAN DEFAULT TRUE,
    fairhousing_review_admin_id INT DEFAULT NULL,
    analytics_enabled BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
    FOREIGN KEY (admin_id) REFERENCES admins(id) ON DELETE SET NULL,
    FOREIGN KEY (fairhousing_review_admin_id) REFERENCES admins(id) ON DELETE SET NULL,
    UNIQUE KEY (tenant_id),
    INDEX (enabled)
);
```

### 6. `ai_nurture_metrics`
Aggregated performance metrics for reporting.

```sql
CREATE TABLE IF NOT EXISTS ai_nurture_metrics (
    id INT AUTO_INCREMENT PRIMARY KEY,
    tenant_id INT DEFAULT NULL,
    agent_id INT DEFAULT NULL,
    period_date DATE NOT NULL, -- daily aggregate
    leads_nurtured INT DEFAULT 0,
    leads_hot INT DEFAULT 0,
    leads_warm INT DEFAULT 0,
    leads_cold INT DEFAULT 0,
    touches_sent INT DEFAULT 0,
    touches_via_email INT DEFAULT 0,
    touches_via_sms INT DEFAULT 0,
    touches_via_in_app INT DEFAULT 0,
    avg_response_time_seconds INT DEFAULT NULL,
    response_rate_pct DECIMAL(5, 2) DEFAULT NULL, -- % of leads who responded
    first_touch_open_rate_pct DECIMAL(5, 2) DEFAULT NULL,
    handoffs_created INT DEFAULT 0,
    handoffs_completed INT DEFAULT 0,
    leads_to_showing INT DEFAULT 0,
    leads_to_offer INT DEFAULT 0,
    avg_touches_per_conversion DECIMAL(5, 2) DEFAULT NULL,
    fairhousing_flags INT DEFAULT 0,
    fairhousing_audits_passed INT DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
    FOREIGN KEY (agent_id) REFERENCES admins(id) ON DELETE CASCADE,
    INDEX (tenant_id, agent_id, period_date)
);
```

---

## API ENDPOINTS

### Core Conversation Management

#### 1. POST `/api/ai-nurture.php?action=getNurtureConversation`
Get full conversation thread (all messages, preferences, handoff status).
- **Auth:** Session token
- **Request:** `{client_id: int, agent_id: int (optional)}`
- **Response:** `{success, data: {conversation: {...}, messages: [...], preferences: {...}, handoff: {...}, temperature: int}}`

#### 2. POST `/api/ai-nurture.php?action=getNurtureMessages`
Get paginated messages from a conversation.
- **Auth:** Session token
- **Request:** `{conversation_id: int, limit: int, offset: int}`
- **Response:** `{success, data: {messages: [...], total: int}}`

#### 3. POST `/api/ai-nurture.php?action=sendNurtureMessage`
Agent sends manual message (not AI-generated). Logged in `ai_nurture_messages`.
- **Auth:** Session token
- **Request:** `{conversation_id: int, body: string, channel: 'email|sms|in_app'}`
- **Response:** `{success, data: {message_id: int, sent_at: timestamp}}`

#### 4. POST `/api/ai-nurture.php?action=pauseNurture`
Pause AI auto-responses for a lead.
- **Auth:** Session token
- **Request:** `{conversation_id: int, reason: string}`
- **Response:** `{success, message: "Nurture paused"}`

#### 5. POST `/api/ai-nurture.php?action=resumeNurture`
Resume AI auto-responses.
- **Auth:** Session token
- **Request:** `{conversation_id: int}`
- **Response:** `{success, message: "Nurture resumed"}`

### Handoff Management

#### 6. POST `/api/ai-nurture.php?action=handoffToHuman`
Manually trigger handoff (agent takes the lead).
- **Auth:** Session token
- **Request:** `{conversation_id: int, agent_id: int, talking_points: string (optional)}`
- **Response:** `{success, data: {handoff_id: int, notification_sent: bool}}`

#### 7. POST `/api/ai-nurture.php?action=getHandoffQueue`
Get list of pending handoffs for logged-in agent.
- **Auth:** Session token
- **Request:** `{limit: int, offset: int}`
- **Response:** `{success, data: {handoffs: [...], total: int}}`

#### 8. POST `/api/ai-nurture.php?action=completeHandoff`
Mark handoff as complete (agent took action).
- **Auth:** Session token
- **Request:** `{handoff_id: int, outcome: 'scheduled_showing|scheduled_consultation|sent_info|no_response'}`
- **Response:** `{success, data: {handoff: {...}}}`

### Temperature & Analytics

#### 9. POST `/api/ai-nurture.php?action=getLeadTemperature`
Get current temperature score + classification for a lead.
- **Auth:** Session token
- **Request:** `{client_id: int}`
- **Response:** `{success, data: {temperature: int, classification: 'hot|warm|cold', breakdown: {...}}}`

#### 10. POST `/api/ai-nurture.php?action=getNurtureMetrics`
Get performance metrics for agent or tenant (date range).
- **Auth:** Session token
- **Request:** `{agent_id: int (optional), start_date: date, end_date: date}`
- **Response:** `{success, data: {metrics: {...}, trends: {...}, comparison: {...}}}`

#### 11. POST `/api/ai-nurture.php?action=getNurtureDashboard`
Get dashboard summary: active conversations, hot leads, handoff queue, today's touches, performance KPIs.
- **Auth:** Session token
- **Request:** `{}`
- **Response:** `{success, data: {active_conversations: int, hot_leads: [...], handoff_queue: [...], kpis: {...}}}`

### Configuration & Compliance

#### 12. POST `/api/ai-nurture.php?action=configureNurture`
Update tenant's AI nurture settings.
- **Auth:** Session token (admin only)
- **Request:** `{enabled: bool, max_ai_touches: int, brand_voice: string, channels: object, temperature_threshold: int, ...}`
- **Response:** `{success, data: {config: {...}}}`

#### 13. POST `/api/ai-nurture.php?action=overrideNurtureMessage`
Admin reviews and approves/rejects flagged message before send.
- **Auth:** Session token (admin only)
- **Request:** `{message_id: int, action: 'approve|reject', notes: string}`
- **Response:** `{success, data: {message_id: int, status: 'approved|rejected'}}`

---

## IMPLEMENTATION STEPS

### Phase 1: Schema & API Setup (Days 1–2)

1. **Create 6 new tables** in MySQL using DDL above. Run migrations via auto-migration check in ai_nurture.php.
2. **Create `/api/ai-nurture.php`** with 13 endpoints. Follow pattern from existing API modules:
   - Auto-migration (create tables if missing)
   - Auth check (session token required)
   - Route by `$_GET['action']` via switch statement
   - PDO prepared statements for all queries
   - JSON response format: `{success: bool, data: {...}, message: string}` or `{error: string, code: int}`
3. **Test each endpoint** locally with curl:
   ```bash
   curl -X POST http://fogbreak.local/api/ai-nurture.php?action=getNurtureConversation \
     -H "Authorization: Bearer $SESSION_TOKEN" \
     -d '{"client_id": 1}'
   ```

### Phase 2: AI Integration (Days 3–4)

4. **Integrate with instruction 03 (AI inference):**
   - Call FastAPI proxy endpoint `/v1/chat/completions` to generate nurture messages
   - Prompt template: `"As an expert real estate agent with style '{brand_voice}', reply to this lead inquiry: {lead_message}. Keep response <200 words. Be personal, reference their stated needs. Sign off with agent name."`
   - Model selection: Use Llama 3.3 70B for initial response (high quality), Mistral 7B for follow-ups (faster)
   - Cache responses for identical prompts (Redis optional, or simple file cache)
5. **Extract intent from lead messages:**
   - Call AI with extraction prompt: `"Extract structured intent from this message: {message}. Return JSON with: budget_min, budget_max, neighborhoods[], timeline_months, must_haves{}, deal_breakers{}. If not mentioned, omit field."`
   - Store result in `ai_nurture_messages.extracted_intent` and sync to `ai_nurture_preferences`
6. **Test:** Send sample lead inquiry, verify AI response generated in <2 seconds

### Phase 3: Fair Housing Integration (Days 5–6)

7. **Extend email.php's Fair Housing audit:**
   - Before sending any AI-generated message, call existing `auditFairHousing($message_body)` function
   - Add new checks specific to nurture (no steering, no pattern discrimination)
   - Log audit result to `ai_nurture_messages.fair_housing_audit` (JSON)
   - If flagged: set `audit_passed = FALSE`, send to compliance admin, DO NOT send message
8. **Compliance admin workflow:**
   - New UI panel "Fair Housing Review Queue" (in admin dashboard)
   - Display flagged messages with reason + suggestion for correction
   - Admin can approve, reject, or edit + re-test message
   - Approved messages sent; audit_passed set TRUE
9. **Test:** Generate message with discriminatory phrase (e.g., "perfect for young families"), verify it's caught and flagged

### Phase 4: Cron Jobs (Days 7–8)

10. **Create `ai_nurture_scheduler` cron job** (runs every 5 minutes):
    - Query `ai_nurture_conversations` with status='active'
    - For each conversation, check if next scheduled touch is due (based on `cadence_sequence` in config)
    - If due: generate message via AI, pass Fair Housing audit, send via email/SMS/in-app
    - Log send to `ai_nurture_messages` with timestamps
    - Idempotent: each touch sent only once (check `sent_at` timestamp)

11. **Create `ai_nurture_temperature` cron job** (runs hourly):
    - Query all active conversations
    - For each, recalculate temperature score based on formula (response speed, specificity, frequency, behavior, recency)
    - Update `ai_nurture_conversations.temperature_score`
    - If score >= `temperature_handoff_threshold` in config AND `enable_auto_handoff = TRUE`:
      - Create entry in `ai_nurture_handoffs` with auto_initiated='ai'
      - Send notification to assigned agent (via in-app alert + email)
    - Trigger UI refresh via WebSocket if connected (optional, for real-time dashboard)

12. **Create `ai_nurture_report` cron job** (runs daily at 8 AM):
    - Aggregate metrics for previous day: leads nurtured, touches sent, response rate, conversions
    - Store in `ai_nurture_metrics` by agent + tenant
    - Email daily summary to agents + manager (optional, can be opt-in via config)

### Phase 5: UI Integration (Days 9–10)

13. **Update fogbreak.html tabs:**
    - Add new "AI Nurture" tab or expand "Clients" tab with nurture panel
    - Show list of active conversations with client name, last message, temperature (color-coded: hot=red, warm=yellow, cold=gray)
    - Click conversation → open detail panel showing full thread (messages + extracted preferences)
    - "Handoff" button to manually trigger handoff (calls endpoint 6)
    - Real-time temperature updates via setInterval polling (every 30 seconds) or WebSocket

14. **Update "Dashboard" tab:**
    - Add "Lead Nurture" section showing:
      - # Hot/warm/cold leads
      - Pending handoffs (priority)
      - Today's touches sent
      - Current response rate (this week)
    - Charts: response time trend, conversion rate, touches per conversion

15. **Update admin settings panel:**
    - New "AI Nurture Configuration" section (visible to admins only)
    - Checkboxes: enable by source (web form, email, SMS)
    - Sliders: max AI touches, temperature threshold, business hours
    - Dropdowns: brand voice, communication frequency
    - Save button → calls endpoint 12

### Phase 6: Integration with Existing Modules (Days 11–12)

16. **Integrate with email.php:**
    - When inbound email arrives (IMAP sync in cron), check sender's client_id
    - If client exists and has active nurture conversation: add to conversation thread
    - If client doesn't exist but email is from form submission: create new lead + new conversation, trigger AI nurture
    - Log to both `email_messages` (existing) and `ai_nurture_messages` (new) to maintain dual audit trail

17. **Integrate with admin.php (clients CRUD):**
    - When creating new client from form, auto-create `ai_nurture_conversations` entry
    - When viewing client detail, show nurture conversation + temperature in sidebar
    - "Preferences" section shows extracted `ai_nurture_preferences` (read-only, auto-updated)

18. **Integrate with drips.php:**
    - Add logic: if client is in active nurture conversation, don't enroll in drip campaign (avoid duplicate touches)
    - Allow agent to exclude clients from drips via checkbox: "This lead is AI-nurtured"

19. **Integrate with lead-scoring.js:**
    - When temperature updates via cron, POST to lead-scoring.js trigger
    - JS listens for WebSocket message or polls `/api/ai-nurture.php?action=getLeadTemperature`
    - Update color coding on client card in real-time

---

## TESTING CRITERIA

### Unit Tests
- [ ] AI message generation: send test inquiry, verify response generated in <3 seconds
- [ ] Fair Housing audit: 10 test messages (5 compliant, 5 not), verify correct flagging
- [ ] Intent extraction: 20 test messages, verify budget/neighborhoods/timeline extracted correctly
- [ ] Temperature scoring: 15 test conversation threads, verify scores calculate correctly
- [ ] Handoff creation: temperature exceeds threshold, verify handoff auto-created and agent notified

### Integration Tests
- [ ] Email inbound: send test email to lead@fogbreak.io, verify it creates conversation + AI responds in 60 sec
- [ ] SMS inbound: send test SMS to agent's Twilio number, verify it creates conversation + AI responds
- [ ] Fair Housing + send: generate discriminatory message, verify it's flagged, NOT sent, admin notified
- [ ] Cron scheduler: run manually, verify 3 pending touches sent, messages logged with sent_at timestamps
- [ ] Cron temperature: run manually, verify scores updated, hot leads trigger handoffs
- [ ] Dashboard: load admin UI, verify "AI Nurture" section shows active conversations, hot leads, pending handoffs

### End-to-End Tests
- [ ] **Scenario: New web form inquiry**
  1. Lead fills form: "Looking for ocean-view condo under $2M in Carmel, timeline 6 months"
  2. Form submission → creates client + conversation
  3. AI generates response within 60 sec (references name, budget, neighborhood, timeline)
  4. Response passes Fair Housing audit
  5. Email sent to lead
  6. Preferences extracted and stored in `ai_nurture_preferences`
  7. Verify: conversation shows in agent's dashboard
- [ ] **Scenario: Adaptive cadence**
  1. Lead replies to AI response within 2 hours
  2. System detects fast response → increases engagement score +15 pts
  3. Next touch scheduled 1 day later (instead of 3) due to adaptive cadence
  4. Verify: `ai_nurture_conversations.last_message_at` updates
- [ ] **Scenario: Handoff at 75+ temperature**
  1. Lead asks "Can I see the Carmel property this weekend?"
  2. Cron temperature job recalculates → score 78 (hot)
  3. Auto-handoff created, agent notified
  4. Verify: handoff in agent's dashboard, notification email received
  5. Agent clicks "Complete handoff" → marked completed, conversation flagged as "handed_off"

### Performance Tests
- [ ] Scheduler cron: 1,000 active conversations, verify all pending touches processed in <30 sec
- [ ] Temperature job: 500 conversations, verify all scores recalculated in <10 sec
- [ ] API response: `getNurtureConversation` with 100+ messages, verify response <500 ms
- [ ] Database indexes: confirm queries use indexes (EXPLAIN ANALYZE on key queries)

### Compliance Tests
- [ ] Fair Housing: 50 AI-generated messages, verify zero steering language
- [ ] Multi-tenant isolation: lead in tenant A cannot see messages from tenant B
- [ ] API auth: unauthenticated request to any endpoint, verify 401 returned

---

## SUCCESS METRICS (First 30 Days)

- **Response time:** <60 sec from inquiry to AI response
- **Response rate:** 50%+ of leads reply to AI message
- **Touches to showing:** Average 8 touches per conversion (vs. 12 with manual)
- **Speed to lead:** 80% of responses within 1 hour (vs. 20% manual)
- **Handoff accuracy:** 90%+ of auto-handoffs are transaction-ready (agent feedback)
- **Fair Housing compliance:** 100% of AI messages pass audit (zero false negatives)
- **Agent time saved:** 3–5 hours per week per agent (AI handling initial triage)

---

**Owner:** Kean (Architecture + Fair Housing oversight)
**Dependencies:** Instruction 03 (AI), Instruction 19 (SMS), email.php (IMAP), admin.php (CRM)
**Tier:** Phase 2.5 High Priority
**Effort Estimate:** 2 weeks (80 hours)
