docs/sync-and-op-log/file-based-sync-flowchart.md
Visual overview of the sync decision tree for file-based providers (Dropbox, WebDAV, LocalFile). For the SuperSync equivalent see supersync-scenarios-flowchart.md.
Both share the same op-log infrastructure (OperationLogSyncService, RemoteOpsProcessingService, conflict detection) but differ in the transport/adapter layer.
flowchart TD
START([Sync Triggered]) --> DL[Download sync-data.json
gap detection handled internally]
%% ── SERVER MIGRATION (file-based specific) ──────────────────
DL --> MIG_CHK{Server migration?
gap + empty server}
MIG_CHK -->|Yes| MIGRATION[Server migration:
handleServerMigration
creates SYNC_IMPORT]
MIG_CHK -->|No| DECRYPT
%% ── DECRYPTION (shared with SuperSync) ────────────────────────
DECRYPT{Encrypted?}
DECRYPT -->|Yes| DECRYPT_OK{Decryption succeeds?}
DECRYPT -->|No| SNAPSHOT_CHK
DECRYPT_OK -->|Yes| SNAPSHOT_CHK
DECRYPT_OK -->|No password configured| NO_PWD_DLG[Enter Password dialog:
Save & Sync / Force Overwrite / Cancel]
DECRYPT_OK -->|Wrong password| WRONG_PWD_DLG[Decrypt Error dialog:
Save & Sync / Use Local / Cancel]
NO_PWD_DLG -->|Save & Sync| START
NO_PWD_DLG -->|Force Overwrite| FORCE_UP[Force upload local state
SYNC_IMPORT]
WRONG_PWD_DLG -->|Save & Sync| START
WRONG_PWD_DLG -->|Use Local| FORCE_UP
%% ── SNAPSHOT vs INCREMENTAL BRANCH (file-based specific) ────
SNAPSHOT_CHK{snapshotState
received?
seq 0 download only}
SNAPSHOT_CHK -->|Yes| SS_OPS
SNAPSHOT_CHK -->|No| HAS_OPS
%% ── SNAPSHOT PATH (file-based specific) ─────────────────────
SS_OPS{Has meaningful
unsynced ops?}
SS_OPS -->|Yes| SS_CONFLICT[SyncConflictDialog:
USE_LOCAL / USE_REMOTE / CANCEL]
SS_OPS -->|No| SS_FRESH{Fresh client?}
SS_FRESH -->|Yes + meaningful
store data| SS_CONFLICT
SS_FRESH -->|Yes + no local data| SS_CONFIRM[Confirm dialog:
Download remote?]
SS_FRESH -->|Not fresh| HYDRATE
SS_CONFLICT -->|Use Local| FORCE_UP
SS_CONFLICT -->|Use Remote| FORCE_DL[Force download
from seq 0]
SS_CONFLICT -->|Cancel| CANCELLED([Sync Cancelled])
SS_CONFIRM -->|OK| HYDRATE[Hydrate from
snapshotState]
SS_CONFIRM -->|Cancel| CANCELLED
HYDRATE --> UPLOAD
%% ── INCREMENTAL OPS PATH (shared logic) ────────────────────
HAS_OPS{Remote ops found?}
%% No remote ops
HAS_OPS -->|No| EMPTY_SVR{Empty server
+ fresh client
+ has local data?}
EMPTY_SVR -->|Yes| SILENT_MIG[Silent server migration
creates SYNC_IMPORT]
EMPTY_SVR -->|No| UPLOAD
SILENT_MIG --> UPLOAD
%% Has remote ops
HAS_OPS -->|Yes| IS_FRESH{Fresh client?}
IS_FRESH -->|No| IS_IMPORT
IS_FRESH -->|Yes + has local data| CONFLICT_DLG[SyncConflictDialog:
USE_LOCAL / USE_REMOTE / CANCEL]
IS_FRESH -->|Yes + no local data| CONFIRM[Confirm dialog:
Download remote?]
CONFIRM -->|OK| APPLY
CONFIRM -->|Cancel| CANCELLED
CONFLICT_DLG -->|Use Local| FORCE_UP
CONFLICT_DLG -->|Use Remote| FORCE_DL
CONFLICT_DLG -->|Cancel| CANCELLED
%% SYNC_IMPORT handling (shared logic)
IS_IMPORT{Contains SYNC_IMPORT?}
IS_IMPORT -->|No| CONFLICT_CHK
IS_IMPORT -->|Yes| ENC_ONLY{Encryption-only change
+ no pending ops?}
ENC_ONLY -->|Yes| APPLY
ENC_ONLY -->|No| IMPORT_HAS{Has pending ops
or meaningful
local data?}
IMPORT_HAS -->|Yes| IMPORT_DLG[ImportConflictDialog:
import reason shown,
Use Server Data recommended]
IMPORT_HAS -->|No| APPLY_IMPORT[Apply full state replacement]
IMPORT_DLG -->|Use Server| FORCE_DL
IMPORT_DLG -->|Use Local| FORCE_UP
IMPORT_DLG -->|Cancel| CANCELLED
%% Conflict detection (shared logic)
CONFLICT_CHK{Vector clock conflict?} -->|CONCURRENT| LWW[Auto-resolve LWW
later timestamp wins
ties → remote wins
archive ops always win]
CONFLICT_CHK -->|No conflict| APPLY
LWW --> APPLY[Apply ops to NgRx store]
APPLY_IMPORT --> UPLOAD
%% ── UPLOAD PHASE (file-based specific) ─────────────────────
APPLY --> UPLOAD[Upload: merge state
into sync-data.json]
UPLOAD --> REV{Rev match
on upload?}
REV -->|OK| IN_SYNC([IN_SYNC ✓])
REV -->|Mismatch| RETRY[Exponential backoff:
re-download, rebuild,
re-upload]
RETRY --> RETRY_CHK{Max retries?}
RETRY_CHK -->|Not exceeded| REV
RETRY_CHK -->|Exceeded| ERROR
FORCE_UP --> IN_SYNC
FORCE_DL --> IN_SYNC
MIGRATION --> IN_SYNC
ERROR([ERROR])
%% Styling
classDef success fill:#2d6,stroke:#1a4,color:#fff
classDef error fill:#d33,stroke:#a11,color:#fff
classDef cancel fill:#888,stroke:#555,color:#fff
classDef dialog fill:#48f,stroke:#26d,color:#fff
classDef action fill:#e90,stroke:#b60,color:#fff,stroke-width:3px
class IN_SYNC success
class ERROR error
class CANCELLED cancel
class SS_CONFIRM,CONFIRM,SS_CONFLICT,CONFLICT_DLG,IMPORT_DLG,NO_PWD_DLG,WRONG_PWD_DLG dialog
class APPLY,APPLY_IMPORT,FORCE_UP,FORCE_DL,MIGRATION,UPLOAD,SILENT_MIG,HYDRATE,RETRY action
Errors thrown during sync are caught by SyncWrapperService._sync(). File-based providers surface additional error types not seen with SuperSync:
flowchart LR
ERR([Error thrown
during sync]) --> TYPE{Error type?}
TYPE -->|DecryptNoPasswordError| PWD_DLG[Enter Password dialog]
TYPE -->|DecryptError| DEC_DLG[Decrypt Error dialog]
TYPE -->|LocalDataConflictError| CONF_DLG[SyncConflictDialog]
TYPE -->|RevMismatchForModelError
NoRemoteModelFile| INC_DLG["Incomplete sync" dialog:
Force Upload / Force Download]
TYPE -->|SyncInvalidTimeValuesError| TIME_DLG["Incoherent timestamps" dialog:
Force Upload / Force Download]
TYPE -->|LockPresentError| LOCK[Snackbar + Force Overwrite action]
TYPE -->|PotentialCorsError| CORS[CORS error snackbar]
TYPE -->|AuthFail / MissingCredentials| AUTH[Auth error snackbar
+ Configure action]
TYPE -->|WebCryptoNotAvailable| CRYPTO[WebCrypto snackbar]
TYPE -->|Timeout| TIMEOUT[Timeout error snackbar]
TYPE -->|Permission error| PERM[Permission error snackbar]
TYPE -->|Other| GENERIC[Generic error snackbar]
classDef dialog fill:#48f,stroke:#26d,color:#fff
classDef snack fill:#f90,stroke:#b60,color:#fff
class PWD_DLG,DEC_DLG,CONF_DLG,INC_DLG,TIME_DLG dialog
class LOCK,CORS,AUTH,CRYPTO,TIMEOUT,PERM,GENERIC snack
Legend:
| Aspect | File-Based (Dropbox, WebDAV, LocalFile) | SuperSync |
|---|---|---|
| Transport | Downloads/uploads a single sync-data.json file | Paginated API (server-side op log) |
| Snapshot path | Full snapshotState on seq 0 download, with its own conflict-checking flow | No snapshot concept — all ops are incremental |
| Gap detection | Adapter detects syncVersion reset / snapshot replacement / partial trimming → re-download from seq 0 | Server handles gap detection internally |
| Server migration | Gap on empty server → needsFullStateUpload → handleServerMigration() | Same concept but detected via different mechanism |
| Upload retry | Rev matching (ETag) + exponential backoff with jitter | Server rejection codes (CONFLICT_CONCURRENT) |
| Piggybacking | Not applicable — no server to piggyback. Concurrent changes are discovered on re-download during retry. | Server returns piggybacked ops in upload response |
| Post-sync encryption prompt | Not applicable | Prompts user to set password or disable sync |
| File-based error types | RevMismatchForModelError, NoRemoteModelFile, SyncInvalidTimeValuesError, LockPresentError, PotentialCorsError | Not applicable |
Enter Password and Decrypt Error dialogs correspond to DecryptNoPasswordError and DecryptError respectively — they are shared with SuperSync and are distinct components with different options.Encryption-only change bypass: when an incoming SYNC_IMPORT has syncImportReason === 'PASSWORD_CHANGED' and there are no meaningful pending ops, the dialog is skipped (data is identical, only encryption changed).moveToArchive operations always win regardless of timestamp.recentOps is empty but state exists and clientId differs; (3) partial trimming — oldestOpSyncVersion > sinceSeq and buffer is full.base × 2^(attempt-1) + random(0..50%) with max retries defined by FILE_BASED_SYNC_CONSTANTS.MAX_UPLOAD_RETRIES.| File | Role |
|---|---|
src/app/imex/sync/sync-wrapper.service.ts | Top-level orchestration + error handling |
src/app/op-log/sync/operation-log-sync.service.ts | Download/upload orchestration, fresh client checks, SYNC_IMPORT handling |
src/app/op-log/sync/operation-log-download.service.ts | Download + internal gap detection |
src/app/op-log/sync-providers/file-based/file-based-sync-adapter.service.ts | File adapter (rev matching, gap detection, snapshot upload) |