Skip to Content
ArchitectureSync algorithm design (superseded)

Shared Sync Algorithm Design

⚠️ Status: superseded (2026-06). The mobile consolidation removed the Room/offline layer, the core-data library, and the per-feature Hilt modules. Post-consolidation, all clients are online-first. This document is retained as a design reference; any future sync re-implementation should build on these goals but adapt to the consolidated shared/ structure.

Background

The Android app previously had a Retrofit-based SyncApi (GET/POST /sync) with SyncRemoteDataSource, SyncRepositoryImpl, and a SyncLocalDataSource using Room DAOs for offline queueing. The sync was Android-only.

Removed in migration (2026-06):

  • SyncApi.kt (Retrofit)
  • SyncRemoteDataSource.kt
  • SyncRepositoryImpl.kt
  • Related Hilt providers in AppModule.kt

Created (still present, unwired):

  • shared/.../services/sync/SyncService.kt — shared Ktor stub

Current state: The SyncService stub exists but is not wired into any feature. All data operations are remote-only via direct HTTP calls.

Design Goals (for future reference)

  1. Multiplatform: Sync works on Android, Desktop, iOS, Web
  2. Conflict Resolution: Last-write-wins or server-authoritative
  3. Offline Queue: Write operations queued locally when offline, replayed when online
  4. Incremental: Only sync changes since last timestamp
  5. Shared Logic: Sync orchestration lives in shared/ module, not platform-specific

Proposed Architecture (for future reference)

┌───────────────────┐ ┌────────────────────┐ │ ViewModel / UseCase │ │ SyncRepository │ │ (triggers sync) │────>│ (orchestrator) │ └───────────────────┘ └─────────┬──────────┘ ┌───────────────┼───────────────┐ │ │ │ ┌───────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ │ SyncService │ │ LocalQueue │ │ Conflict │ │ (Ktor HTTP) │ │ (DataStore) │ │ Resolver │ └───────┬──────┘ └─────────────┘ └─────────────┘ ┌───────▼──────┐ │ Server: /sync │ └──────────────┘

Server Sync Endpoints (Existing, unchanged)

  • GET /sync?lastSyncTimestamp=<long> — pull changes since timestamp
  • POST /sync — push local changes, receive merged result

Sync Data Model (existing, to be wired)

@Serializable data class SyncPayload<T>( val created: List<T>, val updated: List<T>, val deleted: List<String>, // IDs val lastTimestamp: Long, ) @Serializable data class SyncResponse( val tasks: SyncPayload<TaskDto>, val habits: SyncPayload<HabitDto>, val workoutDays: SyncPayload<WorkoutDayDto>, val lastTimestamp: Long, )

Implementation Priority (if revived)

  1. Phase 1: SyncService with getSyncData()/saveSyncData() — already done (stub)
  2. Phase 2: Local change queue using DataStore<Preferences> (shared module)
  3. Phase 3: Sync orchestrator in shared/ — pull + push + merge
  4. Phase 4: Automatic sync triggers (network available, periodic, manual)
  5. Phase 5: Desktop + iOS integration

Current Limitations

  • Server sync endpoints exist; client implementation is the gap
  • No offline queue exists post-consolidation
  • lastSyncTimestamp would need to be stored per-user in DataStore
  • The offline/sync question is tracked as tech-debt TD-08