The whole journey
Four phases — eligibility, activation, dispatch, resolution — with ops and the audit ledger running across all of them.
Master flow
flowchart TB
subgraph P1["1 · Eligibility (straight-through)"]
A1[Onboarding questions]-->A2["Capture passport + EID / employment letter"]
A2-->A3{"On-device check
blur, corners, glare, MRZ, face"}
A3-->|fail|A2
A3-->|pass|A4[Upload to UAE VPS]
A4-->A5{"Server pre-screen
score, classify, OCR"}
A5-->|pass STP|A6[Advance to payment]
A5-->|flag|OPS1[("Ops exception queue")]
end
subgraph P2["2 · Activation"]
A6-->B1[Choose tier]
B1-->B2{"Apple Pay / card / Tabby (no IAP)"}
B2-->|success|B3["Active · entitlement set"]
B2-->|fail / cancel|B1
B3-->B4["Tier-2: ops assigns policy number
30-day Profile Verification window"]
end
subgraph P3["3 · Emergency"]
B3-->C1["Arm (hold 3s)"]
C1-->C2["Pre-dispatch hold
slide to cancel"]
C2-->C4["Dispatch fires
+ background location starts"]
end
subgraph P4["4 · Dispatch and resolution"]
C4-->D1["Sequential round-robin
firms (configurable, N>=1)"]
C4-->D2[Notify consulate]
C4-->D3[Notify trusted contacts]
D1-->D4{Accept within SLA?}
D4-->|no|D5["Escalate email+SMS, cc ops
+1h grace, then next firm"]
D5-->D1
D4-->|all exhausted|OPS2[("Ops manual handling")]
D4-->|yes|D6[Firm confirms client contact]
D6-->D7{Tier-2 insured?}
D7-->|yes|E1[Ops sends insurance pack]
E1-->E2["Firm initiates claim
100k legal + 50k bond"]
D7-->|no|E3["Case proceeds, Tier-1"]
end
C4-.->LED[("Notification ledger
append-only, user-viewable")]
D2-.->LED
D3-.->LED
Live case — timing
sequenceDiagram
participant U as Client
participant S as ELA System
participant F as Law firms
participant C as Consulate
participant T as Trusted contacts
participant O as Ops
participant I as Insurer
U->>S: Arm (normal or duress)
S->>F: Notify firm 1 (round-robin)
S->>C: Notify consulate (audited email)
S->>T: Notify contacts (SMS/WA)
Note over S,F: SLA 12h working / 24h weekend+holiday
alt Firm accepts in SLA
F->>S: Accept + confirm client contact
else SLA breach
S->>F: Escalate email+SMS (cc ops) + 1h grace
S->>F: Advance to firm 2..5
S->>O: All exhausted, manual
end
opt Tier-2 insured
O->>F: Send insurance pack (policy, limits, contact)
F->>I: Initiate claim (after 30-day window)
end
S-->>U: Live timeline, every notification tappable
Client & family buyer
The person who may be detained — and the family member who can purchase on their behalf. The account holder must complete document capture; coverage attaches to a verified identity.
flowchart TB
subgraph ON["Onboarding"]
W[Welcome]-->PERM["Permissions: location, notifications, contacts, biometric"]
PERM-->ACC["Account + OTP"]
ACC-->PER["Personal: name, DOB, gender"]
PER-->ADDR["Address + emirate"]
ADDR-->NAT["Nationality (+ optional 2nd)"]
NAT-->MED["Medical (optional)"]
MED-->PRI["Priors (sets insurance eligibility)"]
PRI-->DOC["Capture passport + EID or letter"]
DOC-->CHK{"On-device check passes?"}
CHK-->|retry|DOC
CHK-->|3 tries used|ESC["Gallery upload or continue to ops"]
CHK-->|pass|TUT["Tutorial: hold, slide-cancel, slide-end"]
ESC-->TUT
end
TUT-->ELIG{"Insurance-eligible? (from Priors)"}
ELIG-->|recorded prior|ESS["Plan picker: Essential only
insurance hidden, framed as a match"]
ELIG-->|clean or dismissed|ALL["Plan picker: Essential / Shield / Family Shield
Family Shield: roster + per-adult self-attest
(see Insurance eligibility tab)"]
ESS-->PAY{"Apple Pay / card / Tabby"}
ALL-->PAY
PAY-->|success|ACT["Active (Tier-1 live immediately)"]
PAY-->|fail|ELIG
ACT-->PVW["Profile Verification Window 30d
insurance live day 31 if verified + policy"]
ACT-->ARM["Detained: hold 3s to arm"]
ARM-->HOLD["Pre-dispatch: slide to cancel"]
HOLD-->DISP[Dispatch fires]
DISP-->LOC["Background location streams
until case-end or battery dies"]
DISP-->TL["Live timeline of all notifications"]
TL-->TAP["Tap a row: exact message + time + delivery"]
DISP-->ENDC["Slide to end (biometric/PIN)"]
Receives
Live on-device capture feedback; in-app access; Tier-2 policy number once assigned; during a case, a tappable timeline of every notification sent on their behalf.
Expected of them
Onboard honestly; keep passport/EID/visa current (app reminds + prompts re-upload). Choose a tier. Tier-2 covers bond overage above 50k.
Pricing · 3 tiers
1,750 Essential · 3,250 Shield (Most Recommended) · 7,000 Family Shield. AED/year, no trial. Paid via Apple Pay / card / Tabby — not IAP (insurance carve-out 3.2.1(v)). 30-day money-back.
Failure handling
Junk doc → rejected in-app, resubmit. Doc later flagged → automated resubmit request; Tier-1 not revoked unless fraud. Payment fails → no access until completed.
Likely friction (pre-empt in messaging)
"Why annual, no trial?"
Committed life-safety product; the single arm is the moment of truth.
"Is my passport leaving the UAE?"
No — all PII stored + processed in the UAE (S3 me-central-1 + VPS), no third-party cloud OCR.
"Arrested on day 3?"
Tier-1 dispatch is active immediately; only the insurance claim waits out grace.
"150k isn't enough"
Be upfront: bond cover capped at 50k, overage on them.
Trusted contact
Nominated during onboarding. No app, no account. An informational recipient and human rallying point — not a decision-maker in the dispatch flow.
flowchart LR NOM["Nominated at onboarding (consent captured)"]-->IDLE["Stands by (no app)"] IDLE-->TRIG["Subscriber arms a case"] TRIG-->MSG["Receives SMS / WhatsApp / email:
subscriber detained, firm and consulate engaged"] MSG-->DEL{Delivered?} DEL-->|yes|ACTC["May contact family or firm"] DEL-->|no|OPSC["Failure logged, visible to subscriber and ops"]
Receives
An outbound alert per triggered case. Every message logged immutably.
Expected of them
Nothing contractual. They are an emergency informant, not on the hook to post bail.
Failure handling
Bad number/email → delivery status recorded, visible to subscriber + ops board.
Likely objections (how to answer)
- "What am I supposed to do?" Nothing required — you're an emergency informant, not on the hook to post bail.
- "Why am I getting this?" The first message self-explains ELA and names the subscriber who added you.
Law firm
Selected by the round-robin engine (5 firms at launch). Works cases in the firm portal. SLA computed from the firm's own configured working hours.
flowchart TB
A["Sequential round-robin assigns a firm"]-->N["Firm notified via portal + client context"]
N-->SLA{"Respond within SLA?
12h in-week / 24h weekend or holiday"}
SLA-->|no|ESCF["Escalate: email + SMS, ops cc, +1h grace"]
ESCF-->NX["Advance to next firm"]
NX-->EX{Firms left?}
EX-->|yes|N
EX-->|no|OPSM["Ops handles manually"]
SLA-->|accept|CONF{"Confirm client contact within 2h?"}
CONF-->|no|CHASE["Ops chases, then re-dispatch"]
CHASE-->NX
CONF-->|withdraws|NX
CONF-->|yes|T{Tier-2 insured?}
T-->|yes after window|PK["Receive insurance pack from ops"]
PK-->CL["Initiate claim: 100k legal + 50k bond"]
T-->|no|WK["Work the case"]
Receives
Case notification + client context via portal. On breach: escalation email+SMS (ops cc'd). For accepted Tier-2: insurance pack (policy number, 100k/50k limits, claims contact, procedure doc).
Boundary rule
Closes 17:30 Fri → 17:31 Fri is the 24h weekend window. Holiday-aware via the public-holiday directory.
Failure handling
Miss SLA → auto escalate + 1h grace → case advances. All 5 exhausted → ops handles manually.
Likely objections (how to answer)
- "12h even on a weekend?" No — the SLA is set from each firm's own working hours; weekends and UAE public holidays get 24h.
- "The SMS escalation feels aggressive." It only fires after a missed SLA, it's a life-safety backstop (a client is detained), and ops is always cc'd.
Consulate
Notified automatically when a national triggers a case. View-only. No portal, no required action — awareness and consular duty-of-care.
flowchart TB
TRIG[Case triggers]-->NAT{Nationalities to notify}
NAT-->P["Primary nationality"]
NAT-->|if added|S2["Second nationality"]
P-->Q1{Consulate in UAE?}
S2-->Q2{Consulate in UAE?}
Q1-->|yes|E1["Auditable email: detained, being assisted"]
Q1-->|no|NF1["Nearest consulate + ops flag (labelled)"]
Q2-->|yes|E2["Auditable email"]
Q2-->|no|NF2["Nearest + ops flag"]
E1-->DEL{Delivered?}
E2-->DEL
DEL-->|yes|STORE["Stored: body + time + message-id (user-viewable)"]
DEL-->|bounce|RETRY["Ops alert + retry + alternate contact"]
Receives
A single auditable email. Full body + timestamp + delivery status + message-ID persisted indefinitely as evidence.
Expected of them
None enforced by ELA. Strictly informational; ELA does not direct the consulate.
Failure handling
No UAE consulate → nearest + ops flag, labelled in the audit trail.
Likely objections (how to answer)
- "Is this real or spam?" The email is clearly branded, factual, and references an auditable case ID.
- "Are you sharing data without consent?" The subscriber consents at onboarding; the notification is sent on their behalf.
Insurance company
Provides a policy number per insured subscriber; covers legal costs and bond up to 150,000 AED. The exact policy-number handoff is still being defined (pinned).
flowchart TB
SU["Shield / Family Shield purchase"]-->SEND["Ops sends client details + payment"]
SEND-->ISSUE["Insurer issues policy number"]
ISSUE-->WIN["ELA: 30-day Profile Verification Window"]
WIN-->LIVE{"Day 31 and docs verified?"}
LIVE-->|claim before|BLOCK["Claim blocked (in window)"]
LIVE-->|yes|COV["Insurance live"]
COV-->CASE["Live Tier-2 case"]
CASE-->CLAIM["Firm initiates claim with pack"]
CLAIM-->ADJ["Adjudicate: up to 100k legal + 50k bond"]
ADJ-->OVER{Bond over 50k?}
OVER-->|yes|CLIENT["Client pays the overage"]
OVER-->|no|DONE[Covered]
Provides
Policy number per insured subscriber; processes claims up to 100k legal + 50k bond (150k total, annual aggregate — confirm wording).
Grace protects them
Claims blocked for 30 days (Profile Verification Window) — prevents day-one adverse selection.
Open / pinned
How the policy number flows back (API vs manual); who collects bond overage above 50k; required client fields; per-incident vs aggregate.
Failure handling
Claim inside grace → blocked before it reaches them. Bond over 50k → overage is the client's.
Insurance eligibility & Family Shield
Priors gate insurance, and Family Shield resolves every insured before charging — so an ineligible person is excluded, never refunded.
flowchart TB
START["Buyer picks a plan"]-->SOLO{Solo or Family Shield?}
SOLO-->|solo|P1["Priors knockout (self)"]
P1-->E1{Recorded prior?}
E1-->|recorded|NOTE["Essential / notification-only
framed as a match, no insurance price"]
E1-->|dismissed or clean|PAYS["Charge Shield at checkout"]
SOLO-->|family|ROSTER["Roster: 2 adults + 2 dependants
Family Shield = flat 7,000, covers up to 4 eligible"]
ROSTER-->MIN["Guardian declares priors for minors"]
ROSTER-->SELF["Primary self-attests"]
MIN-->PAYF["Charge flat 7,000 at checkout
(do not wait on a slow 2nd adult)"]
SELF-->PAYF
NOTE-->PAYE["Charge Essential"]
PAYS-->ACT["Active (Tier-1 immediately)"]
PAYF-->ACT
PAYF-->|invite 2nd adult|ADULT2
PAYE-->ACTE["Active — notification-only
no insurance, no verification window"]
ACT-->WIN["Profile Verification Window 30d
insurance attaches day 31 if verified + policy"]
ADULT2["2nd adult self-attests later
via invite handshake (own PDPL consent)"]-->L{Eligible?}
L-->|dismissed or clean|ACTV["Insurance activates for them
no extra charge (flat), no blocking"]
L-->|recorded|NOTE2["Stays notification-only
flat price unchanged, nothing to refund"]
ACTV-->WIN
Why no refunds
Eligibility resolves before the charge, and Family Shield is a flat 7,000 covering up to 4 eligible — a recorded-prior member is notification-only with no price change, so there's nothing to refund. No auth-hold (card holds expire in ~7 days); we charge once at checkout.
PDPL (per-adult)
Each adult self-attests their own priors via an invite handshake with their own consent. The primary may declare for minors only — never for another adult.
Framing
Ineligible = routed to notification-only as a match ("the right fit for you"), never a rejection. No "criminal / denied / ineligible" wording on-screen; rationale stays in T&Cs.
Needs counsel
CBUAE product class (free-look), per-member activation ("approved other than applied for"), PDPL cross-border. No PCC for the dismissed exception.
Insurance status workflow
Insurance state is tracked per named member. The subscription can be active while a specific Family Shield member is pending, excluded, active, voided, or cancelled.
flowchart TB START["Priors gate passed
insurance tiers are selectable"]-->PAY["Charge at checkout
Shield 3,250 or Family Shield 7,000"] PREKNOCKOUT["Recorded prior during onboarding"]-.->NA["member.insurance_status = not_applicable
Essential only; insurance tiers hidden"] PAY-->SPLIT{Member path} SPLIT-->|solo Shield buyer|SOLO["Primary member record"] SPLIT-->|Family primary or minor|FAM_READY["Named member present at checkout"] SPLIT-->|Family 2nd adult not ready|INVITE["Invite sent
adult self-attests later"] SOLO-->PROFILE{"Profile complete and clear?"} FAM_READY-->PROFILE INVITE-->PENDING["pending_profile_resolution
missing adult consent / attestation"] PENDING-->ATTEST{"Adult self-attests"} ATTEST-->|recorded prior|EXCLUDED["excluded
notification-only; flat 7,000 unchanged"] ATTEST-->|clean or dismissed|PROFILE PROFILE-->|flagged docs, unclear prior, expired doc, missing consent|PENDING PROFILE-->|clear|WINDOW["pending_profile_window
30-day Profile Verification Window"] PENDING-.->TASK1["Ops task: request fix, review docs,
record decision reason"] WINDOW-->|day 31 reached|POLICY["pending_policy_assignment
waiting for policy number / insurer acceptance"] WINDOW-.->TASK2["System task: hold coverage
until window expires"] POLICY-->|policy number assigned|ACTIVE["active
coverage attached for this member"] POLICY-->|underwriting exclusion|EXCLUDED POLICY-->|admin failure / no response|ESCALATE["Ops escalation
status remains pending_policy_assignment"] POLICY-.->TASK3["Ops task: submit/attach policy,
capture policy number"] ESCALATE-->POLICY ACTIVE-->CLAIM{"Claim or later review"} PENDING-->FRAUD{"Fraud / material misrepresentation confirmed?"} WINDOW-->FRAUD POLICY-->FRAUD ACTIVE-->FRAUD CLAIM-->|insurer voids / fraud proven|VOIDED["voided
coverage treated as never valid"] FRAUD-->|yes|VOIDED FRAUD-->|no|KEEP["No void action
member remains in current status"] CLAIM-->|claim handled normally|ACTIVE PENDING-->|refund / cancellation / renewal failure / member removed|CANCELLED["cancelled
coverage ended prospectively"] WINDOW-->|refund / cancellation / renewal failure / member removed|CANCELLED POLICY-->|refund / cancellation / renewal failure / member removed|CANCELLED ACTIVE-->|refund / cancellation / renewal failure / member removed|CANCELLED
Family Shield
excluded can apply to one additional adult while the 7,000 AED subscription remains active. Other eligible named members continue through the insurance workflow.
Solo knockout
A solo user who records a prior during onboarding never enters this insurance workflow. Shield and Family Shield are hidden before price; Essential is the only selectable plan.
Pending profile
pending_profile_resolution is not automatic after every payment. It only applies when the member profile has a blocker: missing adult attestation, flagged docs, unclear prior answer, expired doc, or consent issue.
Policy assignment
pending_policy_assignment means the member is profile-clear and window-eligible, but ELA is waiting for insurer acceptance, policy number attachment, or manual policy admin.
Voided vs cancelled
voided is fraud or material misrepresentation and may be insurer- or ops/legal-driven. cancelled is prospective: refund, renewal failure, policy termination, or member removal.
ELA ops team (PH) & UAE supervisor
Always-on operators in the admin portal. They never block the happy path — STP auto-passes clean docs. They handle exceptions, monitor dispatch, and run insurance setup.
flowchart TB
subgraph KYC["KYC exceptions (async, never blocks STP)"]
K1[Flagged doc arrives]-->K2["Three-pane: queue / viewer / decision"]
K2-->K3{Decision}
K3-->|approve|K4[Cleared]
K3-->|resubmit|K5["Automated message to user"]
end
subgraph DIS["Dispatch monitor (UAE 06:00-21:00)"]
M1["Live SLA traffic-light countdowns"]-->M2{Breach or exhausted?}
M2-->|breach|M3["Auto-escalate + manual Escalate-now"]
M2-->|exhausted|M4["Manual takeover within 1h"]
end
subgraph INSU["Insurance setup"]
N1["Enter policy number: confirm-on-save + read-back"]-->N2["Starts verification window"]
N3["Firm accepted + confirmed contact"]-->N4["Click Send insurance pack"]
end
subgraph AUD["Consulate audit"]
A1["Append-only: exact email + time + message-id"]-->A2["Exportable evidence"]
end
K5 ~~~ M1
M4 ~~~ N1
N4 ~~~ A1
Sees
KYC three-pane viewer; dispatch timelines + traffic-light SLAs (server time, dual UAE/PH clock); consulate audit (append-only, exportable); client 360; audit log.
Does
Clear doc exceptions (never reject on OCR alone); monitor + escalate; enter policy number (starts grace); send insurance pack after accept+confirm; maintain directories (firm hours, holidays, grace configs).
Failure handling
Board disconnect → stale-data banner (never silently freezes). Tamper signals raise queue priority. Clock skew → server-authoritative deadlines.
Hours — what runs 24/7 vs what waits
The system runs 24/7: arming at any hour instantly notifies law firms (round-robin), the consulate, and trusted contacts, and starts background location — no human needed. The ops desk is staffed UAE 06:00–21:00 Mon–Sun (configurable). Only human actions wait for desk hours: manual takeover when firms are exhausted (≤1h), doc-exception review, and insurance-pack send — because UAE firms and insurers are closed overnight anyway.
Edge cases & open gaps
The P0s and P1 cluster were resolved in the 2026-05-26 grill — decisions are now in prd-first-iteration.md v2. Kept here for the record. Genuine opens (mostly business calls + un-grilled P2s) flagged below.