UNIVERSAL AUTO SYNC GUIDE

Ecosistema completo para organización y gestión de contenido con interfaces espaciales

🔄 Universal Auto-Sync Implementation Guide

Date: November 18, 2025
Purpose: Enable automatic MongoDB sync for ALL data changes


✅ Step 1: Initialize Universal Auto-Sync (ONE TIME SETUP)

Add to your main.ts or app initialization:

// apps/gograb-space/src/main.ts

import { UniversalAutoSyncService } from '@libs-foundational/core-angular';

// ... in your bootstrap function ...

const universalAutoSync = injector.get(UniversalAutoSyncService);
await universalAutoSync.initialize();

console.log('✅ Universal Auto-Sync enabled - ALL storage changes will sync to MongoDB!');

That's it! Every storage.put() and storage.remove() call will now automatically sync to MongoDB.


✅ Step 2: Verify It's Working

Test 1: Save Universe Layout

  1. Open Universe Builder
  2. Make changes to layout
  3. Click "Save"
  4. Watch console:
[UniversalAutoSync] 🔍 Detected write on universe: universe_1763427157418
[UniversalAutoSync] 🔄 Syncing universe: universe_1763427157418
[SyncEngine] 📤 Calling SpaceApiService.updateUniverse
✅ Universe synced to backend

Test 2: Check MongoDB

# Query MongoDB
db.space_YOUR_SPACE_ID.universes.findOne({ _id: "universe_1763427157418" })

# Should show updated layout
{
  _id: "universe_1763427157418",
  name: "...",
  layout: { ... },  // ← Updated!
  updatedAt: "2025-11-18T..."
}

🎯 How It Works

Architecture

User clicks "Save"
      ↓
Component calls storage.put(key, data)
      ↓
UniversalAutoSync intercepts the call
      ↓
Detects entity type from key (universe_, space_, page_, etc.)
      ↓
Debounces for 1 second (batches rapid changes)
      ↓
Queues sync operation
      ↓
SyncEngine syncs to MongoDB
      ↓
✅ Done! (User never waits)

Key Features

✅ Zero Configuration: No code changes needed in components
✅ Automatic Detection: Knows what entity type from storage key
✅ Smart Batching: Combines rapid changes
✅ Debouncing: Waits 1s before syncing (configurable)
✅ Offline-First: Local save happens immediately
✅ Background Sync: MongoDB update doesn't block UI


🔧 Configuration (Optional)

Change Debounce Time

// Make sync faster (500ms) or slower (2000ms)
universalAutoSync.updateConfig({
  debounceTime: 500 // milliseconds
});

Exclude Certain Keys

universalAutoSync.updateConfig({
  excludeKeys: ['temp_', 'cache_', 'draft_'] // Never sync these
});

Add Custom Entity Patterns

universalAutoSync.updateConfig({
  entityPatterns: {
    space: /^space_/,
    universe: /^universe_/,
    page: /^page_/,
    galaxy: /^galaxy_/,  // ← Custom entity
    section: /^section_/  // ← Custom entity
  }
});

📊 Monitoring

Check Sync Stats

// In console
const autoSync = injector.get(UniversalAutoSyncService);
console.log(autoSync.stats());

// Output:
{
  totalDetected: 45,   // Total changes detected
  totalSynced: 42,     // Successfully synced
  totalSkipped: 3,     // Excluded keys
  lastSync: Date(...)  // Last sync time
}

Flush Pending Syncs

// Force immediate sync of all pending changes
await autoSync.flushPendingSyncs();
console.log('✅ All changes synced immediately!');

🎨 Alternative: Directive Approach (More Explicit)

If you want explicit control per button:

Option A: Simple Button Sync

<!-- universe-builder.component.html -->
<button class="btn-secondary" 
        (click)="saveLayout()"
        ggAutoSync 
        [syncEntity]="'universe'" 
        [syncData]="currentLayout()"
        [syncId]="universeId()">
  <i class="fas fa-save"></i>
  Save
</button>

Import the directive:

import { AutoSyncDirective } from '@libs-foundational/core-angular';

@Component({
  imports: [CommonModule, AutoSyncDirective, ...], // ← Add here
  // ...
})

Option B: Debounced Input Sync

<input [(ngModel)]="universeName"
       ggAutoSync
       [syncEntity]="'universe'"
       [syncProperty]="'name'"
       [syncId]="universeId()"
       [syncDebounce]="1000"
       [syncTrigger]="'change'">

🚀 Service-Level Auto-Sync (Decorator)

For service methods:

import { AutoSync } from '@libs-foundational/core-angular';

@Injectable()
export class UniverseService {
  private syncEngine = inject(SyncEngineService); // ← Required for decorator
  private logger = inject(LoggerService);         // ← Required for decorator

  @AutoSync({ entity: 'universe', operation: 'update' })
  async updateUniverse(universe: Universe): Promise<Universe> {
    // Save locally (offline-first)
    await this.storage.put(`universe_${universe.id}`, universe);
    
    // Return triggers auto-sync ✨
    return universe;
  }

  @AutoSync({ entity: 'universe', operation: 'create' })
  async createUniverse(universe: Universe): Promise<Universe> {
    await this.storage.put(`universe_${universe.id}`, universe);
    return universe; // ← Auto-synced!
  }

  @AutoSync({ 
    entity: 'universe', 
    operation: 'delete',
    extractId: (result, universeId) => universeId 
  })
  async deleteUniverse(universeId: string): Promise<void> {
    await this.storage.remove(`universe_${universeId}`);
    // ← Auto-synced with ID from parameter
  }
}

🎯 Recommendation

Use Universal Auto-Sync (Option 1) because:

✅ Works everywhere automatically
✅ No code changes needed
✅ Can't forget to add sync
✅ Consistent behavior
✅ Easy to maintain

Use Directive/Decorator (Options 2-3) when you need:

⚙️ Explicit control
⚙️ Different sync behavior per action
⚙️ Special sync timing


📝 Summary

Before (Your Current Code)

async saveLayout(): Promise<void> {
  this.logger.info('Layout saved successfully');
  // Already auto-saves in canvas
}

Problem: Saves to local storage only, doesn't sync to MongoDB ❌

After (With Universal Auto-Sync)

NO CODE CHANGES NEEDED! ✨

Just initialize once in main.ts:

await injector.get(UniversalAutoSyncService).initialize();

Now EVERY storage operation syncs automatically:


🧪 Testing Checklist


Status: Ready to implement! 🚀
Effort: 5 minutes (just add initialization)
Impact: Universal auto-sync for everything!