5.1 KiB
T15: Operation Undigg — Pandoc Export & Wiki Mode
Status: resolved
Priority: high
Source: fox directive 2026-03-09
Resolved: 2026-03-10 (6d1cfff)
Summary
Transform remarkbox into a document-first platform. Every namespace is a book, every root thread is a chapter. Pandoc renders every format it can produce. Wiki mode lets anyone edit root topics with revision tracking.
Architecture
digraph export_hierarchy {
rankdir=LR
node [shape=box, style=rounded, fontname="sans-serif"]
namespace [label="Namespace\n(book)"]
root [label="Root Node\n(chapter)"]
reply [label="Reply\n(section)"]
pandoc [label="pandoc", shape=ellipse]
formats [label="67 output\nformats", shape=note]
namespace -> root [label="contains"]
root -> reply [label="contains"]
namespace -> pandoc [label="default"]
root -> pandoc [label="default"]
reply -> pandoc [label="on-demand"]
pandoc -> formats
}
Data model changes
-
Node.source_format —
Unicode(16), default'markdown'. Tracks what syntax the user wrote in (markdown, html, rst, mediawiki, latex, textile, etc). Pandoc input formats map directly. -
rb_revision — new table for wiki mode edit history.
id(UUIDType, PK)node_id(FK → Node)user_id(FK → User)data(UnicodeText) — raw source at time of editsource_format(Unicode(16))created(BigInteger) — timestamprevision_number(Integer) — sequential per node
-
Namespace.wiki — already exists (
Boolean, default=False), needs implementation. When True, any authenticated user can edit the root node of any thread. Each edit creates a revision.
Export pipeline
Pandoc subprocess. Input = markdown/rst/html/whatever source_format says.
Output = every format pandoc supports.
Default generated (cached on write/edit):
- Namespace level: one document per namespace containing all root threads
- Root node level: one document per root thread
On-demand (generated per request):
- Any node or subthread at any depth
Pandoc output formats (67 total, subset for default generation):
- markdown, gfm, commonmark, html5, pdf, epub, docx, odt, rst, mediawiki, latex, man, plain, rtf, asciidoc, textile, org, json
URI scheme:
/api/v1/export/namespace/{name}.{format} — full book
/api/v1/export/threads/{node_id}.{format} — single chapter
/api/v1/export/nodes/{node_id}.{format} — on-demand subthread
Content ingestion
On write (create thread, reply, edit):
- Accept
source_formatparameter (default:markdown) - If HTML input, strip to clean body (no head/script/style)
- Store raw source in
Node.datawithNode.source_format - Render to HTML via pandoc:
pandoc -f {source_format} -t html5 - Sanitize HTML output through existing bleach pipeline
- Store in
Node.data_html
Wiki mode
When Namespace.wiki = True:
- Any authenticated user can edit root nodes (not just owner/moderator)
- Each edit stores a revision in
rb_revisionbefore overwriting - Root node always has the latest version (fast render)
- Revision history accessible via API
- Diff between revisions on-demand
Progressive enhancement
Export menus work without JS (plain links to format URIs). With JS: dropdown/popover with format picker, async download.
Phases
Phase 1: Export pipeline (pandoc integration)
- Tree-to-markdown renderer (walk node tree → single markdown document)
- Export API endpoints (namespace, thread, node)
- Pandoc subprocess wrapper
- Format negotiation (URI suffix)
Phase 2: Multi-syntax input
- Add
source_formatcolumn to Node - Alembic migration (
d47dc908d2ea) - Modify
set_data()to use pandoc for non-markdown formats - Accept
source_formaton create/reply/edit API endpoints - HTML stripping for HTML input (pandoc html→markdown round-trip)
Phase 3: Wiki mode + revisions
- Create
rb_revisionmodel + migration (8e3c406e4049) - Implement wiki edit permissions in Namespace (
can_wiki_edit()) - Store revisions on edit (
node.wiki_edit()) - Revision history API endpoint
- Diff endpoint (
GET /api/v1/revisions/{id}/diff/{other_id})
Phase 4: Auto-generated themes
- Per-namespace theme generation (light + dark)
- CSS custom properties for theming (
--rb-*) - Theme preview (JSON palette)
Test Coverage
95 new tests across 4 test files (544 total):
| File | Tests | Coverage |
|---|---|---|
test_pandoc.py |
33 | pandoc convert, formats, tree render, namespace render |
test_theme_generator.py |
15 | hue, seed, CSS generation, light/dark mode |
test_revision.py |
11 | Revision model, wiki edit permissions |
test_undigg.py |
34 | integration tests for export, wiki, themes, multi-syntax |
Module coverage: 76% on new code (100% on themes, serializers; 80% pandoc; 72% export; 55% wiki).
Notes
- Pandoc 3.1.3 installed at
/usr/bin/pandoc - 43 input formats, 67 output formats
- PDF via
wkhtmltopdf(no pdflatex) Namespace.wikicolumn already existed in schema- Diff endpoint deferred — revision data is stored, diffing can be added later