Data Synchronization
Relevant source files
The following files were used as context for generating this wiki page:The data synchronization system in BMSview is built on a local-first sync architecture. This design prioritizes offline functionality and performance by treating the browser's IndexedDB as the primary data source for read operations. The server remains the authoritative source for conflict resolution. This approach significantly reduces server load by using intelligent, periodic synchronization instead of constant server requests.
The core of this system is the SyncManager, which orchestrates the entire process. It uses metadata comparison to make intelligent decisions about when to push local changes or pull server updates. Critical user actions employ a "dual-write" strategy to ensure data is sent to the server immediately, while most read operations follow a "cache-first" pattern.
Sources: ARCHITECTURE.md, GEMINI.md
Architecture Overview
The synchronization architecture is composed of several key components on the frontend that work together to manage local data and communicate with the backend sync endpoints.
The following diagram illustrates the high-level architecture of the frontend components involved in data synchronization.
Sources: ARCHITECTURE.md
Key Components
| Component | Responsibility | Source File |
|---|---|---|
SyncManager | Orchestrates the entire sync process, including periodic scheduling, intelligent decision-making, and status tracking. | src/services/syncManager.ts |
LocalCache | Manages IndexedDB storage using Dexie.js, handling data persistence and sync status. | src/services/localCache.ts |
ClientService | An API wrapper that implements the cache-first data fetching strategy and dual-write pattern. | services/clientService.ts |
AppState | Global React state that holds sync-related fields like isSyncing, lastSyncTime, and syncError. | state/appState.tsx |
| Sync UI | React components, like SyncStatusIndicator, that display the current sync status to the user. | src/components/SyncStatusIndicator.tsx |
| Netlify Sync Functions | Serverless functions that handle metadata comparison, incremental data fetching, and data pushes. | netlify/functions/sync-*.cjs |
Sources: ARCHITECTURE.md, PHASE_COMPLETION_VERIFICATION.md
SyncManager
The SyncManager is a singleton class that serves as the central controller for all synchronization activities. It is responsible for scheduling periodic syncs, executing them, and maintaining the overall sync state.
Sources: src/services/syncManager.ts
Core Responsibilities & Methods
| Method | Description |
|---|---|
startPeriodicSync() | Starts a recurring timer (default 90 seconds) to perform background synchronization. |
stopPeriodicSync() | Clears the sync timer, typically called when the application unmounts to prevent memory leaks. |
resetPeriodicTimer() | Resets the sync timer. This is called after critical user actions (dual-writes) to ensure a fresh sync occurs soon after. |
forceSyncNow() | Triggers an immediate, manual synchronization cycle. |
getSyncStatus() | Returns the current synchronization state, including isSyncing, lastSyncTime, syncError, and nextSyncIn. |
destroy() | Stops all timers and cleans up resources. |
Sources: src/services/syncManager.ts, ARCHITECTURE.md, tests/frontend-sync.e2e.test.js
Periodic Sync Lifecycle
The periodic sync is the default mechanism for keeping the local cache and server data aligned. It runs on a 90-second interval.
This sequence diagram shows the flow of a periodic sync operation.
Intelligent Sync Logic
Instead of syncing on every operation, the SyncManager uses an "intelligent sync" algorithm to determine the necessary action by comparing local and server metadata. This reduces unnecessary network traffic. The intelligentSync function is the core of this logic.
The decision flow is as follows:
This logic is validated in tests, which cover scenarios like an empty local cache, a newer local cache, and identical states.
Sources: ARCHITECTURE.md, tests/frontend-sync.e2e.test.js:132-192, src/services/syncManager.ts
Data Flow Strategies
Dual-Write for Critical Actions
For critical write operations like creating a new analysis or registering a system, a dual-write pattern is used. The data is sent to the server and written to the local cache simultaneously. After the operation, the periodic sync timer is reset to ensure the system state is reconciled quickly.
Actions using this pattern include:
analyzeBmsScreenshot()registerBmsSystem()linkAnalysisToSystem()
Sources: ARCHITECTURE.md, PHASE_COMPLETION_VERIFICATION.md
Cache-First for Read Operations
Read operations, such as fetching a list of systems or analysis history, use a cache-first strategy. The application first attempts to retrieve data from the local IndexedDB. If the data is not found in the cache (a "cache miss"), it then fetches the data from the server and populates the cache for future requests.
Sources: ARCHITECTURE.md
Frontend Integration
The synchronization system is integrated into the React frontend through a custom hook and UI components, providing users with real-time feedback on the sync status.
useSyncStatus Hook
Components can subscribe to live sync status updates using the useSyncStatus hook. This hook provides an object containing the current state of the SyncManager.
The hook returns a SyncStatus object with the following shape:
interface SyncStatus {
isSyncing: boolean;
lastSyncTime: Record<string, number | null>;
syncError: string | null;
nextSyncIn: string; // e.g., 'pending', 'stopped', 'in 30s'
}
Sources: src/hooks/useSyncStatus.ts
SyncStatusIndicator Component
This UI component provides a visual representation of the sync status. It displays:
- The current status (e.g., "Synced", "Syncing", "Error").
- The time since the last successful sync.
- A button to trigger a manual sync (
forceSyncNow). - The count of pending items waiting to be synced.
The indicator changes color based on the status: green for synced, yellow for syncing, and red for an error.
Sources: src/components/SyncStatusIndicator.tsx, SYNC_INTEGRATION_GUIDE.md
Conclusion
The local-first data synchronization architecture is a cornerstone of the BMSview application, designed for resilience, performance, and a good user experience. By leveraging an intelligent, periodic sync mechanism, it dramatically reduces server load and network dependency. The combination of the SyncManager, cache-first and dual-write strategies, and clear UI feedback creates a robust system that functions effectively both online and offline.