# Data syncs correctly when reconnected after offline period

- **Pattern:** `ab-001881` (`mobile-offline-storage.sync-conflicts.data-sync-on-reconnect`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001881
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001881)

## Why it matters

An app that does not automatically sync on reconnect forces users to manually pull-to-refresh or restart the app to see changes made on another device or from the server. CWE-362 applies when the window between going offline and reconnecting allows remote state to diverge without the client knowing. ISO 25010:2011 reliability.recoverability requires that the app reaches a consistent state after a connectivity gap without user intervention. In collaborative or multi-device scenarios, the failure to auto-sync on reconnect means users work on stale data, potentially overwriting remote changes.

## Severity rationale

High because missing auto-sync on reconnect leaves local and remote state silently diverged, which can cause data overwrites or user confusion in multi-device scenarios.

## Remediation

Detect the offline→online transition in your `NetInfo` listener and trigger a full sync cycle — upload queued local changes first, then fetch remote updates, then reconcile.

```tsx
import { useEffect, useRef, useState } from 'react';
import NetInfo from '@react-native-community/netinfo';

export function useSyncOnReconnect() {
  const [isOnline, setIsOnline] = useState(true);
  const wasOnline = useRef(true);

  useEffect(() => {
    const unsub = NetInfo.addEventListener(async (state) => {
      const online = state.isConnected ?? false;
      if (!wasOnline.current && online) {
        // Transition: offline → online
        await drainQueue(executeAction);   // flush local writes
        await fetchRemoteUpdates();        // pull server state
        await reconcileConflicts();        // merge (see conflict-resolution-strategy)
      }
      wasOnline.current = online;
      setIsOnline(online);
    });
    return unsub;
  }, []);

  return isOnline;
}
```

Run this hook at root navigator level so the sync fires regardless of which screen the user is on when connectivity returns.

## Detection

- **ID:** `data-sync-on-reconnect`
- **Severity:** `high`
- **What to look for:** Examine the sync implementation. Look for code that detects reconnection and initiates data sync. Check that sync fetches both local changes and remote updates.
- **Pass criteria:** Count all network state transition handlers in the codebase. When network reconnects, app triggers sync that uploads local changes and downloads remote updates. At least 1 handler must detect the offline-to-online transition and initiate sync. User sees merged data without manual refresh.
- **Fail criteria:** No automatic sync on reconnect. User must manually refresh or re-launch app to see changes.
- **Skip (N/A) when:** Never — automatic sync is essential.
- **Cross-reference:** The Mobile Navigation & Deep Linking audit (`mobile-navigation-linking`) covers cold-start deep link handling which intersects with sync-on-reconnect behavior.
- **Detail on fail:** `"App does not sync on reconnect. Users must manually refresh app to see remote changes or confirm their local changes were uploaded."`
- **Remediation:** Implement automatic sync on connection restore:

  ```tsx
  import { useEffect, useState } from 'react';
  import NetInfo from '@react-native-community/netinfo';

  export function useSyncOnReconnect() {
    const [isOnline, setIsOnline] = useState(true);
    const lastOnlineState = useRef(true);

    useEffect(() => {
      const unsubscribe = NetInfo.addEventListener(state => {
        const online = state.isConnected ?? false;

        // Detect transition from offline to online
        if (!lastOnlineState.current && online) {
          console.log('Connection restored, syncing...');
          syncAllData();
        }

        setIsOnline(online);
        lastOnlineState.current = online;
      });

      return unsubscribe;
    }, []);

    return isOnline;
  }

  async function syncAllData() {
    try {
      // Upload pending changes
      await processQueue();

      // Download latest data
      await fetchRemoteData();

      // Merge if needed
      await reconcileData();

      console.log('Sync complete');
    } catch (error) {
      console.error('Sync failed:', error);
    }
  }
  ```

## External references

- cwe CWE-362
- iso-25010 reliability.recoverability

Taxons: error-resilience, data-integrity

HTML version: https://auditbuffet.com/patterns/ab-001881
