# Runbook — Data Subject Access Request (DSAR)

A user (data subject) asks for their data under PDPA §30 / GDPR Art. 15.

## SLA

- Acknowledge within **3 business days**.
- Fulfill within **30 days** (PDPA + GDPR).

## Identity verification (required first)

Verify the requester:

1. Match the request email to an active `User.email` for the tenant.
2. Send a confirmation link to that email (single-use, 1h expiry).
3. Require the click before generating the export.

Refuse if you can't verify — but tell the requester why and how to verify.

## Steps

1. Open a DSAR ticket; assign to the DPO.
2. Operator runs:
   ```bash
   ADMIN_USER_ID="<the user id>" pnpm tsx tools/dsar/export.ts   # script lives under tools/dsar/ when implemented
   ```
   Generates: `users.json`, `user_roles.json`, `documents.json`, `approval_requests.json`, `audit_logs.json`, plus a human-readable PDF summary.
3. Redact co-parties (approvers, document collaborators) — replace their identifiers with opaque labels.
4. Store the export via `em-file-storage` under `<tenantId>/dsar/<ticketId>/`.
5. Generate a signed download URL (1h expiry, single-use enforced at the file naming + a one-time-token table).
6. Send the link to the verified email.
7. Audit: `pdpa.dsar.fulfilled` with `metadata: { ticketId, requester_user_id }`.

## What's in the export

Every Confidential field for the requester:

- `User` row
- `UserRole` + `Role` names
- `RefreshToken` — counts + last-used IPs (NOT the hashes)
- `Document` metadata + signed URLs for the blobs
- `ApprovalRequest` where they are submitter or step approver (co-parties redacted)
- `AuditLog` where `userId = requester`

## What's NOT in the export

- Restricted-tier values (password hashes, token hashes, secrets).
- Other subjects' identifiers (redact to `user_<opaque>`).
- Backup contents — backups have their own retention + restoration is admin-only.

## Refusal

You may refuse under PDPA §31 / GDPR Art. 12(5) if:

- The request is manifestly unfounded or excessive (e.g. repeated DSARs in days).
- Granting it would adversely affect others' rights.

Document refusal reasoning in the ticket + audit log.

## After fulfillment

- Re-verify in 6 months that the export blob was deleted (its expiry is 30 days; this is the safety check).
- Track DSAR volume in the compliance dashboard.
