Import .docx and .odt as new pages #63
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#63
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
Best-effort structural import of Word/OpenOffice documents is a core vision feature (fidelity contract: ADR 0009).
Scope
Import pipeline: upload document → conversion job (pandoc → Markdown + extracted media) → media stored as pond files with document references rewritten →
markdownToDoc→ new page (title from filename or first heading) with initial Yjs state. Build the fidelity fixture corpus (fixtures/import/): representative.docx/.odtfiles (headings, lists, nested lists, tables, images, links, bold/italic) with expected Markdown, as a regression suite.Acceptance criteria
Technical notes
Dependencies
Depends on #30, #62.
Size: ~2 days
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.Done in
546e827. Pipeline fully green (all 7 contexts); deployed to Test + Int and verified live.What shipped
POST /ponds/:id/import(pond-editor gated) uploads a.docx/.odt, enqueues an import job on the #62 conversion queue, and produces a new page in the pond; the client pollsGET /jobs/:idforresultPageId.source → htmlwithembed-resourcesinlines every image as adata:URI, thenhtml → gfmyields clean structural Markdown with those URIs still inline. Embedded images are stored as pond files (with quota accounting) and their references rewritten to file ids on the Markdown text before parsing (the editor parser only admits png/jpeg/gif/webpdata:URIs, so this also avoids leaking base64 as literal text for other types). Title = a leading top-level heading (removed from the body) else the file name.quota_exceeded.Acceptance criteria
fixtures/import/(article + formatting, each.docx/.odt, headings/lists/nested/tables/images/links/bold/italic) with snapshot*.expected.md;import.fixtures.test.tsruns the real two-pass conversion against the pinnedpandoc/core:3.6and asserts each.import.service.db.test.tsand live (see below).conversion_failed(pandoc rejects),import_unsupported_format(wrong extension, de+en); unsupported embedded image types are dropped, not fatal.import.fixtures.test.ts; limits (25 MiB input, 60 s per pass) documented infixtures/import/README.mdandpandoc.converter.ts.Tests:
import.service.db.test.tsdrives the full pipeline with a fake converter (runs in CI);import.fixtures.test.tsruns the real corpus + timing against a reachable sidecar (skips when none — same pattern as #62's real-pandoc check). api suite 206 green.Live verification
int.dorfteich.cloud): importedarticle.docxinto a pond end-to-end → jobsucceeded, page Field Notes (field-notes) created, the embedded image stored as animage/pngpond file (73 B) linked to the page.readyzconverter: ok.test.dorfteich.cloud): import route deployed (401 unauthenticated),readyzconverter: ok, migrations applied. CD smoke tests against Test green.Note: no new sidecar — import reuses the pandoc sidecar already provisioned on both stages in #62. Follow-ups: #64 import UI, #65 export.