17.1 - Global Modules Sync Analysis

Complete analysis of MongoDB modules architecture and synchronization strategy

17.1 - Global Modules Sync Analysis

Date: December 29, 2025
Session: 17.1
Confidence: 97%


🔍 Problem Analysis

Current State

MongoDB Database: gograb-api

modules collection: 0 documents ❌

MongoDB Database: space_{spaceId}

space_modules collection: All modules are here ✅

Local Codebase: modules/ directory

├── structural/
│   ├── sidebar-nav/     ← Angular module with manifest
│   ├── top-nav/         ← Angular module with manifest
│   ├── footer/          ← Angular module with manifest
│   ├── page-renderer/   ← Angular module with manifest
│   └── ...
├── business/
│   └── restaurant-management-*/  ← Business modules
├── layout/
│   └── split-sidebar/, dashboard/, etc.
└── ...

Root Cause

  1. No seeding mechanism: Global modules were designed but never populated
  2. Spaces are self-contained: All modules go to space_modules collection
  3. No code-to-DB sync: Local manifests don't sync to MongoDB

🏗️ Architecture Understanding

Module Storage Layers

Layer Location Purpose Current State
Code Modules modules/ directory Angular rendering logic ✅ Working
Global Modules gograb-api/modules Reusable templates ❌ Empty
Space Modules space_{id}/space_modules Per-space instances ✅ Working

How They Should Connect

// 1. Code Module (Angular) - provides rendering capability
@ModuleDecorator({ id: 'sidebar-nav' })
export class SidebarNavModule implements BrowserModuleContract {
  readonly manifest: ModuleManifest = {
    id: 'sidebar-nav',  // ← manifestId
    // ...
  };
}

// 2. Global Module (MongoDB) - provides reusable template
{
  "_id": "sidebar-nav",
  "name": "Sidebar Navigation",
  "manifestId": "sidebar-nav",  // ← Links to code module
  "type": "navigation",
  "defaultConfig": { /* default settings */ },
  "ai": { /* AI metadata for discovery */ }
}

// 3. Space Module (MongoDB) - extends global with customizations
{
  "_id": "mod-nav-restaurant-123",
  "extendsGlobal": "sidebar-nav",  // ← References global
  "moduleId": "sidebar-nav",        // ← References code module
  "defaultConfig": { /* space-specific overrides */ }
}

💡 Solution: Global Modules Seeding

Approach: Backend Seeding Script

Create a seeding mechanism that:

  1. Reads manifests from local code modules
  2. Generates GlobalModule documents
  3. Upserts to gograb-api/modules collection

Implementation Options

Option A: NestJS Seeder (Recommended) ⭐

Pros:

Cons:

Option B: Standalone Script

Pros:

Cons:

Option C: Frontend-Triggered Sync

Pros:

Cons:

Recommended: Option A - NestJS Seeder


📝 Implementation Plan

Phase 1: Create Global Module Seeds Data

// apis/backend-api/src/app/global-modules/seeds/core-modules.seed.ts

import { CreateGlobalModuleDto } from '../global-modules.service';

export const CORE_MODULES_SEED: CreateGlobalModuleDto[] = [
  // Structural Modules
  {
    _id: 'sidebar-nav',
    name: 'Sidebar Navigation',
    version: '1.0.0',
    type: 'navigation',
    manifestId: 'sidebar-nav',
    defaultConfig: {
      collapsible: true,
      theme: 'auto',
      position: 'left'
    },
    ai: {
      description: 'Collapsible sidebar navigation component',
      keywords: ['navigation', 'sidebar', 'menu', 'links'],
      capabilities: ['navigation', 'routing', 'menu-rendering'],
      useCases: ['Main app navigation', 'Admin dashboard sidebar'],
      complexity: 'simple',
      setupTime: 5,
      examplePrompts: ['Add a sidebar navigation', 'Create navigation menu'],
    },
    placement: {
      recommendedParents: ['layout-container', 'split-sidebar'],
      allowedLevels: ['nested'],
      defaultPosition: 'sidebar'
    },
    category: 'navigation',
    isCore: true,
    author: 'GoGrab Team',
    tags: ['navigation', 'core', 'structural']
  },
  {
    _id: 'top-nav',
    name: 'Top Navigation',
    version: '1.0.0',
    type: 'navigation',
    manifestId: 'top-nav',
    defaultConfig: {
      showLogo: true,
      sticky: true
    },
    ai: {
      description: 'Top navigation bar with logo and menu items',
      keywords: ['navigation', 'header', 'top-bar', 'menu'],
      capabilities: ['navigation', 'branding', 'responsive'],
      complexity: 'simple',
    },
    category: 'navigation',
    isCore: true,
    author: 'GoGrab Team',
    tags: ['navigation', 'core', 'structural']
  },
  {
    _id: 'page-renderer',
    name: 'Page Renderer',
    version: '1.0.0',
    type: 'page-module',
    manifestId: 'page-renderer',
    defaultConfig: {
      showToolbar: false,
      autoHeight: true
    },
    ai: {
      description: 'Renders pages with widgets from editor-web-lib',
      keywords: ['page', 'content', 'widgets', 'render'],
      capabilities: ['page-rendering', 'widget-composition'],
      complexity: 'moderate',
    },
    category: 'core',
    isCore: true,
    author: 'GoGrab Team',
    tags: ['page', 'core', 'content']
  },
  // Layout Modules
  {
    _id: 'layout-split-sidebar',
    name: 'Split Sidebar Layout',
    version: '1.0.0',
    type: 'layout',
    manifestId: 'layout-split-sidebar',
    defaultConfig: {
      sidebarWidth: '280px',
      sidebarPosition: 'left'
    },
    ai: {
      description: 'Two-column layout with sidebar and main content area',
      keywords: ['layout', 'sidebar', 'split', 'two-column'],
      capabilities: ['layout', 'responsive'],
      complexity: 'simple',
    },
    category: 'layout',
    isCore: true,
    author: 'GoGrab Team',
    tags: ['layout', 'core', 'structural']
  },
  // Add more core modules...
];

Phase 2: Create Seeder Service

// apis/backend-api/src/app/global-modules/global-modules-seeder.service.ts

import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { GlobalModulesService } from './global-modules.service';
import { CORE_MODULES_SEED } from './seeds/core-modules.seed';

@Injectable()
export class GlobalModulesSeederService implements OnModuleInit {
  private readonly logger = new Logger(GlobalModulesSeederService.name);

  constructor(private readonly globalModulesService: GlobalModulesService) {}

  async onModuleInit() {
    // Auto-seed on startup if empty
    const stats = await this.globalModulesService.getStats();
    if (stats.total === 0) {
      this.logger.log('🌱 No global modules found, seeding...');
      await this.seedCoreModules();
    } else {
      this.logger.log(`✅ Global modules already seeded (${stats.total} modules)`);
    }
  }

  async seedCoreModules(): Promise<{ created: number; skipped: number }> {
    this.logger.log('🌱 Seeding core global modules...');
    
    let created = 0;
    let skipped = 0;

    for (const moduleData of CORE_MODULES_SEED) {
      try {
        await this.globalModulesService.upsert(moduleData);
        created++;
        this.logger.log(`  ✅ ${moduleData._id}`);
      } catch (error) {
        skipped++;
        this.logger.warn(`  ⚠️ Skipped ${moduleData._id}: ${error.message}`);
      }
    }

    this.logger.log(`🌱 Seeding complete: ${created} created, ${skipped} skipped`);
    return { created, skipped };
  }

  async reseed(): Promise<{ created: number; skipped: number }> {
    this.logger.log('🔄 Reseeding global modules...');
    return this.seedCoreModules();
  }
}

Phase 3: Add Admin Endpoint

// In global-modules.controller.ts

@Post('seed')
@UseGuards(JwtAuthGuard, AdminGuard)
async seedModules(@Req() req) {
  this.logger.log(`🌱 Admin ${req.user.email} triggering module seed`);
  return this.seederService.reseed();
}

🔄 Module Promotion Workflow

Space → Global Promotion

When a space module proves valuable and should be reusable:

// POST /api/admin/promote-module
{
  "spaceId": "space_abc",
  "moduleId": "mod-custom-dashboard-123",
  "globalId": "dashboard-analytics",  // New global ID
  "name": "Analytics Dashboard"
}

Promotion Criteria

  1. Quality: Well-tested, no errors
  2. Reusability: Useful for multiple spaces
  3. Documentation: Has AI metadata
  4. Independence: Works without space-specific data

📊 Configuration Resolution

When a module is used in a universe, config is merged:

// Resolution priority (later wins)
const finalConfig = {
  ...globalModule.defaultConfig,      // 1. Base defaults
  ...spaceModule.defaultConfig,       // 2. Space customization
  ...structureNode.config             // 3. Instance override
};

Example:

// Global: sidebar-nav
{ collapsible: true, theme: 'auto', position: 'left' }

// Space: mod-nav-restaurant
{ theme: 'dark', items: [...] }

// Universe structure instance
{ items: [...different items...] }

// Final resolved:
{ collapsible: true, theme: 'dark', position: 'left', items: [...] }

✅ Recommendation Summary

Aspect Recommendation Confidence
Seeding Approach NestJS Seeder Service 97%
Auto-seed On startup if empty 95%
Admin API POST /seed endpoint 96%
Promotion Manual curation process 98%
Sync Direction Code → MongoDB (one-way) 97%

Why This Approach?

  1. Maintainability: Seed data is code, tracked in git
  2. Type Safety: Uses existing TypeScript schemas
  3. Reliability: Backend controls the data
  4. Flexibility: Can re-seed or update via admin API
  5. AI-Ready: Includes AI metadata for discovery

🚀 Next Steps

  1. Create seed data file with all core modules
  2. Implement GlobalModulesSeederService
  3. Add to GlobalModulesModule providers
  4. Create admin seed endpoint
  5. Test seeding on backend startup
  6. Document promotion workflow

📚 Related Documentation