Dirty Tracking & Autosave
Relevant source files
The following files were used as context for generating this wiki page:
Dirty Tracking and Autosave is a core persistence mechanism in Dotorixel designed to preserve user work against browser crashes, accidental refreshes, or mobile app termination. It replaces immediate or "on-unload-only" saving with a proactive, debounced system that tracks changes at a granular level.
The system ensures that only modified components of the workspace are written to IndexedDB, minimizing I/O overhead while maintaining high data integrity. It leverages Svelte's reactivity to detect changes in canvas content or workspace structure and flushes these changes after a period of user inactivity.
Sources: issues/010-debounced-auto-save.md, issues/007-session-persistence.md
System Architecture
The autosave architecture consists of three primary layers: the detection layer (Svelte components and state), the orchestration layer (AutoSave class), and the persistence layer (SessionPersistence and IndexedDB).
Component Interaction
The AutoSave class coordinates with the Workspace and SessionPersistence modules. It maintains an internal timer and a set of "dirty" document IDs to track what needs to be saved.
The diagram above illustrates the flow from change detection to physical storage in IndexedDB.
Sources: issues/010-debounced-auto-save.md, src/routes/editor/+page.svelte
Dirty Tracking Mechanism
Dirty tracking is implemented to avoid unnecessary writes. The system distinguishes between the workspace structure (tab order, active tab) and individual document content (pixels, dimensions).
Detection Strategies
- Canvas Changes: Monitored via an
$effectin the editor route that watches therenderVersionof each editor instance. This avoids false positives during tab switches by using a per-editorMapto track version history. - Workspace Changes: Triggered when tabs are added, closed, or reordered.
- Stable IDs: Every
EditorStatehas adocumentId(auto-generated UUID) that is preserved on restore. This allows the system to perform targetedput()operations in IndexedDB.
Sources: issues/010-debounced-auto-save.md, src/lib/canvas/editor-state.svelte.ts:16-17, src/routes/editor/+page.svelte
Tracking State
The AutoSave class manages dirty states using the following structure:
| Element | Tracking Method | Description |
|---|---|---|
| Workspace Metadata | Boolean Flag | Tracks if tab order or active index has changed. |
| Documents | Set<string> | A collection of UUIDs representing dirty EditorState instances. |
| Pending Save | Promise | Tracks in-flight async saves to synchronize with flush(). |
Sources: issues/010-debounced-auto-save.md, src/lib/session/auto-save.test.ts:74-80
Autosave Lifecycle
The autosave process follows a debounced execution pattern to batch rapid user interactions (like drawing a stroke or resizing) into a single database write.
Debounce and Flush
- Trigger: A change occurs, calling
markDirty(). - Debounce: A timer starts for 3–5 seconds. New changes reset this timer.
- Execution: When the timer expires, or a "safety net" event occurs,
flush()is called. - Selective Write:
SessionPersistence.save()is called with an optionaldirtyDocIdslist. Unchanged documents are skipped. - Cleanup: Dirty flags are cleared upon successful completion of the save operation.
Sources: issues/010-debounced-auto-save.md, src/lib/session/auto-save.test.ts:28-40
Safety Nets
To prevent data loss in scenarios where the debounce timer might not fire (e.g., closing the tab immediately after a change), the system implements immediate flushes on specific browser events:
beforeunload: Triggers an immediate, non-debounced save when the window is closing.visibilitychange(hidden state): Ensures data is saved on mobile browsers (like Safari) wherebeforeunloadmay be unreliable.
Sources: issues/010-debounced-auto-save.md, issues/007-session-persistence.md, src/routes/editor/+page.svelte
Sequence of a Save Operation
This sequence shows how multiple rapid changes are batched before reaching the persistence layer.
Sources: issues/010-debounced-auto-save.md, src/lib/session/auto-save.test.ts:101-112
Implementation Details
The implementation relies on specific configurations and state management techniques to ensure performance and reliability.
Configuration Options
| Option | Default Value | Description |
|---|---|---|
| Debounce Interval | 3000ms - 5000ms | Inactivity period required before flushing dirty data. |
| Storage Provider | IndexedDB | High-capacity binary-friendly local storage. |
| ID Strategy | Stable UUID | Preserved IDs to enable upsert semantics in storage. |
Sources: issues/010-debounced-auto-save.md, issues/007-session-persistence.md, src/lib/session/auto-save.test.ts:21
Document Cleanup
When a tab is closed, the AutoSave system is notified via notifyTabRemoved(docId). During the next flush, the system ensures that the orphaned document record is deleted from IndexedDB, preventing storage bloat.
Sources: issues/008-single-tab-session-save-restore.md, src/lib/session/auto-save.test.ts:84-100
Conclusion
The Dirty Tracking & Autosave system provides a robust foundation for user data safety in Dotorixel. By combining Svelte’s reactive detection with a debounced persistence strategy and stable document IDs, the system achieves a balance between frequent data preservation and efficient resource usage. The use of multiple browser event listeners further ensures that work is captured even under abrupt session termination scenarios.