Unified contacts (Flutter mobile β shipped) β
Cross-reference for React web (aldilaijanre) parity. Mobile Flutter is the reference implementation.
Routes (mobile) β
| Purpose | Path |
|---|---|
| Contacts list | /clients |
| Party 360 detail | /clients/:unifiedPersonId |
| Duplicate review (admin) | /admin/duplicate-review |
| Legacy party registry | /admin/party-registry β redirects to /clients?admin=1 |
| Legacy CRM client id | /brokerage/crm/clients/:clientsTableId β redirects when unified_person_id set |
| Brokerage CRM list | /brokerage/crm/clients β unified list |
Data spine β
- Identity:
unified_persons(individuals + organizations) - CRM overlays:
clientsβ max one row per(unified_person_id, system)(aldilaijan/khobara) - Detail id: always
unified_persons.idon/clients/:id
List UX β
- Segmented People / Entities
- Server-side
searchParties()β no fetch-all registry - Khobara personas: same list with
linkedSystem: khobara - Nav label: People & entities (
nav.clients)
Detail UX (360) β
PartyDetailScreen tabs (persona-gated via PartyDetailVisibility):
- Profile β individual or organization
- Brokerage β deals, requests, properties, Aldilaijan CRM
- Valuation β valuations, requests, tahdeed, Khobara CRM
- Financial β invoices
- Activity β interaction timeline
Web parity checklist β
- [x] Single list over
unified_persons(people + entities), not separate Party Registry browse β React/clients - [x] Detail at party id with brokerage / valuation / finance sections β React
/clients/:id(PartyDetail) - [x] Legacy CRM client detail redirects to
/clients/:unifiedPersonIdwhen linked β CrmClientDetailGate - [x] Persona-scoped tab visibility β
partyDetailVisibility.ts - [x] Bilingual names:
name_ar+ structured parts +name_enβ list + detail display - [x] Admin duplicate review + orphan relink tooling β
/admin/duplicate-review - [x] Organization edit on party 360 β Flutter
OrganizationFormScreen+ ReactOrganizationFormvia/clients/:id/edit - [x] Inline CRM actions on party tabs β Flutter
showCrmActionPicker; ReactCrmActionMenu(note / contact / interaction) - [x] Legacy pages retired β
UnifiedPersons,BuyersListremoved; routes redirect to/clients
Key Flutter files β
lib/features/individuals/screens/individuals_list_screen.dartlib/features/parties/screens/party_detail_screen.dartlib/data/repositories/party_registry_repository.dartlib/data/repositories/party_activity_repository.dart
Production ops β identity convergence β
After bulk imports or duplicate merges, admins should verify Phase-5 monitor views trend toward zero:
| View | Meaning | Resolve via |
|---|---|---|
vw_potential_duplicate_parties (match_kind = civil_id) | Same civil ID on multiple unified_persons | Duplicate review β Parties tab β merge |
vw_potential_duplicate_parties (match_kind = folded_name) | Folded-name collision | Duplicate review β Parties tab β merge |
vw_duplicate_clients | Multiple clients rows per (unified_person_id, system) | Duplicate review β Clients tab β merge |
vw_clients_without_party | CRM client with no unified_person_id | Duplicate review β Relink orphan clients |
vw_identity_drift_watch | Snapshot name drift vs party registry | Data quality dashboard β review row |
Where to watch
- Flutter:
/clientsadmin KPI strip + Identity convergence row (admins only); app-bar merge badge when party dupes > 0. - React:
/clients(admin) β same summary + convergence tiles;/admin/duplicate-reviewfor merge + orphan relink. - Valuation data quality (both): full convergence card with deep links.
Weekly checklist
- Open
/clients?admin=1β confirm convergence counts (or zero). - Run orphan relink once if
clientsWithoutParty> 0. - Clear party/client duplicate queues before large imports.
- After merge sessions, refresh list β
vw_potential_duplicate_partiesshould drop for merged keys.
See migration supabase/migrations/20260622120000_phase5_dedup_drift_views.sql and lib/data/repositories/data_quality_repository.dart (fetchConvergenceHealth).
