# Wundklar · MD and Art. 15 exports

Audit-package and data-subject exports built from leased, checkpointed jobs that resume after a tick deadline.

Two export flows share one engine: the Medizinischer Dienst (MD) audit
package the PDL hands to a reviewer, and the GDPR Article 15 copy a patient
can request. Both include encrypted bytes the application already holds;
the Art. 15 variant pseudonymises foreign patient references and limits the
scope to one patient. Decision:
[ADR-0030](/docs/adr/0030-md-audit-package-format);
code:
[`packages/api/src/features/exports`](https://github.com/CarlosZiegler/wundklare/blob/main/packages/api/src/features/exports/exports.service.ts).

## Container [#container]

Standard AES-256 `.zip` (AE-2) written with
[`@zip.js/zip.js`](https://github.com/CarlosZiegler/wundklare/blob/main/packages/report/package.json)'s
streaming writer directly into R2 multipart. The package can be opened by
7-Zip with the password shown once in the UI; it is never stored. The MD
package carries intimate full originals under the organization intimate key
(OIK) decrypted inside a logged system job
([ADR-0017](/docs/adr/0017-client-side-envelope-encryption-and-key-hierarchy)).

Entries inside the archive:

- `manifest.json` — the authoritative map (entity, id, sha256 of the
  plaintext, chain pointer).
- `patients/<id>/` — one folder per patient in scope: metadata, consents,
  prescriptions, trail excerpts.
- `wounds/<id>/` — classification, assessments and measurements (every
  version), plan versions, dressing changes.
- `photos/<id>/` — the full originals (`full.bin`) and the crop / thumbnail
  used in the UI, each with its own `sha256`.
- `trail.jsonl` — the per-Organization hash chain for the patients in
  scope so a reviewer can replay it independently.

## Checkpointed resume [#checkpointed-resume]

Building a package costs more than one tick's 25-second budget. The job
`exportsBuild` holds a lease on `export_job` and writes a `state jsonb`
checkpoint between entries. A tick that times out releases the lease; the
next tick continues from the checkpoint
([ADR-0022](/docs/adr/0022-background-work-stays-in-the-cron-tick)). A
crash discards the in-progress part and the next lease rebuilds it.

Fallback strategy for very large exports (around 412 MB for a long-running
organization): the engine switches to multi-volume output ("Teil n von m")
and uploads each volume separately. The spike that pins the strategy lives
under
[`docs/wundklar/measurements`](https://github.com/CarlosZiegler/wundklare/blob/main/docs/wundklar/README.md).

## Lifecycle [#lifecycle]

- `exports.request` writes an `export_job` under the clinical boundary
  ([ADR-0031](/docs/adr/0031-one-clinical-authorization-boundary)); the
  reason is kept with the trail.
- The user is shown the download link and the password on the desktop
  reports page; the trail records the purpose
  (`view_full` or `legal_export`).
- The archive expires after 72 hours; the retention job deletes it with a
  receipt
  ([ADR-0033](/docs/adr/0033-retention-erasure)).

