Skip to main content
Jabal Al Noor Pharmacy Digital Commerce Platform
Case StudyCompliance

Health data that cannot leave the country

UAE health-data residency, after the incumbent storage vendor turned out to be unable to provide it and the backup plan went offline.

Client
Jabal Al Noor Pharmacy
Industry
Pharmacy retail
Outcome
Prescriptions resident in UAE North

Prescriptions are health data generated in the UAE. Two regimes apply:

  • Federal Law No. 2 of 2019 (ICT in the Health Sector) plus MOHAP Ministerial Decision 51/2021 — health data may not be stored or processed outside the UAE unless one of ten narrow exceptions applies.
  • UAE PDPL (Federal Decree-Law No. 45 of 2021) — a general privacy regime, with fines up to AED 5 million.

The vendor problem

Cloudflare R2 hosts everything else on this project and cannot do this. Verified against R2 documentation rather than assumed:

FeatureCoverageUseful here
Location hintswnam, enam, weur, eeur, apac, ocNo Middle East option
Jurisdictionseu, fedramp onlyThe only real residency guarantee, and neither is the UAE
Regional ServicesMentions the UAEGoverns decryption in transit, not where objects rest

Then the backup plan went offline

The plan was AWS S3 me-central-1. By build time both AWS UAE regions were down indefinitely with no recovery timeline on the AWS status dashboard. The build pivoted to Azure Blob Storage in UAE North — same residency guarantee, different vendor.

The original AWS reasoning is kept struck through in the design doc rather than deleted, so the history of why we did not end up on AWS survives.

What shipped

Storage

Prescriptions live in a private Azure container with no CDN in front. The database stores the raw blob name rather than a URL, precisely so nothing can ever be served unsigned, and every read mints a fresh ten-minute read-only per-blob SAS. A keyFromUrl() fallback handles legacy rows from when prescriptions briefly lived on R2.

Product images and delivery-proof photos stay on R2: non-health, no residency constraint, no reason to pay for the stricter path.

Captured as append-only records rather than a boolean on the user row.

  • Registration requires healthDataConsent: z.literal(true) — Zod rejects the request if unchecked
  • Marketing consent defaults to false, with no pre-ticked box
  • Both grants and declines are recorded, so the trail proves what was actually offered
  • Versioned by a CONSENT_POLICY_VERSION constant, so old rows stay attributable to the text the user really saw
  • Prescription upload re-confirms consent per upload, because a fresh prescription is fresh health data

Data-subject rights

Shipped as self-service: a JSON export of profile, addresses, orders with line-item snapshots, prescription metadata, reviews and full consent history. Prescription file URLs are deliberately omitted, since a signed URL would expire minutes later.

Deletion is a reviewed workflow rather than an immediate erase, and erasure anonymises in place. The email becomes a unique erased+{id}@ placeholder rather than NULL, to avoid colliding with the unique constraint on repeat erasures, while orders and prescriptions are retained to avoid orphaning rows with accounting and regulatory retention needs.

The honest part

The design doc records this as provisional engineering, not a legal determination. Prescription retention minimums under UAE pharmacy law are unresolved, and no UAE healthcare-data lawyer has reviewed whether anonymise-in-place satisfies PDPL erasure for this data mix.

That is flagged for counsel rather than quietly assumed. Engineering flags exposure; counsel rules on classification.