Real-Time Sync & Storage System

Comprehensive guide to the Real-Time Synchronization and Storage System architecture, including Yjs integration, Flash Persistence, and MongoDB sync.

⚡ Real-Time Sync & Storage System

Status: ✅ Production Ready

The GoGrab Space storage system is a state-of-the-art, offline-first, real-time synchronization engine that seamlessly bridges the gap between local browser storage (IndexedDB/OPFS), collaborative editing (Yjs), and persistent cloud storage (MongoDB).


🏗️ Architecture Overview

The system is built on three pillars:

  1. Flash Persistence (Local): Instant saves to GgStorage (IndexedDB/OPFS).
  2. Real-Time Collaboration (Peer-to-Peer/Server): Yjs CRDTs over WebSocket for sub-second updates across clients.
  3. Cloud Sync (Background): HttpMongoDBSyncAdapter for reliable, batched synchronization with MongoDB.

🔄 Data Flow Diagram

graph TD
    subgraph "Browser Client A"
        UI[UI Components] <-->|Signals/Effects| FP[Flash Persistence]
        FP <-->|Read/Write| Gg[GgStorage (IndexedDB)]
        Gg <-->|Events| RTS[RealtimeSyncService]
        RTS <-->|Updates| Yjs[Yjs Doc]
        Gg <-->|Batched Sync| HTTP[HttpMongoDBSyncAdapter]
    end

    subgraph "Browser Client B"
        UI2[UI Components] <--> FP2[Flash Persistence]
        FP2 <--> Gg2[GgStorage]
        Gg2 <-->|Events| RTS2[RealtimeSyncService]
        RTS2 <-->|Updates| Yjs2[Yjs Doc]
    end

    subgraph "Backend Infrastructure"
        WS[WebSocket Gateway] <-->|Sync Protocol| Yjs
        WS <-->|Sync Protocol| Yjs2
        HTTP <-->|REST API| API[Backend API]
        API <-->|Persist| DB[(MongoDB)]
    end

    Yjs <-->|WebSocket| WS
    Yjs2 <-->|WebSocket| WS

🧩 Key Components

1. RealtimeSyncService (@libs-foundational/core-angular)

The brain of the collaboration system.

2. GgStorage (@storage-system)

The unified storage layer.

3. HttpMongoDBSyncAdapter (@storage-system)

The bridge to the cloud.

4. Yjs Server (backend-api)

The real-time relay.


🗄️ Database Strategy

The system is designed to handle Generic, Restricted, and User-Specific databases/collections seamlessly.

1. Configuration

Collections are configured in app.config.ts via provideHttpMongoDBSync.

provideHttpMongoDBSync({
  apiUrl: environment.backendApiUrl,
  collections: [
    // 🌌 Core Platform Data (Restricted by Space/Universe ID)
    { name: 'universes', syncInterval: 5000 },
    { name: 'spaces', syncInterval: 10000 },

    // 🌍 Generic/Public Data (Accessible by all users)
    { name: 'public_assets', syncInterval: 30000 },
    { name: 'marketplace_items', syncInterval: 30000 },

    // 👤 User-Specific Data (Restricted by User ID)
    { name: 'user_settings', syncInterval: 5000 },
    { name: 'user_preferences', syncInterval: 10000 }
  ],
  autoInitialize: true,
  autoSync: true
})

2. Access Control (Backend)

The StorageController in the backend handles the generic sync endpoints:

Security Model:


🚀 How It Works (The "Magic")

Scenario: User Adds a Section to a Universe

  1. User Action: User clicks "Add Section" in GridCanvasComponent.
  2. Local Save: this.storage.put(layoutKey, newLayout) is called.
  3. Flash Update:
    • GgStorage emits local event → UI updates instantly.
    • GgStorage posts to BroadcastChannel → Other tabs update instantly.
  4. Real-Time Broadcast:
    • RealtimeSyncService.broadcastStorageChange() is called.
    • Updates Yjs sharedMap.
    • Yjs sends update via WebSocket to Backend.
  5. Remote Sync:
    • Backend relays update to other clients.
    • Other Client receives Yjs update.
    • syncRemoteChangesToStorage() writes to their local IndexedDB.
    • Their GgStorage emits event → Their UI updates instantly.
  6. Cloud Persistence:
    • HttpMongoDBSyncAdapter (in background) picks up the change.
    • Sends PUT /api/storage/sync/universes/:id to Backend.
    • Backend saves to MongoDB.

✅ Verification

To verify the system is working:

  1. Open two different browsers (e.g., Chrome and Safari).
  2. Navigate to the same Universe URL.
  3. Open the Real-Time Debug Panel (bottom right).
  4. Ensure both show:
    • WebSocket: ✅ Connected
    • Yjs Sync: ✅ Synced
  5. Make a change in one browser.
  6. Observe the change appear instantly in the other browser.

🔮 Future Enhancements