Vault import job: endpoint, orchestration, rollback #117
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
1 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: stwaidele/dorfteich#117
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
Wire the transform module into the conversion-job queue and the page/file/label services: one job imports the whole vault under the chosen parent, with the chosen labels, all-or-nothing.
Scope
options Json?onconversion_jobs({parentPageId, labelIds, frontmatterMode}for vault jobs; existing kinds unaffected).ConversionJobService.enqueuegainsoptionsand an optionalmaxInputBytes— the 25 MiB default protects the pandoc sidecar, which a vault job never touches; vault jobs passMAX_UPLOAD_PARSE_BYTES(64 MiB).POST /ponds/:pondId/import/vault(multipartfile=.zip, body fieldsparentPageId?,labelIds[]?,frontmatterMode), gated@RequiresPondRole('pond_admin')— the single-file import stays editor-gated. Kindimport_vaultrides the existingisImportKindworker routing.ImportService: transform (#116) → batch slug reservation via a new publicPagesService.reserveSlugs(pondId, titles)helper (shares the suffix mechanic withgenerateUniqueSlugInPond;insertPageaccepts a pre-reserved slug) → container pages top-down (empty state,parentId) → note pages → image assets viafiles.upload+linkAttachmentsToPage(image nodes carry the fileId), other instance-allowed types as attachments, disallowed dropped with a log line → labels find-or-create (nesteda/b→ label hierarchy, default color) + assign in-process (no HTTP round-trips), plus the dialog labels.rollbackMediaspirit; makes the worker's 3-attempt retry safe. Error codesimport_vault_invalid_zip,import_vault_too_large,quota_exceeded,conversion_failed(translated de+en). On successresultPageId= the mount parent (null = pond root).Acceptance criteria
page_linksrows point at the imported pages, labels incl. nested, images linked), collision with pre-existing pond slugs, depth merge under a deep parent, quota exhaustion mid-import rolls back completely (no pages, no files, quota unchanged), non-admin editor gets 403, oversized zip / unpacked ceiling rejected.Technical notes
apps/api/src/import-export/{import.controller.ts,import.service.ts,conversion-job.service.ts,import.constants.ts},apps/api/src/pages/pages.service.ts,apps/api/src/labels/labels.service.ts,apps/api/src/files/files.service.ts,apps/api/prisma/schema.prisma.Dependencies
Requires #116.
Size
~2 days.
Implemented in
8ae0102.POST /ponds/:pondId/import/vault(pond-admin-gated) takes the ZIP plus a JSON options field; the archive is parsed at enqueue for fast 400s and the job (import_vault, riding the existing worker routing) runs the #116 transform, then creates containers top-down, notes with their uploaded images/attachments, and labels from tags (nested tags build a label hierarchy) plus the dialog labels. All-or-nothing: any failure hard-deletes the created pages and removes the stored files (quota restored), which also makes the worker's retry safe. Supporting:conversion_jobsgained a nullableoptionsjsonb + amaxInputBytesoverride (the 25 MiB default only guards the pandoc sidecar);insertPageaccepts a pre-reserved slug; and pages born with content now seed their outgoingpage_linksrows — imported pages would otherwise stay invisible to backlinks and the graph until their first collab save.import-vault.e2e.db.test.tscovers gating, the full fixture import, quota rollback, and a clean re-import.