# ADR 0009: Pandoc + Gotenberg sidecars for import/export - Status: accepted - Date: 2026-07-04 ## Context Requirements: Markdown as the primary import/export format (including copy/paste), import of Word (`.docx`) and OpenOffice/LibreOffice (`.odt`) documents, export to Word, OpenOffice, and PDF. Kickoff decision: import is **best-effort structural** — headings, paragraphs, lists, tables, images, links, bold/italic are preserved reliably; layout fidelity (columns, text boxes, exact spacing) is explicitly out of scope. Document conversion is CPU-heavy and full of parser edge cases; it must not run inside the Node API process. ## Decision - **Markdown** conversion (both directions, including clipboard paste) is implemented **in-process** in TypeScript via `prosemirror-markdown` with extensions for our custom nodes (wikilinks, section styles). This is the primary, lossless-as-possible path. - **`pandoc-server`** (official pandoc image, HTTP server mode, internal network only) handles: - import: `.docx` / `.odt` → Markdown (+ extracted media, which the API stores as uploads and rewrites to image nodes), - export: Markdown → `.docx` / `.odt` (structure-true best effort). - **Gotenberg** (internal only) handles **PDF export**: the API renders the page to standalone HTML (same renderer as the public read-only HTML endpoint, with the pond's fonts inlined) and sends it to Gotenberg's Chromium route. PDF output is for reading/sharing, not print production. - The API's `import-export` module orchestrates conversions asynchronously (job table + polling endpoint) with size limits and timeouts; sidecar failures degrade gracefully into a user-visible error, never a crash. - Plugin blocks render their manifest-declared static `fallback` in all exports (ADR 0008). ## Consequences - Two extra containers in the Compose stack; both are stateless, official images, and internal-only (no ingress). Self-hosting stays `docker compose up`. - Import fidelity is testable: a fixture corpus of `.docx`/`.odt` files with expected Markdown output lives in the repo (stories reference it). - Copy/paste from Word into the editor goes through the editor's HTML paste handling (structural, same fidelity philosophy), not through pandoc. ## Alternatives considered - **mammoth.js in-process** for docx: good HTML output, but no `.odt` support and no export direction; pandoc covers all four directions with one tool. - **LibreOffice headless for everything**: heavyweight, slower startup, layout-oriented rather than structure-oriented output. - **Browser-print PDF (client-side)**: inconsistent results across clients; server-side Chromium (Gotenberg) gives reproducible PDFs and enables "export without opening the page".