improvement(sockets): position persistence on drag end, perms call only on joining room#1571
Conversation
…ly on joining room
There was a problem hiding this comment.
Greptile Overview
Summary
This PR implements performance optimizations for the real-time collaborative workflow editor by addressing two key areas: position update persistence and permission checking. The changes introduce a commit-based system for position updates where intermediate drag movements are broadcast for real-time collaboration but only persisted to the database when the drag operation completes. Additionally, the permission system has been refactored to cache user roles during room join and use synchronous role-based checks instead of repeated database queries.The implementation spans multiple layers of the application: the frontend workflow editor now sends position updates with a commit flag (false during drag, true on drag end), the socket server differentiates between broadcast-only and persistent operations, and the database operations layer only writes to the database when explicitly committed. For permissions, the socket server now stores user roles in the presence data structure when users join rooms, enabling fast role-based permission checks using a static configuration instead of database queries.
These changes integrate well with the existing collaborative architecture by maintaining the real-time experience while reducing database load. The commit pattern aligns with established workflow patterns like undo/redo operations, and the role caching mechanism leverages the existing presence management system in the socket server.
Important Files Changed
Changed Files
| Filename | Score | Overview |
|---|---|---|
apps/sim/socket-server/rooms/manager.ts |
5/5 | Added role field to UserPresence interface for caching user permissions |
apps/sim/socket-server/validation/schemas.ts |
5/5 | Added optional commit field to BlockOperationSchema for position persistence control |
apps/sim/socket-server/database/operations.ts |
5/5 | Added condition to only persist position updates when commit flag is true |
apps/sim/hooks/use-undo-redo.ts |
5/5 | Added commit:true parameter to position updates in undo/redo operations |
apps/sim/contexts/socket-context.tsx |
4/5 | Implemented commit-based position update throttling with immediate send on commit |
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx |
5/5 | Modified drag handlers to send non-committed updates during drag and committed updates on drag end |
apps/sim/socket-server/middleware/permissions.ts |
4/5 | Refactored permissions to use static role-based checks instead of database queries |
apps/sim/socket-server/handlers/workflow.ts |
3/5 | Added role caching during room join but inconsistent permission handling in request-sync |
apps/sim/socket-server/index.test.ts |
4/5 | Updated tests to reflect new synchronous permission checking and role caching |
apps/sim/socket-server/handlers/operations.ts |
4/5 | Implemented early returns for non-committed position updates and role-based permission checks |
apps/sim/hooks/use-collaborative-workflow.ts |
4/5 | Added commit parameter to position updates with conditional queuing logic |
Confidence score: 4/5
- This PR implements well-architected performance optimizations that should significantly reduce database load during collaborative editing
- Score reflects solid implementation with minor inconsistencies in permission handling and some complexity in the throttling logic
- Pay close attention to
apps/sim/socket-server/handlers/workflow.tsfor the inconsistent permission check in request-sync handler
Sequence Diagram
sequenceDiagram
participant User
participant WorkflowComponent as Workflow Component
participant ReactFlow
participant CollaborativeWorkflow as Collaborative Hook
participant SocketContext as Socket Context
participant SocketServer as Socket Server
participant Database
User->>WorkflowComponent: "Drag block from toolbar"
WorkflowComponent->>WorkflowComponent: "onDragStart: Generate block data"
User->>ReactFlow: "Drag over canvas"
ReactFlow->>WorkflowComponent: "onDragOver event"
WorkflowComponent->>WorkflowComponent: "Calculate position & check container intersection"
WorkflowComponent->>WorkflowComponent: "Highlight drop zones"
User->>ReactFlow: "Drop block on canvas"
ReactFlow->>WorkflowComponent: "onDrop event"
WorkflowComponent->>WorkflowComponent: "preventDefault() & parse drag data"
WorkflowComponent->>WorkflowComponent: "Calculate final position from mouse coordinates"
WorkflowComponent->>WorkflowComponent: "Generate unique ID and name"
WorkflowComponent->>WorkflowComponent: "Check for auto-connect (findClosestOutput)"
alt Auto-connect enabled and closest block found
WorkflowComponent->>WorkflowComponent: "determineSourceHandle() for closest block"
WorkflowComponent->>WorkflowComponent: "Create auto-connect edge"
end
WorkflowComponent->>CollaborativeWorkflow: "collaborativeAddBlock(id, type, name, position, ...)"
CollaborativeWorkflow->>CollaborativeWorkflow: "Generate block config & subBlocks"
CollaborativeWorkflow->>CollaborativeWorkflow: "Add to operation queue"
CollaborativeWorkflow->>WorkflowComponent: "Apply locally (immediate UI feedback)"
WorkflowComponent->>ReactFlow: "Update nodes state"
ReactFlow->>User: "Block appears on canvas"
CollaborativeWorkflow->>SocketContext: "emitWorkflowOperation('add', 'block', payload)"
SocketContext->>SocketServer: "workflow-operation event"
SocketServer->>SocketServer: "Validate permissions & operation"
SocketServer->>Database: "persistWorkflowOperation()"
par Persist to database
Database->>Database: "INSERT into workflowBlocks"
alt Auto-connect edge present
Database->>Database: "INSERT into workflowEdges"
end
Database->>SocketServer: "Success confirmation"
and Broadcast to collaborators
SocketServer->>SocketContext: "Broadcast to other users in room"
SocketContext->>CollaborativeWorkflow: "Apply remote operation"
CollaborativeWorkflow->>WorkflowComponent: "Update local state"
WorkflowComponent->>ReactFlow: "Update nodes for collaborators"
end
SocketServer->>SocketContext: "operation-confirmed event"
SocketContext->>CollaborativeWorkflow: "Confirm operation in queue"
CollaborativeWorkflow->>CollaborativeWorkflow: "Remove from pending operations"
Note over User,Database: Block successfully added and synced across all collaborators
Additional Comments (1)
-
apps/sim/socket-server/handlers/workflow.ts, line 123-127 (link)logic: This permission check contradicts the PR's goal of reducing DB calls. Consider using the cached role from the room's UserPresence instead of calling
verifyWorkflowAccessagain.
11 files reviewed, 3 comments
|
|
||
| // Apply light throttling only to position updates for smooth collaborative experience | ||
| const isPositionUpdate = operation === 'update-position' && target === 'block' | ||
| const { commit = true } = payload || {} |
There was a problem hiding this comment.
logic: Default value commit = true seems incorrect - should default to false to maintain throttling behavior for intermediate updates
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/sim/contexts/socket-context.tsx
Line: 603:603
Comment:
**logic:** Default value `commit = true` seems incorrect - should default to `false` to maintain throttling behavior for intermediate updates
How can I resolve this? If you propose a fix, please make it concise.| role: string, | ||
| operation: string | ||
| ): { allowed: boolean; reason?: string } { | ||
| const allowedOperations = ROLE_PERMISSIONS[role] || [] |
There was a problem hiding this comment.
style: Consider adding validation for unknown roles - empty array fallback could allow all operations to be denied silently, which might be confusing during debugging
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/sim/socket-server/middleware/permissions.ts
Line: 47:47
Comment:
**style:** Consider adding validation for unknown roles - empty array fallback could allow all operations to be denied silently, which might be confusing during debugging
How can I resolve this? If you propose a fix, please make it concise.
Summary
Type of Change
Testing
Tested by observing sockets server logs
Checklist