Data Protection Impact Assessment — GoDating
Version: 1.1 · updated 2026-05-05 · for open Denmark beta Controller: PX7 Digital · Hyltebjerg Allé 43, 2720 Vanløse, Danmark · [email protected] Scope: All processing performed by the GoDating product surfaced at godating.app and godating.dk.
This DPIA exists because GoDating processes special-category personal data at scale: photos used for visual identification, profile data used for affective matching, and a current verification-selfie workflow that may reveal special-category traits. A future provider-side biometric path remains optional and inactive at launch. Article 35 GDPR is still triggered by the present processing posture.
1. Description of processing
1.1 Data categories
| Category | Examples | Where stored | Retention |
|---|---|---|---|
| Account identifiers | email, email_hash (HMAC-SHA256), locale, role | D1 users | Until deletion request + 30 d soft-delete grace |
| Profile content | display name, DOB, age-confirmed flag, area, postal code, gender identity, shown-as, interested-in, relationship intention, bio | D1 profiles, profile_prompt_answers | Same as account |
| Photos | up to 6 JPEG/HEIC; SHA-256 of original; EXIF stripped before storage | R2 godating-prod-profile-photos; references in D1 profile_photos | Same as account; R2 grace 30 d after soft-delete |
| Verification selfie | one still selfie with a prompted gesture; selfie SHA-256; perceptual-hash similarity aids; moderator decision | R2 godating-prod-profile-photos / verification bucket path; D1 verification_requests | Selfie deleted within 90 d of approve/reject/withdrawal; decision outcome retained with account |
| Behavioural | likes, passes, blocks, reports | D1 profile_actions, user_blocks, user_reports, user_action_budgets | 24 months rolling, then aggregated only |
| Communications | chat messages (text), safety signals on chat (NSFW classifier scores), per-message metadata | D1 chat_messages, chat_message_metadata, chat_safety_signals | 12 months rolling; safety signals retained for the lifetime of the chat thread |
| Date plans | proposed dates, accepted/declined state, optional venue | D1 date_plans | 12 months rolling |
| Moderation evidence | reported content, reviewer decisions, admin audit trail | D1 moderation_actions, user_moderation_actions, admin_audit_log, admin_support_notes | 5 years (regulatory + DSA evidence preservation) |
| Authentication state | one-time email confirmation tokens, magic-link session cookies (httpOnly+Secure), social-sign-in linkages | D1 user_email_confirmations, user_social_accounts, user_profile_access_links | Tokens expire ≤ 15 min; sessions ≤ 14 d sliding |
| Notification opt-ins | push subscription endpoints, recap email preferences | D1 push_subscriptions, notification_preferences, weekly_recap_preferences, notification_deliveries | Until unsubscribe |
| Cross-handle integration data | Intus profile import consents and the imported subset | D1 intus_consents, intus_imported_profiles, intus_pending_imports, intus_visibility_settings | Tied to the Intus consent record; revoked on Intus side propagates within 24 h |
| Operational telemetry | client error events with userId, route, stack | D1 client_error_events | 90 d rolling |
| Vector representations | 128-dim cosine vectors derived from values_json + relationship_signals_json for ANN matching | Cloudflare Vectorize godating-prod-compat | Refreshed every sweep cycle; deleted on account deletion |
| Behavioural-pool snapshots | daily discovery pool per user (KV) | Cloudflare KV PROFILES_RATE_LIMIT namespace and successor pool namespace | 7 d rolling |
| Future external biometric provider (not active) | hosted liveness or identity-verification flow if GoDating later activates one | Provider not selected; not yet collected | Provider retention will be documented before activation; see §6 |
Special categories (Article 9 GDPR) processed:
- Photos that may visually reveal racial origin, ethnic origin, religious symbols.
- Bio + relationship-intention free text that may reveal sexual orientation, religious belief, philosophical conviction, political opinion.
- Verification selfies that may visually reveal racial origin, ethnic origin, religious symbols, health indications, or other special-category traits.
- Future provider-side biometric data for unique identification only if separately activated later.
Lawful basis for special categories: Article 9(2)(a) — explicit, granular consent captured at intake (profile_consents rows with verbatim consent text + timestamp), revocable at any time. No special-category processing happens before the corresponding profile_consents row exists.
1.2 Processing purposes
- Account creation + authentication — magic-link email login, optional Apple/Google sign-in (post-launch).
- Profile creation + presentation — collecting profile data and showing it to other matched users.
- Discovery + matching — daily pool generation via either §12.6 weighted-attribute heuristic OR §12.6.1 Vectorize cosine ANN (feature-flagged); mutual-like detection.
- Communication between matched users — text chat, future voice/image messages, date-plan proposals.
- Safety + moderation — automated CSAM hash check, NSFW classifier on photos and chat, reactive review of user reports, account-level enforcement (warn/strike/suspend/delete).
- Notifications — magic-link email, match notifications, weekly recap, push when subscribed.
- Operational integrity — error telemetry, abuse rate-limiting, capacity planning, anti-fraud signals.
- Cross-handle continuity — letting users import an existing Intus / GoToBe profile shape with a fresh consent step.
1.3 Lawful bases
| Purpose | Article 6 basis | Notes |
|---|---|---|
| Account + authentication | 6(1)(b) Contract | Cannot deliver service without identity |
| Profile presentation | 6(1)(b) Contract | Same |
| Discovery + matching | 6(1)(b) Contract | The product IS matching |
| Chat | 6(1)(b) Contract | Same |
| Safety + moderation | 6(1)(c) Legal obligation (DSA, CSAM reporting) + 6(1)(f) Legitimate interest (platform integrity) | Strict-necessity scoping; balancing test recorded in §3 |
| Notifications | 6(1)(a) Consent for push + recap; 6(1)(b) for transactional (login link, account confirmations) | Granular toggles in notification_preferences |
| Telemetry | 6(1)(f) Legitimate interest | No identifying cookies; pseudonymous error context |
| Cross-handle import | 6(1)(a) Explicit consent | New intus_consents row required per import |
1.4 Data subjects
- Adults (18+, age confirmed at intake) located in Denmark for the open beta.
- Future expansion to other EU jurisdictions will trigger a DPIA addendum.
- No children's data processed at any point.
1.5 Recipients / data sharing
- Internal:
admin_operatorsrows withrole=moderatoror higher; admin actions audit-logged inadmin_audit_log. - Subprocessors: Cloudflare Inc. (US, with EU data-residency for D1/R2), Resend (US, EU residency available), Intus / GoToBe (PX7-controlled, same controller umbrella). The current verification selfie flow stays within the Cloudflare / GoDating stack. Any future external biometric provider will require a DPA addendum + DPIA update before activation.
- No ad-tech, no third-party analytics SDKs, no data brokers, no model-training partners.
- Law-enforcement disclosures: only on valid Danish or EU legal process, recorded in
admin_audit_logwith case reference.
1.6 International transfers
- Cloudflare D1 + R2 are configured for EU residency where supported. Vectorize index region is the closest available EU region.
- Resend is US-headquartered with EU data-region available; transactional email metadata may transit US infrastructure under SCCs.
- DPA + SCCs in place with each subprocessor; status tracked in
/legal/subprocessors(published).
2. Necessity + proportionality
For each purpose in §1.2 we asked: can we ship without this data?
- Email + password-equivalent (magic link) for auth — Yes; alternative is anonymous link-only profiles, but breaks identity-verification + abuse recovery. Email retained as minimum.
- DOB — Required for age-gating and age-cohort matching. We store as date; we do NOT compute age client-side without server validation.
- Postal code — Required for area-of-life matching. We store the 4-digit code; we do not store street address.
- Photos — Core to product. We strip EXIF before storage. We do not OCR or run face recognition on photos for indexing.
- Verification selfie — Required only for users who request verification. We use one still selfie plus a simple gesture prompt and perceptual-hash-assisted moderator review. We do not store a biometric template or facial-feature vector.
- Bio free text — Core to product. Pre-publish moderation classifier reduces risk of disclosed-without-intent special-category content.
- Vectorize embeddings — Strict subset: derived only from
values_json+relationship_signals_json, not from photos or bio. Stored without PII; re-derivable from D1 if lost. - Chat history — Required for harassment evidence + user re-reading. 12-month retention is the minimum that supports DSA Article 16 evidence preservation.
We do NOT collect: phone numbers (until launch-week SMS verification, separate consent), real-time location, contacts list, calendar, browsing history outside our domains.
3. Risks + mitigations
| Risk | Likelihood | Severity | Mitigation |
|---|---|---|---|
| Scam / fake-account rings at scale | High (dating market reality) | Medium (financial harm to users; reputational) | Cloudflare Turnstile on intake + login; Level 1 verification via gesture selfie + moderator review; automated CSAM/NSFW/authenticity gates on uploads; per-IP rate limits on request-link (5/h); admin second-factor on moderation tools |
| CSAM upload | Low (adults-only) but absolutely zero-tolerance | Catastrophic | Pre-store CSAM hash check (NCMEC + Microsoft PhotoDNA when contracted); auto-block + report to NCMEC equivalent (DK: Red Barnet) per CSAM runbook; tabletop exercise required before public scale |
| Re-identification via vector embeddings | Low | Medium | Vectorize stores user-id only as metadata; vector dimensions are non-invertible (FNV-1a hash bag + ordinal one-hot); never expose vectors via public API |
| Profile-stalking / unwanted contact | Medium | Medium-High | Block + report flow; mutual-match-only chat; no public discovery of non-public profiles; public-profile opt-in is per-user with a separate consent row |
| Data-subject access request flooding | Low | Low (operational) | /api/account-export endpoint generates a self-service ZIP of the user's full record; tested in CI |
| Subprocessor breach (Resend, Cloudflare) | Low | Medium | Minimum-data principle: Resend gets only email + magic-link payload; Cloudflare hosts everything but data is encrypted at rest and access is audit-logged |
| Moderator bias | Medium | Medium | Two-strike review for terminal account actions; admin actions logged in admin_audit_log; appeal flow specified in spec §16.10 |
| Biometric mis-identification (future provider path) | Not assessed until provider is selected | High | DPIA addendum required before activation; clear opt-out alternative (manual review) must always exist |
| Data retention drift | Medium | Low-Medium | Retention jobs documented in the retention runbook; test coverage required before launch |
3.1 Residual risk after mitigations
Acceptable for open Denmark beta scale (target: < 10k MAU before promotion). Re-evaluation triggers: any item moves to High likelihood + High severity; MAU exceeds 10k; biometric activation; cross-border expansion; first regulatory inquiry.
4. Data-subject rights
| Right | How exercised | Implementation |
|---|---|---|
| Access | In-app "Export my data" → /api/account-export | Returns a ZIP with profile, photos, chat history, action log |
| Rectification | In-app profile editor | Backed by /api/profile/update |
| Erasure | In-app "Delete my account" | Soft-delete immediately; hard-delete after 30 d grace (see retention table); R2 photo grace job removes binaries |
| Restriction | Email [email protected] | Manual operator action; logged |
| Portability | Same as Access (machine-readable JSON) | |
| Object | Granular toggles for notifications + recap; per-purpose consent toggles | notification_preferences + profile_consents |
| Withdraw consent | In-app per consent toggle | Each toggle change writes a new profile_consents row with the new state |
| Complain to supervisor | Datatilsynet (Danish DPA) | Linked from /legal/privacy |
| Not be subject to automated decision | Discovery + ranking is automated, but no terminal account decision is taken automatically; CSAM hit auto-blocks but is reviewed by a human within 24 h | Spec §16.7 |
Response SLA: 30 days from request receipt (GDPR maximum); operationally targeting 7 days.
5. Consultation
- DPO: none required (small organisation, no large-scale special-category processing AT THE LAUNCH SCALE planned for the Denmark beta). Trigger to appoint: > 25k MAU OR biometric activation OR any breach involving special-category data.
- Datatilsynet: Pre-consultation under Article 36 not currently triggered (residual risk assessed as not high). Will re-evaluate before scaling beyond Denmark.
- Affected users: This DPIA is published at
godating.app/legal/dpiaso prospective users can review processing posture before signing up.
6. Outstanding actions before broad launch
| Action | Owner | Blocks |
|---|---|---|
Activate Turnstile on /intake + login | AI agent / Cloudflare operator | Open Denmark beta scale-up |
| Migrate to magic-link sessions | AI agent | Open Denmark beta scale-up |
| Sign DPAs with Resend + Cloudflare for EU SCC coverage | Jørgen | Public launch beyond beta |
| Re-open external biometric-provider decision + file DPIA addendum only if launch posture changes | Jørgen + counsel | Any future provider-side biometric activation |
Publish ROPA at /legal/ropa | AI agent (this batch) | DSA + Article 30 compliance |
| 5-year admin_audit_log retention job | AI agent | DSA evidence preservation |
7. Approval
| Field | Value |
|---|---|
| Drafted by | HQ Dispatch agent (Claude) on 2026-05-04 |
| Reviewed by | Jørgen Larsen (PX7 Digital) — product review pending; Danish/EU counsel review tracked separately |
| Effective date | On publication at godating.app/legal/dpia |
| Next review | 2026-11-04 (6 months) OR on any §3.1 trigger, whichever comes first |
| Version history | v1.1 — clarified current verification-selfie posture and future provider addendum path; v1.0 — initial draft, open Denmark beta posture |