Skip to main content

Overview

The SmartProductSync system is a sophisticated real-time catalog synchronization engine that provides instant product loading using localStorage cache while maintaining real-time updates from Firestore.

Architecture

Dual-Mode Strategy

Instant Load: Products load immediately from localStorage cache Real-Time Updates: Firebase onSnapshot provides delta updates only for changed products

Implementation

The SmartProductSync is defined in public/js/app.js:12-113:
const SmartProductSync = {
    STORAGE_KEY: 'pixeltech_master_catalog',
    isListening: false,
    
    async init() {
        // 1. Instant cache load
        const localData = localStorage.getItem(this.STORAGE_KEY);
        let lastSyncTime = 0;
        
        if (localData) {
            const parsed = JSON.parse(localData);
            runtimeProductsMap = parsed.map || {};
            lastSyncTime = parsed.lastSync || 0;
            allProductsCache = Object.values(runtimeProductsMap);
        }

        // 2. Start real-time connection
        this.listenForUpdates(lastSyncTime);
        return true;
    }
}

Key Features

1. Offline-First Caching

Products are stored in localStorage with the key pixeltech_master_catalog:
{
  map: { [productId]: productData },
  lastSync: 1234567890 // Timestamp
}
On first load, the catalog appears instantly from cache without waiting for Firebase.

2. Delta Updates with onSnapshot

The sync system uses Firestore’s onSnapshot to listen only for changes since the last sync:
listenForUpdates(lastSyncTime) {
    let q;
    
    if (lastSyncTime === 0) {
        // First-time user: Download all active products
        q = query(collectionRef, where("status", "==", "active"));
    } else {
        // Returning user: Listen only for updates since last visit
        q = query(collectionRef, where("updatedAt", ">", new Date(lastSyncTime)));
    }
    
    onSnapshot(q, (snapshot) => {
        snapshot.docChanges().forEach(change => {
            // Process only changed documents
        });
    });
}

3. Change Detection

The system analyzes document changes to minimize resource usage:
snapshot.docChanges().forEach(change => {
    const data = change.doc.data();
    const id = change.doc.id;

    if (change.type === 'added' || change.type === 'modified') {
        if (data.status === 'active') {
            runtimeProductsMap[id] = { id, ...data };
        } else {
            delete runtimeProductsMap[id];
        }
    } else if (change.type === 'removed') {
        delete runtimeProductsMap[id];
    }
});

Performance Benefits

Instant Load

Products appear in ~50ms from localStorage

Bandwidth Savings

Only downloads changed products (delta sync)

Always Fresh

Real-time updates for price/stock changes

State Persistence

The system automatically saves state after each update:
saveState() {
    const state = {
        map: runtimeProductsMap,
        lastSync: Date.now()
    };
    localStorage.setItem(this.STORAGE_KEY, JSON.stringify(state));
}

UI Updates

When the catalog updates, a global event is dispatched:
window.dispatchEvent(new Event('catalogUpdated'));
Components listen for this event to re-render with updated prices/stock:
window.addEventListener('catalogUpdated', () => {
    // Refresh product grids, cards, etc.
    refreshAllGrids();
});

Usage Example

Initialize the sync system on page load:
// In app.js initialization
await SmartProductSync.init();
loadPromoSlider();
loadBestSellers();

Error Handling

If localStorage quota is exceeded, the cache won’t persist but the app continues functioning with live data.
try {
    localStorage.setItem(this.STORAGE_KEY, JSON.stringify(state));
} catch (e) {
    console.warn("⚠️ Quota exceeded. Cache won't persist.");
}

Best Practices

  1. Always initialize before loading UI components
  2. Listen for catalogUpdated events in dynamic components
  3. Handle cache corruption gracefully with try-catch
  4. Update updatedAt timestamps in Firestore when products change

Build docs developers (and LLMs) love