Data Protection Impact Assessment¶
Facilitator Referral Attribution System¶
| Field | Value |
|---|---|
| Document ID | DPIA-2026-001 |
| Processing activity | Facilitator referral attribution via HMAC-signed cookie |
| Controller | Curaway Global Health Technologies |
| Date | 2026-05-05 |
| Plan reference | PR #651 Phase 2 Task 2.2 |
| Related issue | #629 |
| Related ADR | ADR-0018 (cross-tenant section) |
| Status | Draft — pending DPO sign-off |
| Companion LIA | docs/compliance/lia-facilitator-referral-attribution.md (LIA-2026-001) |
1. Description of Processing¶
What: When a patient arrives via a facilitator referral link, the system records facilitator_id on the patient and case records so commission can accrue correctly and so the facilitator can access shared case data after the patient grants consent.
Why: Facilitators are external licensed agents who bear patient acquisition costs and provide coordination services (appointment scheduling, translation, pre-travel logistics). Commission attribution is the contractual mechanism by which their services are funded. Without accurate attribution, the facilitator-mediated coordination model collapses and patients lose access to facilitator support. The legitimate interest is threefold: (a) contractual performance with facilitators, (b) accurate financial audit records, (c) enabling the consent-gated coordination workflow.
Scope: This DPIA covers the referral attribution sub-flow only — from link creation to commission accrual. It does not re-assess the broader patient data lifecycle (covered by Curaway's main privacy notice and data processing agreements).
Legal basis: Legitimate interests (GDPR Art. 6(1)(f)) for cookie placement and attribution recording. Processing is necessary for the performance of the facilitator service agreement and does not override patient privacy interests given the minimal data involved (only facilitator_id — not health data).
Who is affected: Patients who arrive via referral link. Facilitators (as data subjects whose ID is processed). No minors are anticipated; facilitators sign a commercial agreement and are institutional or professional actors.
2. Necessity and Proportionality¶
Why a cookie?
UTM parameters embedded in the URL persist only for the browser tab session and are lost on redirect or if the patient bookmarks the link and returns later. The referral funnel for cross-border medical travel typically spans days to weeks (patient researches, discusses with family, then registers). A persistent cookie is proportionate to that timeline.
Why not server-side IP-based attribution?
IP-based attribution would require logging patient IP addresses against facilitator IDs, creating a biometric-adjacent linkage without consent. This is more invasive than a cookie containing only facilitator_id.
Why not an explicit "I have a referral code" input?
Explicit code entry creates friction for patients who are not tech-fluent (a significant portion of cross-border medical travel patients). It also creates a failure mode where patients arrive via a link but abandon registration when prompted for a code they don't understand.
Why HMAC-signed rather than encrypted?
The cookie payload contains only facilitator_id (a non-personal, internal UUID) and a 16-hex-character HMAC truncated signature — format: {facilitator_id}.{HMAC-SHA256[:16]} (verified at app/services/referral_link_service.py:89-101). No timestamp is embedded in the cookie payload. There is no PII in the payload; encryption would add complexity without adding privacy benefit. HMAC signature provides tamper-detection sufficient to prevent slug-forging attacks without requiring symmetric key management for decryption.
TTL of 1 year: Proportionate to the referral funnel duration. The cookie is consumed one-shot at registration (apps/patient-app/src/lib/referralCookie.ts:66-80 in curaway-health-navigator), so it does not persist beyond the point of use on any patient who completes registration.
Minimisation audit:
| Data element | Necessary? | Alternative considered |
|---|---|---|
facilitator_id in cookie |
Yes — attribution target | N/A: must identify which facilitator |
| HMAC signature (16 hex chars) | Yes — tamper-detection | Encryption: rejected (over-engineered; no PII to protect) |
| Timestamp in cookie | No — absent by design | N/A: not included in cookie payload (verified referral_link_service.py:89-101) |
| Patient identity in cookie | No — absent by design | N/A: not collected pre-registration |
| Raw IP address | No — absent by design | IP attribution: rejected (invasive) |
ip_hash (SHA-256 of IP) in events row |
Yes — click analytics; consent-gated | Stored only when has_consent=True (referral_link_service.py:571-583). Hashed, not raw. Counsel should confirm whether hashed IP is PII under applicable guidance. |
ua_hash (SHA-256 of User-Agent) in events row |
Yes — bot/abuse detection; consent-gated | Stored only when has_consent=True. Hashed, not raw. Same PII question as ip_hash. |
| Device fingerprint | No — absent by design | Fingerprinting: rejected (disproportionate) |
3. Data Flow¶
Each step identifies what data moves, across what boundary, and what lawful ground applies.
| Step | Action | Data in transit | Boundary crossed | PII? |
|---|---|---|---|---|
| 1 | Facilitator creates referral link | facilitator_id, slug, landing_path |
Facilitator portal → backend | No (facilitator_id is internal UUID) |
| 2 | Patient GETs /api/v1/public/r/{slug} |
slug inbound; 302 redirect. Two cookies set if and only if has_consent=True: (a) curaway_ref — HMAC-signed facilitator_id, format {facilitator_id}.{HMAC[:16]}, no timestamp (referral_link_service.py:89-101); (b) curaway_ref_slug — raw slug for analytics (public_referral.py:258-268). Pre-consent redirect: counter increment only, no cookies, no events row. |
Public internet → backend → patient browser | Consent-gated: if has_consent=True, events row stores ip_hash (SHA-256 of IP) and ua_hash (SHA-256 of User-Agent) — hashed, not raw PII (referral_link_service.py:571-583). Pre-consent: counter-only, no PII captured. |
| 3 | Patient registers; patient-app reads cookie | referred_by_facilitator_id posted to POST /api/v1/patients/register |
Patient browser → backend; cookie consumed (one-shot) | Yes — joins with patient identity at this point; covered by registration consent |
| 4 | Case created | Case.referred_by_facilitator_id frozen (immutable) |
Within backend; no external transfer | Yes — frozen on case row; covered by case consent |
| 5 | Patient grants facilitator access | case_shares row created |
Within backend | Yes — consent event |
| 6 | Commission accrues | payment_locked D4 lifecycle hook fires |
Within backend | No — uses internal IDs only |
Key data-minimisation note for Step 2: The slug-resolution endpoint (app/routers/public_referral.py:134-270) sets cookies only when has_consent=True (public_referral.py:244-268). Two cookies are set on consent: curaway_ref (HMAC-signed facilitator_id, no timestamp) and curaway_ref_slug (raw slug identifier, low PII materiality — slugs are random strings, not user-identifying). When consent is absent, the endpoint records a counter increment only — no cookies, no events row, no ip_hash or ua_hash stored. This consent-gated design strengthens the privacy posture: the cookie itself is consent-dependent, not pre-consent. When consent is given, the events row stores ip_hash and ua_hash (SHA-256 hashes — not raw values). Counsel should confirm whether hashed IP/UA constitutes PII under applicable supervisory authority guidance (ICO / CNIL).
Pre-consent UTM telemetry (Step 2a — FF-gated addition): When feature flag referral_preconsent_utm_enabled is ON, a second, slimmer event row (referral_link.click_preconsent) is emitted if has_consent=False AND any utm_* parameter is present in the redirect request. This row contains ONLY: slug, facilitator_id, utm_source, utm_medium, utm_campaign, utm_content, utm_term, landing_path. It does NOT contain ip_hash, ua_hash, region, or any patient identifier. Justification: UTM strings are business/analytics metadata describing which campaign or channel drove the visit — they are not user identifiers and are classified as non-PII business metadata under this DPIA. Consent-gated logging would miss dominant first-visit traffic (pre-consent arrivals), making campaign attribution structurally impossible. The flag is defaulted OFF so counsel can review before activation (see §9 item 6). Implementation: app/services/referral_link_service.py (record_click, pre-consent branch) and app/models/event.py (EventType.REFERRAL_LINK_CLICK_PRECONSENT).
Cross-border: EU patient browser → app.curaway.ai (Cloudflare edge, EU PoP) → backend on Railway (ap-south-1). Transfer is covered by Curaway's standard SCCs (see Section 8).
4. Recipients¶
| Recipient | Data they can see | Condition |
|---|---|---|
| Curaway platform (controller) | All attribution data | Always |
| Coordinator (Curaway staff) | Full case including referred_by_facilitator_id |
Role: coordinator |
| Facilitator | Case content via case_shares; commission summary via /commissions |
Only after patient grants consent (Step 5). Attribution-only commissions are returned as commission rows only — GET /api/v1/facilitator/commissions does not join to case content. UI annotation ("case not shared" badge) tracked under plan PR #651 Task 5.5 |
| Provider | Redacted clinical snapshot | No facilitator data exposed to provider |
| Analytics / Langfuse | case_id, patient_id (UUID) |
No facilitator attribution in LLM traces |
DP-4 constraint (attribution-only cases): A facilitator whose referral did not result in a consent grant can see that a commission is pending attribution to their account but cannot see any case details. The data isolation is structural — the commissions table holds only attribution + amount fields and the /commissions endpoint does not join to case content. UI distinction (showing the row in a muted/badged style) is FE work tracked under plan PR #651 Task 5.5.
5. Retention¶
| Data | Retention | Basis |
|---|---|---|
curaway_ref cookie (HMAC-signed facilitator_id) |
1 year TTL; consumed one-shot at registration | Minimum necessary for funnel duration |
curaway_ref_slug cookie (raw slug) |
1 year TTL; same lifecycle as curaway_ref |
Analytics identifier; low PII materiality |
referral_links table |
Indefinite; links can be deactivated, not deleted | Audit trail; facilitator agreement records |
patients.referred_by_facilitator_id |
Lifetime of patient record; SET NULL on Art. 17 erasure | FK with ON DELETE SET NULL |
cases.referred_by_facilitator_id |
Lifetime of case record; SET NULL on Art. 17 erasure | FK with ON DELETE SET NULL |
referral_link_clicks events (incl. ip_hash, ua_hash) |
90 days then aggregated to count-only | Hashed analytics data; no raw PII |
| Commission accrual records | 7 years (financial audit obligation) | GDPR Art. 17(3)(b) — legal obligation exception |
Erasure note: Patient-initiated erasure under GDPR Art. 17 triggers the existing cascade erasure handler. referred_by_facilitator_id on both patients and cases becomes NULL via FK constraint. Commission accrual records that have already settled are retained in anonymized form under the Art. 17(3)(b) legal obligation defence (financial audit, tax records). Unsettled commissions at time of erasure are voided.
6. Risks and Mitigations¶
| Risk | Likelihood | Impact | Mitigation | Residual |
|---|---|---|---|---|
Cookie spoofing (forging facilitator_id in HMAC payload) |
Low | Low — only misattributes commission | HMAC verification at POST /patients/register (app/routers/patients.py:58-68); mismatched signatures rejected and logged to telemetry |
Accepted |
CSRF on /patients/register |
Low | Medium — could force registration with attacker-chosen facilitator | Clerk-issued JWT required on registration endpoint; cross-origin requests rejected by CORS policy | Accepted |
| Unintended attribution persistence across devices | Medium | Low — patient uses different device, no cookie present → no attribution | One-shot consumption at registration is definitive; no attribution without cookie is treated as organic; documented in facilitator T&Cs as expected behaviour | Accepted |
| Two facilitators referring same patient | Medium | Low — only one attribution recorded | Last-cookie-wins per public_referral_spec §14.1; both facilitators are notified of outcome; documented in facilitator agreement |
Accepted |
| Bot scraping referral links inflating click counts | Medium | Low — pre-consent: counter only; post-consent: hashed ip_hash/ua_hash stored (not raw PII) | UA filter on /api/v1/public/r/{slug}; consent gate prevents events row on pre-consent scraping; bot-detection telemetry as Phase 5 follow-up |
Accepted |
| Patient erasure under GDPR Art. 17 breaking commission records | Inherent (legal right) | N/A — handled by design | Cascade deletion sets referred_by_facilitator_id to NULL; settled commission accruals retained anonymized under Art. 17(3)(b) |
Compliant |
| Cookie write fails on strict CSP browsers | Low | Low — patient receives no attribution; organic funnel continues | FE #182 strict CSP includes services.curaway.ai in connect-src; verified in preview before production |
Accepted |
Facilitator ID exposed in client-side cookie (curaway_ref) |
Low | Low — internal UUID, no PII, no health data | Cookie is Secure; SameSite=Lax; httponly=False intentional (patient-app JS must read for registration submission, spec §5.2); payload contains only internal ID + HMAC |
Accepted |
curaway_ref_slug cookie contains identifying slug |
Low | Low — slugs are random strings, not user-identifying under current process controls | If facilitators are ever permitted to set custom slugs containing identifiers (e.g., their own name), the slug cookie becomes PII-adjacent and this DPIA must be re-assessed. Currently a process control: slug generation is system-managed and non-identifying. | Accepted (monitor) |
ip_hash/ua_hash treated as non-PII when hashed |
Low | Medium — supervisory guidance on hashed IP varies by jurisdiction | Counsel must confirm whether SHA-256 hashed IP constitutes PII under ICO/CNIL guidance. Currently treated as pseudonymous analytics data. | Requires legal review |
| UTM strings in pre-consent event classified as non-PII | Low | Medium — UTM strings could theoretically contain user-identifying content if facilitators embed such data in campaign URLs | (1) UTM strings are business metadata (source/medium/campaign/content/term) with no structural requirement to contain PII. (2) Facilitator T&Cs should prohibit embedding PII in UTM params. (3) Flag defaulted OFF for counsel review before activation. (4) No ip_hash, ua_hash, or patient identifier is stored in pre-consent row. | Requires counsel confirmation (§9 item 6) |
Overall risk level: Low. No special-category data is processed in this flow. The cookie payload contains no health data, no racial or ethnic origin, no biometric data. The predominant risk is commission misattribution, which is a financial rather than privacy risk. The consent-gated cookie design and hashed-only telemetry strengthen the privacy posture relative to many comparable attribution implementations.
7. Data Subject Rights¶
| Right | How exercised | Implementation |
|---|---|---|
| Access (Art. 15) | Patient data export | referred_by_facilitator_id included in standard GDPR data export package |
| Rectification (Art. 16) | Not applicable | Attribution is derived from an event (link click) and frozen at case creation (app/services/case_service.py:19-50). The immutability constraint (DP-C) is by design — post-hoc mutation would enable commission fraud. Facilitator T&Cs and patient privacy notice explain this. |
| Erasure (Art. 17) | Standard erasure request flow | CASCADE handler sets referred_by_facilitator_id to NULL on both patient and case rows. Settled commission records anonymized and retained under Art. 17(3)(b). |
| Portability (Art. 20) | Standard data export | Included in machine-readable export |
| Objection (Art. 21) | Patient may decline consent grant (Step 5) | Withholding consent prevents facilitator from accessing case data. Attribution-only commission accrues server-side (legitimate interest basis) but facilitator sees no case content. Patient may also submit erasure request to clear attribution entirely. |
| Automated decision-making (Art. 22) | N/A | Attribution is mechanical (cookie read → DB write), not a decision affecting the patient's legal status or similar significant effect. |
Consent and attribution independence: Attribution (Step 4) is distinct from access consent (Step 5). A patient can be attributed to a facilitator without ever granting that facilitator access to their case. The facilitator earns a referral commission but sees no case data. This separation is architecturally enforced.
8. Cross-Border Considerations¶
EU patients are registered under tenant-curaway-patients with data residency in ap-south-1 (Mumbai, India). Facilitators may be located in any jurisdiction; the facilitator_id field is an internal UUID — it does not constitute personal data of the facilitator in isolation without the facilitator directory, which is held separately.
Transfer mechanism: EU patient data flowing to Railway backend (ap-south-1) is covered by Curaway's existing Standard Contractual Clauses (SCCs) under GDPR Art. 46(2)(c). This DPIA does not change the cross-border transfer posture established in the main DPA.
Special-category data: facilitator_id is not special-category data under GDPR Art. 9. It is not health data, racial or ethnic origin, political opinion, religious belief, biometric data, or data concerning sexual orientation. The referral attribution flow does not make the cross-border transfer of special-category data more complex than what is already covered by the main DPA.
Provider jurisdiction: Providers are in destination countries (India, Turkey, Thailand, Spain). Provider-facing data views do not include facilitator attribution data (see Section 4).
9. Consultation and Sign-Off¶
No high-risk processing requiring supervisory authority consultation has been identified. Risk level is Low (see Section 6). This DPIA is sufficient under GDPR Art. 35(7) without prior consultation under Art. 36.
Sections requiring legal review before finalisation:
- Art. 17(3)(b) defence for retaining anonymized commission accruals post-erasure — confirm with counsel that financial audit obligation is established under applicable jurisdiction law (India Companies Act 2013 / UK Companies Act 2006 as applicable to facilitator contracts).
- Legitimate interest basis (Art. 6(1)(f)) — confirm that the Legitimate Interests Assessment (LIA) is documented separately and that the balancing test has been completed. LIA is at
docs/compliance/lia-facilitator-referral-attribution.md. - Facilitator T&Cs — confirm that last-cookie-wins attribution policy and rectification exclusion are explicitly disclosed.
ip_hash/ua_hashclassification — confirm with counsel whether SHA-256 hashed IP address and User-Agent string constitute personal data under applicable supervisory authority guidance (ICO, CNIL). See §6 risk row and §2 minimisation audit.curaway_ref_slugcookie — confirm slug values are never configured to contain personally identifying strings (e.g., facilitator names). Currently a process control, not a technical enforcement (see §6 risk row).- Pre-consent UTM telemetry — counsel must confirm UTM strings are not classified as PII or special-category data under their applicable guidance. Currently classified as business metadata (campaign source, medium, name, content, term). The
referral_preconsent_utm_enabledfeature flag is defaulted OFF so this flag can be disabled if counsel objects. No ip_hash, ua_hash, region, or patient identifier is stored in the pre-consent event row. Activation requires counsel sign-off on this item. See §3 (Step 2a) and §6 (UTM risk row).
DPO sign-off:
Name: Srikanth Donthi
Title: CPO/CTO (acting DPO under Curaway MVP governance)
Date: 2026-05-05
Signature: ____________________
10. Review Schedule¶
| Trigger | Action |
|---|---|
| Annual review | 2027-05-05 |
| Material change to attribution flow (new data elements, new recipients, new cross-border transfers) | Immediate re-assessment |
| Supervisory authority guidance on cookie attribution for healthcare platforms | Review within 30 days of guidance publication |
| Phase 5 bot-detection implementation | Update Section 6 bot-scraping row |
| Any change to slug generation (custom/vanity slugs) | Reassess curaway_ref_slug PII classification immediately |
| Supervisory authority ruling on hashed IP as PII | Immediate re-assessment of §2 and §5 |
This document was produced as part of PR #651 Phase 2 Task 2.2 and updated under issue #666. Source references: app/routers/public_referral.py:134-270, app/services/referral_link_service.py:54-67, app/services/referral_link_service.py:89-101, app/services/referral_link_service.py:557-583, app/routers/patients.py:58-68, app/services/case_service.py:19-50, curaway-health-navigator/apps/patient-app/src/lib/referralCookie.ts:66-80.