Khurram Badar / Archive / Papers / RRS SPA Engine — Architecture

RRS SPA Engine — Architecture

briefing · 2026-07-01 · 1457 words · Khurram Badar

0. The one rule that makes this legally sound 1.

ai · legal · real estate · strategy · uae

RRS SPA Engine — Architecture

Autonomous Sales & Purchase Agreement generation, signature, and registration
for the RRS CRM. Extends migrations 001–004. Dual-jurisdiction by design:
**RAK (primary — NH Collection RAK)** and **Dubai (channel-partner / future
inventory)**.

---

0. The one rule that makes this legally sound

**The engine assembles; it never authors.**

The SPA template is drafted by RRS's lawyers and — in RAK — the *form of the
agreement is subject to RAK Municipality approval* (Law No. 12 of 2023 /
Decree 12 implementing rules). The engine's job is to populate an approved,
versioned template with verified deal data, validate completeness against the
regulator's checklist, route for signature, and keep an immutable audit trail.
No generative text ever enters a binding clause. (AI is permitted for
*non-binding* artifacts only: cover letters, buyer-facing plain-language
summaries, translations clearly marked as convenience copies.)

---

1. Jurisdiction matrix (what the deep dive established)

| Concern | RAK (NH Collection RAK) | Dubai (if applicable) |
|---|---|---|
| Regulator | RERA-RAK under RAK Municipality (Emiri Decree 22/2008; Law 12/2023) | DLD / RERA Dubai |
| Off-plan sale precondition | Developer in Developer Register + project in Projects Register + **Off-Plan Sale Permit** | Project registered with DLD before any SPA/payment (Law 13/2008) |
| Transaction registration | **Initial Register** via RAK e-services ("Off Plan Sale Registration Service") | **Oqood** portal, within 90 days of signing |
| Registration payload | Undertaking form, passport, authorized signatory ID, SPA (3 key pages: property & party details, **escrow account page**, **installment plan page**, signatures) | Executed SPA + buyer docs; 4% fee (2% buyer / 2% developer) + AED 10+10 |
| Escrow | Certified Account Trustee; **per-unit sub-accounts**; withdrawals need RERA payment-voucher approval; 5% retention 1yr post-completion | RERA-approved project escrow (Law 8/2007) |
| Template control | **Agreement form approved by RAK Municipality** | Developer template; DLD standards |

The schema therefore carries `jurisdiction` on the project, and every
compliance gate is jurisdiction-parameterized. Adding Abu Dhabi later is a
config row, not a refactor.

2. E-signature strategy

- Federal Decree-Law 46/2021 + Cabinet Resolution 28/2023 make e-signatures
enforceable; courts have upheld them in real-estate sales. **Qualified
Electronic Signature (QES)** — UAE PASS-class, via a TDRA-listed Qualified
Trust Service Provider — is the primary rail because it carries the same
legal weight as wet ink.
- **Wet-ink fallback is a first-class path**, not an afterthought: some
authority submissions may still require it, and counsel must confirm what
RERA-RAK accepts for Initial Register filing. The document state machine
supports both (`sign_method` per signatory; a scanned executed copy can be
attached to complete the same state transition).
- Every signature event stores: method, provider reference, signer identity
evidence (Emirates ID / passport ref), timestamp, and document hash at time
of signing (SHA-256), so any later dispute can prove exactly what was signed.

3. The SPA lifecycle state machine

```
draft ──► generated ──► internal_review ──► sent_for_signature ──► partially_signed

▲ (regenerate on data change; old version archived, never mutated) ▼
void ◄── cancelled fully_executed

registered ◄── submitted_for_registration
(Initial Register / Oqood ref stored,
deal.stage auto-advances to oqood_escrow)
```

Hard rules enforced in the database (triggers), not just the UI:

- **G1 — Booking gate:** generation requires a recorded booking deposit
(token) receipt against the deal, into the project's escrow (per-unit
sub-account ref for RAK).
- **G2 — Identity gate:** buyer KYC complete — passport (and Emirates ID if
resident), nationality, and for corporate buyers: trade licence + authorized
signatory. Names are merged *exactly* as on the ID; the #1 cause of
registration rejection is name-spelling mismatch.
- **G3 — Inventory gate:** unit `available` or already reserved *by this
deal*. Generation atomically reserves the unit (reuses migration 003's
double-sale guard).
- **G4 — Compliance gate:** project has a valid off-plan sale permit + escrow
account (IBAN + trustee) on file for its jurisdiction; template version is
`approved` status. No approved template ⇒ engine refuses.
- **G5 — Payment-plan gate:** milestones must sum to exactly 100% of price,
and (off-plan) be milestone-linked, since ambiguous schedules are the classic
SPA pitfall and RAK escrow releases are construction-verified.
- **G6 — Immutability:** once `sent_for_signature`, the document row is
frozen; any change voids and regenerates as a new version. `fully_executed`
documents can never be altered, only superseded by a lawyer-drafted addendum
(mutual consent, Art. 267 UAE Civil Code territory — out of engine scope by
design).

4. Generation pipeline (deterministic)

```
deal_id ─► gather() ─► validate(G1..G5) ─► merge(template vN, data) ─► render PDF
│ │ │
│ merge-field report SHA-256 hash
▼ (any UNRESOLVED field stored on row
snapshot JSON stored = hard failure)
(exact data used, forever)
```

1. **gather()** pulls: buyer KYC, unit + project (incl. permit no., escrow
IBAN/trustee, plot no.), price, payment plan rows, PDC register, parties'
legal names, jurisdiction. Snapshot is stored as JSONB on the document row —
the SPA is reproducible byte-for-byte forever.
2. **validate()** runs gates G1–G5 and produces a machine-readable checklist
(also what the admin sees as "why can't I generate?").
3. **merge()** fills `{{merge_fields}}` in the approved template. Unresolved
field ⇒ abort. Field-to-column mapping lives in `spa_template.field_map`
(JSONB) so lawyers can evolve templates without code changes.
4. **render** to PDF/A (server-side, e.g. docx template → LibreOffice/Gotenberg
or HTML → Chromium). RAK's three registration-critical sections are
structural template parts: *Property & Parties*, *Escrow Account*,
*Installment Plan* — each independently validated as present and populated.
5. Output goes to Supabase Storage (private bucket `spa-documents`), path +
hash on the row. Storage RLS mirrors table RLS.

5. Payment plan, PDCs, and escrow mapping

- `payment_plan` (per deal) → `payment_milestone` rows: `{seq, label, trigger
(on_booking | on_signing | construction_pct | on_handover | date), pct,
amount, due_date}`. Trigger types map to RAK's construction-verified escrow
release model.
- `pdc` register: post-dated cheques with bank, cheque no., amount, due date,
status (`held → deposited → cleared | bounced | replaced`) linked to a
milestone. Bounce flips the deal to `at_risk` flag and notifies admin.
- `payment` rows record actual receipts with escrow reference; G1 reads this.
- VAT: residential off-plan first supply is typically zero-rated; commercial
differs. Stored as `vat_treatment` on the plan, set by config not hardcoded
— finance/counsel own the value.

6. Registration handoff

Neither RAK's Initial Register nor Dubai's Oqood offers a public write API to
third parties — registration is performed by the developer through the
authority portal. The engine automates *everything up to the portal*:

- Assembles the **registration pack** per jurisdiction (RAK: undertaking form,
buyer passport copy, authorized signatory ID, executed SPA with the three
key pages; Dubai: executed SPA + buyer docs + fee calc 4% split).
- Tracks `submitted_for_registration → registered` with the authority
reference (Initial Register no. / Oqood no.), which auto-advances
`deal.stage` to `oqood_escrow` (existing trigger then flips commission to
payable and unit to `spa_signed`).
- Deadline watchdog: Dubai deals get a 90-day countdown from execution; RAK
per the deadline RERA-RAK specifies. Breach = red alert on the command deck.

7. Who may do what (RLS extension)

| Action | admin | in-house agent | channel partner |
|---|---|---|---|
| Create/approve template versions | ✔ (approve = two-person: uploader ≠ approver) | ✘ | ✘ |
| Enter buyer KYC | ✔ | ✔ (own deals) | ✔ (own org's deals) |
| Read buyer KYC | ✔ | own deals | own org's deals |
| Trigger generation | ✔ | request → admin approves | request → admin approves |
| Send for signature | ✔ | ✘ | ✘ |
| Record registration | ✔ | ✘ | ✘ |

Buyer KYC (passport numbers, Emirates ID) is the most sensitive data in the
system: separate `buyer` table, tight RLS, and document images live in a
private storage bucket — never in table columns.

8. What stays human (deliberately)

- **Template content** — lawyers draft, RAK Municipality approves the form,
admin uploads; two-person approval in-system.
- **Final send** — a human admin clicks "send for signature" after the
internal-review state. The engine makes this a 30-second review, not a
3-day drafting cycle; it does not remove the accountable human.
- **Addenda / amendments / terminations** — legal events with Civil Code
consequences; the engine records them, never composes them.

9. Build order

1. Run `005_spa_engine.sql` (tables + RLS + gate triggers, validated below).
2. `POST /api/crm/spa/generate` — gather → validate → merge → render → store.
(Server-side, service_role, behind admin/approval check.)
3. `POST /api/crm/spa/[id]/send` — e-sign provider integration (pick a
TDRA-listed QES provider; DocuSign-class works for AES tier + wet-ink scan
fallback), webhook back to record signature events.
4. Registration pack export (`GET /api/crm/spa/[id]/registration-pack` → zip).
5. Command-deck widgets: SPA funnel, signature aging, registration deadline
countdown, PDC bounce alerts.

10. Open items for RRS counsel (not assumptions — explicit questions)

1. Confirm the RAK Municipality-approved SPA form for NH Collection RAK and
supply it as template v1.
2. Confirm RERA-RAK's accepted execution method for Initial Register filing
(QES / wet-ink / either) and the registration deadline it specifies.
3. Confirm VAT treatment per unit class and the exact escrow trustee +
per-unit sub-account referencing convention for the project.
4. Confirm the developer-side signatory (which RRS entity + authorized
signatory whose ID goes in the registration pack).

← Dubai REST Parity Plan — RRS Concierge Intelligence LayerMajor exchanges →
Two years of working thought, indexed.
Ask me to present it in your conference room — WhatsApp +971 55 623 9111
Book Session →