Drag-and-Drop & Module System Integration
Complete guide to how modules are created, stored, and used in the Modular Universe Builder
Drag-and-Drop & Module System Integration
Overview
The Modular Universe Builder (modular-universe) is now fully integrated with the module creation system (modularity-lib), enabling a complete workflow from module creation to platform building.
🎯 Complete Workflow
1. Creating Modules
Via Modularity Library (modularity-lib):
// User clicks "Create Module" button
// → Opens ModuleCreationWizardComponent
// → User selects pages, widgets, flows
// → Wizard calls ModulePackagerService.packageModule()
// Result: Module is:
// ✅ Saved to GgStorage (IndexedDB + MongoDB)
// ✅ Registered with ModuleRegistryService
// ✅ Available in ModulePaletteComponent
// ✅ Usable immediately (no page refresh needed)
Storage Locations:
GgStorage:
├── modularity/generated-modules/{moduleId}/manifest (ModuleManifest)
├── modularity/generated-modules/{moduleId}/files (GeneratedModuleFiles)
└── modularity/module-metadata/{moduleId} (Metadata)
File System (via backend API):
└── modules/generated/{slug}/
├── src/lib/
│ ├── components/
│ ├── services/
│ └── {module-name}.module.ts
└── package.json
2. Displaying Modules in Palette
Module Merging Strategy (ModuleMergingService):
// Combines three sources:
1. Hardcoded BrowserModuleContract instances (from ModuleRegistry)
2. Simple manifests (from ModuleRegistry.getAllModules())
3. User-created modules (from GgStorage with prefix 'modularity/generated-modules')
// Filters out system modules:
- By ID: singularity, space-map, editor, modularity, widgets-manager, launch-station
- By category: 'core-tool', 'system'
- By tags: 'system', 'core-tool', 'internal'
Result: ModulePaletteComponent shows all available user-facing modules.
3. Drag-and-Drop System
Implementation:
<!-- Parent: cdkDropListGroup connects all nested drop lists -->
<div class="modular-universe-builder" cdkDropListGroup>
<!-- Source: Module Palette -->
<lib-module-palette>
<div class="items-list" cdkDropList [cdkDropListConnectedTo]="[]">
<div cdkDrag [cdkDragData]="{ type: 'module', data: manifest }">
<!-- Module item -->
</div>
</div>
</lib-module-palette>
<!-- Target: Grid Canvas Sections -->
<lib-grid-canvas>
<lib-grid-section>
<div class="section-content"
cdkDropList
[cdkDropListData]="section"
(cdkDropListDropped)="onContentDrop($event, section)">
<!-- Drop zone -->
</div>
</lib-grid-section>
</lib-grid-canvas>
</div>
Drop Behavior (GridCanvasComponent.onContentDrop()):
// Case 1: Dropping into EMPTY section
// → Assign module/widget directly to section
// → Update section.contentType = 'module' | 'widget'
// → Update section.moduleId or section.widgetId
// Case 2: Dropping into section WITH CONTENT
// → Create nested child section
// → Add to section.children array
// → Supports recursive nesting (modules inside modules)
4. Recursive/Nested Module Support
Data Structure:
interface SectionConfig {
id: string;
name?: string;
contentType: 'empty' | 'module' | 'widget' | 'page' | 'custom';
moduleId?: string;
widgetId?: string;
// ✨ NEW: Nested sections for container modules
children?: SectionConfig[];
// Layout, positioning, behavior, etc.
}
Recursive Rendering (GridSectionComponent):
<lib-grid-section [section]="parent" [depth]="0">
<!-- Section content -->
<!-- Recursively render children -->
@if (section.children && section.children.length > 0) {
@for (child of section.children; track child.id) {
<lib-grid-section [section]="child" [depth]="depth + 1">
<!-- Nested section (can have its own children) -->
</lib-grid-section>
}
}
</lib-grid-section>
Visual Feedback:
- Depth badges show nesting level
- Left border indicates nested sections
- Background tint for nested items
- Indentation based on depth
🔄 Real-Time Synchronization
Storage System (GgStorage)
Features:
- Flash Persistence: Instant write to IndexedDB
- MongoDB Sync: Automatic background sync when online
- Cross-Tab Sync: Changes reflect across all open tabs
- Offline-First: Works without internet connection
Module Lifecycle:
// 1. Create Module
await modulePackager.packageModule(config);
// → Saves to GgStorage
// → Registers with ModuleRegistry
// → Syncs to MongoDB (if online)
// 2. Load Module
const modules = await moduleMergingService.getMergedModules();
// → Loads from GgStorage (fast!)
// → Merges with hardcoded modules
// → Filters system modules
// 3. Use Module
// Module is dragged onto canvas
// → onContentDrop() updates section
// → saveLayoutConfiguration() persists to GgStorage
// → MongoDB sync happens automatically
🎨 Widget Integration
Widget Sources
1. Pre-built Widgets (widgets-manager):
// Loaded from: space_{spaceId}_widget_{widgetId}
// Examples: Hero Section, Product Card, Contact Form, etc.
2. Custom Widgets (created in Widget Builder):
// Created via: Widget Builder UI
// Stored in: GgStorage with space-specific keys
// Available in: ModulePaletteComponent > Widgets tab
3. Module Widgets (part of packaged modules):
// Defined in: ModuleManifest.embeddableComponents
// Generated during: Module packaging process
// Usable as: Standalone widgets or module components
Widget Rendering
Currently, widgets display as placeholders in the builder:
<div class="widget-content">
<i class="fas fa-puzzle-piece"></i>
<p>Widget: {{ section.widgetId }}</p>
</div>
Future Enhancement: Dynamic widget rendering using WidgetRendererService.
🚀 Module Usability
What Makes a Module "Usable"?
A module is considered usable when it:
✅ Has a valid manifest (ModuleManifest):
- ID, name, version, description
- Routes (for navigation)
- Embeddable components (for reuse)
- Public actions (for inter-module communication)
✅ Is properly stored:
- In GgStorage (runtime access)
- In File System (build-time inclusion)
- Registered in ModuleRegistry
✅ Can be instantiated:
- Has generated component files
- Has platform-agnostic types
- Has deployment bundle
✅ Is discoverable:
- Shows up in ModulePaletteComponent
- Can be dragged and dropped
- Can be assigned to sections
Current State
✅ Fully Working:
- Module creation via wizard
- Module storage (dual storage)
- Module discovery (merging service)
- Module palette display
- Drag-and-drop into sections
- Nested module support
⚠️ Placeholder Rendering:
- Modules show as placeholders (
Module: {moduleId}) - Widgets show as placeholders (
Widget: {widgetId})
🔮 Future Enhancement:
- Dynamic module rendering (load and instantiate components)
- Visual module preview in builder
- Edit mode for module content
- Module parameter configuration UI
🔗 Integration Points
1. Modularity Lib → Modular Universe
// ModuleCreationWizardComponent emits:
@Output() moduleCreated = new EventEmitter<string>();
// ModularUniverseBuilderComponent receives:
onModuleCreated(moduleId: string): void {
this.closeEditor();
this.loadAvailableModules(); // Refresh palette
}
2. Module Palette → Grid Canvas
// Palette provides drag data:
{
type: 'module' | 'widget',
data: ModuleManifest | SpaceWidget
}
// Canvas receives drop:
onContentDrop(event, section):
- Extracts drag data
- Updates section content
- Persists to GgStorage
3. Grid Canvas → Section Config Panel
// Canvas emits:
@Output() sectionSelected = new EventEmitter<SectionConfig>();
// Panel receives:
// → Shows section properties
// → Allows editing contentType, moduleId, widgetId
// → Changes persist via GridCanvas.updateSection()
🎯 Best Practices
Creating Modules
- Use the Wizard:
ModuleCreationWizardComponentensures proper structure - Select Assets: Choose pages, widgets, and flows that work together
- Name Descriptively: Use clear names for discoverability
- Tag Appropriately: Tags help with filtering and organization
Using Modules
- Drag from Palette: All modules are draggable
- Drop into Sections: Empty sections accept modules directly
- Nest for Complexity: Drop into filled sections to create nested structures
- Configure via Panel: Use Section Config Panel for fine-tuning
Storage Strategy
- Trust GgStorage: Automatic sync, offline-first
- Don't Manual Sync: Flash persistence handles it
- Use Prefixes: Follow the pattern (
modularity/,space_, etc.) - Check Sync Status: Use
ModuleStorageService.getAllSyncStatuses()
📊 Architecture Diagram
┌─────────────────────────────────────────────────────────────┐
│ Modular Universe Builder │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────┐ ┌─────────────────────────────┐ │
│ │ Module Palette │─────▶│ Grid Canvas │ │
│ │ (Drag Source) │ │ (Drop Target) │ │
│ │ │ │ │ │
│ │ Modules Tab │ │ ┌─────────────────────┐ │ │
│ │ Widgets Tab │ │ │ Section (empty) │ │ │
│ └──────────────────┘ │ │ [Drop here] │ │ │
│ │ │ └─────────────────────┘ │ │
│ │ │ │ │
│ ▼ │ ┌─────────────────────┐ │ │
│ ┌──────────────────┐ │ │ Section (module) │ │ │
│ │ Module Merging │ │ │ ├─ Child Section │ │ │
│ │ Service │ │ │ └─ Child Section │ │ │
│ │ │ │ └─────────────────────┘ │ │
│ │ • Hardcoded │ └─────────────────────────────┘ │
│ │ • User-Created │ │ │
│ │ • Filtered │ ▼ │
│ └──────────────────┘ ┌─────────────────────────────┐ │
│ │ │ Section Config Panel │ │
│ │ │ (Property Editor) │ │
│ ▼ └─────────────────────────────┘ │
│ ┌──────────────────┐ │
│ │ GgStorage │◀────────────────────────────────────┤
│ │ (Flash Persist) │ │
│ └──────────────────┘ │
│ │ │
│ ├──▶ IndexedDB (Offline) │
│ └──▶ MongoDB (Online Sync) │
│ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Modularity Library │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Module Creation Wizard │ │
│ │ Step 1: Type Selection │ │
│ │ Step 2: Basic Info │ │
│ │ Step 3: Content (Pages, Widgets, Flows) │ │
│ │ Step 4: Configuration │ │
│ │ Step 5: Preview & Generate │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Module Packager Service │ │
│ │ • Load Assets │ │
│ │ • Generate Platform-Agnostic Types │ │
│ │ • Generate Module Manifest │ │
│ │ • Generate Module Files │ │
│ │ • Create Deployment Bundle │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Module Storage Service (Dual Storage) │ │
│ │ • Save to GgStorage (Runtime) │ │
│ │ • Save to File System (Build-time) │ │
│ │ • Register with ModuleRegistry │ │
│ │ • Track Sync Status │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
🎉 Summary
The Modular Universe Builder now provides a complete, Ferrari-level module system:
✅ Create: Modules via visual wizard ✅ Store: Dual storage (runtime + build-time) ✅ Discover: Merged module palette with filtering ✅ Use: Drag-and-drop onto canvas ✅ Nest: Recursive sections for complex layouts ✅ Persist: Flash persistence with MongoDB sync ✅ Scale: Supports unlimited modules and nesting
This is the foundation for building "the most powerful platform builder in the universe." 🚀