Skip to content

Repository files navigation

Offline-First Sync Demo (React Native)

Overview

This project demonstrates a simple offline-first mobile application that allows users to submit two types of data:

  • Small data (text input)
  • Large data (image selection)

All user actions are persisted locally first, reflected immediately in the UI, and then safely synced to a backend when network connectivity is available.

The focus of this implementation is correct offline behavior, reliability, and clarity, not visual polish.


Core Design Principles

  1. Local-first

    • User actions are saved locally immediately.
    • The UI updates optimistically without waiting for the network.
  2. Deferred sync

    • Network sync happens only when connectivity is available.
    • Sync retries automatically on app start or reconnect.
  3. Small before Large

    • Small payloads are always synced before large payloads.
    • This improves reliability under poor network conditions.
  4. Single source of sync control

    • Synchronization logic is centralized in a global context.
    • Screens never manage network or sync state directly.

High-Level Flow

  1. User submits data (Small or Large)
  2. Data is validated locally
  3. Data is stored in persistent storage with status pending
  4. UI immediately shows “Saved (pending sync)”
  5. When online:
    • Pending items are loaded
    • Items are sorted (Small → Large)
    • Items are synced sequentially
  6. On success:
    • Item is removed from the local queue
    • UI updates to “Saved”

Sync Architecture

SyncContext

A global SyncContext is responsible for:

  • Listening to network connectivity changes
  • Triggering sync on:
    • App start
    • Offline → online transitions
  • Ensuring only one sync runs at a time

Screens interact with sync only via:

requestSync()

This keeps UI components simple and avoids duplicated sync logic.


Retry & Failure Handling

  • Retry attempts are tracked only in memory during a single sync run
  • If an item fails 3 times in a row:
    • It is skipped
    • Left in the queue
    • Retried on the next sync attempt
  • Failed items are never deleted unless a sync succeeds

This avoids:

  • Infinite retry loops
  • Permanently “poisoning” valid data

Edge Cases Considered

  • App killed during sync
  • Network loss mid-request
  • Duplicate retries after partial failures
  • Device restart while offline
  • Multiple rapid user submissions
  • Flaky or slow connections

All queued data remains safe until successfully synced.


Simplifications Made (Intentional)

To keep the solution focused and clear:

  • No background services
  • No conflict resolution or CRDTs
  • No persisted retry counters
  • No chunked uploads for large data
  • No backend implementation (simulated sync)

These were consciously excluded to avoid over-engineering for a take-home task.


Tradeoffs

Pros

  • Simple, readable, and reliable
  • Correct offline-first behavior
  • Easy to extend
  • Clear separation of concerns

Cons

  • Large payloads stored as base64 (not ideal for production)
  • No resume support for partial uploads
  • No backend idempotency implementation (not required here)

Potential Improvements

Given more time or production requirements, this system could be improved by:

  • Storing large files on disk instead of base64
  • Using resumable uploads for large data
  • Adding backend-side idempotency keys
  • Introducing background sync (platform-specific)
  • Adding sync progress indicators per item

Running the App

Requirements

  • Node.js
  • Yarn or npm
  • React Native environment set up

Install dependencies

npm install
# or
yarn install

Run the app

npx react-native run-ios
# or
npx react-native run-android

Note on Testing

This application is best tested on a real device, especially for offline behavior and network state changes. Simulators may not accurately reflect real-world connectivity conditions.


Testing Offline Behavior

  1. Launch the app
  2. Enable airplane mode
  3. Add Small and Large items
  4. Kill the app
  5. Reopen the app (data persists)
  6. Disable airplane mode
  7. Observe automatic sync

System Design Diagram

System Design Diagram

The diagram illustrates:

  • Local queue
  • Sync triggers
  • Small vs Large prioritization
  • Retry flow
  • Network-driven sync lifecycle

Final Notes

This implementation prioritizes correctness, simplicity, and real-world behavior over complexity.
All major architectural decisions are intentional and aligned with offline-first principles.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages