Skip to content

GDPR Export

sarmakska edited this page Jun 7, 2026 · 2 revisions

GDPR Export

StaffPortal provides a data-portability export so a member can download everything the system holds about them as a single portable document, satisfying the right to data portability.

What is exported

The endpoint gathers every personal-data table for the subject. The canonical list lives in GDPR_TABLES in lib/gdpr.ts and the export route:

  • user_profiles, user_roles
  • attendance, wfh_records, attendance_corrections
  • leave_requests, leave_balances
  • expenses, purchase_requests
  • diary_entries, visitors (visits the member hosted), feedback, complaints
  • audit_logs (events attributed to the member)

The route asserts at module load (assertGdprCoverage) that its SOURCES list covers every table in GDPR_TABLES. Declaring a new personal-data table without wiring it into the export fails the build and the test suite, so an incomplete export can never reach a data subject. The guard is exercised by tests/gdpr.test.mjs.

The document

The response is a JSON document assembled by buildGdprBundle:

{
  "schemaVersion": "1.0",
  "generatedAt": "2026-05-31T09:00:00.000Z",
  "subject": { "userId": "...", "email": "...", "fullName": "..." },
  "sections": [ { "table": "user_profiles", "description": "...", "records": [ ... ] } ],
  "recordCount": 42
}

It is streamed as an attachment with a dated, filesystem-safe filename such as staff-portal-export-ada-acme-com-2026-05-31.json.

Access

  • Self-service. Any signed-in member opens Settings, Privacy and data, and selects Download my data. The endpoint defaults to the caller's own records.
  • Administrator. An admin can export another member with GET /api/gdpr/export?userId=<id>. Non-admins requesting another user receive 403.

Every export, self-service or admin, is recorded in the audit log as a gdpr_export event with the record count and whether it was a self-export.

Implementation

  • Route: app/api/gdpr/export/route.ts. Resolves the subject, authorises, fetches each table in parallel with the service-role client, and audits the export.
  • Pure assembly and filename helpers: lib/gdpr.ts, covered by tests/gdpr.test.mjs.

Troubleshooting

  • 403 Forbidden. Only administrators can export another user. Omit userId to export your own data.
  • A section is empty. The subject has no rows in that table, which is normal.

Related

Clone this wiki locally