Privacy & Consent
En resumen
Privacy & Consent operationalises GDPR across the entire platform: data export, 30-day grace deletion with cascading anonymisation, granular consent records, parental consent for minors, per-user privacy settings on profiles, append-only data-access audit, cookie consent for both authenticated and anonymous visitors, support-access consent that gates sys-operator impersonation, and a self-service support portal that surfaces every consent decision and audit event back to the user.
Cómo funciona
Privacy is enforced through a small set of dedicated models and a single user-facing surface. ConsentRecord captures explicit opt-ins by type — marketing, photo_publication, data_sharing, analytics — and every change is timestamped and audited. ParentalConsent extends the model for minors: when a profile's age falls below the tenant's threshold, consent endpoints refuse to record an opt-in until a verified guardian has approved, with verification recorded against a guardian auth identity.
PrivacySettings is embedded in PlayerProfile and controls what other users see — profile visibility, results, ranking, club affiliation, date of birth — with hidden profiles returning 404 to non-owners and public search respecting the same visibility. CookieConsentRecord covers four canonical categories (essential, functional, analytics, marketing) and supports both authenticated users and anonymous browsers via dual subject identification. DataRetentionPolicy is configurable per tenant, telling background jobs when to archive, anonymise or delete categories of data.
GDPR data subject rights are exposed under /me: GET /me/data-export streams a JSON archive; POST /me/data-deletion-request begins the 30-day grace window before anonymisation cascades through results, rankings and audit references. DataAccessAuditLog is an append-only record of every read of personal data; users can pull their own access history under GET /data-access-audit/me (Art. 15). Support-access consent is the user's veto on operator impersonation: the support portal at /me/support shows pending grant requests linked to a SysSupportTicket, and the user must approve before any sys-operator can act on their account.
An SSE stream pushes new requests to an in-app banner, the activity-summary endpoint aggregates exactly how many reads/writes the operator performed, and notification preferences let the user pick email/push/in-app channels (break-glass transitions bypass opt-outs by compliance rule). The self-view activity timeline (GET /me/activity-timeline) surfaces login, billing, notification, support-grant, incident and legal events in one stream, with operator names masked according to per-tenant impersonation_actor_visibility.
Capacidades clave
- GDPR data export and 30-day grace deletion with cascading anonymisation
- ConsentRecord, ParentalConsent (minors) and CookieConsentRecord across four categories
- PrivacySettings embedded in PlayerProfile with field-level visibility control
- DataAccessAuditLog append-only with self-view (Art. 15) endpoint
- Support-access consent gating sys-operator impersonation, with SSE notifier
- User support portal aggregating consent decisions, tickets and history
- Self-view activity timeline and per-channel notification preferences with break-glass override
En la práctica
A user in Norway opens /me/support after spotting a banner about a pending support request. The portal shows a Norwegian sys-operator asking to view her account to investigate a billing complaint she filed earlier; the request links to her ticket. She approves the grant for one hour.
While the operator works, an SSE-driven activity counter shows reads incrementing in real time. Later she opens GET /me/support/access-grants/{id}/activity-summary and confirms the operator made 12 reads and one write — exactly the refund she requested. The next day she revokes the (already expired) grant for tidiness, downloads her cookie-consent record from /me/cookie-consent/me, and pulls her full data archive via /me/data-export to verify everything is in order.
Funcionalidades de este subsistema
20| ID | Status | Funcionalidades |
|---|---|---|
| F02.05.01 | Entregado | GDPR data subject rights — GET /me/data-export, POST /me/data-deletion-request with anonymisation (PL-208, PL-F0205a) ✅ PL-F0205a |
| F02.05.02 | Entregado | Data retention policies — configurable per tenant via DataRetentionPolicy model (PL-208, PL-F0205a) ✅ PL-F0205a |
| F02.05.03 | Entregado | Consent management — ConsentRecord model with marketing, photo_publication, data_sharing, analytics types (PL-208, PL-F0205a) ✅ PL-F0205a |
| F02.05.04 | Entregado | Minor/youth data protection — ParentalConsent model with guardian verification, blocks consent for minors without parental approval (PL-208, PL-F0205a) ✅ PL-F0205a |
| F02.05.05 | Entregado | Privacy settings per user — PrivacySettings embedded in PlayerProfile (profile visibility, results, ranking, club, DOB) — GET/PUT /player-profiles/{id}/privacy-settings subresource, owner-only update, hidden profiles return 404 to non-owners, public search respects visibility ✅ PL-F0205b |
| F02.05.06 | Entregado | Audit log of all data access — DataAccessAuditLog append-only model, record_access() best-effort service, GET /data-access-audit admin listing, GET /data-access-audit/me GDPR Art. 15 right-of-access, audit rows on profile reads/lists/exports ✅ PL-F0205b |
| F02.05.07 | Entregado | Cookie consent and tracking preferences — CookieConsentRecord model with 4 canonical categories, GET /cookie-consent/categories, POST /cookie-consent upsert, GET /cookie-consent/me, GET /cookie-consent/anonymous/{id}, PATCH /cookie-consent/{id}, POST /cookie-consent/{id}/withdraw, dual subject identification authenticated+anonymous, GET /me/privacy-overview combined snapshot ✅ PL-F0205b |
| F02.05.08 | Entregado | Support-access consent — user-side portal at /me/support/access-grants for consent over sys-operator impersonation. Approve / deny / revoke grants that reference a SysSupportTicket; every transition is audited. Full contract in docs/engineering/security/support-access-consent.md; operator-side in F21.02a. ✅ PL-T141 |
| F02.05.09 | Entregado | User support portal — /me/support landing aggregate in both app/ (mobile-first) and admin/ (desktop-first) with three columns (pending requests, open tickets, recent history). Surfaces consent decisions inline without navigating away. ✅ PL-T143 |
| F02.05.10 | Entregado | Access-history drill-in — GET /me/support/access-grants/{id}/activity-summary aggregates sys-audit rows by impersonation_id so the target user can see exactly how many reads / writes the operator performed and when. ✅ PL-T143 |
| F02.05.11 | Entregado | Real-time pending-request notifier — SSE stream GET /me/support/access-grants/stream pushes new grant requests to the in-app banner; 2-second polling loop in the service, heartbeat every 15 s, 10-minute client-reconnect cap. ✅ PL-T143 |
| F02.05.12 | Entregado | User-scoped support tickets — GET/POST /me/support/tickets, GET /me/support/tickets/{id}, POST …/reply, POST …/close. Reporter-only; operator-internal notes hidden from the thread; reuses the T130 intake_ticket service. ✅ PL-T143 |
| F02.05.13 | Entregado | Per-channel notification preferences — GET/PUT /me/support/notifications/preferences toggles email / push / in-app. Break-glass transitions bypass opt-outs by compliance rule. ✅ PL-T143 |
| F02.05.14 | Entregado | User activity log (self-view) — GET /me/activity-timeline?user_email=…&kinds=… returns the user-facing subset of the sys-timeline (PL-T145). Login, billing, notification, support-grant, incident and legal events flow through unchanged; sys_action rows are redacted to "Support agent viewed your account" and operator identities may be masked per tenant impersonation_actor_visibility. Surfaces: app/app/settings/activity-log.tsx (mobile) + admin/app/(dashboard)/privacy/activity-log.tsx (federation admins). Read-only; scoped automatically to the caller by email. ✅ PL-T145 |
| F02.05.15 | Entregado | Granular consent scope versioning — ConsentScopeDefinition per (tenant_id, scope_key, version) with monotonic version-bump and auto-superseding. Categories: marketing / analytics / operational / subprocessor / photo / research. Existing user consents stay attributable to the exact text the subject saw — no auto-revoke on republish. Endpoints: GET/POST /dpo/consent-scopes, GET /dpo/consent-scopes/{key}/versions, POST /dpo/consent-scopes/{key}/retire. Audit-log category gdpr_consent_versioning. ✅ PL-T221 |
| F02.05.16 | Entregado | DPO-on-behalf DSAR — DpoAccessRequest model with status FSM (draft → submitted → in_review → fulfilled / rejected / cancelled). DPO files data_export / rectification / erasure / restriction / portability with mandatory legal_ground. Inline append-only audit_trail mirrored to global AuditLog (category=gdpr_dpo). Endpoints: GET/POST /dpo/access-requests, GET /dpo/access-requests/{id}, POST .../submit, POST .../cancel. Cancel blocked once fulfilment_started_at is set. ✅ PL-T221 |
| F02.05.17 | Entregado | DSAR-job proxy for DPO portal — GET /dpo/data-export-jobs lists GdprPortabilityExport jobs initiated through the DPO console; GET /dpo/data-export-jobs/{id} returns status + signed download URL + expires_at. Reuses F16-DSAR pipeline — PL-T221 only initiates and links. ✅ PL-T221 |
| F02.05.18 | Entregado | Cross-tenant DPO overview — POST /dpo/cross-tenant-overview for international DPOs (CEP/FIPJP) holding gdpr:dpo:read in 1–20 tenants. Returns per-tenant {tenant_id, open_requests, active_scopes}. In-memory parallel fan-out — no automatic cross-tenant DB join. Operator's own tenant always allowed; system-scope tokens get full body.tenants. ✅ PL-T221 |
| F02.05.19 | Entregado | DPO capability gates — new capabilities gdpr:dpo:read, gdpr:dpo:write. Capability-deny logged to AuditLog with action=capability.deny so federation security teams can chase unauthorised attempts. System-scope tokens implicitly hold all capabilities. ✅ PL-T221 |
| F02.05.20 | Entregado | DPO admin console — /(dashboard)/dpo (overview), /dpo/consent-scopes (publish + version history + retire), /dpo/access-requests (kanban with 6 columns + detail with shared AuditTrail component), /dpo/cross-tenant (per-tenant tile with setActiveTenant deep-link). Hidden for affiliate / venue / individual tenant types. ✅ PL-T221 |
Subsistemas relacionados
Partes interesadas que necesitan este subsistema
Aparece en 3 análisis de partes interesadas