Consider using Y.Map instead of Y.Array for jobs/triggers/edges in Y.Doc
Nobody has claimed this yet.
- Dominant language
- Elixir
- Stars
- 296
- Forks
- 86
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 50
Description
Context
When multiple users apply an AI-generated workflow simultaneously, the Y.Array CRDT can create duplicate entries. This happens because Y.Array's push() operation is always additive - concurrent pushes from different users all get merged.
Current data structure:
ydoc.getArray('jobs') // Y.Array<Y.Map>
ydoc.getArray('triggers') // Y.Array<Y.Map>
ydoc.getArray('edges') // Y.Array<Y.Map>
Current apply logic (in YAMLStateToYDoc.applyToYDoc):
const jobsArray = ydoc.getArray('jobs');
jobsArray.delete(0, jobsArray.length); // Clear
jobsArray.push(transformedJobs); // Add new
When two users click Apply concurrently:
- Both delete operations target the same items
- Both push operations add the same items
- CRDT merge includes BOTH pushes → duplicate entries
Current Solution (Implemented)
We implemented server-coordinated locking via Phoenix Channel:
- When a user clicks Apply, backend broadcasts
workflow_applyingto all clients - All clients disable their Apply buttons
- When apply completes, backend broadcasts
workflow_applied - All clients re-enable Apply buttons
This is 100% effective because the server is the single source of truth.
Files changed:
lib/lightning_web/channels/workflow_channel.ex- Addedstart_applying_workflowanddone_applying_workflowhandlersassets/js/collaborative-editor/stores/createWorkflowStore.ts- Channel listeners and coordination methodsassets/js/collaborative-editor/components/AIAssistantPanelWrapper.tsx- Calls coordination methods
Proposed Future Improvement
Change the Y.Doc structure to use Y.Map keyed by ID:
ydoc.getMap('jobs') // Y.Map<id, Y.Map>
ydoc.getMap('triggers') // Y.Map<id, Y.Map>
ydoc.getMap('edges') // Y.Map<id, Y.Map>
Why this would be better:
map.set(id, data)is idempotent - two users setting the same key = same result, no duplicates- More semantically correct (entities are keyed by ID)
- Simpler apply logic without needing coordination
What would need to change:
-
Frontend:
YAMLStateToYDoc.applyToYDoc- Usemap.set(id, data)instead ofarray.push()createWorkflowStore.ts- Update observers to read from maps- Convert map values to arrays for Immer state (React expects arrays)
-
Backend:
lib/lightning/collaboration/workflow_serializer.ex- ChangeYex.Doc.get_arraytoYex.Doc.get_map- Update initialization and extraction logic
Priority
Low - The server-coordinated solution works perfectly. This is an architectural improvement for cleaner CRDT semantics, not a bug fix.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing YAMLStateToYDoc.applyToYDoc and the observers in assets/js/collaborative-editor/stores/createWorkflowStore.ts, then inspect lib/lightning/collaboration/workflow_serializer.ex. The migration is done when jobs, triggers, and edges use keyed maps consistently and frontend state still receives arrays without duplicate entries during concurrent applies.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- elixir, typescript
- Domain
- backend, distributed-systems, frontend
- Issue type
- Refactor
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100