Integration Guide

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

🔧 Complete Integration Guide

Step-by-step guide to integrating the storage system into your Angular application.


Step 1: Basic Setup

Install (Already Available)

The storage system is part of your NX monorepo - no installation needed!

Add Provider

// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideGgStorage } from '@storage-system';

export const appConfig: ApplicationConfig = {
  providers: [
    provideGgStorage({
      namespace: 'my-app',  // Unique identifier for your app
      cache: { 
        maxItems: 1000,     // Cache up to 1000 items
        ttlMs: 300000       // 5 minutes TTL
      }
    })
  ]
};

Step 2: Service Integration

Inject StorageService

import { Component, inject } from '@angular/core';
import { StorageService } from '@storage-system';

@Component({
  selector: 'app-example',
  template: `...`
})
export class ExampleComponent {
  private storage = inject(StorageService);

  async ngOnInit() {
    // Use storage here
  }
}

Basic Operations

// Save data
await this.storage.put('user-profile', {
  name: 'John Doe',
  email: '[email protected]'
});

// Load data
const profile = await this.storage.get<UserProfile>('user-profile');

// Check existence
if (await this.storage.has('user-profile')) {
  console.log('Profile exists');
}

// Remove data
await this.storage.remove('temp-data');

// List keys
const keys = await this.storage.list({ prefix: 'user/' });

// Clear data
await this.storage.clear('cache/');

Step 3: Flash Persistence (Recommended)

Auto-Persistent Signals

Use Flash Persistence for automatic state management:

import { Component } from '@angular/core';
import { autoFlashState } from '@storage-system';

@Component({
  selector: 'app-settings',
  template: `
    <div>
      <label>
        Theme:
        <select [value]="settings().theme" 
                (change)="updateTheme($any($event.target).value)">
          <option value="light">Light</option>
          <option value="dark">Dark</option>
        </select>
      </label>
      
      <label>
        <input type="checkbox" 
               [checked]="settings().notifications"
               (change)="toggleNotifications()">
        Enable Notifications
      </label>
    </div>
  `
})
export class SettingsComponent {
  // ✨ Automatically persisted across sessions!
  settings = autoFlashState('app-settings', {
    theme: 'light',
    notifications: true,
    language: 'en'
  });

  updateTheme(theme: string) {
    this.settings.update(s => ({ ...s, theme }));
    // 💾 Automatically saved!
  }

  toggleNotifications() {
    this.settings.update(s => ({ ...s, notifications: !s.notifications }));
    // 💾 Automatically saved!
  }
}

With MongoDB Sync

Add optional database and collection for cloud sync:

const userPreferences = autoFlashState('preferences', {
  theme: 'dark',
  language: 'en'
}, {
  database: 'app-data',        // MongoDB database
  collection: 'user-prefs',    // MongoDB collection
  priority: 'high'             // Sync every 5 minutes
});

Step 4: Reactive Patterns

Storage Signals

Create reactive signals from storage:

@Component({
  template: `
    <div class="profile">
      @if (userProfile(); as profile) {
        <h1>{{ profile.name }}</h1>
        <p>{{ profile.email }}</p>
      } @else {
        <p>Loading...</p>
      }
    </div>
  `
})
export class ProfileComponent {
  private storage = inject(StorageService);

  // Reactive signal - automatically updates UI when storage changes
  readonly userProfile = this.storage.asSignal<UserProfile>(
    'user/profile',
    null
  ).value;

  async ngOnInit() {
    // Load profile
    await this.loadProfile();
  }

  async loadProfile() {
    const profile = await this.fetchProfileFromAPI();
    await this.storage.put('user/profile', profile);
    // UI automatically updates!
  }
}

Computed Values

Derive state from storage signals:

@Component({
  template: `
    <div [attr.data-theme]="currentTheme()">
      <h1>{{ welcomeMessage() }}</h1>
    </div>
  `
})
export class DashboardComponent {
  private storage = inject(StorageService);

  // Base storage signals
  userProfile = this.storage.asSignal<UserProfile>('user/profile', null).value;
  settings = this.storage.asSignal<Settings>('user/settings', {
    theme: 'light'
  }).value;

  // Computed signals
  currentTheme = computed(() => this.settings().theme);
  welcomeMessage = computed(() => {
    const profile = this.userProfile();
    return profile ? `Welcome, ${profile.name}!` : 'Welcome!';
  });
}

Step 5: Advanced Configuration

Performance Optimization

provideGgStorage({
  namespace: 'my-app',
  cache: { maxItems: 2000, ttlMs: 600000 },
  strategy: 'balanced',  // or 'speed' | 'durable'
  performance: {
    monitoring: true,           // Enable performance tracking
    redundancy: true,          // Enable smart data mirroring
    adaptiveStrategy: true,    // Enable intelligent adapter selection
    batchProcessing: true,     // Enable operation batching
    microCacheBudget: 150 * 1024  // 150KB micro-cache
  }
})

Custom Adapter Preference

provideGgStorage({
  namespace: 'my-app',
  cache: { maxItems: 1000, ttlMs: 300000 },
  adapterPreference: 'opfs',  // Prefer OPFS when available
  strategy: 'speed'            // Maximum performance
})

Step 6: Cloud Sync (Optional)

MongoDB Integration

Add MongoDB sync for cloud persistence:

// app.config.ts
import { provideMongoDBSync } from '@storage-system';

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
  })
]

Firebase Integration

Add Firebase/Firestore sync:

import { FirestoreSyncAdapter } from '@storage-system';

@Component({})
export class MyComponent {
  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');
  }
}

Step 7: Pre-Loading & Hydration

APP_INITIALIZER Setup

Pre-load critical data for instant access:

// app.config.ts
import { APP_INITIALIZER } from '@angular/core';
import { FlashStateHydratorService } from '@storage-system';

export const appConfig: ApplicationConfig = {
  providers: [
    provideGgStorage({ namespace: 'my-app' }),
    {
      provide: APP_INITIALIZER,
      useFactory: (hydrator: FlashStateHydratorService) => {
        return async () => {
          // Pre-load critical states
          await hydrator.preloadStates([
            'user-profile',
            'user-settings',
            'app-config'
          ]);
          console.log('✅ States pre-loaded');
        };
      },
      deps: [FlashStateHydratorService],
      multi: true
    }
  ]
};

Instant State Access

Access pre-loaded state without await:

@Component({})
export class AppComponent {
  private hydrator = inject(FlashStateHydratorService);

  constructor() {
    // Instant access (no await needed - already pre-loaded)
    const profile = this.hydrator.getInstantState<UserProfile>('user-profile');
    if (profile) {
      console.log('Profile loaded instantly:', profile.name);
    }
  }
}

Step 8: Monitoring & Debugging

Performance Monitoring

@Component({})
export class AdminComponent {
  private storage = inject(StorageService);

  checkPerformance() {
    const stats = this.storage.getPerformanceStats();
    if (stats) {
      console.log('Cache hit rate:', stats.cacheHitRate);
      console.log('Avg operation time:', stats.avgDuration, 'ms');
      console.log('Total operations:', stats.totalOperations);
    }

    const cacheStats = this.storage.getMicroCacheStats();
    console.log('Cache usage:', cacheStats.size, '/', cacheStats.budget);
    console.log('Cache hit rate:', cacheStats.hitRate);
  }
}

Storage Inspector

Add the Storage Inspector component for visual debugging:

import { StorageInspectorComponent } from '@storage-system';

@Component({
  template: `
    <router-outlet />
    @if (environment.development) {
      <ux-storage-inspector />
    }
  `,
  imports: [RouterOutlet, StorageInspectorComponent]
})
export class AppComponent {}

Common Integration Patterns

Pattern 1: User Profile Management

@Injectable({ providedIn: 'root' })
export class UserService {
  private storage = inject(StorageService);
  
  private profileSignal = this.storage.asSignal<UserProfile>('user/profile', null).value;

  // Expose as readonly
  readonly profile = this.profileSignal.asReadonly();

  async updateProfile(updates: Partial<UserProfile>) {
    const current = this.profileSignal();
    if (current) {
      const updated = { ...current, ...updates };
      await this.storage.put('user/profile', updated);
      // Signal automatically updates!
    }
  }

  async logout() {
    await this.storage.clear('user/');
  }
}

Pattern 2: Application Settings

@Injectable({ providedIn: 'root' })
export class SettingsService {
  // Auto-persistent settings
  readonly settings = autoFlashState('app-settings', {
    theme: 'light' as 'light' | 'dark',
    language: 'en',
    notifications: true,
    autoSave: true
  });

  // Computed values
  readonly isDarkMode = computed(() => this.settings().theme === 'dark');

  toggleTheme() {
    const current = this.settings().theme;
    this.settings.update(s => ({
      ...s,
      theme: current === 'light' ? 'dark' : 'light'
    }));
  }
}

Pattern 3: Cache Management

@Injectable({ providedIn: 'root' })
export class ApiCacheService {
  private storage = inject(StorageService);

  async cacheResponse<T>(endpoint: string, data: T, ttlMs = 300000) {
    await this.storage.put(`cache/api/${endpoint}`, {
      data,
      timestamp: Date.now(),
      ttl: ttlMs
    });
  }

  async getCached<T>(endpoint: string): Promise<T | null> {
    const cached = await this.storage.get<{
      data: T;
      timestamp: number;
      ttl: number;
    }>(`cache/api/${endpoint}`);

    if (!cached) return null;

    // Check if expired
    if (Date.now() - cached.timestamp > cached.ttl) {
      await this.storage.remove(`cache/api/${endpoint}`);
      return null;
    }

    return cached.data;
  }

  async clearCache() {
    await this.storage.clear('cache/api/');
  }
}

Testing Integration

Unit Testing

import { TestBed } from '@angular/core/testing';
import { provideGgStorage, StorageService } from '@storage-system';

describe('MyComponent', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        provideGgStorage({
          namespace: 'test',
          cache: { maxItems: 100, ttlMs: 60000 }
        })
      ]
    });
  });

  it('should save and load data', async () => {
    const storage = TestBed.inject(StorageService);
    
    await storage.put('test-key', { value: 'test' });
    const result = await storage.get('test-key');
    
    expect(result).toEqual({ value: 'test' });
  });
});

Troubleshooting

Issue: Data Not Persisting

Check adapter availability:

const caps = storage.getCapabilities();
console.log('Available adapters:', caps);

Issue: Slow Performance

Enable monitoring:

const stats = storage.getPerformanceStats();
console.log('Performance:', stats);

Check micro-cache:

const cacheStats = storage.getMicroCacheStats();
console.log('Cache efficiency:', cacheStats.hitRate);

Issue: Quota Exceeded

The system automatically migrates to OPFS. If issues persist:

// Clear old cache data
await storage.clear('cache/');

// Check current usage
const keys = await storage.list();
console.log('Total keys:', keys.length);

Next Steps


You're now ready to integrate the storage system into any Angular application! 🚀