Tab 1

Fields catalog

Every borrower-provided input in the proposed flow. Grouped by surface. Doc uploads are modeled as logical fields, not one fixed database column per file slot.

Form 1

Lead qualification

Anonymous calculator plus contact capture. The live form shows mortgage pre-approval immediately after the property-found question.

17 fields
#Field IDLabelTypeRequiredValidationSource form / stepSupabase column (proposed)Notes
Form 2

Dashboard profile questions

21 logical questions after OTP. The live dashboard already carries service selection and co-applicant gating state; this page treats them as contract fields.

21 fields
#Field IDLabelTypeRequiredValidationSource form / stepSupabase column (proposed)Notes
Form 2.5

Co-applicant branch

Only unlocked when `has_co_applicant = yes`. The current dashboard copy already reflects this branch.

7 fields
#Field IDLabelTypeRequiredValidationSource form / stepSupabase column (proposed)Notes
Form 3

Docs + final submission

Three borrower answers plus logical upload fields. Bank statements and identity documents stay grouped here because storage is row-based, not fixed-column.

18 fields
#Field IDLabelTypeRequiredValidationSource form / stepSupabase column (proposed)Notes
Tab 2

Computed fields

Derived outputs the frontend can show immediately or the backend can persist. This table intentionally mixes display math, policy booleans, and score components because they all shape the API contract.

43 derived outputs
Field nameFormula / sourceDepends onUsed inNotes
Calculator source

Closing-cost math comes from the canonical Dubai closing-cost formula. The dashboard can keep it client-side now and move to an engine call later without changing field names.

Gate drift

`eligibility-gates.json` also defines G11-G13. This page keeps G1-G10 as requested and flags the extra gates as post-contract extensions.

Category J wiring

Category J (Sector Tier, weight 10%) is now modelled. Source: employer_name from F2 → sector lookup against the underwriting-engine employer taxonomy (~25 named employers in v0.1.1, expandable to ~370 via APP-1844). T4/T5 sectors score 0 — feeds the auto-decline pathway in addition to gate G7 employment-tenure logic.

Tab 3

Relationships

Three diagrams capture the contract shape: journey flow, prefill chain, and doc-extraction surface.

Data flow: F1 → dashboard → engine

One borrower row. Progressive enrichment. Documents update the same record and trigger the decision engine.

flowchart TB F1["Form 1
contact + property + residency + income"] --> H["URL params +
create buyer_lead row"] H --> D["Dashboard reads buyer_lead
and shows cost breakdown"] D --> F2["Form 2 updates same row
21 inputs + service selection"] F2 --> G{"has_co_applicant?"} G -->|yes| F25["Form 2.5 writes co_app_* fields"] G -->|no| F3["Form 3 starts"] F25 --> F3 F3 --> DOCS["Supabase Storage + buyer_document rows"] DOCS --> OCR["OCR + bank-statement parsing
fills extracted fields"] OCR --> ENG["Underwriting engine call
indicative_scs + fee_tier_id + decision"] ENG --> SAVE["Update buyer_lead
decision fields + gates_failed"]

Prefill chain: F1 → F2 → F2.5

Ask once. Display later. Re-verify only the phone.

F1 source fieldF2 / F2.5 destinationTreatment
fullNameF2 contact_nameDisplay only
emailInputF2 contact_emailDisplay only
phoneInputF2 phone_otp_verifiedRe-verify via OTP
heroValueF2 property_budgetDisplay only
areaMultiF2 property_areaDisplay only
propertyTypeF2 property_typeEditable
bedroomsF2 bedroomsEditable
residencyF2 residency_statusEditable
incomeInput + commissionInputF2 household_income_total + variable_incomeSplit editable
householdIncomeInput + partnerCommInputF2 has_co_applicant = yesSets gate ON
(when has_co_applicant = yes)F2.5 co_app_monthly_income + co_app_variable_incomePrefilled from F1 partner inputs

Doc-to-field extraction map

File uploads do not just unlock the next step. They replace manual questions and finalize gates.

Document uploadFields it populates
Emirates IDDoB · Nationality · EID number
PassportRomanized name · Nationality · Passport number · Expiry
Visa pageResidency duration · Visa type · Sponsor
Bank statementsVariable income patterns · Rent payment · Savings buffer · Recurring debits
AECB reportAECB score · Credit history · Existing debts · Defaults
Salary certificateEmployer · Salary · Tenure · Allowances
Employment letterRole · Tenure confirmation
Trade licenseBusiness name · License number · Years in business
Audited financialsBusiness revenue · Business profit
Tab 4

Doc extraction

OCR and parser requirements by tile. Keep the manual-review path first-class because AECB PDFs and self-employed financials will not be clean enough every time.

8 extraction lanes
Doc tileRequired ifExtracted fieldsOCR vendor (proposed)Confidence thresholdManual review fallback
Tab 5

Supabase schema

Three-table proposal. `buyer_lead` remains the orchestration spine. `buyer_document` becomes extraction-aware. `buyer_journey` gives the CTO an explicit audit trail instead of inference from timestamps.

Table 1

`buyer_lead`

Extended from the current lead row. This is the single API record the dashboard and engine mutate.

67 columns
ColumnTypeDefaultConstraintsSourceNotes
Table 2

`buyer_document`

Existing document row with extraction metadata added. One file upload = one row.

12 columns
ColumnTypeDefaultConstraintsSourceNotes
Table 3

`buyer_journey`

New audit trail table for progress, abandonment, and replay. Useful for CRM routing, analytics, and support.

7 columns
ColumnTypeDefaultConstraintsSourceNotes
Alter vs new

buyer_lead is mostly ALTER. buyer_document adds extraction columns. buyer_journey is net-new.

Indexes

buyer_lead(session_id) unique, buyer_lead(status, updated_at desc), buyer_lead(decision, decision_at desc), buyer_document(buyer_id, doc_kind, uploaded_at desc), buyer_journey(buyer_id, step, entered_at desc).

JSON boundaries

Use jsonb only for extracted document payloads and journey snapshots. Everything queryable in ops or underwriting stays first-class.