# 25 — Home Valuation & CMA Widget

**Status:** Design phase | **Priority:** High (lead capture, listing appointment prep) | **Dependencies:** 00 (MASTER-PLAN), 18 (MLS-INTEGRATION), 15 (NEXTJS-WEB-APP)

**Completion Target:** 8 weeks | **Effort:** 320 hours | **Owner:** Lead capture + listing intelligence

---

## OVERVIEW

The Home Valuation & CMA Widget provides two linked tools: (1) an embeddable instant home valuation tool for seller lead capture (address input → AVM estimate with lead form), and (2) a full Comparative Market Analysis (CMA) builder for agents preparing listing appointments (subject property + 3-6 comps → branded PDF/HTML presentation with price recommendations and market analysis).

Luxury Presence generated 186,000+ leads from their home search tools and 228,000 from Google One Tap in 2024. Fogbreak replaces ShowingTime's basic valuation UI with a sophisticated lead-capture-first funnel that feeds directly into CRM.

**What It Replaces:** ShowingTime's valuation tool (basic), generic home value estimators (unbranded), manual CMA creation in Word/Excel.

**What It Adds:**
- Embeddable valuation widget (Next.js + vanilla JS) with AVM + lead capture
- Automated CMA builder (subject + comps → branded presentation)
- Market trend data (median price, DOM, inventory, price-per-sqft by location)
- Confidence scoring on valuations
- Lead capture flow with auto-CRM enrollment + drip triggering
- White-label branding (tenant brand config + custom agent branding)
- PDF/HTML/email delivery of CMAs
- Comp selection intelligence (similar square footage, days on market, sale recency)

**Why It Matters:** Most real estate transactions begin with valuation. By providing instant, branded estimates on the agent's website, Fogbreak captures seller leads at the moment they want to know what their home is worth — and auto-routes them into nurture drips. CMA generation currently takes agents 30+ minutes in Excel; automating it to 2 minutes saves ~5 hours/week per agent.

---

## DATABASE SCHEMA

### home_valuations

```sql
CREATE TABLE home_valuations (
  id INT AUTO_INCREMENT PRIMARY KEY,
  tenant_id INT,
  property_address VARCHAR(255) NOT NULL,
  property_zip VARCHAR(10),
  property_beds INT,
  property_baths DECIMAL(2, 1),
  property_sqft INT,
  property_lot_sqft INT,
  property_year_built INT,
  property_type ENUM('single_family', 'condo', 'townhouse', 'multi_family', 'land', 'other'),

  avm_estimate_low DECIMAL(12, 2),
  avm_estimate_mid DECIMAL(12, 2),  -- Primary estimate
  avm_estimate_high DECIMAL(12, 2),
  avm_confidence INT,  -- 0-100 (e.g., 78 means 78% confident)
  avm_source VARCHAR(100),  -- 'zillow', 'attom', 'house_canary', 'internal_ml'
  avm_last_updated TIMESTAMP,

  lead_name VARCHAR(255),  -- Captured from form
  lead_email VARCHAR(255),
  lead_phone VARCHAR(20),
  lead_property_owner BOOLEAN DEFAULT FALSE,  -- Did they confirm ownership?
  lead_agent_assigned INT,  -- agent admin.id, if pre-assigned
  lead_source ENUM('valuation_widget', 'cma_builder', 'mobile_app', 'email_campaign'),
  lead_status ENUM('new', 'contacted', 'qualified', 'nurture', 'closed'),

  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  FOREIGN KEY (tenant_id) REFERENCES tenants(id),
  FOREIGN KEY (lead_agent_assigned) REFERENCES admins(id),
  INDEX (tenant_id),
  INDEX (property_address),
  INDEX (property_zip),
  INDEX (avm_confidence),
  INDEX (lead_email),
  INDEX (created_at)
);
```

### cma_reports

```sql
CREATE TABLE cma_reports (
  id INT AUTO_INCREMENT PRIMARY KEY,
  tenant_id INT,
  agent_id INT NOT NULL,  -- Agent who created this CMA
  subject_property_address VARCHAR(255) NOT NULL,
  subject_avm_low DECIMAL(12, 2),
  subject_avm_mid DECIMAL(12, 2),
  subject_avm_high DECIMAL(12, 2),

  recommended_list_price_low DECIMAL(12, 2),  -- Based on comps + trends
  recommended_list_price_high DECIMAL(12, 2),
  recommended_list_price_mid DECIMAL(12, 2),  -- Primary recommendation

  market_trend_median_price DECIMAL(12, 2),
  market_trend_dom INT,  -- Average days on market
  market_trend_inventory_months DECIMAL(4, 1),  -- Months of inventory
  market_trend_price_per_sqft DECIMAL(8, 2),
  market_trend_market_condition ENUM('buyers', 'sellers', 'balanced'),  -- Market tilt

  cma_title VARCHAR(255),  -- e.g., "CMA for 123 Ocean Ave, Carmel"
  cma_prepared_date DATE,
  cma_prepared_by VARCHAR(255),  -- Agent name
  cma_notes TEXT,  -- Agent commentary
  cma_style VARCHAR(50),  -- 'modern', 'traditional', 'luxury', etc. (brand-specific)

  pdf_generated BOOLEAN DEFAULT FALSE,
  pdf_path VARCHAR(500),  -- Path to generated PDF
  pdf_generated_at TIMESTAMP,

  html_generated BOOLEAN DEFAULT FALSE,
  html_content LONGTEXT,  -- Rendered HTML for email/sharing

  shared_with_client INT,  -- client_id if linked to CRM client
  shared_date TIMESTAMP,
  email_subject VARCHAR(255),  -- Template for sharing via email
  email_body TEXT,

  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  FOREIGN KEY (tenant_id) REFERENCES tenants(id),
  FOREIGN KEY (agent_id) REFERENCES admins(id),
  FOREIGN KEY (shared_with_client) REFERENCES clients(id),
  INDEX (tenant_id, agent_id),
  INDEX (created_at)
);
```

### cma_comps

```sql
CREATE TABLE cma_comps (
  id INT AUTO_INCREMENT PRIMARY KEY,
  tenant_id INT,
  cma_id INT NOT NULL,
  mls_number VARCHAR(50),
  comp_address VARCHAR(255),
  comp_zip VARCHAR(10),
  comp_beds INT,
  comp_baths DECIMAL(2, 1),
  comp_sqft INT,
  comp_lot_sqft INT,
  comp_year_built INT,
  comp_style VARCHAR(100),
  comp_condition ENUM('excellent', 'good', 'fair', 'poor'),

  sale_price DECIMAL(12, 2),
  sale_date DATE,
  days_on_market INT,
  price_per_sqft DECIMAL(8, 2),

  adjustments JSON,  -- { "beds_diff": -1, "beds_adjustment": -15000, "condition_diff": "good", "condition_adjustment": -10000, ... }
  adjusted_price DECIMAL(12, 2),  -- sale_price + adjustments
  adjustment_percentage DECIMAL(5, 2),  -- Relative adjustment %

  comp_relevance_score INT,  -- 0-100, how similar to subject (sqft, beds, sale recency, location proximity)

  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  FOREIGN KEY (tenant_id) REFERENCES tenants(id),
  FOREIGN KEY (cma_id) REFERENCES cma_reports(id),
  INDEX (tenant_id, cma_id),
  INDEX (comp_relevance_score DESC)
);
```

### valuation_configs

```sql
CREATE TABLE valuation_configs (
  id INT AUTO_INCREMENT PRIMARY KEY,
  tenant_id INT,
  avm_provider VARCHAR(100),  -- 'zillow', 'attom', 'house_canary', 'internal_ml'
  avm_api_key VARCHAR(1000),  -- Encrypted
  avm_api_endpoint VARCHAR(500),

  widget_enabled BOOLEAN DEFAULT TRUE,
  widget_embed_code VARCHAR(2000),  -- HTML snippet for website embedding
  widget_primary_color VARCHAR(7),  -- Hex color
  widget_accent_color VARCHAR(7),
  widget_cta_text VARCHAR(100),  -- "Get Free Valuation", etc.

  cma_enabled BOOLEAN DEFAULT TRUE,
  cma_default_style VARCHAR(50),  -- 'modern', 'traditional', 'luxury'
  cma_include_market_trends BOOLEAN DEFAULT TRUE,
  cma_include_agent_notes BOOLEAN DEFAULT TRUE,
  cma_pdf_watermark VARCHAR(200),  -- "Prepared for discussion purposes only"

  lead_capture_require_ownership BOOLEAN DEFAULT TRUE,  -- Force email/phone confirmation
  lead_auto_enroll_drip VARCHAR(100),  -- 'seller_nurture', 'buyer_nurture', none
  lead_assign_to_agent INT,  -- Default agent for valuation leads

  market_trend_radius_miles INT DEFAULT 3,  -- Geographic radius for market analysis
  comp_search_radius_miles INT DEFAULT 2,  -- Radius for comp selection
  comp_max_price_variance_pct INT DEFAULT 20,  -- Comps within +/-20% of subject price
  comp_max_sqft_variance_pct INT DEFAULT 25,  -- +/- 25% sqft variance

  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  FOREIGN KEY (tenant_id) REFERENCES tenants(id),
  UNIQUE KEY (tenant_id),
  INDEX (avm_provider)
);
```

### valuation_leads

```sql
CREATE TABLE valuation_leads (
  id INT AUTO_INCREMENT PRIMARY KEY,
  tenant_id INT,
  home_valuation_id INT,  -- Links to home_valuations table
  lead_first_name VARCHAR(100),
  lead_last_name VARCHAR(100),
  lead_email VARCHAR(255),
  lead_phone VARCHAR(20),
  lead_address VARCHAR(255),
  lead_zip VARCHAR(10),

  lead_is_owner BOOLEAN,  -- Confirmed ownership
  lead_is_interested_selling BOOLEAN,  -- Response to "interested in selling?"
  lead_is_interested_refinance BOOLEAN,
  lead_estimated_equity DECIMAL(12, 2),  -- Calculated from AVM - estimated mortgage

  source_page_url VARCHAR(500),  -- What website/page was widget on?
  source_campaign VARCHAR(100),  -- UTM tracking

  imported_to_crm BOOLEAN DEFAULT FALSE,
  imported_to_crm_at TIMESTAMP,
  imported_as_client_id INT,  -- clients.id after import

  followed_up_by INT,  -- admins.id of agent who followed up
  followup_date TIMESTAMP,

  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  FOREIGN KEY (tenant_id) REFERENCES tenants(id),
  FOREIGN KEY (home_valuation_id) REFERENCES home_valuations(id),
  FOREIGN KEY (imported_as_client_id) REFERENCES clients(id),
  FOREIGN KEY (followed_up_by) REFERENCES admins(id),
  INDEX (tenant_id),
  INDEX (lead_email),
  INDEX (imported_to_crm)
);
```

---

## API ENDPOINTS (api/valuations.php)

### requestValuation

**POST /api/valuations.php?action=requestValuation**

Request instant home valuation. Takes address + optional lead info. Returns AVM estimate + lead form HTML if not provided lead data.

```json
REQUEST:
{
  "property_address": "123 Ocean Ave, Carmel, CA 93921",
  "property_beds": 4,
  "property_baths": 2.5,
  "property_sqft": 3200,
  "property_year_built": 1985,
  "property_type": "single_family",
  "lead_name": "John Smith",
  "lead_email": "john@example.com",
  "lead_phone": "831-555-0123",
  "lead_property_owner": true
}

RESPONSE (success):
{
  "success": true,
  "data": {
    "valuation_id": 5678,
    "property_address": "123 Ocean Ave, Carmel, CA 93921",
    "avm_estimate_low": 2800000,
    "avm_estimate_mid": 3100000,
    "avm_estimate_high": 3400000,
    "avm_confidence": 82,
    "avm_source": "zillow",
    "avm_last_updated": "2026-03-29T14:00:00Z",
    "lead_captured": {
      "name": "John Smith",
      "email": "john@example.com",
      "phone": "831-555-0123"
    },
    "next_step": "CMA available upon request"
  }
}
```

### getValuation

**GET /api/valuations.php?action=getValuation&valuation_id=5678**

Retrieve full valuation details. For leads, requires email verification or agent access.

```json
RESPONSE (success):
{
  "success": true,
  "data": {
    "valuation_id": 5678,
    "property": {
      "address": "123 Ocean Ave, Carmel, CA 93921",
      "beds": 4,
      "baths": 2.5,
      "sqft": 3200,
      "year_built": 1985,
      "type": "single_family"
    },
    "avm": {
      "estimate_low": 2800000,
      "estimate_mid": 3100000,
      "estimate_high": 3400000,
      "confidence": 82,
      "source": "zillow",
      "last_updated": "2026-03-29T14:00:00Z"
    },
    "market_context": {
      "neighborhood": "Carmel, CA",
      "median_price": 3050000,
      "price_per_sqft": 956,
      "days_on_market_avg": 28,
      "inventory_months": 2.1
    }
  }
}
```

### createCMA

**POST /api/valuations.php?action=createCMA**

Create a new CMA report. Agent selects subject property address, bedroom/bath, square footage, and Fogbreak auto-suggests comps.

```json
REQUEST:
{
  "agent_id": 12,
  "subject_property_address": "123 Ocean Ave, Carmel, CA 93921",
  "subject_property_beds": 4,
  "subject_property_baths": 2.5,
  "subject_property_sqft": 3200,
  "subject_property_year_built": 1985,
  "subject_avm_mid": 3100000,
  "cma_title": "CMA for 123 Ocean Ave, Carmel",
  "cma_notes": "Excellent location near Carmel Point. Recent upgrades to kitchen.",
  "cma_style": "luxury"
}

RESPONSE (success):
{
  "success": true,
  "data": {
    "cma_id": 987,
    "subject_property_address": "123 Ocean Ave, Carmel, CA 93921",
    "subject_avm_mid": 3100000,
    "suggested_comps": [
      {
        "mls_number": "ML123456",
        "comp_address": "456 Scenic Rd, Carmel, CA 93921",
        "comp_beds": 4,
        "comp_baths": 2.5,
        "comp_sqft": 3150,
        "sale_price": 3050000,
        "sale_date": "2026-02-15",
        "days_on_market": 21,
        "comp_relevance_score": 94
      },
      ...
    ],
    "preliminary_list_price_mid": 3150000,
    "next_step": "Review comps and click 'Generate CMA'"
  }
}
```

### addComps

**POST /api/valuations.php?action=addComps**

Manually add comps to a CMA, or confirm auto-selected comps.

```json
REQUEST:
{
  "cma_id": 987,
  "comp_ids": [
    { "mls_number": "ML123456", "comp_address": "456 Scenic Rd, Carmel, CA 93921" },
    { "mls_number": "ML654321", "comp_address": "789 Lobos St, Carmel, CA 93921" }
  ]
}

RESPONSE (success):
{
  "success": true,
  "data": {
    "cma_id": 987,
    "comps_added": 2,
    "adjusted_list_price_mid": 3120000,
    "recommended_price_range": [3050000, 3180000]
  }
}
```

### removeComps

**POST /api/valuations.php?action=removeComps**

Remove a comp from CMA and recalculate pricing.

```json
REQUEST:
{
  "cma_id": 987,
  "comp_mls_number": "ML123456"
}

RESPONSE (success):
{
  "success": true,
  "data": {
    "cma_id": 987,
    "comps_remaining": 4,
    "recalculated_list_price_mid": 3140000
  }
}
```

### generateCMAPdf

**POST /api/valuations.php?action=generateCMAPdf**

Generate branded PDF of CMA report. Async job; returns job_id for polling. PDF stored in `/pdf/` directory.

```json
REQUEST:
{
  "cma_id": 987,
  "include_agent_notes": true,
  "include_market_trends": true
}

RESPONSE (success):
{
  "success": true,
  "data": {
    "cma_id": 987,
    "job_id": "pdf_job_abc123",
    "status": "processing",
    "estimated_seconds": 8,
    "polling_endpoint": "/api/valuations.php?action=getPDFStatus&job_id=pdf_job_abc123"
  }
}
```

### getMarketTrends

**GET /api/valuations.php?action=getMarketTrends&zip=93921&radius_miles=3&days=90**

Return market trend data for a location. Used in CMA + valuation widgets.

```json
RESPONSE (success):
{
  "success": true,
  "data": {
    "location": "Carmel, CA 93921",
    "radius_miles": 3,
    "period_days": 90,
    "median_sale_price": 3050000,
    "median_price_change_pct": 2.3,  -- Up 2.3% vs prior period
    "days_on_market_avg": 28,
    "days_on_market_trend": -2,  -- Decreasing (faster sales)
    "inventory_months": 2.1,
    "price_per_sqft": 956,
    "price_per_sqft_change_pct": 1.8,
    "market_condition": "sellers",  -- Plenty of demand
    "top_3_price_ranges": [
      { "range": "under_1m", "count": 5, "median": 850000 },
      { "range": "1m_3m", "count": 23, "median": 2100000 },
      { "range": "3m_plus", "count": 8, "median": 4200000 }
    ],
    "list_vs_sale_ratio": 98.2  -- Average sale price is 98.2% of list
  }
}
```

### configureAVM

**POST /api/valuations.php?action=configureAVM**

Configure AVM provider (Zillow, ATTOM, HouseCanary, internal ML). Admin only.

```json
REQUEST:
{
  "avm_provider": "attom",
  "avm_api_key": "***",
  "avm_api_endpoint": "https://api.attomdata.com/..."
}

RESPONSE (success):
{
  "success": true,
  "data": {
    "avm_provider": "attom",
    "configured_at": "2026-03-29T14:30:00Z",
    "test_result": "Connection successful"
  }
}
```

### getValuationLeads

**GET /api/valuations.php?action=getValuationLeads&limit=50&status=new**

List captured valuation leads (seller leads from widget). Admin/agent only.

```json
RESPONSE (success):
{
  "success": true,
  "data": {
    "total_leads": 147,
    "new_leads": 12,
    "leads": [
      {
        "valuation_lead_id": 234,
        "lead_name": "John Smith",
        "lead_email": "john@example.com",
        "lead_phone": "831-555-0123",
        "property_address": "123 Ocean Ave, Carmel, CA 93921",
        "avm_estimate_mid": 3100000,
        "lead_is_owner": true,
        "lead_is_interested_selling": true,
        "lead_status": "new",
        "created_at": "2026-03-29T12:45:00Z",
        "imported_to_crm": false
      },
      ...
    ]
  }
}
```

### importValuationLead

**POST /api/valuations.php?action=importValuationLead**

Import a valuation lead into CRM. Creates clients record, triggers seller nurture drip, creates task for agent.

```json
REQUEST:
{
  "valuation_lead_id": 234,
  "assign_to_agent_id": 12
}

RESPONSE (success):
{
  "success": true,
  "data": {
    "valuation_lead_id": 234,
    "imported_as_client_id": 5678,
    "client_name": "John Smith",
    "drip_enrollment": "seller_nurture",
    "task_created": true,
    "task_id": 99,
    "task_due_date": "2026-04-02"
  }
}
```

### generateLandingPage

**POST /api/valuations.php?action=generateLandingPage**

Generate a high-converting landing page for a property valuation campaign. Returns shareable URL.

```json
REQUEST:
{
  "property_address": "123 Ocean Ave, Carmel, CA 93921",
  "property_avm_mid": 3100000,
  "agent_name": "Kean Matthams",
  "agent_photo_url": "https://...",
  "campaign_name": "carmel_listings_march"
}

RESPONSE (success):
{
  "success": true,
  "data": {
    "landing_page_id": 456,
    "url": "https://fogbreak.io/landing/carmel_listings_march",
    "preview_url": "https://fogbreak.io/landing/carmel_listings_march?preview=1",
    "qr_code_url": "https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=https://fogbreak.io/landing/carmel_listings_march",
    "meta_title": "What's Your Carmel Home Worth? Free Instant Estimate",
    "meta_description": "Get an instant, accurate valuation of your Carmel home. Prepared by Kean Matthams."
  }
}
```

---

## IMPLEMENTATION STEPS

### Phase 1: AVM Integration (Weeks 1-2)

1. **Select AVM provider** — Evaluate Zillow, ATTOM, HouseCanary, CoreLogic:
   - Zillow: Free API (up to 100/month), ~70% accuracy
   - ATTOM: $0.05/lookup (5,000 lookups = $250), ~78% accuracy, property history
   - HouseCanary: $25/month (up to 500), ~85% accuracy
   - Choose based on tenant volume + accuracy requirements. Default: HouseCanary for high accuracy, ATTOM for scale.

2. **Implement AVM lookup function** in valuations.php:
   - Query MLS data (from instruction 18)
   - Fall back to external API (Zillow/ATTOM/HouseCanary)
   - Store result in home_valuations table
   - Confidence scoring: Official MLS data = 95%, API estimate = 75-85%, extrapolated = 60%

3. **Build confidence scoring**:
   - Confidence = based on data recency + comp count + property record completeness
   - Recent sale in 30 days (same property) = 95%
   - Comps available within 2 miles = +10%
   - Recent market data = +5%
   - Formula: base_confidence + comp_bonus + data_recency_bonus, capped at 100

4. **Test AVM accuracy**: Compare estimates to actual sales (backtest 100+ properties).

### Phase 2: Valuation Widget (Weeks 2-4)

1. **Build Next.js widget component** (instruction 15 integration):
   - Address autocomplete (Google Places API)
   - Beds/baths/sqft inputs (optional; can be auto-filled from address)
   - "Get Free Valuation" button
   - Responsive design (mobile-first)
   - Tenant-configurable CSS variables (--primary, --accent, etc.)

2. **Build lead capture form** (shows AFTER valuation):
   - Name, email, phone fields
   - "I own this property" checkbox (for CCPA compliance)
   - "I'm interested in selling" optional checkbox
   - Privacy text + opt-in checkbox for drips
   - Branded submit button

3. **Implement embed code generator**:
   - Generate `<script>` tag for agent websites
   - Loads widget in iframe from fogbreak.io/widget/valuation
   - Configurable colors via URL params
   - Analytics tracking (UTM, source page)

4. **Test responsiveness**: Desktop, tablet, mobile. Test on WordPress, Wix, Squarespace.

### Phase 3: CMA Builder (Weeks 3-6)

1. **Build CMA creation wizard** (Next.js):
   - Step 1: Subject property (address, beds, baths, sqft)
   - Step 2: AVM estimate display (confidence scored)
   - Step 3: Auto-suggest comps (query MLS, filter by radius + price/sqft variance)
   - Step 4: Manual comp selection (agent can add/remove)
   - Step 5: Price adjustments (agent adds adjustments per comp: bed difference, condition, etc.)
   - Step 6: Review & generate

2. **Implement comp selection algorithm**:
   - Query MLS for properties sold in last 90 days within comp_search_radius_miles
   - Filter: beds within ±1, sqft within ±25%, price within ±20% of subject
   - Sort by relevance_score (similar sqft + recent sale + same condition)
   - Return top 8-12 suggestions; agent picks 3-6

3. **Build price adjustment logic**:
   - Predefined adjustments: per bed ($25k-75k typical), per bath ($15k-40k), condition (-$10k to +$30k), lot size, etc.
   - Agent can override adjustments
   - Formula: adjusted_price = sale_price + sum(adjustments)
   - Calculate average adjusted price across comps → recommended list price

4. **Implement market trend calculation**:
   - Pull median sale price, DOM, inventory, price-per-sqft from MLS data (last 90 days)
   - Store in cma_reports
   - Display in CMA presentation

5. **Test comp accuracy**: Generate 10 CMAs manually, verify comps are truly comparable, verify price adjustments are reasonable.

### Phase 4: CMA Presentation & PDF Generation (Weeks 5-7)

1. **Build CMA HTML template** (branded, responsive):
   - Header: Agent name, CMA date, subject address
   - Executive summary: Recommended list price range + confidence
   - Subject property details: Beds, baths, sqft, features, photo (if available from MLS)
   - Market context: Median price, DOM, inventory, market condition
   - Comp analysis table: Address, sale price, adjustments, adjusted price
   - Price adjustment chart (visual breakdown)
   - Recommended pricing section (range + reasoning)
   - Agent notes (optional)
   - Footer: Disclaimer ("Prepared for discussion purposes only"), confidentiality notice

2. **Implement brand theming**:
   - Use tenant's brand colors from config (--primary, --accent, --bg, --text)
   - Logo placement (top-left or centered)
   - Font family (configured per tenant)
   - Brand presentation applies via tenant configuration

3. **Build PDF generation** (via wkhtmltopdf or Puppeteer):
   - Convert HTML → PDF
   - Preserve styling, images, layout
   - Add watermark: "Prepared for discussion purposes only"
   - Page numbers, header/footer
   - Generate filename: `CMA_[Address]_[Date].pdf`
   - Store in `/pdfs/` directory on Bluehost

4. **Build email delivery**:
   - Generate email template with embedded CMA HTML or PDF attachment
   - Subject line template: "CMA for [Address] — Recommended List Price [Range]"
   - Clickable CMA link (shareable URL)
   - Track opens/clicks

5. **Test PDF rendering**: Generate 20 CMAs, verify PDF quality, confirm branding applied correctly.

### Phase 5: Lead Capture Flow (Week 7)

1. **Build lead import flow**:
   - Valuation leads captured in valuation_leads table
   - Admin reviews leads (getValuationLeads endpoint)
   - One-click import to CRM (importValuationLead endpoint)
   - Creates clients record with source = 'home_valuation'
   - Auto-fills property_estimate (avm_estimate_mid)
   - Sets lead_status = 'seller' (or 'buyer' if opted for buyer nurture)

2. **Auto-enroll in drips**:
   - Home_valuation lead source → seller nurture drip (default)
   - Or custom drip per tenant configuration
   - Add interaction record (type = 'valuation_request')

3. **Create follow-up task**:
   - Task for assigned agent: "Follow up on valuation request for [Address]"
   - Due date: 24 hours
   - Priority: medium

4. **Send lead notification**:
   - Email to assigned agent: "New valuation lead: [Name], [Address]"
   - Include estimated equity (avm_mid - estimated_mortgage)
   - Include lead contact info
   - Link to valuation details

### Phase 6: Integration (Week 8)

1. **Integrate with instruction 18 (MLS Integration)**:
   - Pull MLS sold data for AVM + CMA comp selection
   - Use MLS property photos in CMA presentation
   - Use MLS days_on_market in market trends

2. **Integrate with instruction 10 (AI Copy Engine)**:
   - Generate CMA email subject/body using AI
   - Generate property description for landing page using AI (Fair Housing audited)

3. **Integrate with drips.php**:
   - Auto-enroll function for valuation leads
   - Trigger seller nurture drip on import

4. **Integrate with instruction 15 (Next.js)**:
   - Deploy valuation widget at fogbreak.io/widget/valuation
   - Deploy CMA builder at fogbreak.io/cma/builder
   - Deploy landing page generator

---

## CRON JOBS (api/cron.php)

### valuation_lead_sync

**Runs:** Every 4 hours | **Duration:** ~3 minutes | **Auth:** API key

```php
// For each valuation_lead with imported_to_crm=false and created_at > 24 hours ago:
//   1. Auto-import to CRM if configured (auto_import_valuation_leads=true)
//   2. Assign to default agent or round-robin
//   3. Enroll in seller nurture drip
//   4. Create follow-up task
// Return summary: {auto_imported: N, awaiting_manual_review: M}
```

### avm_refresh

**Runs:** Weekly (Monday 2 AM) | **Duration:** ~15 minutes | **Auth:** API key

```php
// For home_valuations with avm_last_updated > 30 days old:
//   1. Re-query AVM provider
//   2. Update avm_estimate_*, avm_confidence, avm_last_updated
//   3. Alert if confidence dropped >10 points (market shift detected)
// Return summary: {refreshed: N, confidence_drops: K}
```

---

## TESTING CRITERIA

### Unit Tests

1. **requestValuation**:
   - Test with valid address (must be in US, ideally with MLS data)
   - Test with address not in MLS (should use fallback API, lower confidence)
   - Test with incomplete address (autocomplete should help)
   - Verify AVM estimate range is reasonable (low < mid < high, all > 0)
   - Verify confidence score 0-100
   - Verify lead capture fields optional until form submitted

2. **createCMA**:
   - Test with subject property in MLS
   - Verify suggested comps are returned
   - Verify comps meet relevance criteria (sqft ±25%, price ±20%, within radius)
   - Verify preliminary list price is reasonable (average adjusted comp price ±5%)

3. **Price adjustment logic**:
   - Test bed adjustment: +$1B per bed, -$25k per bed missing
   - Test bath adjustment: +$15k per bath, -$10k per bath missing
   - Test condition adjustment: good vs excellent should adjust by ~$20k
   - Verify adjusted prices reasonable

4. **Market trends**:
   - Test getMarketTrends for known zip (e.g., 93921)
   - Verify median price > 0
   - Verify DOM is reasonable (10-60 days typical)
   - Verify inventory_months is reasonable (1.5-4 typical)
   - Verify market_condition assignment (buyers/sellers/balanced)

### Integration Tests

1. **Valuation lead flow**:
   - Fill valuation widget form
   - Verify lead captured in valuation_leads table
   - Verify home_valuations record created
   - Verify avm_estimate populated

2. **CMA creation flow**:
   - Create CMA with subject property
   - Auto-suggest comps
   - Manually select 4 comps
   - Generate CMA
   - Verify cma_reports record created
   - Verify comps linked to CMA

3. **PDF generation**:
   - Generate PDF from CMA
   - Verify PDF created successfully
   - Verify PDF contains: subject property, comps, price recommendation, market trends
   - Verify branding applied (colors, logo, fonts)
   - Verify watermark present

4. **Lead import**:
   - Create valuation lead
   - Import to CRM
   - Verify clients record created with source = 'home_valuation'
   - Verify task created for agent
   - Verify drip enrollment triggered

5. **Email delivery**:
   - Share CMA via email
   - Verify email sent to client
   - Verify email contains CMA preview or PDF attachment
   - Verify open/click tracking works

### Performance Tests

1. **AVM lookup speed**: <2 seconds (cached result <500ms)
2. **Comp selection algorithm**: <3 seconds (for 5,000 MLS records)
3. **CMA PDF generation**: <8 seconds
4. **Widget load time**: <1 second on 3G connection

### Security Tests

1. **Authentication**: All valuation endpoints require session or API key
2. **Tenant isolation**: Valuations/CMAs only visible to owner tenant
3. **Lead privacy**: Valuation leads marked as CCPA-compliant (opt-in)
4. **SQL injection**: Test with malicious address/email values; verify PDO prepared statements prevent injection
5. **XSS**: Test CMA notes field with script tags; verify HTML-escaped in PDF

---

## WHITE-LABEL BRANDING

All presentations use tenant's brand configuration stored in the tenants table:
- **Brand colors:** primary, accent, background, text (per tenant config)
- **Typography:** font-family configured per tenant
- **Logo:** managed per tenant

CMA PDF, widget, landing pages all respect tenant brand colors, typography, logo placement.

---

## ESTIMATED COSTS

- **AVM API**: HouseCanary ($25/month, 500/month), or ATTOM ($0.05/lookup, ~$250/month at scale)
- **MLS data**: Included from instruction 18
- **PDF generation**: Puppeteer (self-hosted, free)
- **Google Places autocomplete**: $0.017 per request (~$170/1000, typical tenant ~$20/month)
- **Google Sheet integration** (optional market trend export): Free

**Typical tenant cost**: $50-100/month (AVM + Places API)

---

## DEPLOYMENT CHECKLIST

- [ ] Select AVM provider and configure API key
- [ ] Create database tables
- [ ] Build api/valuations.php module
- [ ] Build valuation widget (Next.js component)
- [ ] Build CMA builder wizard (Next.js)
- [ ] Implement comp selection algorithm
- [ ] Test AVM accuracy (backtest 50+ properties)
- [ ] Build CMA HTML template (all 3 brands)
- [ ] Implement PDF generation (wkhtmltopdf or Puppeteer)
- [ ] Test PDF rendering (20 CMAs, verify branding)
- [ ] Build email delivery + sharing
- [ ] Integrate with MLS (instruction 18)
- [ ] Build lead import flow → CRM
- [ ] Test lead-to-CRM flow (valuation → client → task → drip)
- [ ] Build landing page generator
- [ ] Add cron jobs
- [ ] Deploy to Bluehost
- [ ] Test widget embed on sample WordPress site
- [ ] Document widget embed code in help articles

---

**Owner:** Kean | **Reviewed by:** Architecture working group | **Next:** Instruction 26 (Ad Campaign Manager)
