Skip to main content

Auto-Save & Conflict Detection

Markdown-OS provides intelligent auto-save functionality with conflict detection to prevent data loss. The system uses debounced saves, file locks, WebSocket notifications, and a conflict resolution dialog to handle concurrent edits safely.

Auto-Save System

Changes are automatically saved after a brief pause in editing:
1

User Edits

User types in the WYSIWYG editor, triggering change events
2

Debounce Timer

A 1-second timer starts (or resets) on each edit
3

Automatic Save

After 1 second of inactivity, content is saved to disk via POST /api/save
4

Save Status Update

UI shows “Saving…”, then “Saved” or error status
The auto-save delay is configurable via AUTOSAVE_DELAY_MS constant (default: 1000ms).

Implementation

Editor Integration

Save Request

The isSaving flag prevents concurrent save requests, ensuring only one save operation runs at a time.

File Locking

The backend uses POSIX file locks to coordinate concurrent access:

Lock Semantics

  • Shared locks (LOCK_SH): Multiple readers can access the file simultaneously
  • Exclusive locks (LOCK_EX): Only one writer can access the file at a time
  • Lock files: Stored as <filename>.md.lock adjacent to the markdown file
Lock files are automatically cleaned up when the handler instance is destroyed.

Atomic Writes

Saves use atomic file replacement to prevent corruption:
1

Write to Temp File

Content is written to .{filename}.tmp in the same directory
2

Fsync

File descriptor is fsynced to ensure data is on disk
3

Atomic Replace

os.replace() atomically replaces the original file
4

Cleanup

Temp file is removed on any failure
Atomic replacement ensures that the file is never in a partially-written state, even if the process crashes during the write.

External Change Detection

The editor detects when files are modified externally using Watchdog:

File Watcher Setup

Event Filtering

Events are throttled to one notification per 200ms to prevent flooding from rapid successive changes.

WebSocket Notifications

External changes are broadcast to connected clients via WebSocket:

Client-Side Handling

If there are no unsaved changes, the editor reloads automatically. If there are unsaved changes, a confirmation dialog is shown.

Conflict Detection

When switching files or receiving external changes, conflicts are detected:

Detection Logic

Conflict Dialog

When a conflict is detected, a 3-button modal is shown:
1

Save My Changes

Overwrites the external changes with your local changes
2

Discard My Changes

Reloads the file from disk, losing your local changes
3

Cancel

Closes the dialog and keeps your local changes without switching files
Choosing “Save My Changes” will overwrite any external edits. Review the changes carefully before deciding.

Internal Write Tracking

The server tracks internal writes to ignore self-triggered watcher events:
Events within 500ms of an internal write are ignored, preventing the editor from reloading its own changes.

Save Status Indicator

The UI displays the current save state:
  • Loaded: Initial state after loading a file
  • Unsaved changes: Content has been edited but not saved
  • Saving…: Save request is in progress
  • Saved: Content successfully saved to disk
  • Save failed: Error occurred during save
  • Reloaded from disk: External changes were reloaded
  • External change ignored: User chose to keep local changes
  • Select a file: No file is currently active (folder mode)

Multi-File Tab Support

In folder mode with tabs enabled, auto-save tracks per-tab state:
Each tab has its own dirty state, last saved content, and auto-save timer, allowing independent tracking of multiple files.

Best Practices

Wait for save confirmation: The save status indicator shows “Saved” when changes are persisted. Wait for this before closing the browser.
Don’t edit externally during active sessions: While conflict detection protects against data loss, it’s best to avoid concurrent edits from multiple sources.
Browser refresh: Unsaved changes are lost on browser refresh. Always wait for the auto-save to complete.
Manual save: You can trigger a manual save by clicking away from the editor or switching to another tab (in folder mode).