Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Phase 3: Sync Engine and Real-Time Collaboration #52593

Open
6 of 19 tasks
youknowriad opened this issue Jul 13, 2023 · 8 comments
Open
6 of 19 tasks

Phase 3: Sync Engine and Real-Time Collaboration #52593

youknowriad opened this issue Jul 13, 2023 · 8 comments
Labels
[Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration [Type] Overview Comprehensive, high level view of an area of focus often with multiple tracking issues

Comments

@youknowriad
Copy link
Contributor

youknowriad commented Jul 13, 2023

This is the overview issue for the collaborative editing project as defined on this post.

The goals are multiple here:

  • Allow multiple users connected to the same WP-Admin to collaborate together on the same content (multiple posts/templates...) live.
  • Enabling offline editing and synchronization of data.
  • Offer a great DevX where developers are freed from thinking about the collaborative editing needs. Data is collaborative and synced by default and abstracted away from the UI developer.

Tasks:

  • Review previews explorations (Collaborative editing using WebRTC #1930 and asblocks).
  • Bootstrap the sync engine architecture and package (being experimental flag) Bootstrap a minimal sync package  #52681
  • Allow persisting and loading data from a local database. (browser, offline-first data)
  • Build a transport communication layer between multiple peers working on the same documents. (WebRTC based on long polling or poling?) [Try] HTTP based PHP signaling server for colaborative editing #53922
  • Extensibility: Allow the transport layer to be replaced ?
  • Design and represent the “presence” of connected peers in the interface. Integrate selection state with other useful parts of the interface, like the block list sidebar.
  • Implement a security layer on top of the transport layer to prevent private data from being shared between peers without the right permissions.
  • Lift concurrent editing restrictions. Right now WordPress locks a post to the current user that is editing it. Another user can take over, but it doesn’t allow two users working on the same post at the same time.
  • Review undo / redo stacks and resolution.
  • Implement the syncing behavior for all the entities of WordPress Data (CRDT representation and config).
  • Employ peer caret and selection primitives that work across block types and design their semantic and visual representation.
  • Explore the possibility of “following a user” as they work through a document.
  • Assess performance and memory usage and impact on non-collaborative editing sessions.
  • Support multi-site (both multi WP and single WP installs) local databases (document ids) Bootstrap a minimal sync package  #52681 (comment)
  • Support syncing for global styles edits Bootstrap a minimal sync package  #52681 (review)
  • Check that all entities are synced properly.
  • Implement e2e tests for collaborative editing and offline syncing.
  • Support inline comments
  • Allow peers to make edits as suggestions to later be accepted/rejected.
@youknowriad youknowriad added the [Type] Overview Comprehensive, high level view of an area of focus often with multiple tracking issues label Jul 13, 2023
@annezazu annezazu added the [Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration label Jul 17, 2023
@prajapatisagar
Copy link
Contributor

Hello Team,

As a first task of this issue, I have added my findings on #23129 PR.

Thanks

@youknowriad
Copy link
Contributor Author

youknowriad commented Jul 19, 2023

Hi @prajapatisagar Thanks for the review there. Actually, the exploration has moved now to this PR #52681 That was a good reminder though, I'm going to close that old PR now.

@youknowriad
Copy link
Contributor Author

I merged the initial bootstrap behind an experimental flag and added a number of todo list items to the current issue. You all feel free to own one of these tasks and iterate on it.

@annezazu
Copy link
Contributor

Out of the list of subtasks for real time collaboration, I've created an issue for inline block commenting so there's a more dedicated space to discuss and explore: #59445

@annezazu annezazu changed the title Sync Engine and Real-Time Collaboration. Sync Engine and Real-Time Collaboration Mar 21, 2024
@annezazu annezazu changed the title Sync Engine and Real-Time Collaboration Phase 3: Sync Engine and Real-Time Collaboration Mar 22, 2024
@priethor priethor unpinned this issue Apr 26, 2024
@creativecoder
Copy link
Contributor

I found this presentation very informative, there may be some useful information for the collaborative sync engine:

"New algorithms for collaborative text editing" by Martin Kleppmann (Strange Loop 2023)

Specific points to highlight:

Automerge is a CRDT (conflict-free replicated data type) engine with a variety of API libraries available (including JS!). Of particular interest it the Peritext merge algorithm which is designed to handle issues specific to merging richtext/markup. I could see this being very useful for creating more elegant revisions for block content.

Screen.Recording.2024-05-01.at.16.42.29.mov

As an example using that technology, there's a prototype collaborative text editor called Upwelling, which is kind of like a combination of Google Docs and git. There's likely some design and technical inspiration there, particularly for asynchronous collaborative editing.

@annezazu
Copy link
Contributor

For anyone following this work, I wanted to connect the dots to this discussion issue from @dmonad. Kevin is sponsored by Automattic to move this work forward and happens to be the author of Yjs! Two weeks ago he shared a lengthy update complete with video demos of some of what he's been working on.

@annezazu
Copy link
Contributor

annezazu commented Jan 7, 2025

For anyone following this work, I wanted to note that there is now an in progress pull request to review as well as a recording of a call where this work was demoed and discussed.

@dmonad
Copy link

dmonad commented Jan 9, 2025

My work in the previous months focused on implementing a reliable sync mechanism of Yjs documents with the WordPress backend. Our constraint is that collaborative editing should be possible while allowing non-collaborative clients (i.e. WordPress plugins, or non-Gutenberg editors) to add changes that will be merged into the collaborative state.

This is not what I wanted to implement initially. But several WordPress devs have made clear that a collaborative-editing extension needs to be fully compatible with existing WordPress plugins. That means that we need to keep two sources of truth in sync - the Yjs state and the state persisted in WordPress. You can follow the discussion that lead to this approach here.

I recently made a PR that implements a reliable sync protocol and which makes the current experimental collaborative-editing experience much more reliable.

This baseline implementation for collaborative editing only syncs using the existing REST Api in WordPress. Hence, the updates propagate quite slowly. That was to be expected, but the implementation works for everyone.

Yjs enables us to mesh different communication protocols together to enable faster syncs between peers. Actually, we can even enable peer-to-peer collaboration. I showed that we can greatly improve the collaborative experience when adding y-webrtc or y-websocket. Realtime sync (via y-webrtc) can be enabled in the experiments page. It will work for all users who can directly communicate with each other (which is not always the case, as some clients can't establish a direct communication to each other).

Users that want a Google-Docs-like realtime experience could set up one of the existing Yjs providers, or we could write a custom WebSocket server in PHP.

We recently had demo session where several collaborators tested the approach. You can find a video recording in @annezazu's article: https://make.wordpress.org/core/2025/01/07/reliable-sync-protocol-pr-live-demo-discussion-for-collaborative-editing/

Now my contract is coming to an end. Big thanks to Automattic for sponsoring me to work on this!
I want to propose future work for someone to take on.

Milestone 2. Make the sync provider a priority (@gutenberg/sync)

Compatibility with the @gutenberg/sync extension should be a requirement for all future work. It is fairly easy to specify how to synchronize a new post entity with a Yjs document. To prevent issues that only arise when collaborative editing is enabled, the posts should always sync to the sync package. We don't necessarily have to enable collaborative editing / sync through the backend. However, reflecting changes to the collaborative Yjs state should be non-optional.

It would be interesting to measure the performance overhead of enabling the sync package. I'm sure there is something we can do to optimize the Yjs-Gutenberg binding.

Milestone 3. Use the Yjs Undo/Redo Manager

Now that the sync package is non-optional, we could rely on the Yjs UndoManager to support selective undo/redo (being able to pick which changes to undo, and which changes to keep). Having a selective UndoManager is important for collaborative applications, because we usually don't want to undo changes from other users when hitting CMD-z. However, it is a useful feature for non-collaborative applications as well.

Yjs efficiently tracks history. It ships with a selective Undo/Redo Manager - you can choose which changes to track, and which changes not to track. It is quite reliable and used by many collaborative editors. Even if Gutenberg decides to stay non-collaborative, it might make sense to use the Yjs undo-manager instead of building a custom one.

You can find more information about this in @gutenberg/sync/CODE.md.

Milestone 4. Render remote awareness state in Gutenberg

Collaborative applications often have "awareness" features that tell the user what other users are currently doing. In Google Docs, you can see remote selection states. A little icon above the selection state indicates who is currently working at that position.

Awareness features help users to non-verbally coordinate in collaborative sessions. Simply showing who is currently working on which block would already go a long way.

If Gutenberg had an API to render such awareness information, it would be quite easy to synchronize that using the @gutenberg/sync package.

Awareness information should not be part of the synced state. In the Yjs ecosystem, we maintain awareness state in a separate Awareness CRDT.

Milestone 5. Evaluate the <!-- y:gutenberg ..--> comment

This was definitely one of the more controversial decisions I made. I believe this approach will work nicely with the existing ecosystem. On the other hand, the y:gutenberg comment consumes additional space in the post content field.

We could also store the comment in a separate table, like Post Meta.

Additional thoughts

Once the @gutenberg/sync package works reliably, we have the opportunity to introduce several additional features.

  1. We can get a diff between two post revisions by comparing two Yjs document states.
  2. We can manage attribution of changes with Yjs as well (who created / deleted which content).
  3. With 1) and 2) we could render a change history by downloading entries from the revision history. This could work similarly to Google Docs.
  4. We could sync two different WordPress sites by merging the Yjs documents contained in the post contents. The changes would be merged automatically.

Addressing the tasks laid out by @youknowriad

Allow persisting and loading data from a local database. (browser, offline-first data)

I'm all for offline applications! But I suggest disabling this feature by default. This can only work reliably when we don't prune the Yjs document from the backend. At this time I'm pretty sure that some users with a lot of documents want to prune Yjs documents in a regular interval. You can only have one or the other.

Both tasks can be done. Currently, we only use the REST API, which is supported by all WP installations. Future explorations can implement different kinds of communication strategies.

Implement a security layer on top of the transport layer to prevent private data from being shared between peers without the right permissions.

This is the reason I added the webrtc under a separate experimental flag. By default, auth* will be handled by the usual REST Api.

Explore the possibility of “following a user” as they work through a document.

That would be part of the awareness feature. It can be easily implemented on-top of the Awareness CRDT. A user could share their current scroll position publically. Other users may choose to follow it.

Support multi-site (both multi WP and single WP installs) local databases (document ids).

I would still be interested to learn more about this.

Allow peers to make edits as suggestions to later be accepted/rejected.

I'm currently thinking about implementing a suggestions API in Yjs. I would love to be involved in the discussion.


I'm pretty excited about WordPress becoming collaborative software. I started Yjs exactly to make the web more collaborative. There is no other software that is more prominent on the web than WordPress. So if I can help with anything, please feel free to reach out to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Real-time Collaboration Phase 3 of the Gutenberg roadmap around real-time collaboration [Type] Overview Comprehensive, high level view of an area of focus often with multiple tracking issues
Projects
None yet
Development

No branches or pull requests

5 participants