Skip to main content

Sync — Requirements

Overview

Sync keeps the mobile app's local WatermelonDB consistent with the server's MariaDB via a pull/push protocol: the app pulls server changes since its last sync timestamp, then pushes its own local changes, with conflicts detected server-side.


User Stories

IDAs a…I want to…So that…
SY-01usersee my messages and conversations after going offlineI can read history without a network connection
SY-02userhave my data automatically synchronised when I reconnectI do not have to manually refresh
SY-03usernever lose a message I sent while offlineMy outbox is reliably delivered once connectivity returns
SY-04rescuerhave all user-reported data available on my deviceI can act on information even in poor-signal areas
SY-05developerdetect and resolve write conflicts predictablyData integrity is maintained across all devices

Functional Requirements

FR-SY-01 — Pull Protocol

  • The mobile app calls GET /sync/pull with the following query parameters:

    ParameterTypeDescription
    last_pulled_atnumberms epoch; only records with updated_at > last_pulled_at are returned
    limitnumberMaximum records per page (default 100)
    cursorstringOpaque pagination cursor for the next page
  • The server returns records from all synced tables scoped to the authenticated user's membership or ownership.

  • The response includes has_more: boolean and next_cursor: string | null for pagination.

  • The app stores the server's pulled_at timestamp and uses it as last_pulled_at on the next pull.

FR-SY-02 — Push Protocol

  • The mobile app calls POST /sync/push with a JSON body containing arrays of changed rows keyed by table name.
  • The server processes tables in dependency order: conversations before messages, messages before message_receipts, calls before call_participants.
  • For each incoming row the server checks: if a local server record exists and its updated_at > last_pulled_at the request returns 409 Conflict for that row.
  • On 409 the app must pull the conflicting rows again before retrying the push.
  • Rows with no conflict are upserted immediately.

FR-SY-03 — Soft Delete

  • Deleted records are never hard-deleted during sync. They are marked is_deleted = true with an updated updated_at.
  • The pull endpoint returns soft-deleted rows so all devices learn about deletions.
  • The app hides soft-deleted records from UI but retains them locally for sync consistency.

FR-SY-04 — Synced Tables

All of the following tables participate in the pull/push cycle:

TableNotes
conversationsOwned or participated in by the current user
conversation_participantsMembership rows for the above conversations
messagesBelonging to synced conversations
message_receiptsFK-guarded: parent message must already exist
callsBelonging to synced conversations
call_participantsFK-guarded: parent call must already exist
peersPeer profile rows visible to the current user

FR-SY-05 — SyncService Trigger

  • SyncService runs a full pull+push cycle on application foreground.
  • SyncService runs a push-only cycle after any local write (message send, call end, receipt update).
  • SyncService runs a periodic background pull every 30 seconds when a network connection is available.
  • Failed sync attempts are retried with exponential back-off (1 s, 2 s, 4 s, … max 60 s).

FR-SY-06 — Schema Versioning

  • WatermelonDB schema version is 10.
  • All syncable models extend SyncableModel which adds created_at, updated_at (ms epoch), and is_deleted columns.
  • Schema upgrades increment the version and provide a migration step; no destructive migrations are permitted (see ADR-0004).

FR-SY-07 — Guest User Hint Map

  • The pull response may include a guest_hints map { [tempId: string]: serverId: string } allowing the app to reconcile locally-generated IDs with server-assigned IDs.
  • The app applies hint remapping before merging pulled records into WatermelonDB.

Non-Functional Requirements

IDRequirement
NFR-SY-01Pull for 100 records must complete in under 500 ms on LAN
NFR-SY-02Push of 50 records must complete in under 1 s on LAN
NFR-SY-03No user-visible data loss on network interruption mid-sync
NFR-SY-04Sync must not block the main thread; all I/O is async

Out of Scope

  • Real-time streaming updates (handled by WebSocket relay in the messaging feature).
  • Binary file/attachment sync (not implemented in v1).
  • Multi-server federation sync.