svelte-kanban
svelte-kanban copied to clipboard
Refactor for CRDT-based multiuser support
Goal
Share the same Kanban board across different browsers or browser tabs, potentially to multiple users over the Internet.
Scope
This effort will clear a path for CRDT support with svelte-kanban.
CRDT features will not be added to svelte-kanban
because they will require additional libraries and changes to the API. It will be fairly easy to add CRDT-based multiuser support to svelte-kanban
without negatively impacting the user experience, performance, API, or code quality.
CRDT support will be implemented in a fork using SyncedStore which integrates YJs and Svelte stores.
Changes Needed
-
SyncedStore
only manages non-array objects ({}
). Therefore,$columns
which is currently awritable( [ ] )
must be refactored as:writable( { columns: [ ] } )
. - Do not overwrite the
$columns
store with a shallow copy. CRDT supports manipulating arrays, e.g., push, pop, and assigning a value to an array index, butSyncedStore
doesn't allow$columns = [...newColumns]
since other users might also add a column at roughly the same time. Instead, do this:$columns = $columns
at the end ofaddCard()
etc.. This will cause Svelte reactivity to kick in without assigning a new array. This idiom also uses less CPU and memory. - Calculate rectangle boundaries for cards on the fly. This information doesn't belong in a database that is shared across browsers with different geometries.
- Remove 'empty' cards from the
$column
store. An empty card looks like a dragged card's shadow where it will be placed when the mouse button is released. There should only be one empty card per Kanban board user. The current implementation allows for many empty cards, causing tricky bugs that are difficult to reproduce.
Additional Improvements
This would be a good opportunity to:
- Remove exports from
store.js
that aren't used - Fix some linter warnings, such as unused imports
- Implement #67
- Fix #51
- Fix #74
- Fix #75
- Implement the first half of #66
Deferred
The following issues apply to multiuser scenarios. Since multiuser mode will not be enabled for this particular issue, they can be addressed later.
- Tracking which card is being dragged using the X,Y coordinates on the board will not work when other users can change the board at the same time. Instead, the id of the card will need to be tracked and the card will need to be located by its id. This will be addressed when #61 is implemented.
- The drop target column can be deleted before the user releases the mouse button. This bug will be addressed after #61.
- The dragged card can be deleted before the user releases the mouse button. This bug will be addressed after #61.
- The column from which a card is dragged can be deleted before the user releases the mouse button. This bug will be addressed after #61.
- Moving a column by one user immediately after another user deletes a column may result in errors
- Moving or dragging a card within a column immediately after another users deletes the same or different card in the target column may result in errors
- Updating a card (eg its title or category) immediately after another user deletes it
The following branch works but you need to run the following first: PORT=4444 npx y-webrtc server.js
https://github.com/good-ware/svelte-kanban/tree/synced-store
Demo
One window is Chrome and the other is Safari.
https://github.com/V-Py/svelte-kanban/assets/12297328/e4c8b0ee-6128-4c9c-b3f6-6f439610da1a
It's a little quirky.
Close up of a move column bug. It only happens when moving a column to the left. Notice when you move a column to the left, an extra card shows up in the new right-most column at the bottom in the other browser/tab.
https://github.com/V-Py/svelte-kanban/assets/12297328/8b39766a-7348-41f7-9c35-a8ea0ffc25e0
The move column bug is fixed. The fix involved using different orders depending on which direction the column is moved.
- When moving right, remove the old column and insert a new column (pre-CRDT method)
- When moving left, insert a new column and remove the old column (new method)
I tried the following method when moving right, which is how it works without CRDT. However, it doesn't work with CRDT:
- When moving right, insert a new column and remove the old column