Documentation
Architecture
Changelog and Snapshots

Changelog and Snapshots

Why this exists

Even with push-on-mutation sync and local IndexedDB persistence, teams sometimes need to answer:

  • "What changed on this note last week?"
  • "Can we restore a note that was deleted by mistake?"
  • "Can we recover the board if the database is empty?"

The changelog and snapshot system provides the audit trail and recovery layer.

Changelog entries

Changelog entries are Markdown fragments written to R2.

ActionTriggerContent
create_noteImmediate (no debounce)Full note snapshot
update_note15-second debounce per noteFull note snapshot at fire time
delete_noteImmediatePre-deletion note snapshot
rename_board15-second debounceNew board name

Why debounced for updates: Writing a changelog entry on every keystroke would be expensive and noisy. The 15-second debounce per note captures the "settled" state after editing stops.

Indexing

After each batch write, the server:

  • Appends entries to the KV changelog index (changelog-index:{boardId})
  • Updates per-note version entries in KV (note-versions:{boardId}:{noteId})
  • Saves an updated current.md (full board snapshot) to R2

Browsing the changelog

The changelog can be browsed in the board UI (if enabled). Entries can be filtered by:

  • Note ID
  • Action type
  • Time range

Board snapshots

A "current snapshot" is the latest full-board Markdown representation stored at current.md in R2.

Point-in-time snapshots may be created:

  • Manually via POST /api/boards/{boardId}/snapshot
  • Automatically via scheduled triggers (if configured)

Snapshots are stored at snapshots/{timestamp}.md and listed via GET /api/boards/{boardId}/snapshot?list=true.

Recovery strategy

R2 recovery fallback

If a client opens a board and has:

  • No local IndexedDB state (first device, cleared browser, new collaborator)
  • AND the D1 database is empty for this board

Then BoardHydrator fetches GET /api/boards/{boardId}/snapshot to retrieve the latest current.md from R2 and restore the board state.

Note restore

A specific note version or deleted note can be restored via:

POST /api/boards/{boardId}/log/restore

This returns the parsed Note object which the client can re-create via the standard sync pipeline.

ChangeLogger client lifecycle

EventAction
Note createdImmediate queue
Note content edited15-second debounce per note ID
Note deletedImmediate queue with pre-deletion snapshot
Board renamed15-second debounce
Auto-flushEvery 30 seconds
Page unloadnavigator.sendBeacon fallback
Component unmountdestroy() — flush pending entries

See also