import/export all user's data #286
Labels
No labels
area:auth
area:ci
area:db
area:infra
area:native
area:pwa
area:service
epic
feature
foundation
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
james/carol#286
Loading…
Add table
Add a link
Reference in a new issue
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?
Let a user export all of their domain data to a portable archive and import it back — into the same instance or a different one. UI lives in the settings screen.
Format — gzipped directory tree (
.tar.gz)textPKs populated byrandomUUID(), so FKs are real UUIDs today. Export emits the existing IDs; cross-file references are by UUID. Each YAML file is a list of entities keyed by their UUID; child rows nest under their parent or carry the parent UUID.manifest.yamlcarriesformatVersion: 1(forward-compat gate),exportedAt, the CarolappVersion(ties to the versioning work in #285), and per-entity counts (drives the import preview).media/holds the raw blobs; YAML references them by relative path (media/<file>). Empty/absent when the user has no uploaded assets.Scope — domain data only
Included: profile (+contacts), skill sections + skills, education, jobs + positions, projects + contributions, people (+ all person_* children), organizations (+ links + key people), notes — plus their media.
Excluded: users/auth (password hashes, OAuth identities, sessions, PATs, login attempts), and user settings/preferences. Auth is instance-bound and unsafe to ship; settings are out of scope for this pass. Revisit if a "full account backup" ticket lands.
Import — user chooses the mode, with a dry-run preview first
Two-step, never trust the file's
user_id(every imported row is re-scoped to the authenticated importer — prevents cross-user injection):Modes (offered in the UI at import time):
API (auth required, user-scoped, RFC 7807 + zod)
GET /api/export→application/gzip,Content-Disposition: attachment; filename=carol-export-<date>.tar.gz. Streams the archive for the authenticated user.POST /api/import/preview(multipart upload) → dry-run summary JSON (counts, per-mode effects, validation errors). Stateless — the client keeps the file.POST /api/import(multipart: file +mode+ confirm) → applies in one transaction, returns a result summary. Re-sends the same file (no server-side staging to expire).File-transfer endpoints, not lists → cursor pagination N/A.
UI — settings screen (
apps/client/app/(app)/account.tsx)New "Your data" card. Strings via the
account.*i18n namespace; Carol's voice (first person, sentence case, no emoji).expo-file-systemsave / share sheet). Spinner while building.expo-document-picker) →POST /api/import/preview→ summary screen showing counts + a mode selector (Replace / Merge / Import as copies) with a destructive-action warning on Replace → confirm →POST /api/import→ success/error result.Cross-cutting
Suggested breakdown (child tickets)
GET /api/export(tar.gz assembly, media copy from blob storage).POST /api/import/preview(schema, referential integrity, zip-slip/size guards).user_idre-scoping.Out of scope (today)
Auth/identity/token export, settings export, scheduled/automatic backups, archive encryption. Pull in via a follow-up ticket if needed.