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
- No seeding mechanism: Global modules were designed but never populated
- Spaces are self-contained: All modules go to
space_modulescollection - 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:
- Reads manifests from local code modules
- Generates GlobalModule documents
- Upserts to
gograb-api/modulescollection
Implementation Options
Option A: NestJS Seeder (Recommended) ⭐
Pros:
- Runs on backend startup (or manually)
- Uses existing
GlobalModulesService - Type-safe with existing schemas
- Can be triggered via admin API
Cons:
- Requires backend changes
Option B: Standalone Script
Pros:
- Independent of backend
- Can run in CI/CD
Cons:
- Duplicates database logic
- No type safety
Option C: Frontend-Triggered Sync
Pros:
- Could sync from ModuleRegistryService
Cons:
- Requires authenticated admin
- Less reliable
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
- Quality: Well-tested, no errors
- Reusability: Useful for multiple spaces
- Documentation: Has AI metadata
- 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?
- Maintainability: Seed data is code, tracked in git
- Type Safety: Uses existing TypeScript schemas
- Reliability: Backend controls the data
- Flexibility: Can re-seed or update via admin API
- AI-Ready: Includes AI metadata for discovery
🚀 Next Steps
- Create seed data file with all core modules
- Implement GlobalModulesSeederService
- Add to GlobalModulesModule providers
- Create admin seed endpoint
- Test seeding on backend startup
- Document promotion workflow