docs/sync-and-op-log/supersync-scenarios-flowchart.md
Visual overview of the main sync decision tree. For full details see supersync-scenarios.md.
flowchart TD
START([Sync Triggered]) --> DL[Download remote ops]
DL --> HAS_OPS{Remote ops found?}
%% No remote ops path
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 path
HAS_OPS -->|Yes| DECRYPT{Encrypted?}
%% Decryption path (two distinct error dialogs)
DECRYPT -->|Yes| DECRYPT_OK{Decryption succeeds?}
DECRYPT -->|No| IS_FRESH
DECRYPT_OK -->|Yes| IS_FRESH
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 Data / 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
%% Fresh client check (under "has remote ops" branch)
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([Sync Cancelled])
CONFLICT_DLG -->|Use Local| FORCE_UP
CONFLICT_DLG -->|Use Remote| FORCE_DL[Force download
from seq 0]
CONFLICT_DLG -->|Cancel| CANCELLED
%% SYNC_IMPORT handling
IS_IMPORT{Contains SYNC_IMPORT?}
IS_IMPORT -->|No| CONFLICT_CHK
IS_IMPORT -->|Yes| IMPORT_CONFLICT{Meaningful
pending ops?}
IMPORT_CONFLICT -->|Yes| IMPORT_DLG[ImportConflictDialog:
import reason shown,
Use Server Data recommended]
IMPORT_CONFLICT -->|No| APPLY_IMPORT[Apply full state replacement
silently — already-synced
store data is not a conflict
PASSWORD_CHANGED falls through here]
IMPORT_DLG -->|Use Server| FORCE_DL
IMPORT_DLG -->|Use Local| FORCE_UP
IMPORT_DLG -->|Cancel| CANCELLED
%% Conflict detection
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
APPLY --> UPLOAD[Upload pending local ops]
UPLOAD --> REJECTED{Server rejects any?}
REJECTED -->|No| PIGGYBACK[Process piggybacked ops]
REJECTED -->|CONFLICT_CONCURRENT| REDOWNLOAD[Re-download & resolve
max 3 retries per entity]
REJECTED -->|VALIDATION_ERROR| PERM_REJECT[Op permanently rejected]
REJECTED -->|Payload too large| ALERT[Alert dialog, sync stops]
REDOWNLOAD --> CONFLICT_CHK
PIGGYBACK --> ENCRYPT_CHK
%% Post-sync encryption check
ENCRYPT_CHK{SuperSync without
encryption?}
ENCRYPT_CHK -->|Yes| ENC_PROMPT[Encryption prompt:
Set password or disable sync]
ENCRYPT_CHK -->|No| IN_SYNC([IN_SYNC ✓])
ENC_PROMPT -->|Password set| ENABLE_ENC[Enable encryption:
delete server → upload encrypted]
ENC_PROMPT -->|Disable SuperSync| DISABLE([Sync Disabled])
ENABLE_ENC --> IN_SYNC
FORCE_UP --> IN_SYNC
FORCE_DL --> IN_SYNC
PERM_REJECT --> ERROR([ERROR])
ALERT --> 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,DISABLE cancel
class CONFIRM,CONFLICT_DLG,IMPORT_DLG,NO_PWD_DLG,WRONG_PWD_DLG,ENC_PROMPT dialog
class APPLY,APPLY_IMPORT,FORCE_UP,FORCE_DL,ENABLE_ENC,UPLOAD,SILENT_MIG action
Legend:
Notes:
Enter Password and Decrypt Error dialogs correspond to DecryptNoPasswordError and DecryptError respectively — they are distinct components with different options.IMPORT_CONFLICT gate uses pending ops only, not store contents (_hasMeaningfulPendingOps()). PASSWORD_CHANGED SYNC_IMPORTs without pending ops fall through this gate naturally to silent acceptance — the data is identical, only the encryption changed. "Meaningful" = TASK/PROJECT/TAG/NOTE create/update/delete or full-state ops — config-only ops don't count. Already-synced store data is not a conflict with the incoming SYNC_IMPORT — the user-facing warning happens on the originating device. Including store contents in the gate would let an old client pick USE_LOCAL and force-upload its stale pre-import state, rolling back the remote import for everyone.moveToArchive operations always win regardless of timestamp.MAX_CONCURRENT_RESOLUTION_ATTEMPTS); if exceeded, ops are permanently rejected.