Single-Editor Model
Why only one user edits at a time and how presence and control transfer work.
Odyn allows only one user to edit a project at a time. All other users connected to the same project see the files in read-only mode. This page explains the design rationale, how presence tracking works, and the mechanisms for transferring edit control.
Why Single-Editor
Real-time collaborative editing (the Google Docs model) requires conflict resolution infrastructure: operational transforms (OT) or conflict-free replicated data types (CRDTs). These systems add significant complexity to both the server and the editor integration.
Odyn's core workflow is code editing and deployment, not simultaneous document collaboration. The single-editor model avoids:
- Merge conflicts: Two users editing the same file cannot produce conflicting changes.
- Cursor synchronization overhead: No need to broadcast cursor positions in real time.
- OT/CRDT complexity: No transformation engine, no version vectors, no conflict resolution UI.
- Undo confusion: Each user's undo history is isolated and predictable.
The trade-off is that only one person edits at a time. For the typical Odyn use case (a developer or small team shipping embed code), this constraint is acceptable. The presence system provides clear visibility into who holds edit control and how to transfer it.
Presence System
When a user opens a project in the editor, a session is created in the project_sessions table. The session tracks:
| Field | Description |
|---|---|
project_id | Which project the user is viewing |
user_id | Who the user is |
session_token | Unique per browser tab (a user with two tabs has two sessions) |
role | editor or viewer |
last_heartbeat | Timestamp of last heartbeat ping |
The first user to open a project becomes the editor. All subsequent users join as viewers.
Heartbeats
Each session sends periodic heartbeat pings to the server. If a session's heartbeat goes stale (no ping within the timeout window), the server marks it as disconnected. If the stale session was the editor, the edit lock becomes available for the next user who requests it.
Presence Display
Active users appear as avatars in the editor header. Each avatar shows the user's name and role (editor or viewer). The current editor is visually distinguished.
Control Transfer
Three mechanisms allow a viewer to become the editor:
Edit Request
- A viewer clicks Request Edit.
- The current editor receives a dialog: accept or decline.
- If accepted, the viewer becomes the editor and the previous editor becomes a viewer.
- If declined, the viewer is notified.
- The request expires after 60 seconds if the editor does not respond.
Take Control
A user can immediately take edit control without waiting for the current editor to respond. This is useful when the current editor is unresponsive or has stepped away. The previous editor is notified via a toast that their edit access was transferred.
Transfer
The current editor can hand off edit access to a specific team member from the presence list. The selected viewer becomes the editor immediately.
Same-User Multi-Tab
A single user can open the same project in multiple browser tabs. Each tab is a separate session with its own session_token. Only one tab holds editor status:
- Tab 1 opens the project and becomes the editor.
- Tab 2 opens the same project and sees "You're editing in another tab."
- The user can click Take Control in Tab 2 to move edit access from Tab 1.
- Tab 1 switches to viewer mode and shows a notification.
This behavior prevents the same user from making conflicting edits across tabs.
Connection States
The editor UI shows connection status:
| State | Display | Cause |
|---|---|---|
| Connected | Green indicator | Normal operation |
| Reconnecting | Yellow indicator, "Reconnecting..." | Temporary network interruption |
| Disconnected | Red indicator, "Disconnected" | Extended network failure |
Session recovery after reconnection preserves the user's role if the heartbeat has not yet expired. If the heartbeat expired during disconnection and another user took editor access, the reconnecting user joins as a viewer.
Roles and Permissions
Edit control interacts with the project's member roles:
| Member role | Can be editor | Can request edit | Can take control |
|---|---|---|---|
| Owner | Yes | Yes | Yes |
| Admin | Yes | Yes | Yes |
| Member | Yes | Yes | Yes |
| Viewer | No | No | No |
A member with the viewer role at the project level cannot become the editor through any mechanism. Only members with owner, admin, or member project roles can hold edit access.
Trade-offs
| Single-editor | Real-time collaboration |
|---|---|
| No merge conflicts | Requires OT/CRDT |
| Simple undo history | Shared undo complexity |
| Clear ownership of changes | Attribution per character |
| One deploy at a time is natural | Concurrent edits may conflict with deploy |
| Lower server load | Requires persistent WebSocket per cursor |
For teams that need simultaneous editing, the recommended workflow is to divide work by project rather than by file within a single project.
Related
- Team Collaboration for the full collaboration workflow.
- Plans and Limits for editor seat limits per plan.