Collaborative document editor inspired by Google Docs and Figma's multiplayer service: real-time multi-cursor editing with operational transformation, an operation log as the source of truth, presence, permissions and version history. A teaching design, not Google's or Figma's internal architecture.
See why saving whole documents breaks as soon as two people edit at once.
What was missing: Nothing yet: one server and one database hold every document.
Why that's risky: Two people typing at once overwrite each other (last write wins), nobody sees others' changes without reloading, and 100K saves per second swamp one server.
What gets added: An app server that saves the whole document on each change, and a database holding one copy per document.
Trade-offs: Simplest possible design, but it has no notion of concurrent edits at all.
Send small operations instead of documents, order them in one place, and never lose a concurrent edit.
What was missing: Edits were whole-document overwrites, so concurrent changes were lost and there was no history.
Why that's risky: Collaborators still don't see each other's changes until they reload: nothing broadcasts the ordered operations yet.
What gets added: A WebSocket path for small operations, a collaboration server that owns each active document and orders its edits with operational transformation (OT), and an append-only operation log as the source of truth. A separate Docs API handles opening and listing files.
Trade-offs: One owner per document gives a simple total order but makes that server a hot spot for very busy documents. CRDTs avoid the central owner at the cost of heavier data structures.
Show every editor's changes and cursors to everyone else in the file within a fraction of a second.
What was missing: Ordered operations reached the log but never reached the other editors; cursors were invisible.
Why that's risky: Snapshots, search and notifications would otherwise run on the typing path and slow every keystroke.
What gets added: A per-file broadcast channel and the gateways' push side, so each transformed operation reaches every other client of the file, plus an in-memory presence service for cursors and selections.
Trade-offs: Presence is deliberately not durable: losing cursor positions on a restart is acceptable, saving them would double database writes.
Move everything that isn't needed to acknowledge an edit into background jobs.
What was missing: Snapshot building, indexing and notifications had nowhere to run except on the typing path.
Why that's risky: Opening files and listing them still hit the primary documents database, and embedded images have no home.
What gets added: A change queue fed by committed operations; a snapshot compactor that folds operations into periodic snapshots; a search indexer and search index; and a notification service for @mentions, comments and shares.
Trade-offs: Search lags edits by a few seconds and notifications are eventually sent, in exchange for typing never waiting on them.
Serve opening, listing and embedded images without loading the primary database.
What was missing: All reads went to the primary database and there was no storage or delivery for images.
Why that's risky: Anyone with a link could still reach any file: there is no permission check on API calls or WebSocket joins, and no record of who accessed what.
What gets added: A read replica for opening and listing files, a media service and object storage for embedded images, and a CDN for the editor's static files and images.
Trade-offs: Replica reads can be a moment behind, which is fine for file lists; the operation log itself is never read from a replica.
Enforce sharing rules on every request and connection, record access, and watch the system's health.
What was missing: No access control on requests or connections, no audit trail, and no visibility into the system's health.
Why that's risky: Remaining risk is operational: hot documents, region failures and convergence bugs must be caught by monitoring and drills.
What gets added: A permissions service (owner, editor, commenter, viewer, link sharing) with a cache invalidated on every sharing change, checks on every API call and WebSocket join, an append-only audit store, and monitoring.
Trade-offs: Permissions are strongly consistent (revoking access applies immediately), unlike search and notifications.
CRDTs guarantee convergence without a central server but are heavier; OT with a central transformer is simpler and efficient for text. Choose based on offline needs and operation semantics.
Buffer ops locally with session IDs and lamport/hybrid clocks; on reconnect, submit to a sync/repair pipeline that deduplicates, orders, and merges changes; surface conflicts in UI when needed.
All access decisions and mutations: who viewed/edited, share link grants, permission changes, doc ownership transfers, and administrative overrides; retain immutable logs with secure retention.
Create deterministic simulations of concurrent edits, fuzz op sequences, and validate snapshot equality across replicas; run load tests for fan‑in/out and operation latency distributions.
Use time‑bounded, scope‑limited tokens for share links; enforce authZ centrally via a permissions service; log all grants and revocations to an audit store.
You're in the middle of an interview session. Leaving now will end your current attempt.
Explore concept overviews, real-system examples, key tradeoffs, and interview talking points for each roadmap section.
You've conquered this phase. These are the skills you now own: