Initial deliverable of the architecture phase: 16 ADRs (stack, CRDT collaboration, plugin sandbox, import/export, backups, CI/CD), data model, permission model, real-time collaboration and plugin concepts, deployment/operations/security documentation, and the milestone roadmap that the implementation issues are derived from. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
58 lines
2.7 KiB
Markdown
58 lines
2.7 KiB
Markdown
# 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".
|