Skip to content
The foundation under itTrust and privacy

Export and delete on request

Take your data out, or close your account, and it finishes.

Anyone signed in can ask for an export of their own record, memberships, organizations, projects and authored documents, or ask for their account to be deleted. Both run as background jobs with retries, so a restart cannot eat the request, and both show states you can watch instead of a spinner and hope.

  • 1

    transaction to accept a request

  • 5

    retries per background job

  • 24h

    before a download link expires

The problem this solves

Without a shared foundation, every team rebuilds these edge cases, differently.

The export that dies at thirty seconds

An export built into a web request works until the data outgrows the timeout. Then the button does nothing and there is no record that anything was attempted.

The half-deleted account

Deletion touches memberships, the teammate row and the sign-in provider. A crash part-way leaves an account that is neither active nor gone, which is worse than either.

Invisible processing

When a request gives no feedback, every one of them turns into a question to someone. Visible states answer it without a conversation.

How it works

The mechanism end to end, as implemented in the repository.

  1. 1

    The request is accepted safely

    The server confirms who is asking from the session, then commits the request row, a visible process run and the job trigger in one idempotent transaction.

  2. 2

    A job picks it up

    The job is enqueued right after the commit, with a scheduled reconciler as a backstop, so the page never waits on the queue.

  3. 3

    The work runs with visible progress

    An export collects the account, memberships, organizations, projects and authored documents into one schema-versioned artifact in storage, updating states as it goes.

  4. 4

    Delivery closes the loop

    An email carries a download link that expires after 24 hours. Deletion removes memberships, anonymizes the teammate row and deletes the sign-in account, tolerating an account that is already gone.

Interactive example

See it working

This walkthrough demonstrates the implemented backend contract without using an account, credentials, or provider calls.

Interactive example

Follow the steps this actually runs

  1. Request acceptedCurrent
  2. Export preparedWaiting
  3. Artifact storedWaiting
  4. User notifiedWaiting

Step 1 of 4: Request accepted

Deterministic sample data only. No account, provider, or network connection is used by the interaction.

Highlights

Why it matters

A request cannot get lost

Accepting a request commits the request, its visible progress run and its job trigger together. Clicking twice still produces one request.

Jobs retry until they settle

Export and deletion run with up to five attempts, and each retry re-locks the row and checks whether the request already finished before redoing anything.

Progress you can watch

Queued, processing and completed are real states on a process run, not a guess drawn by the page.

Engineering guarantees

What this does and does not promise

Safety boundary

This is working machinery, not legal sign-off. Which categories of data we hold, how long we keep them, and the wording we give people still need a human review against our own obligations.

Implementation evidence

The boundary above is code, not a claim. These files carry the contract:

  • src/features/privacy/server.ts
  • src/features/privacy/jobs.ts
  • src/registries/data-exports.ts
Questions

Frequently asked questions

What export and delete on request rests on

The docs describe the same contracts this page demonstrates.