Final phase of the wiki upgrade (see WIKI_UPGRADE.md).
Schema (additive): wiki_revisions table (per-save content snapshots).
The FULLTEXT index on wiki_pages(title, body) shipped in Phase 1.
Search:
- MATCH ... AGAINST natural-language search over title + body, ordered by
relevance
- public: GET /public/wiki?q= (published only); admin: GET /admin/wiki?q=
(all statuses)
- public wiki index gains a search box; admin list gains a search field
Revision history:
- every create/update snapshots the page into wiki_revisions
- admin endpoints: list revisions, get one, and restore (restore overwrites
the page, rebuilds links, and appends a new revision — history stays
append-only); logged as wiki.revision.restore
- editor gains a History modal: revision list + word-level diff (jsdiff) of a
chosen revision against the current page, with one-click restore
Verified end-to-end: search matches body and title; two edits produce three
revisions; diff renders added/removed words; restore reverts and records a new
revision. No console errors.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replaces the raw-HTML textarea in the wiki editor with a TipTap (ProseMirror)
WYSIWYG editor.
- new RichTextEditor component: bold/italic/strike, H2/H3, bullet+ordered
lists, blockquote, code block, divider, link, inline image, undo/redo
- generalized POST /admin/uploads (reuses the screenshot multer config) →
{ url }; the editor uploads inline images through it
- editor output still passes through the Phase 1 server-side sanitizer on
save and DOMPurify on render
- lazy-loaded as its own chunk so the public bundle doesn't ship TipTap
(public ~82kB gzip; editor chunk ~106kB gzip loaded only in admin)
- RTE styling added to theme.css (toolbar, active states, prose content)
Verified: uploads serve as images; H2/H3 + lists + link + inline image
round-trip through the WYSIWYG and render sanitized on the public page.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Foundation & safety phase of the wiki upgrade (see WIKI_UPGRADE.md).
Schema (additive, idempotent via ensureSchema):
- new wiki_categories table; wiki_pages gains category_id, excerpt,
published, published_at, sort_order, and a FULLTEXT index
- migration ALTERs guarded with IF NOT EXISTS for existing databases
- seed reworked into 4 sections with the 8 starter pages assigned
Security:
- new utils/sanitizeHtml.js (sanitize-html allowlist); wiki bodies are
sanitized on every save, and the article renders through DOMPurify
- strips <script>, event handlers (onerror), and javascript: URLs
Backend:
- public: published-only list with ?category filter + /wiki/categories
- admin: extended page CRUD, PATCH publish toggle, category CRUD;
drafts visible to admin, hidden from public
- all writes logged to activity_log
Frontend:
- data-driven public wiki index (sections + real descriptions; removed
hardcoded blurbs/Roman numerals) with ?category filtering
- article: category breadcrumb + sanitized render
- admin: Section/Status columns, draft/publish + section + excerpt in the
editor, and a Manage sections modal
Verified end-to-end against MariaDB 11: migration clean, XSS neutralized,
drafts hidden, client builds, server boots.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>