Protected prepared privacy exports
This slice extends existing immutable v1/v2 prepared artifacts. It does not generate another snapshot, create public storage or bearer links, certify delivery outside Debelu, or complete a privacy case.
Members open Privacy & Security, pass Supabase authenticator two-step verification, and check up to five prepared snapshots. The existing Support profile view handles access/portability requests and questions about unavailable snapshots. Existing verified authenticator factors can be challenged; users without one can enroll an authenticator and verify its six-digit code. The old profile download button and unbounded UserService.exportUserData entry point are retired; both member and legacy staff callers receive HTTP 410 with instructions to use prepared exports or support.
The new /api/users/me/privacy-exports router authenticates the current token, requires aal2, has no staff capability requirement, sets private/no-store headers before guards, and accepts no subject parameter. Its GET list, POST /:id/download, and POST /:id/acknowledge operations bind the verified current user. The service-role-only RPCs recheck current account status and the live case subject, revision, in-progress access/portability type, identity verification and lack of hold. Terminal/stale/expired artifacts are unavailable. Revoking account access, changing case revision/identity, or placing a case hold immediately prevents fresh downloads and acknowledgments.
SQL verifies immutable UTF-8 payload bytes and SHA256 against the existing 10 MiB artifact contract before issuing a ten-minute random nonce. The backend repeats digest/byte checks; the client repeats these using Web Crypto, checks that its current session still belongs to the same subject, and initiates a JSON file save. Only then does the client send authenticated nonce/hash/byte acknowledgment. SQL binds those values to the issued artifact and subject, checks live case authority and expiry again, and atomically records a verified_client_download_acknowledgment receipt, privacy case event, and audit entry. Exact replay is idempotent. Receipt meaning is an authenticated client assertion that matching bytes were verified and a save was initiated; the browser cannot prove disk persistence. Neither sending the response nor the acknowledgment is described as external delivery or DSAR completion. A failure after save initiation explicitly tells the member to check device downloads before retrying.
Private receipt storage has no direct browser or service-role grants. Evidence permits only the initial verified timestamp transition and deletion after thirty days; immutable artifacts retain their existing expiry and payload destruction. The existing expiry job deletes aged subject receipts before deleting old artifacts and retains artifacts referenced by newer receipts. A global transaction lock serializes nonce capacity checks; each subject is limited to twenty issuances daily, and total retained nonce receipts are bounded at 60,000. No payload or case evidence is stored in browser persistent storage.
Local checks: backend subject service and route adversarial tests; retired legacy service test; storefront digest, substitution, failed-save and truthful UI tests; representative in-memory SQL checks in scripts/db-subject-privacy-export-checks.mjs. Native deployed migration reconciliation, real MFA sessions and authenticated multi-browser validation remain release checks. No hosted migrations or customer actions were performed.