Data export for account holders (GDPR portability) #68
Labels
No Label
area:auth
area:docs
area:export
area:ops
area:storage
area:supply-chain
auth
backend
blocked
collab
deployment
docs
effort:L
effort:M
effort:S
frontend
plugins
qa
vs-nfd
vs-nfd:blocker
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: stwaidele/dorfteich#68
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Access/portability requests must be answerable by the user alone (security.md §Privacy).
Scope
Endpoint + settings UI: 'Export my data' — ZIP with profile JSON, list of memberships/grants, and the Markdown export of the personal pond plus owned shared ponds (reusing #65); rate-limited; generated as a job with download link (expiring).
Acceptance criteria
Technical notes
Dependencies
Depends on #65.
Size: ~0.5 day
Conventions: English code/comments, clear human-readable code, no hard-coded UI strings (ADR 0012, add
deanden), permission checks only via the shared guard (docs/architecture/permissions.md). Read the referenced ADRs before starting.Implemented in
462eca9(pipeline green: all 7 CI/CD contexts, deployed to Test + promoted to Int).Self-service GDPR data export, built on the existing conversion-job queue (#62) and the pond Markdown export (#65) — reused, not duplicated.
Endpoint & job
POST /users/me/data-export(@AuthenticatedOnly), rate-limited per account (3 / hour →429 rate_limited). Enqueues adata_exportconversion job; the client polls and downloads via the generic owner-scopedGET /jobs/:id/GET /jobs/:id/result.kind === 'data_export', resolvesDataExportServicethrough a token (no DI cycle, mirroring the import pipeline), builds the ZIP and stores it with anexpiresAt(24 h).ZIP contents
profile.json— the caller's own account fields (the data-minimization set).memberships.json— every role grant the user holds, grouped per pond with anownerflag: metadata only, no foreign content.ponds/<slug>/…— Markdown + media for only the ponds the user owns (personal + owned shared), each routed through the shared read-permission filter.Expiry & minimization
expiresAtpasses; an hourly scheduleddata-export-purgejob drops the stored bytes (security.md §Privacy).Acceptance criteria
data-export.service.db.test.ts).TOP SECRETcontent never appears anywhere in the archive (asserted).429on the 4th request within the window.Notable
ExportService.streamPondMarkdownZipinto a sharedappendPondMarkdown(archive, user, pond, prefix)used by both the pond ZIP and the data export (byte-identical for the #65 path,prefix='').pollJob/downloadJobResultbetween the document-export and data-export hooks (job-download.ts).ConversionJob.expiresAt(+ migration20260710120000_data_export_expiry).medium(2 agents): 0 correctness findings; the one reuse finding (web poll/download duplication) is addressed.No stage provisioning needed — no new sidecar or compose change (the queue and scheduler already exist on both stages).