Real-time collaboration architecture from frontend perspective: WebSocket gateway with sticky sessions by docId, stateful Yjs doc actor tier handling CRDT merge, separate Redis pub-sub for ephemeral awareness/cursors, IndexedDB-backed offline ops queue, snapshot persistence to Postgres+S3. Four scenarios: presence cursor broadcast (15 Hz throttle + interpolation), CRDT concurrent merge (commutative ops, no transform), offline reconnect with vector-clock catchup, multi-cursor with server-side ACL denial and client rollback. Includes ADR comparing Liveblocks managed vs Yjs+Hocuspocus self-host vs PartyKit edge.
WebSocket даёт двусторонний transport, но не persistent log, authorization model или convergence. Collaborative system отдельно определяет document datatype, durable acknowledgement, reconnect protocol, presence lifetime, access revocation и compaction frontier.
CRDT может гарантировать deterministic convergence при выполнении своих delivery/merge assumptions. Это не гарантирует business invariants, semantic quality или мгновенную синхронизацию; disconnected replicas могут оставаться разными, пока не получат одинаковые updates.
| Компонент | Роль в модели |
|---|---|
| Editor A | WebSocket session |
| Editor B | WebSocket session |
| Authenticated Realtime Gateway | WebSocket session; WebSocket session; authorize document operation; validated update; consume accepted updates |
| Document Authorization | authorize document operation |
| CRDT Document Room | validated update; append before durable ack; load and checkpoint; publish accepted update; ephemeral presence |
| Durable Update Log | append before durable ack; truncate safe prefix |
| Versioned Snapshot Store | load and checkpoint; write verified snapshot |
| Ordered Room Fan-out | publish accepted update; consume accepted updates |
| Ephemeral Awareness | ephemeral presence |
| Safe-frontier Compactor | truncate safe prefix; write verified snapshot |
Two authorized editors create concurrent CRDT updates. The room validates size/schema, appends accepted updates durably, applies them and fans them out; duplicates remain harmless at the datatype layer.
Проверяемый исход: After both replicas receive the same accepted updates they converge deterministically; presence remains separate from document history.
Editor A reconnects with a state vector rather than assuming socket continuity. The room loads a snapshot/log frontier, computes the missing update and returns it; client updates can be retried idempotently.
Проверяемый исход: Reconnect repairs missed messages without full history when retained state permits; an unsupported old frontier receives a full snapshot resync.
Editor A publishes cursor/presence through the authenticated room. The awareness channel removes that state after disconnect timeout without appending a document deletion or changing authored content.
Проверяемый исход: Presence can disappear and later be republished independently while the durable document remains unchanged.
Document access is revoked while a socket is open. Gateway rechecks authorization, closes the room subscription and rejects later updates; previously downloaded content cannot be remotely erased by protocol promise.
Проверяемый исход: Future reads/writes stop promptly, audit records the revocation, and re-grant requires a new authorized sync rather than trusting the old socket.
The compactor writes and verifies a snapshot at a durable log sequence. It truncates only a prefix no supported offline actor needs, or marks older clients for mandatory full snapshot resync.
Проверяемый исход: Compaction bounds retained history without invalidating the convergence/reconnect contract for supported clients.
active_recipients − 1; egress_bytes ≈ update_bytes × recipients + protocol_overhead.replay_bytes = retained_missing_updates_bytes or one snapshot plus delta; choose the smaller only if both represent the same verified document frontier.room_memory ≈ active_document_state + awareness_state + bounded_socket_buffers + indexes; durable log bytes are storage, not room RAM.Числа и bounds выше действуют только при названных units, population и assumptions. Ни паттерн, ни browser API сами по себе не задают SLA, capacity или correctness.
Диаграмма показывает Yjs-like update algebra поверх durable service. Она не доказывает Byzantine safety, linearizability, business-invariant preservation, guaranteed delivery, end-to-end encryption или unlimited offline retention.
Введите числа или выберите пресет