Users can see who changed what and restore old states (ADR 0013).
- shared: dependency-free word-level Markdown diff (diffMarkdown) with a
unit test; PageVersionContentView; PAGE_RESTORE_CHANNEL + PageRestoreRequest.
- api: GET /pages/:id/versions (list), GET .../:versionId (read-only HTML +
Markdown for diffing), POST .../:versionId/restore. Every route requires
write access — viewing history is gated like editing (permissions.md).
Restore checks permission, then emits the page_restore NOTIFY; history is
append-only (the api never deletes a version).
- collab: a page_restore listener applies the restore on the live document via
openDirectConnection — it snapshots the current state as a PRE_RESTORE
version, then replaces the content in one transaction, so every connected
client converges and the change persists like a normal edit.
- web: HistoryPanel (version list with time/trigger/label/contributors, a
read-only render of a selected version, a Markdown diff against the current
page, and a restore action), toggled from the page menu. de+en strings.
Tests: shared diff (added/removed/round-trip/edges); collab restore DB test
(a connected client converges on the restored content; a pre-restore snapshot
is appended alongside the original — append-only); api list/get/restore
(newest-first, rendered content, write-permission gate, restore returns the
target without mutating history).
This completes M3 (real-time collaboration & history, #33–#42).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PGdhRiwU1WRL4XxJfZYipY