---
id: 06-core-dsr
epic: dsr-consent-and-cookie-banner
title: core-dsr — scaffold, interfaces, Payload impls, recording doubles, handlers, dsrRouter
type: technical-story
status: done
feature: core-dsr
depends-on: [02-audit-enum-amendment]
blocks: [07-core-api-router-composition]
created: 2026-05-19T12:00:00Z
updated: 2026-05-19T20:39:14.972Z
---

## Goal

Scaffold `@repo/core-dsr` and deliver the complete DSR capability: four GDPR interfaces (`IDataExport`, `IDataDelete`, `IDataRectify`, `IProcessingRestriction`), their Payload-backed implementations walking Epic A's `custom.pii` tags and Story 01's `custom.subject` linkage, four recording doubles in `core-testing`, DI binders, protocol-agnostic handlers, and the `dsrRouter` tRPC router.

## Why

Every EU-bound consumer needs endpoints to satisfy GDPR Arts. 15–18 + 20. The DSR interfaces encapsulate the cascade walk over `custom.subject`-linked collections so consumers never reinvent it. The Payload impls drive the reference implementation; the recording doubles let feature tests assert DSR behaviour without Payload. The tRPC router surfaces the capability to `core-api` (Story 07).

## Done when

- `pnpm turbo gen core-package dsr` produces a green package shell.
- `IDataExport`, `IDataDelete`, `IDataRectify`, `IProcessingRestriction` interfaces exist in `core-dsr/<interface>.interface.ts`.
- `core-dsr/contexts/user-data.jsonld` ships the schema.org JSON-LD `@context`.
- `PayloadDataExport.exportSubjectData("alice", "json")` walks `users` + any `custom.subject`-linked collections, returning a `UserDataBundle` with `asSelf` for `kind: "self" | "owner"` rows and `asReference` for `kind: "reference"` rows.
- `PayloadDataDelete.deleteSubjectData("alice", "soft")` flips `processingRestrictedAt`, NULLs exportable PII, redacts `reference`-role linked fields to `null`, emits one audit entry per affected collection, returns a `DeletionCertificate`.
- `PayloadDataDelete.deleteSubjectData("alice", "cascade-hard")` hard-deletes `self`/`owner` rows and redacts `reference` fields immediately (admin-only; auth check at procedure level).
- `PayloadDataRectify.updateSubjectField` updates the specified field and emits a `RESTRICT` audit entry with `reason: "art-16-request"`.
- `PayloadProcessingRestriction.{setRestriction, isRestricted}` toggles and reads `processingRestrictedAt`; emits `RESTRICT`/`UNRESTRICT` audit entries.
- `RecordingDataExport`, `RecordingDataDelete`, `RecordingDataRectify`, `RecordingProcessingRestriction` test doubles in `core-testing` record calls and payloads; unit tests assert shape.
- DI binders `core-dsr/di/bind-production.ts` + `core-dsr/di/bind-dev-seed.ts` wire all four interfaces; `assertFeatureConformance` passes at boot.
- Contract tests cover: happy path per role/mode, multi-subject row redaction (only the requesting subject's link is redacted, row preserved), JSON-LD `@context` correctness (parsed by `jsonld` library in test only), audit emission shape per operation, restriction flag honored by `isRestricted`.
- Protocol-agnostic handlers in `core-dsr/handlers/{export,delete,rectify,restrict}-handler.ts` return normalized `{ status, body, headers }`.
- `dsrRouter` in `core-dsr/dsr.router.ts` exports `export`, `delete`, `rectify`, `restrict` procedures with auth checks; integration tests assert response shapes and error passthrough.
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass after each task.

## In scope

- `pnpm turbo gen core-package dsr` scaffold.
- Four GDPR interfaces + `UserDataBundle` + `DeletionCertificate` types.
- `core-dsr/contexts/user-data.jsonld` (schema.org `@context`; consumer-overridable).
- `PayloadDataExport`, `PayloadDataDelete`, `PayloadDataRectify`, `PayloadProcessingRestriction` Payload-backed implementations.
- `RecordingData*` test doubles in `packages/core-testing/`.
- DI binders in `core-dsr/di/`.
- Protocol-agnostic handlers in `core-dsr/handlers/`.
- `dsrRouter` tRPC router in `core-dsr/dsr.router.ts`.

## Out of scope

- `core-api` appRouter composition (Story 07).
- Streaming `IDataExport` — in-memory `UserDataBundle` only (streaming v2 deferred).
- `dsr_rectifications` separate audit collection — main audit log via `reason: "art-16-request"` tag is sufficient.
- `withRestriction` brand-treatment — consumer calls `isRestricted` where needed; no wrapper.
- 30-day grace period hard-delete — handled by Epic A's existing retention purge job (no new code here).
- Consent checks on DSR use cases — DSR operations are subject-rights fulfilment, not consent-gated.

## Tasks

- [x] Run `pnpm turbo gen core-package dsr` + define `IDataExport`, `IDataDelete`, `IDataRectify`, `IProcessingRestriction` interfaces in `core-dsr/<interface>.interface.ts` + add `UserDataBundle` + `DeletionCertificate` types + ship `core-dsr/contexts/user-data.jsonld`; all gates pass.
- [x] Add `PayloadDataExport`, `PayloadDataDelete`, `PayloadDataRectify`, `PayloadProcessingRestriction` Payload-backed implementations walking `custom.pii` tags and `custom.subject` linkage (cascade semantics per role: self/owner/reference) + `RecordingDataExport`, `RecordingDataDelete`, `RecordingDataRectify`, `RecordingProcessingRestriction` test doubles in `packages/core-testing/` + DI binders `core-dsr/di/bind-production.ts` and `core-dsr/di/bind-dev-seed.ts`; contract tests covering happy path per role/mode, multi-subject row redaction, JSON-LD `@context` correctness, audit emission shape, restriction flag; all gates pass.
- [x] Add protocol-agnostic handlers in `core-dsr/handlers/{export,delete,rectify,restrict}-handler.ts` + `dsrRouter` tRPC router in `core-dsr/dsr.router.ts` with auth checks; integration tests asserting procedure response shapes and error passthrough; all gates pass.
