# Data requests

`privacy:` in `app.jadpo` turns on generated routes for a person's
requests to export or erase their data. Jadpo generates the endpoints
only, never the pages: your frontend builds the page, and a recipe can
show you one. There are three ways a request starts.

## Self-service by email

`privacy: { self_service: {} }` turns it on. Anyone can ask by email
address, without signing in:

1. Your frontend posts the address to `POST /privacy/requests`
   (`address`). It answers `202` for every address, so it never reveals
   who has an account, and sends an email to check the address.
2. The email's single-use link opens your frontend's path, set as
   `self_service: { link: "/privacy/confirm" }`, at the browser origin,
   with a token.
3. That page posts `POST /privacy/requests/confirm` (`token`, and `kind`:
   `export` or `erasure`) to create the request.
4. The erasure confirmation email has a cancel link, which opens
   `self_service: { cancel_link: "/privacy/cancel" }`. That page posts
   `POST /privacy/requests/cancel` (`token`).

Loading a frontend page uses up nothing, so a mail scanner that follows
the links confirms and cancels nothing.

## Signed in

`POST /privacy/export` and `POST /privacy/erasure` need a recent sign-in
([`RouteAuthentication.fresh`](routes-signed-in-by-default.md#check-the-caller-again-routeauthenticationfresh))
and act only on the caller's own record: there is no person id to pass.
Export answers `202` and delivers a download link when it is ready.

## Made by staff

Requests received by email or phone are made through generated actions,
after staff have checked who the person is. You grant them in
`policy.jadpo`, as `privacy.create_request: [StaffRole.support]`. Each
request records who created it and how the person's identity was
checked. The export still goes to the person's own email, never to the
staff member.

A schedule or subscriber never makes a request. The only erasure that
happens on a schedule is retention's.

## Exports

An export is delivered as a single-use download link that expires after 7
days, never as an attachment. The file is encrypted at rest and deleted
when the link expires, and every download is in the access records. You
set where the files are kept in `privacy: { exports: { store: keep: } }`.

## Erasures

An erasure waits out a cooling-off period your app sets, 14 days by
default, and the confirmation email has a cancel link. The completion
email says what was kept and why, since the person must be told. So an
entity marked `Erasure.retained` needs a wording in its domain's language
files, which the email lists.

## Deadlines and events

Every request is a record with its one-month legal deadline.
`jadpo privacy requests` and the console list them, and one nearing its
deadline raises an alert.

Each step emits an event: `PrivacyRequestReceived`, `PrivacyExportReady`
(with the download link), `PrivacyErasureScheduled`,
`PrivacyErasureCompleted` and `PrivacyRequestOverdue`. The built-in
emails are subscribers to these events. Your app can add its own, to
post to Slack or a CRM, say, or replace the emails. With no mail
connection, the compiler requires a subscriber that delivers
`PrivacyExportReady`.

## Protection

The routes have [rate limits](rate-limits.md), their
links are single-use and short-lived, and every step is in the access
records.

## Changing the routes

These routes take `path:` and `routes: false` like every
[generated route](generated-routes.md). They run over generated
`privacy.request`, `privacy.confirm` and `privacy.cancel` operations,
which keep every protection.

## The privacy emails

The privacy emails are the address check, export ready, erasure confirmed
and erasure completed. They are [built-in emails](built-in-emails.md),
which you can change as much as you need, in five levels:

1. Jadpo's own email, as it comes.
2. Its words, changed in the root `translations/` folder under
   `jadpo: { }` ([Translations](failures-for-client-apps.md#jadpos-and-packages-text)).
3. Your app's shared email layout.
4. Your app's own `EmailMessage`, with `email:`.
5. Your app's own sending, with `send:`.

They go through your app's one `email:` connection in `application { }`,
and need `application { display_name: }`.

Each email has a built-in type, and a request type for `send:`:
`PrivacyAddressCheckEmail`, `PrivacyExportEmail`,
`PrivacyErasureConfirmedEmail` and `PrivacyErasureCompletedEmail`. You set
them in `privacy: { emails: { address_check: { } export_ready: { }
erasure_confirmed: { } erasure_completed: { } } }`. Each entry takes
`email:` or `send:`, never both. Their fields are on the
[Built-in services](built-in-emails.md) page.
