BUILD SPEC — Outreach Engine (cockpit module)
**For:** Claude Code, working in the live Uniestate platform repo.
**Goal:** Add a new **"Outreach Engine"** tab to the founders' cockpit. It is the *outbound* counterpart to the existing inbound demand engine: it finds and warms buyers and turns prepared outreach actions into pipeline — for both whole-unit and tokenization/fractional buyers.
> **Read first, then build.** Before writing code, inspect the current cockpit so this matches reality: find the cockpit component, its tab/nav mechanism, the shared store (the lead store — likely `useStore`, with `leads` / `addLead` / `moveStage` or similar), and the theme tokens (cream `#F4F1EA`, ink `#16130E`, gold `#A8915E`, the AI teal `#0E7C7B`, Cormorant Garamond display, Inter body, JetBrains Mono labels). **Reuse the existing store, tokens, and component patterns. Do not introduce a new design language or a second state system.** If any name below differs in the repo, adapt to the repo's real names — this spec describes behaviour and structure, not exact identifiers.
---
1. Where it goes
- Add a cockpit tab labelled **"Outreach"** alongside the existing tabs (Pipeline / Analytics / AI Agent, or whatever the current set is).
- It renders a new component, suggested `OutreachEngine`, in the same content area, using the same dark cockpit styling as the other tabs.
- No routing changes beyond the tab. No new top-level pages.
2. The core idea (build the UI around this)
Outreach is organised as **four lanes, ordered safest → riskiest**, left to right. Each lane is a live queue of **outreach actions** the AI has prepared for a human to approve. The ordering is deliberate and must be visible: the safe lanes look primary; the risky lane looks gated.
| # | Lane | What's in it | Compliance posture |
|---|------|--------------|--------------------|
| 1 | **Re-engage** | People who already touched Uniestate: abandoned reservations, dormant waitlist members, brochure downloaders, stalled pipeline leads | ✅ Safe — prior engagement = lawful basis |
| 2 | **Partners & channels** | Brokers, golden-visa/immigration consultants, wealth managers, portals (Bayut, dubizzle, Property Finder) | ✅ Safe — B2B referral relationships |
| 3 | **Intent signals** | *Public* buying signals: forum/Reddit posts about RAK/Dubai property, LinkedIn engagement on relevant content | ⚠️ Grey — human approves every send |
| 4 | **Direct outreach** | Cold contacts | ⛔ Gated — blocked unless consent status allows it |
3. Data model (extend the store; keep it client-side simulated like the rest of the demo)
Add to the shared store. All simulated client-side, consistent with how the existing leads/pipeline are mocked. Mark the real connection points with `// API`.
```
OutreachContact {
id
name
market // ISO-ish code reusing existing MARKETS (IN, GB, RU, CN, DE…)
lane // 'reengage' | 'partners' | 'intent' | 'direct'
buyerType // 'whole' | 'token' (the whole-unit vs tokenization toggle filters on this)
project // optional project id from existing PROJECTS
source // e.g. 'Abandoned reservation', 'Waitlist · dormant 30d', 'Bayut partner',
// 'RAK investor forum', 'LinkedIn signal', 'Imported list'
signal // short human-readable reason this person is here (the "why now")
channel // 'whatsapp' | 'email' | 'call' | 'inapp'
consent // 'engaged' | 'opted_in' | 'unknown' | 'opted_out'
status // 'suggested' | 'approved' | 'sent' | 'replied' | 'converted' | 'suppressed'
draft // AI-composed message text (see Composer)
lang // buyer language for the draft (English, Arabic, Hindi, Mandarin, Russian, German…)
created
}
OutreachPartner { // for the Partners lane's directory view
id, name, type // 'Mortgage broker' | 'Golden-visa consultant' | 'Wealth manager' | 'Portal'
market, referrals, leadsRouted, status // 'active' | 'invited' | 'paused'
}
```
Seed ~10–14 contacts spread across the four lanes and both buyerTypes, plus ~5 partners, so the board looks alive on first load (mirror how the pipeline is seeded today).
Store actions to add: `approveOutreach(id)`, `sendOutreach(id)` (flips to 'sent', then after a short timeout simulate some → 'replied'), `suppressOutreach(id)`, `editDraft(id, text)`, and **`convertOutreachToLead(id)`** — this is important: a replied/converted outreach contact should **call the existing `addLead(...)`** so it flows into the normal pipeline with `source` preserved (attribution). Reuse the existing toast/pulse so an outreach conversion lights up the Pipeline tab just like an inbound lead does. This keeps "one brain" true.
4. The screen layout
**Top bar of the module:**
- Title "Outreach Engine" + one-line subtitle: *"Find and warm buyers — then reach the hands already raised."*
- A **buyer-type toggle**: `Whole-unit` | `Tokenization` | `All` — filters the board by `buyerType`.
- A small KPI strip (reuse cockpit KPI card style): **Prepared** (suggested count), **Approved/sent today**, **Replies**, **Outreach → pipeline** (count converted), **Suppressed/opt-outs**.
**The four-lane board** (horizontal, scrollable on narrow screens, same column styling as the pipeline):
- Each lane has a header with its name, a count, and a **compliance chip** (green ✅ / amber ⚠️ / red ⛔ as per the table).
- Each card in a lane shows: name + market flag, `buyerType` pill, the **signal** ("why now"), the channel icon, a **consent badge**, and an AI-score-style confidence if cheap to reuse.
- Card actions: **Approve**, **Edit draft**, **Send**, **Suppress**. For lane 4, Approve/Send are disabled unless `consent` ∈ {opted_in, engaged} — show a lock + reason instead.
**The AI Outreach Composer (panel or modal):**
- Opens from a card. Shows the AI-drafted message in the contact's `lang`, tailored to lane + buyerType + project.
- Whole-unit draft → leads with the property, yield, payment plan, viewing offer.
- Tokenization draft → leads with fractional entry ("from as little as…"), the VARA-licensed-partner framing, "register your interest / join the waitlist." **Never claims Uniestate operates the tokenization** — Uniestate is builder/promoter; partner runs the rails. Keep this wording guardrail in the generated copy.
- Buttons: **Approve & queue**, **Regenerate**, **Edit**, **Escalate to human**. Mark the model call `// API: LLM outreach composer`.
5. Compliance guardrail layer (this is not optional — it's the selling point)
The UAE is strict (TDRA rules on unsolicited marketing; PDPL requires a lawful basis). Build the guardrails as *visible UI*, because "compliant by design" is part of what we're selling:
- **Consent badge on every contact** (Engaged / Opted-in / Unknown / Opted-out) with colour.
- **Direct lane is gated:** any contact with `consent` = 'unknown' or 'opted_out' cannot be approved or sent — the button is locked and shows the reason ("No lawful basis — consent required").
- **Global suppression list:** an opt-out instantly sets `status='suppressed'` and the contact can never be re-queued. Add a visible "Suppressed / opt-outs" counter.
- **Throttle note + quiet-hours:** show a small "respects send limits & local quiet hours" indicator. Simulated, but mark `// API: rate limiter / quiet-hours by timezone`.
- A short **compliance footer** on the module: *"Built to UAE marketing & data rules (TDRA · PDPL). Outreach prioritises engaged and opted-in contacts; cold contact is gated on lawful basis."*
6. Partners lane specifics
Lane 2 is slightly different — it has a **partner directory** view in addition to action cards:
- A compact table of `OutreachPartner` rows: name, type, market, referrals, leads routed, status.
- Action per partner: **Send launch pack** (co-branded), **Invite**, **Pause**.
- A line explaining the model: *"Reach buyers through who already holds them — brokers, visa consultants, wealth managers and portals. Equip them; route their leads back into the cockpit."* (This is the PRYPCO/Bayut-dubizzle playbook.)
7. Attribution (close the loop)
- When an outreach contact converts, it becomes a normal lead via the existing `addLead`, carrying its `source` and `lane` so the cockpit **Analytics** tab's "lead source" / attribution already counts it. If Analytics groups by channel/source, make sure outreach sources appear there. No separate analytics screen needed.
8. Styling / quality bar
- Match the existing cockpit exactly: dark panel, gold accents, Cormorant headings, Mono labels, the same card and KPI components. Reuse, don't reinvent.
- Fully responsive; the four lanes scroll horizontally on mobile like the pipeline does.
- Keep all AI logic transparent/simulated client-side (consistent with the rest of the demo), every real hook marked `// API`.
- No localStorage/sessionStorage. Keep state in the existing store.
9. Acceptance checklist (the build is done when…)
1. New **Outreach** tab appears in the cockpit and renders the four-lane board.
2. Buyer-type toggle filters between whole-unit and tokenization contacts.
3. Each lane shows the correct compliance chip; lane 4 cards are **gated** when consent is unknown/opted-out (button locked + reason shown).
4. The **Composer** opens, shows a language-appropriate draft, and tokenization drafts use the *builder-not-exchange / VARA-licensed-partner* framing (never "Uniestate tokenizes").
5. **Approve → Send → Replied → Convert** flow works; a converted contact appears in the **Pipeline** tab via the existing `addLead`, with its source preserved, and triggers the existing toast/pulse.
6. Opt-out moves a contact to a suppression state it can't leave; the opt-out counter updates.
7. KPI strip and the compliance footer render.
8. Visuals are indistinguishable in style from the existing cockpit tabs; responsive; no console errors; no browser storage used.
10. Out of scope (don't build)
- Real sending of any message; real scraping of forums/LinkedIn; real partner APIs. All simulated, marked `// API`.
- Any actual storage or transmission of personal data.
- Changing the customer-facing site. This is cockpit-only.
---