Skip to content

Server-side operation acknowledgment & client reconciliation #6

Description

@FuJacob

Context

The server currently relays messages without any acknowledgment protocol. Clients have no way to know if an operation succeeded, failed validation, or was rejected due to permissions/conflicts. Sim's server confirms or rejects every structural operation so clients can reconcile.

What to build

Server: Ack/Nack protocol

  • For every structural operation received, server responds to the sender only with:
    • { type: "ack", opId: "...", status: "ok" } on success
    • { type: "nack", opId: "...", status: "error", reason: "..." } on failure (validation, conflict, permissions)
  • Value ops (text edits) don't need individual acks — they're optimistic

Client: Reconciliation on nack

  • On ack: mark operation as complete in the operation queue, proceed to next
  • On nack: depending on reason:
    • Validation error: revert local state, remove from queue
    • Conflict: re-fetch authoritative state for that entity, apply server version
    • Permissions: revert local state, show user notification
  • On timeout (no ack within N seconds): retry the operation (ties into operation queue retry logic)

Operation IDs

  • Every outbound operation needs a unique opId (UUID) so acks can be correlated
  • Add opId field to CanvasOutboundEvent types

Current code references

  • services/collab/src/main/java/com/leetdoodle/collab/handler/CanvasWebSocketHandler.java — relay logic (no ack today)
  • frontend/src/canvas/hooks/useCanvasCollab.tssend() with no response handling
  • frontend/src/shared/events.ts — event types (no opId field today)

Acceptance criteria

  • Structural ops receive ack/nack from server
  • Client operation queue waits for ack before proceeding
  • Nack triggers appropriate reconciliation (revert, re-fetch, or notify)
  • Timeout triggers retry
  • opId field added to outbound events

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