Skip to content

feat: Learner data export and account deletion — NDPR/GDPR self-service - #1093

Merged
Anuoluwapo25 merged 1 commit into
bakeronchain:mainfrom
anidroid1184:feat/1080-learner-data-rights
Aug 26, 2026
Merged

feat: Learner data export and account deletion — NDPR/GDPR self-service#1093
Anuoluwapo25 merged 1 commit into
bakeronchain:mainfrom
anidroid1184:feat/1080-learner-data-rights

Conversation

@anidroid1184

@anidroid1184 anidroid1184 commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds self-service NDPR/GDPR data export and account deletion for authenticated learners, covering asynchronous archive generation, signed short-lived downloads, a 30-day deletion grace period, and cancellation.
  • Makes the off-chain/on-chain boundary explicit: off-chain personal data is erased or anonymised according to policy, while public Stellar records remain immutable.
  • Implements issue feat: Learner data export and account deletion — NDPR/GDPR self-service #1080 in commit 4ee3cd1b7f2aa8ff75c5c68f8401c01286fcd707 (27 files, 2,276 additions, 11 deletions).

Backend and database

  • Adds POST /api/me/export, owned export status and signed download endpoints, deletion status/cancel endpoints, and DELETE /api/me with the exact DELETE MY ACCOUNT phrase plus fresh SEP-10 re-authentication by the same wallet.
  • Adds a background worker for queued exports and expired deletion requests. Export archives are gzip-compressed tar files containing README.txt and one JSON file per configured relation; completion email is sent only when an existing contact email can be resolved.
  • Adds migration 033 and its undo migration for export jobs, deletion requests, and an admin-visible deletion audit log. Production requires a DATA_EXPORT_SIGNING_SECRET of at least 32 characters.

Data policy and foreign keys

  • LearnVault has no central users table or foreign keys to one; the account identifier is a Stellar wallet address. The policy therefore enumerates migration-defined address columns through migration 032 instead of relying on a user-table cascade.
  • Private/profile/contact/KYC/authentication/activity relations are erased. Community, audit, aggregate, and ledger-mirror relations are anonymised with a one-way deletion pseudonym so dependent context remains usable.
  • Hard deletion runs in one transaction and checks every configured relation for remaining occurrences of the original address before commit. Migration 033's explicit FK is account_deletion_audit_log.deletion_request_id -> account_deletion_requests.id with ON DELETE RESTRICT.
  • Public on-chain LRN transfers, minted ScholarNFTs, treasury transactions, governance activity, and indexed ledger facts cannot be erased; this is disclosed before confirmation.

Frontend

  • Adds a "Your data" section to the authenticated learner's own profile with export status polling, a signed archive link, deletion scheduling, a pending-deletion banner, and one-click cancellation.
  • Extends ConfirmDialog with typed confirmation and shows the irreversible on-chain-record warning before the wallet signing step.

i18n and documentation

  • Adds all data-rights strings in English, Spanish, French, Swahili, and the ps pseudo-locale.
  • Documents the per-table erase/anonymise policy and migration inventory in docs/learner-data-rights.md; updates generated/static OpenAPI coverage and server/.env.example.

Security

  • Export status is owner-scoped; download URLs use HMAC-SHA256 tokens with a 15-minute expiry and timing-safe signature comparison.
  • Deletion requires an authenticated session, exact typed confirmation, and a fresh SEP-10 signature whose wallet matches the current session.
  • Dynamic SQL identifiers are restricted to a strict identifier allowlist; row values remain parameterized. Completed deletion records retain a SHA-256 subject hash rather than the raw wallet address.
  • No private keys or real secrets are added. The example signing value is a documented placeholder, and production startup fails without an explicitly configured secret.

Type of Change

  • Bug fix
  • New feature
  • Smart contract change
  • Documentation
  • Breaking change
  • Other (please describe)

Checklist

  • Tests added or updated
  • No hardcoded secrets or private keys
  • If contract change: cargo test passes — not applicable; no contract code changed
  • If frontend change: npm run typecheck passes — not claimed separately; the GitHub Frontend build passed, while the available local verification focused on the new component tests
  • If backend change: npm test passes — the two targeted data-rights suites pass, but the repository-wide server suite has unrelated pre-existing failures listed below
  • Related issues linked (Closes #...)
  • Self-review completed
  • Code follows project style guidelines

Screenshots (if applicable)

Not included. The behavior is covered by component tests; no browser screenshot run was recorded in the available verification.

Testing

Passing checks

  • Targeted backend Jest suites: 9/9 tests passed across data-rights.service.test.ts and me-data-rights.routes.test.ts.
  • Targeted frontend Vitest suite: 5/5 tests passed in DataRightsSettings.test.tsx.
  • GitHub Actions: 3/3 checks passed — Server build and test (the workflow runs the server TypeScript build), Frontend build, and Contract tests.
  • OpenAPI lint: valid specification; Redocly reported 151 repository-wide warnings.

Repository-wide pre-existing failures

These are separated from the focused #1080 results and were not changed by this PR:

  • Full server Jest run: 51/65 suites passed; 483/493 tests passed. Fourteen suites failed from existing ESM/TypeScript/configuration and unrelated test issues.
  • Full frontend Vitest run: 50/63 files passed; 369/423 tests passed. Thirteen files / 54 tests failed in unrelated existing components and pages.
  • Repository ESLint: 1 existing error in src/pages/CreateBounty.tsx plus 240 warnings; no data-rights lint error was reported (one import-order warning exists in the new service).
  • GitHub's server and frontend build checks pass on the PR merge commit despite those broader local-suite failures.

Environmental limitation

  • Migration 033 was not executed against a live PostgreSQL database because neither PostgreSQL nor Docker was available in the verification environment. SQL, constraints, indexes, FK order, and the undo migration were reviewed statically; this is not a substitute for a live migration/rollback rehearsal.

Additional Notes

  • The current schema has no canonical learner email. Export-ready email is therefore best-effort from existing scholarship reminder contact data; status remains visible in account settings when no email exists.
  • The migrations do not currently define standalone lesson-progress or quiz-submission tables. Existing learner progress represented by enrollments and milestone work represented by milestone_reports are included, and future user-keyed tables must extend the policy and all-relations deletion coverage.
  • CI dependency installation reports existing dependency audit findings; dependency remediation is outside feat: Learner data export and account deletion — NDPR/GDPR self-service #1080 and no dependency versions are changed here.

Closes #1080

Provide NDPR/GDPR export and grace-period erasure flows while preserving
public ledger records and dependent community content safely.

Fixes bakeronchain#1080
@anidroid1184
anidroid1184 force-pushed the feat/1080-learner-data-rights branch from 4ee3cd1 to 4be6056 Compare August 25, 2026 17:49
@Anuoluwapo25
Anuoluwapo25 merged commit ed5f8b2 into bakeronchain:main Aug 26, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Learner data export and account deletion — NDPR/GDPR self-service

2 participants