Jadpo is experimental and not ready for production. These docs follow the compiler's main branch as of 30 Oct 2026. What's built · Install 0.1.0
jadpo
Reference: Personal data

Personal data

Data requests

On this page

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) 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, 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. 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, 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).
  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 page.

Markdown for agents: /docs/data-requests.md.Built from Jadpo main at a707efb.