ELA · FIRST ITERATION · DATA FLOW

End-to-end flows, by stakeholder

How a case moves from onboarding to bail across every party. Use the tabs to see each stakeholder's view — what they receive, what's expected of them, and where the flow still has open gaps. Provisional where marked; the insurance-setup handoff is still being defined.

The whole journey

Four phases — eligibility, activation, dispatch, resolution — with ops and the audit ledger running across all of them.

Client System / ELA Ops Law firm Consulate Insurer

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.

12h · inside working week 24h · weekend / holiday +1h escalation grace accept = take the case
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.

Resolved in grill (2026-05-26)

P0·1 ✓Coverage attachment. Tier-1 active at payment; insurance attaches day≥31 (Profile Verification Window) AND docs verified AND policy assigned; fraud voids.
P0·2 ✓Ops coverage. UAE 06:00–21:00 Mon–Sun (configurable); live-case takeover ≤1h within hours; night cases still auto-dispatch instantly + honest expectation copy.
P0·3 ✓Duress. Separate trigger dropped for v1; `duress_flag` plumbing kept dormant; active-case end requires biometric/PIN so a confiscating officer can't cancel.
P0·4 ✓Policy not yet assigned. No insurance payout until day31 + verified + policy assigned — consistent with P0·1.
P0·5 ✓Expired doc. Expired passport/EID hard-blocks + resubmit; unreadable expiry → STP-pass + ops-flag.
P1·6 ✓Refund/renewal. 30-day money-back (forfeit on arm/claim); refund blocked during active case; NO renewal grace + pre-renewal warnings.
P1·7 ✓Resubmit dead-end. After 3 failed captures → gallery upload + "continue anyway → ops reviews".
P1·8 ✓Accept-then-silent. 2h (working-hours) accept→confirm timer; miss → ops chase → re-dispatch; withdrawal → immediate re-dispatch. (Firm-walks-if-claim-fails moved to risk register — contractual.)
P1·9 ✓Two firms accept. Round-robin is sequential (one firm at a time) — clash avoided by design; first-accept-wins tiebreak.
P1·10 ✓Consulate routing. Optional 2nd nationality (editable in profile), both notified; bounce → ops alert + retry + alternate; nearest-consulate fallback labelled.
P1·11 ✓Audit honesty. SendGrid message-id (fallback "id unavailable"); stub/pre-launch labelled "simulated", never "delivered".

Still open

PINInsurance setup process — partner, API vs manual, policy issuance + return of policy number. Ops-mediated entry is the v1 placeholder.
BIZFamily Shield economics (4×1,500 pass-through vs 7,000 price) · VAT exemption on the insurance portion · final firm roster count (1 today, 3–5 hoped) · bond-overage collector (>50k) · admin auth/SSO + MFA.
RISKFirm dead-man's-land — firm may drop a client if a claim fails. Contractual: engagement letter must commit the firm regardless of claim outcome. · Apple review may push Essential into IAP.
P2Not yet grilled (P2): onboarding abandonment (resume/TTL) · is push mandatory · OTP provider + lockout/resend · accidental-arm / notification recall · offline-arm SLA-clock semantics · holiday-directory integrity check · employment-letter strictness.