Implement consent revocation and data deletion
epic-geographic-peer-mentor-map-consent-privacy-task-004 — Add revokeConsent(mentorId, orgId) method to location-consent-service that atomically marks the consent record as revoked, hard-deletes all stored location coordinates for the mentor from the mentor_locations table, and records a GDPR-compliant deletion audit event with timestamp. Revocation must be irreversible and synchronous before returning success.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 3 - 413 tasks
Can start after Tier 2 completes
Implementation Notes
Implement as a Supabase Edge Function (Deno) or PostgreSQL RPC function using BEGIN/COMMIT to wrap the three operations atomically. Use RETURNING count(*) from the DELETE to capture rows_deleted without a separate SELECT. Store the function behind a POST endpoint that accepts { mentorId, orgId } in the body; validate these against JWT claims at the top of the handler before touching the database. For the audit log insert, use a separate INSERT after the DELETE inside the same transaction — if the audit insert fails, the whole transaction rolls back, which is the correct GDPR behavior (deletion without audit is worse than no deletion).
Define a typed Dart class RevokeConsentResult and a sealed exception hierarchy (ConsentAlreadyRevokedException, ConsentUnauthorizedException) for clean error handling on the Flutter side. Avoid using Supabase's soft-delete patterns here — GDPR Article 17 requires hard deletion of personal data.
Testing Requirements
Unit tests: mock Supabase client to verify transaction structure (revoke + delete + audit in one tx), verify rollback on simulated delete failure, verify 403 on mismatched JWT claims, verify ConsentAlreadyRevokedException on already-revoked consent. Integration tests against a local Supabase instance: seed mentor_locations with 5 rows, call revokeConsent, assert zero rows remain and audit log contains correct metadata. Test all three organization roles (mentor, coordinator, admin) to confirm only the owning mentor can invoke revocation. Test concurrent invocations to verify no race condition leaves partial data.
Coverage target: 90%+ for revokeConsent and its transaction helper.
If the privacy policy text or consent terms change after mentors have already opted in, existing consent records may become legally insufficient, requiring re-consent from all opted-in mentors which could temporarily reduce map coverage.
Mitigation & Contingency
Mitigation: Store a consent_version field on every consent record. Implement a consent version check in location-consent-service that compares the stored version against the current policy version from location-privacy-config and flags stale consents for re-consent prompting.
Contingency: If a policy update invalidates existing consents, suppress affected mentors from the map, queue them for re-consent notification via the existing in-app notification system, and restore map visibility only after new consent is recorded.
A poorly designed consent dialog may lead to low opt-in rates, reducing map utility for coordinators to the point where the feature delivers insufficient value to justify maintenance cost.
Mitigation & Contingency
Mitigation: Follow plain-language writing guidelines from the cognitive accessibility feature. User-test the dialog with 2-3 peer mentors from Blindeforbundet before implementation is finalised. Ensure the dialog explains the benefit to the mentor, not just the data collection facts.
Contingency: If opt-in rate after launch is below 40%, conduct a targeted usability study and iterate on dialog copy and layout. The coordinator can also send a bulk opt-in invitation notification (per the user story) to non-consenting mentors.