Skip to content

Canvas snapshot & reconnection recovery #9

Description

@FuJacob

Context

The CRDT op log is currently in-memory only on the collab server (docOpLog in CanvasWebSocketHandler). Server restart = all CRDT history lost. Reconnecting clients get stale or empty state. Sim uses durable server-side snapshots + op logs for crash recovery and reconnection.

What to build

Server-side: Periodic snapshots

  • Persist full canvas snapshots to PostgreSQL at regular intervals (e.g., every 30s of activity, or on significant structural changes)
  • Snapshot = serialized state of all nodes + edges + CRDT document states
  • Keep last N snapshots for rollback capability

Durable CRDT op log

  • Move docOpLog from in-memory Map<String, List<JsonNode>> to PostgreSQL
  • Move docSeenOpKeys dedup set to DB (or derive from op log)
  • Index by (canvasId, docId, seq) for efficient range queries

Reconnection protocol

  • Client sends sync_request with its stateVector (already implemented)
  • Server responds with ops since that vector from durable storage (not in-memory)
  • If gap is too large (client too far behind), send full snapshot instead

Crash recovery

  • On server restart, load active canvas state from latest snapshot + pending ops from durable log
  • Resume serving without data loss

Current code references

  • services/collab/src/main/java/com/leetdoodle/collab/handler/CanvasWebSocketHandler.java — in-memory docOpLog, docSeenOpKeys, handleSyncRequest()
  • frontend/src/shared/crdt/document.tsgetStateVector(), getOpsSince() (client-side sync protocol already exists)
  • frontend/src/shared/crdt/useCanvasCrdt.ts — sync request hook

Acceptance criteria

  • CRDT op log persisted to PostgreSQL
  • Canvas snapshots saved periodically
  • Reconnecting client receives missed ops from durable storage
  • Server restart doesn't lose canvas state
  • Large gaps trigger full snapshot sync instead of op replay

Metadata

Metadata

Assignees

No one assigned

    Labels

    Full-stackFrontend and backend work

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions