CRM ENGINE — BUILD SPEC
**For:** Claude Code (has eyes on the live `uniestate` repo — source of truth)
**Target:** add a **Deals & Relationships** layer to the existing founders' Cockpit
**Format mirrors:** `OUTREACH-ENGINE-SPEC.md` — paste-ready, reuse the live store/tokens/patterns, all AI/sending simulated and marked `// API`
**Governing thesis (do not lose):** *The tokenization partner makes tokenization possible. Uniestate's platform makes it sell out.* This CRM operationalizes the **demand engine** — waitlist, scarcity, allocation, pipeline — not a generic sales tool.
---
0. Read before building
1. **Open the live repo first.** This spec assumes the current Cockpit already has: a lead pipeline (5 stages), AI lead scoring, next-best-action, Founder Digest, AI Agent inbox, Analytics/attribution, and the Outreach tab (in build). **Do not rebuild any of these.** The CRM extends them.
2. **Reuse, don't duplicate:**
- The existing lead store and its `addLead` (customer-side → cockpit "one brain" flow). Every object below hangs off the same store.
- The existing design tokens: cream background, black **Cormorant Garamond** headings, single **gold** accent (~`#A8915E`), rounded corners, light/editorial. **No new palette.** If a token isn't already defined, add it to the existing token module, don't inline hexes.
- The existing nav/tab pattern — add tabs the same way the Outreach tab was added.
3. **Uniestate is a developer, not a brokerage.** The default lens is **developer sales**. Broker features live behind a **Uniestate Capital** toggle (the Abu Dhabi brokerage subsidiary) so they never muddy the developer view.
4. **Verify-before-claim.** Don't mark a view "done" until it renders in a clean build (exit 0) and you've grep'd the live bundle for the new strings. Flag anything you couldn't verify (e.g. mobile on a real viewport).
---
1. What this adds — one paragraph
A **Deals & Relationships** layer with two lenses over the existing shared store. **Developer core** (default): unit-level **inventory** per project/SPV, a **waitlist & scarcity** engine (the operational form of the PRYPCO demand thesis), **payment-plan milestones**, and **broker-channel management** (developers sell *through* brokers — EOI → allocation → performance). **Broker module** (behind the Capital toggle): RERA/Trakheesi/Form A **compliance ledger**, portal **lead dedup**, and **commission** splits. Both lenses read and write the same store and feed the same attribution — one brain.
---
2. Data model — extend the existing store
Add these collections to the current store (names are suggestions; match existing conventions). Keep all money in AED; keep source dates on any market figure.
```
// --- DEVELOPER CORE ---
project = { // extend existing project objects if they exist
id, name, emirate, // "Dubai" | "RAK"
spv, // per-project SPV label (Uniestate operates per-project SPVs)
status, // "Launching soon" | "Selling" | "Sold out"
type, // "Off-plan" | "Ready"
handover, // e.g. "Q4 2027" | "Ready"
paymentPlan, // e.g. "60/40", "50/50 post-handover"
units: [unitId...],
}
unit = {
id, projectId,
ref, // "PV-0704"
beds, sizeSqft, floor, view,
priceAed,
status, // "Available" | "Reserved" | "EOI" | "Sold"
allocatedTo, // leadId | null
brokerId, // channel deal? which broker firm | null (direct)
}
waitlistEntry = {
id, projectId, leadId,
joinedAt, rank, // FIFO rank = scarcity mechanic
ticketAed, // intended spend
notified, // has the launch invite gone out
segment, // "Investor" | "End-user" | "Fractional/Token"
}
milestone = { // payment plan schedule per allocated unit
id, unitId, leadId,
label, // "Booking (10%)", "Handover (40%)"
pct, amountAed,
dueLabel, // "On reservation" | "Sep 2026" | "Q4 2027"
status, // "paid" | "due" | "upcoming" | "overdue"
}
// --- BROKER CHANNEL (developer-side view of brokers who sell for you) ---
brokerFirm = {
id, name, // "Betterhomes", "Allsopp & Allsopp", independent...
reraOfficeNo,
eois, // count of expressions of interest submitted
allocations, // units allocated to their clients
closed, // units closed
commissionPct, // channel commission agreed
}
// --- BROKER MODULE (Uniestate Capital's OWN agents — behind Capital toggle) ---
agent = { id, name, brn /* RERA BRN */, langs:[], activeLeads }
compliance = { // per deal, Capital lens only
leadId,
formA, // bool — owner approved in Dubai REST
trakheesiPermit, // "TRK-2026-xxxxx" | null
goldenVisaEligible, // bool (>= AED 2M)
}
commission = { // per closed/closing deal, Capital lens
leadId, saleAed,
grossPct, // e.g. 0.02
vatPct, // 0.05 on the commission
dldFeePct, // 0.04 transfer (informational)
agentSplitPct, // e.g. 0.5
}
```
**Seed realistically** from the known portfolio so the demo reads as live: Playa Viva (Al Marjan, launching), Oasis Lofts, RAK Tower, Yasmin Village, Union Tower (selling); the five sold-out projects as `status:"Sold out"`. Use **illustrative** unit/price data and **label it illustrative in a caption** — do not present invented unit prices as verified Uniestate figures (operating rule: never present illustrative as real).
---
3. Surfaces to build
Add under the Cockpit. **Developer tabs always visible; Capital tabs appear when the "Uniestate Capital" toggle is on** (top-right of the CRM header, defaulting off).
3.1 Inventory & Allocation *(developer core)*
3.2 Waitlist & Scarcity *(developer core — THE MOAT)*
3.3 Payment Plans *(developer core)*
3.4 Broker Channel *(developer core)*
3.5 Compliance Ledger *(Capital module — behind toggle)*
3.6 Commission *(Capital module — behind toggle)*
---
4. Compliance & integrity guardrails (visible, not buried)
- **Broker features are Capital-only.** Never imply Uniestate-the-developer holds RERA broker cards or advertises listings. The toggle enforces the separation in the UI.
- **Trakheesi/Form A gate** shown as real workflow state, per §3.5 — this is the credibility detail generic CRMs miss; keep it accurate.
- **Illustrative data is labelled illustrative** wherever unit prices / commission figures appear.
- **No invented people.** Agents/brokers in seed data are clearly sample records; the reserved Leadership module stays reserved until the client supplies real bios.
- **Tokenization stays builder-not-exchange.** The Fractional/Token segment in the waitlist is a *demand segment*, not a claim that Uniestate operates tokenization. No "Uniestate will tokenize" language anywhere.
---
5. "One brain" wiring (the whole point)
- A customer-side lead (concierge command bar) already lands in the pipeline. This CRM lets a founder **act on it**: join to a waitlist → allocate a unit → generate milestones → (Capital lens) run compliance + commission — all writing back to the **same lead record and same attribution**.
- Every action appends to the existing activity feed and updates existing Analytics; do **not** fork a parallel data source.
- Attribution must still answer the demand-engine question already in Analytics: *which source country / channel / project is producing pipeline value* — now extended with sell-through and waitlist-coverage.
---
6. Build order (verify at each step)
1. Extend store + seed (projects/units/waitlist/milestones/brokers; Capital collections). Clean build, exit 0.
2. Inventory & Allocation tab (developer). Allocate action wired to store. Verify unit flips + milestones generate.
3. Waitlist & Scarcity tab + "send launch invite" → pipeline. Verify it reaches the existing pipeline.
4. Payment Plans tab + Digest overdue hook. Verify roll-up math.
5. Broker Channel tab.
6. Capital toggle → Compliance Ledger + Commission tabs. Verify they're hidden when toggle off.
7. Bundle grep for new strings on the deploy; screenshot each tab. Flag mobile/real-device as the outstanding human check (per prior sessions — browser tool locks ~1600px).
---
7. Acceptance checklist
- [ ] No new palette; all colors/fonts from existing tokens (grep confirms no stray hexes).
- [ ] Every new object hangs off the existing store; `addLead`/activity/attribution reused, not forked.
- [ ] Developer lens works with Capital toggle **off**; broker tabs appear only when **on**.
- [ ] Allocate → unit status flips + milestone schedule generated + activity logged.
- [ ] Waitlist "send invite" reaches the existing pipeline.
- [ ] Illustrative unit/commission data is captioned illustrative.
- [ ] No broker-card / advertise / "will tokenize" language on the developer side.
- [ ] Clean build (exit 0); live-bundle grep for new strings; per-tab screenshots.
- [ ] Mobile-on-real-device flagged as the open human check, not asserted done.
---
8. Copy anchors (brand-true, reuse verbatim)
- Waitlist header: **"Demand, before the launch."**
- Scarcity stat caption: *"Waitlist covers {x}% of available units."*
- Sell-through headline: **"{x}% sold-through"** as the developer's hero number per project.
- Moat line (leave-behind): **"The rails didn't sell out. The demand engine did."**
- Capital toggle label: **"Uniestate Capital — brokerage operations."**