Cloud Sync Guide
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
☁️ Complete Cloud Sync Guide
Comprehensive guide to all cloud synchronization options: MongoDB, Firebase/Firestore, and REST APIs.
Overview
Our storage system provides optional cloud synchronization while maintaining blazing-fast local-first performance.
Session 166.3 Update: For fire-and-forget backend sync with persistent retry queue, use the new BackendSyncEngine. It provides
SyncDescriptor<T>(5-line descriptor per feature) +syncToBackend()(one-liner for autoFlashState signals) with automatic offline detection, retry, and dedup. The patterns below remain valid for advanced/custom sync scenarios.
Key Principles
- Offline-First: Local storage always fast (0.3ms cache hits)
- Optional: Cloud sync is completely optional
- Strategic: Configure per-collection/key strategies
- Flexible: MongoDB, Firebase, or REST API backends
- Resilient (Session 166.3): Persistent retry queue survives page refresh
📡 MongoDB Sync (Recommended)
Why MongoDB?
- Offline-First by Default: Maintains local 0.3ms performance
- Strategic Sync: Configure per-collection (offline-first, online-first, realtime)
- Priority-Based: Critical (immediate), high (5min), normal (30min), low (manual)
- Smart Conflict Resolution: Last-write-wins, merge, or custom
- Real-Time Optional: MongoDB Change Streams for collaboration
- Flexible: Works with any MongoDB Atlas cluster
Quick Setup
// app.config.ts
import { provideMongoDBSync } from '@storage-system';
export const appConfig: ApplicationConfig = {
providers: [
provideGgStorage({ namespace: 'my-app' }),
provideMongoDBSync({
connectionString: environment.mongoDbUri,
database: 'my-app',
defaultStrategy: {
mode: 'offline-first', // Local first, sync in background
priority: 'normal', // Sync every 30 minutes
conflictResolution: 'last-write-wins'
},
enableRealtime: true, // Enable Change Streams
autoInit: true // Initialize on app start
})
]
};
Basic Usage
import { autoFlashState } from '@storage-system';
// Automatic MongoDB sync with offline-first strategy
const userPreferences = autoFlashState({
key: 'preferences',
defaultValue: { theme: 'dark', language: 'en' },
database: 'app-data',
collection: 'user-preferences',
priority: 'high' // Sync every 5 minutes
});
// Instant local access (0.3ms) + background sync to MongoDB
userPreferences.set({ theme: 'light', language: 'es' });
Advanced Configuration
provideMongoDBSync({
connectionString: 'mongodb+srv://...',
database: 'my-app',
defaultStrategy: {
mode: 'offline-first',
priority: 'normal',
conflictResolution: 'merge' // Field-level merge
},
enableRealtime: true,
autoInit: true,
// Per-collection overrides
collectionConfig: {
'chat-messages': {
mode: 'realtime', // Real-time for chat
priority: 'critical' // Immediate sync
},
'user-analytics': {
mode: 'offline-first', // Offline for analytics
priority: 'low' // Manual sync only
}
}
})
Sync Strategies
Offline-First (Default)
{
mode: 'offline-first',
priority: 'normal' // Sync every 30 minutes
}
- Use For: Most app data, user preferences, settings
- Performance: 0.3ms local access
- Behavior: Save locally instantly, sync in background
Online-First
{
mode: 'online-first',
priority: 'high' // Sync every 5 minutes
}
- Use For: Collaborative data, shared documents
- Performance: Network-dependent
- Behavior: Save to cloud first, fallback to local
Realtime
{
mode: 'realtime',
priority: 'critical' // Immediate sync
}
- Use For: Chat, live collaboration, real-time features
- Performance: Real-time propagation
- Behavior: MongoDB Change Streams for instant updates
Priority Levels
critical: Immediate sync (< 1 second)high: Every 5 minutesnormal: Every 30 minutes (default)low: Manual sync only
Conflict Resolution
// Last-Write-Wins (Default)
conflictResolution: 'last-write-wins'
// Field-Level Merge
conflictResolution: 'merge'
// Custom Logic
conflictResolution: (local, remote) => {
// Your custom merge logic
return { ...remote, ...local };
}
Complete Example
// services/data.service.ts
@Injectable({ providedIn: 'root' })
export class DataService {
// Critical data - immediate sync
authToken = autoFlashState({
key: 'auth-token',
defaultValue: null,
database: 'auth',
collection: 'tokens',
priority: 'critical'
});
// User preferences - sync every 5 min
preferences = autoFlashState({
key: 'user-prefs',
defaultValue: { theme: 'light', language: 'en' },
database: 'user',
collection: 'preferences',
priority: 'high'
});
// Analytics - manual sync only
analytics = autoFlashState({
key: 'analytics',
defaultValue: [],
database: 'analytics',
collection: 'events',
priority: 'low'
});
}
🔥 Firebase/Firestore Sync
Why Firebase?
- Real-Time Updates: Instant cross-device synchronization
- Multi-Database: Switch between databases dynamically
- Collection Management: Create and switch collections at runtime
- Proven: Battle-tested Google infrastructure
Quick Setup
import { FirestoreSyncAdapter } from '@storage-system';
@Component({})
export class AppComponent {
private storage = inject(StorageService);
async ngOnInit() {
const adapter = new FirestoreSyncAdapter({
databaseId: 'g-space-db-standard',
collection: 'app-data'
});
await adapter.waitForReady();
this.storage.setSyncAdapter(adapter);
console.log('✅ Firebase sync enabled');
}
}
Configuration
interface FirestoreSyncConfig {
databaseId?: string; // Firebase database ID
collection?: string; // Firestore collection name
// Firebase credentials auto-detected from environment
}
Core Operations
Push Changes
const changes = [{
key: 'user/profile',
op: 'put',
value: { name: 'John Doe', email: '[email protected]' },
updatedAt: Date.now()
}];
const result = await adapter.push(changes);
console.log('Synced:', result.acked);
Pull Changes
// Pull all changes
const pullResult = await adapter.pull(null, 100);
console.log('Retrieved:', pullResult.changes.length);
// Apply changes locally
for (const change of pullResult.changes) {
if (change.op === 'put') {
await storage.put(change.key, change.value);
}
}
Real-Time Sync
const unsubscribe = await adapter.setupRealtimeSync((changes) => {
console.log('Real-time changes:', changes);
for (const change of changes) {
if (change.op === 'put') {
await storage.put(change.key, change.value);
}
}
});
// Cleanup on destroy
ngOnDestroy() {
unsubscribe();
}
Database Management
// Switch between databases
await adapter.switchDatabase('g-space-db-ent');
console.log('Switched to enterprise database');
// Create new collection
await adapter.createCollection('user-preferences');
// Switch collection
await adapter.setCollection('project-data');
// Get current database info
const info = adapter.getDatabaseInfo();
console.log('Database:', info);
Complete Example
@Injectable({ providedIn: 'root' })
export class FirebaseSyncService {
private storage = inject(StorageService);
private adapter: FirestoreSyncAdapter;
async initialize() {
this.adapter = new FirestoreSyncAdapter({
databaseId: 'g-space-db-standard',
collection: 'app-data'
});
await this.adapter.waitForReady();
this.storage.setSyncAdapter(this.adapter);
// Setup real-time sync
await this.setupRealtimeSync();
}
private async setupRealtimeSync() {
await this.adapter.setupRealtimeSync(async (changes) => {
for (const change of changes) {
if (change.op === 'put') {
await this.storage.put(change.key, change.value);
} else if (change.op === 'remove') {
await this.storage.remove(change.key);
}
}
});
}
async switchToEnterprise() {
await this.adapter.switchDatabase('g-space-db-ent');
}
}
🌐 REST API Sync
Why REST API?
- Flexibility: Works with any HTTP backend
- Custom Logic: Full control over sync behavior
- Existing APIs: Integrate with existing infrastructure
Quick Setup
import { ApiSyncAdapter } from '@storage-system';
const adapter = new ApiSyncAdapter({
baseUrl: 'https://api.myapp.com',
endpoint: '/storage/sync',
apiKey: environment.apiKey,
headers: {
'Authorization': `Bearer ${token}`
}
});
storage.setSyncAdapter(adapter);
Mock API Integration
For development and testing:
// mock-api/storage.mock.ts
import { MockApiHandler } from '@mock-api/core';
export const storageMockApi: MockApiHandler[] = [
// Pull changes
{
method: 'GET',
path: '/api/storage/sync',
handler: (req) => {
const cursor = req.query.cursor || '0';
return {
cursor: Date.now().toString(),
changes: [
{
key: 'user/profile',
op: 'put',
value: { name: 'John', updated: true },
updatedAt: Date.now()
}
]
};
}
},
// Push changes
{
method: 'POST',
path: '/api/storage/sync',
handler: (req) => {
const changes = req.body.changes;
// Store changes
mockDatabase.set(changes);
return {
success: true,
processed: changes.length
};
}
}
];
Configuration
interface ApiSyncConfig {
baseUrl: string; // API base URL
endpoint: string; // Sync endpoint
apiKey?: string; // API key
headers?: Record<string, string>; // Custom headers
conflictResolution?: 'last-write-wins' | ((local, remote) => any);
}
Complete Example
@Injectable({ providedIn: 'root' })
export class ApiSyncService {
private storage = inject(StorageService);
async initialize() {
const adapter = new ApiSyncAdapter({
baseUrl: environment.apiUrl,
endpoint: '/storage/sync',
headers: {
'Authorization': `Bearer ${this.getToken()}`,
'Content-Type': 'application/json'
},
conflictResolution: (local, remote) => {
// Custom conflict resolution
if (remote.updatedAt > local.updatedAt) {
return remote;
}
return local;
}
});
this.storage.setSyncAdapter(adapter);
// Start periodic sync
this.startPeriodicSync();
}
private startPeriodicSync() {
setInterval(async () => {
await this.performSync();
}, 300000); // Every 5 minutes
}
private async performSync() {
const adapter = this.storage.getSyncAdapter();
if (!adapter) return;
try {
// Pull remote changes
const status = await adapter.getStatus();
const pullResult = await adapter.pull(status.cursor);
// Apply changes locally
for (const change of pullResult.changes) {
if (change.op === 'put') {
await this.storage.put(change.key, change.value);
}
}
console.log('✅ Sync complete');
} catch (error) {
console.error('❌ Sync failed:', error);
}
}
}
📊 Comparison Matrix
| Feature | MongoDB | Firebase | REST API |
|---|---|---|---|
| Setup Complexity | Medium | Low | Low |
| Real-Time Updates | Change Streams | Native | Custom |
| Offline-First | ✅ Built-in | Requires setup | Requires setup |
| Conflict Resolution | ✅ Advanced | Basic | Custom |
| Priority-Based Sync | ✅ Built-in | Custom | Custom |
| Scalability | Excellent | Excellent | Depends |
| Cost | Pay-as-you-go | Pay-as-you-go | Your backend |
| Best For | Production apps | Real-time apps | Existing APIs |
🎯 Choosing the Right Sync
Use MongoDB If:
- ✅ You need offline-first with strategic sync
- ✅ You want priority-based sync intervals
- ✅ You need advanced conflict resolution
- ✅ You're building a production application
Use Firebase If:
- ✅ You need real-time synchronization
- ✅ You want multi-database support
- ✅ You prefer Google infrastructure
- ✅ You need quick setup
Use REST API If:
- ✅ You have an existing API backend
- ✅ You need custom sync logic
- ✅ You want full control over sync behavior
- ✅ You're integrating with legacy systems
🚀 Best Practices
1. Start Offline-First
Always keep local performance optimal:
// ✅ Good: Local always fast
const settings = autoFlashState({
key: 'settings',
defaultValue: {},
database: 'app',
collection: 'settings',
priority: 'normal' // Background sync
});
// ❌ Avoid: Blocking on network
await fetch('/api/settings'); // Slow!
2. Use Appropriate Priorities
Match sync priority to data importance:
// Critical: Auth tokens
priority: 'critical' // Immediate sync
// High: User preferences
priority: 'high' // Every 5 minutes
// Normal: App data
priority: 'normal' // Every 30 minutes
// Low: Analytics
priority: 'low' // Manual sync only
3. Handle Offline Gracefully
// Detect online/offline
window.addEventListener('online', () => {
console.log('✅ Back online - syncing...');
syncService.performSync();
});
window.addEventListener('offline', () => {
console.log('📴 Offline - changes queued');
});
4. Monitor Sync Status
const syncStatus = inject(SyncStatusService);
// Watch sync status
effect(() => {
const status = syncStatus.status();
console.log('Sync status:', status);
console.log('Pending operations:', status.pendingOperations);
});
📚 Related Documentation
- MongoDB Overview - MongoDB architecture
- MongoDB Getting Started - 5-minute setup
- MongoDB Advanced - Custom strategies
- Firebase Integration - Complete guide
- Firebase Advanced - Enterprise features
Choose the sync strategy that fits your needs - all maintain local-first performance! ⚡