Widget System Architecture - Master Plan

Comprehensive architecture defining Core UI Widgets vs Custom Widgets and Widget-to-Module conversion

πŸ—οΈ Widget System Architecture - Master Plan

Last Updated: November 17, 2025
Status: 🎯 MASTER PLAN
Purpose: Define widget system architecture and widget-to-module conversion strategy


🎯 EXECUTIVE SUMMARY

The Core Question

"How do widgets and modules work together in our platform?"

The Answer

Widgets and modules serve different but complementary purposes:

🧩 MODULES (Building Blocks) = Complete Features with Logic + State + Routing
β”œβ”€β”€ Contain multiple widgets
β”œβ”€β”€ Have their own state management
β”œβ”€β”€ Can communicate via ActionRegistry
β”œβ”€β”€ Follow BrowserModuleContract
└── Example: sidebar-nav, top-nav, footer modules

🎨 WIDGETS (UI Components) = Pure Presentation + Basic Interaction
β”œβ”€β”€ Reusable UI elements
β”œβ”€β”€ No business logic (only presentation)
β”œβ”€β”€ Configured via inputs/outputs
β”œβ”€β”€ Live inside modules
└── Example: button, input, card, panel

πŸ“Š ARCHITECTURAL HIERARCHY

The Complete Stack

🌌 UNIVERSE (Top Level)
  └── Has Grid System (modular-universe)
      └── Each Section = Module Slot
          β”œβ”€β”€ 🧩 STRUCTURAL MODULES (navigation, layout containers)
          β”‚   β”œβ”€β”€ Sidebar Navigation Module
          β”‚   β”œβ”€β”€ Top Navigation Module  
          β”‚   └── Footer Module
          β”‚
          β”œβ”€β”€ 🧩 FEATURE MODULES (complete functionality)
          β”‚   β”œβ”€β”€ User Management Module
          β”‚   β”œβ”€β”€ E-commerce Cart Module
          β”‚   └── Content Management Module
          β”‚
          └── 🧩 PAGE MODULES (content pages built with editor-web-lib)
              └── Contains Custom Widgets
                  β”œβ”€β”€ 🎨 CUSTOM WIDGETS (built in widget-builder)
                  β”‚   β”œβ”€β”€ User Profile Card
                  β”‚   β”œβ”€β”€ Product Showcase
                  β”‚   └── Feature Section
                  β”‚   └── Built from β†’ CORE UI WIDGETS ↓
                  β”‚
                  └── 🎨 CORE UI WIDGETS (from ux-ui-* libraries)
                      β”œβ”€β”€ ux-ui-core: button, input, card, chip
                      β”œβ”€β”€ ux-ui-extended: menu, panel, portal
                      β”œβ”€β”€ ux-ui-feedback: toast, dialog, modal
                      └── ux-ui-forms: checkbox, select, range

🎨 WIDGET SYSTEM ARCHITECTURE

1. Core UI Widgets (Foundation Layer)

Purpose: Atomic, reusable UI components with NO business logic

Location: libs/libs-ui/ux-ui-* libraries

Characteristics:

Example - Button Widget:

@Component({
  selector: 'ux-button',
  standalone: true,
  template: `<button [class]="buttonClasses()">{{ label() }}</button>`
})
export class UxButtonComponent {
  label = input<string>('Click me');
  variant = input<'primary' | 'secondary' | 'ghost'>('primary');
  size = input<'sm' | 'md' | 'lg'>('md');
  disabled = input<boolean>(false);
  
  onClick = output<MouseEvent>();
  
  // Computed styles based on inputs
  buttonClasses = computed(() => {
    return `btn btn-${this.variant()} btn-${this.size()}`;
  });
}

Core UI Widget Libraries:

libs/libs-ui/
β”œβ”€β”€ ux-ui-core/         # Buttons, inputs, cards, chips, icons
β”œβ”€β”€ ux-ui-extended/     # Menus, panels, portals, context-menu
β”œβ”€β”€ ux-ui-feedback/     # Toasts, dialogs, modals, alerts
└── ux-ui-forms/        # Checkboxes, selects, ranges, switches

2. Custom Widgets (Composition Layer)

Purpose: Composed widgets combining Core UI Widgets for specific use cases

Location: Created in widget-builder, stored in widgets-manager

Characteristics:

Example - User Profile Card Widget:

// Generated by widget-builder
@Component({
  selector: 'custom-user-profile-card',
  standalone: true,
  imports: [UxButtonComponent, UxChipComponent, UxCardComponent],
  template: `
    <ux-card variant="elevated">
      <img [src]="avatarUrl()" />
      <h3>{{ userName() }}</h3>
      <p>{{ userBio() }}</p>
      <ux-chip [label]="userRole()" />
      <ux-button 
        label="View Profile" 
        (onClick)="onViewProfile.emit($event)" />
    </ux-card>
  `
})
export class CustomUserProfileCardWidget {
  // Properties from property groups
  avatarUrl = input.required<string>();
  userName = input.required<string>();
  userBio = input<string>('');
  userRole = input<string>('User');
  
  // Events
  onViewProfile = output<void>();
}

Custom Widget Structure:

Custom Widget
β”œβ”€β”€ Grid Layout (defined in visual designer)
β”œβ”€β”€ Core UI Widgets (placed in grid)
β”œβ”€β”€ Property Groups (configuration interface)
β”œβ”€β”€ Variants (different styles/configurations)
└── Singularity Flows (optional interactivity)

🧩 MODULE SYSTEM ARCHITECTURE

What is a Module?

A module = Complete feature with logic, state, and UI

Key Difference from Widgets:

WIDGET:  Data In β†’ Render UI β†’ Events Out
MODULE:  Complete Feature + State + Logic + Routes + API

Module Characteristics

Module Types

type ModuleType = 
  // STRUCTURAL MODULES (layout/navigation)
  | 'navigation'   // TopNav, Sidebar, Footer
  | 'layout'       // Grid containers, sections
  
  // FEATURE MODULES (complete functionality)
  | 'feature'      // Cart, Auth, Search, CRM
  | 'data'         // Data providers, API integrations
  
  // CONTENT MODULES
  | 'page'         // Content pages (built with editor-web-lib)
  
  // LOGIC MODULES
  | 'flow'         // Singularity logic flows
  
  // WIDGET MODULES
  | 'widget';      // ⚠️ When widgets need to become modules

πŸ”„ WIDGET-TO-MODULE CONVERSION STRATEGY

When Should a Widget Become a Module?

Keep as Widget if:

Convert to Module if:

Conversion Process

Step 1: Identify the Need

User creates "Shopping Cart" widget
β†’ Realizes it needs to:
  - Store cart state
  - Sync with backend
  - Communicate with checkout module
  - Have its own routes (/cart, /cart/checkout)
β†’ Time to convert to module!

Step 2: Conversion Tool (Widget-to-Module Generator)

Location: libs/libs-widgets/widget-builder (new feature)

Process:

  1. User clicks "Convert to Module" in widget-builder

  2. System generates:

    modules/custom-modules/<widget-name>/
    β”œβ”€β”€ src/
    β”‚   β”œβ”€β”€ lib/
    β”‚   β”‚   β”œβ”€β”€ components/
    β”‚   β”‚   β”‚   └── <widget-name>.component.ts  # Original widget
    β”‚   β”‚   β”œβ”€β”€ services/
    β”‚   β”‚   β”‚   └── <widget-name>.service.ts     # State management
    β”‚   β”‚   β”œβ”€β”€ <widget-name>.manifest.ts
    β”‚   β”‚   └── <widget-name>.module.ts          # Module wrapper
    β”‚   └── index.ts
    β”œβ”€β”€ project.json
    β”œβ”€β”€ tsconfig.json
    └── README.md
    
  3. Module manifest includes:

    {
      id: 'custom-<widget-name>',
      type: 'widget', // Indicates it's a widget-based module
      embeddableComponents: [
        {
          id: '<widget-name>',
          componentType: WidgetComponent,
          category: 'widget'
        }
      ],
      publicActions: {
        // Generated from widget events
      }
    }
    

Step 3: Module Registration


🎯 REVISED WIDGET SYSTEM COMPONENTS

1. Widget Gallery (widget-showcase/widget-gallery)

Purpose: Browse and demo CUSTOM widgets only

URL: /widgets/gallery

Features:


2. Widget Guide (widget-showcase/widget-guide)

Purpose: Documentation and variant creation for CORE UI WIDGETS

URL: /widgets/guide

Features:

Variant Creator Flow:

  1. User selects Core UI Widget (e.g., button)
  2. Opens variant creator (widget-demo component)
  3. Adjusts properties (size, color, style)
  4. Names variant (e.g., "CTA Button - Blue")
  5. System generates variant config:
    {
      id: 'cta-button-blue-v1',
      baseWidget: 'ux-button',
      properties: {
        variant: 'primary',
        size: 'lg',
        styles: { background: '#3b82f6' }
      }
    }
    
  6. Variant saved to storage-system
  7. Variant appears in widget-builder component palette

3. Widget Builder (widget-builder)

Purpose: Create custom widgets using Core UI Widgets

URL: /widgets/builder

Redesigned Architecture:

A. Three-Panel Layout

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              β”‚                      β”‚              β”‚
β”‚   SIDEBAR    β”‚   MAIN CANVAS        β”‚  LIVE PANEL  β”‚
β”‚              β”‚                      β”‚              β”‚
β”‚  (Compact)   β”‚   (Grid Designer)    β”‚  (Preview +  β”‚
β”‚              β”‚                      β”‚   Config)    β”‚
β”‚              β”‚                      β”‚              β”‚
β”‚  - Navigator β”‚   Modes:             β”‚  - Live      β”‚
β”‚  - Component β”‚   β€’ Design           β”‚    Preview   β”‚
β”‚    Palette   β”‚   β€’ Property Bind    β”‚  - Property  β”‚
β”‚  - Quick     β”‚   β€’ Flow Attach      β”‚    Editor    β”‚
β”‚    Stats     β”‚   β€’ Preview          β”‚  - Variants  β”‚
β”‚              β”‚                      β”‚  - Code Gen  β”‚
β”‚              β”‚                      β”‚              β”‚
β”‚  Collapsible β”‚                      β”‚  Collapsible β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

B. Mode-Based Canvas (Inspired by modular-universe)

type WidgetBuilderMode =
  | 'design'          // Grid-based visual designer
  | 'property-bind'   // Connect properties to components
  | 'flow-attach'     // Attach Singularity flows
  | 'preview';        // Live preview with test data

Design Mode:

Property Bind Mode:

Flow Attach Mode:

Preview Mode:

C. Component Palette (Enhanced Sidebar)

Structure:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 🧩 WIDGET BUILDER   β”‚
│─────────────────────│
β”‚ πŸ“Š Quick Stats      β”‚
β”‚ β€’ 9 Property Groups β”‚
β”‚ β€’ 3 Variants        β”‚
β”‚ β€’ 2 Flows Attached  β”‚
│─────────────────────│
β”‚ 🎨 Component Paletteβ”‚
β”‚                     β”‚
β”‚ πŸ“¦ Core UI Widgets  β”‚
β”‚  β”œβ”€ Basics          β”‚
β”‚  β”‚  β”œβ”€ Button (5)   β”‚ ← Shows variant count
β”‚  β”‚  β”œβ”€ Input (3)    β”‚
β”‚  β”‚  └─ Card (4)     β”‚
β”‚  β”œβ”€ Forms           β”‚
β”‚  β”‚  β”œβ”€ Checkbox     β”‚
β”‚  β”‚  └─ Select       β”‚
β”‚  └─ Feedback        β”‚
β”‚     β”œβ”€ Toast        β”‚
β”‚     └─ Dialog       β”‚
β”‚                     β”‚
β”‚ πŸ—οΈ Custom Widgets   β”‚
β”‚  └─ My Widgets (3)  β”‚
β”‚                     β”‚
β”‚ ⚑ Singularity       β”‚
β”‚  └─ Available Flows β”‚
│─────────────────────│
β”‚ 🧭 Quick Navigation β”‚
β”‚ β€’ Properties β†’      β”‚
β”‚ β€’ Variants β†’        β”‚
β”‚ β€’ Flows β†’           β”‚
β”‚ β€’ Code β†’            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Improvements:

D. Live Panel (Always Visible)

Combines preview + configuration

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 🎬 LIVE PREVIEW      β”‚
│──────────────────────│
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚                  β”‚ β”‚
β”‚ β”‚  Widget renders  β”‚ β”‚
β”‚ β”‚  here in         β”‚ β”‚
β”‚ β”‚  real-time       β”‚ β”‚
β”‚ β”‚                  β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ Breakpoint: πŸ“± πŸ’» πŸ–₯️  β”‚
│──────────────────────│
β”‚ βš™οΈ CONFIGURATION     β”‚
│──────────────────────│
β”‚ Tabs: [Props][Vars]  β”‚
β”‚                      β”‚
β”‚ Active Property:     β”‚
β”‚ β€’ Name: User Name    β”‚
β”‚ β€’ Type: string       β”‚
β”‚ β€’ Default: ""        β”‚
β”‚ β€’ Required: βœ“        β”‚
│──────────────────────│
β”‚ πŸ“‹ Quick Info        β”‚
β”‚ β€’ Total Props: 9     β”‚
β”‚ β€’ Total Variants: 3  β”‚
β”‚ β€’ Last Saved: 2m ago β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Benefits:


πŸ’Ύ FLASH PERSISTENCE STRATEGY

Complete State to Persist

interface WidgetBuilderWorkspaceState {
  // Widget definition
  widgetId: string;
  widgetName: string;
  widgetType: CoreWidgetType;
  widgetDescription: string;
  
  // Design
  gridLayout: GridLayout;
  components: DesignElement[];
  
  // Configuration
  propertyGroups: PropertyGroup[];
  propertyValues: WidgetPropertyValues;
  variants: WidgetVariant[];
  flows: FlowBinding[];
  
  // UI State (CRITICAL - currently missing!)
  uiState: {
    activePanel: 'design' | 'properties' | 'variants' | 'code' | 'preview';
    activeMode: WidgetBuilderMode;
    sidebarCollapsed: boolean;
    livePanelCollapsed: boolean;
    expandedSections: string[];
    selectedComponentId: string | null;
    activeVariantId: string | null;
    codeViewMode: 'component' | 'template' | 'styles' | 'all';
    previewBreakpoint: 'mobile' | 'tablet' | 'desktop';
  };
  
  // Metadata
  lastSaved: number;
  lastModified: number;
  autoSaveEnabled: boolean;
}

Storage Keys

// Current widget workspace
`widget-builder:workspace:${widgetId}`

// UI preferences (global)
`widget-builder:ui-preferences:${userId}`

// Recent widgets
`widget-builder:recent-widgets:${userId}`

// Auto-save backup
`widget-builder:autosave:${widgetId}`

Flash Persistence Implementation

// In widget-builder-workspace.component.ts
import { GgStorage } from '@storage-system';

export class WidgetBuilderWorkspaceComponent {
  private storage = inject(GgStorage);
  
  // Auto-save effect
  private autoSaveEffect = effect(() => {
    const state: WidgetBuilderWorkspaceState = {
      widgetId: this.widgetId(),
      widgetName: this.widgetName(),
      // ... all state
      uiState: {
        activePanel: this.activePanel(),
        activeMode: this.canvasMode(),
        // ... all UI state
      },
      lastSaved: Date.now()
    };
    
    // Flash persistence - saves immediately
    this.storage.set(`widget-builder:workspace:${this.widgetId()}`, state);
  });
  
  // Load state on init
  async ngOnInit() {
    const widgetId = this.route.snapshot.params['widgetId'];
    if (widgetId) {
      const state = await this.storage.get<WidgetBuilderWorkspaceState>(
        `widget-builder:workspace:${widgetId}`
      );
      
      if (state) {
        // Restore complete state
        this.widgetName.set(state.widgetName);
        this.activePanel.set(state.uiState.activePanel); // ← RESTORE UI STATE!
        this.canvasMode.set(state.uiState.activeMode);
        // ... restore everything
      }
    }
  }
}

🎯 IMPLEMENTATION ROADMAP

Phase 1: Core UI Widget Separation (Week 1)

Phase 2: Widget Builder Redesign (Week 2-3)

Phase 3: Flash Persistence (Week 3)

Phase 4: Widget-to-Module Conversion (Week 4)

Phase 5: Integration & Polish (Week 5)


🎨 KEY DESIGN PRINCIPLES

1. Separation of Concerns

Core UI Widgets β†’ Basic building blocks (ux-ui-*)
Custom Widgets  β†’ Composed for specific use cases (widget-builder)
Modules         β†’ Complete features with logic (modules/)

2. Progressive Enhancement

Start Simple  β†’ Use Core UI Widget variants
Need More     β†’ Create Custom Widget in builder
Complex Logic β†’ Convert to Module

3. Reusability First

Everything is reusable at every level:
- Core UI Widgets have variants
- Custom Widgets are templates
- Modules are self-contained

4. AI-Trainable Architecture

Clear patterns at every level make AI training effective:
- Core UI Widgets: Learn from existing components
- Custom Widgets: Learn from user creations
- Modules: Learn from module manifests

πŸ“š RELATED DOCUMENTATION


Status: 🎯 Ready for Implementation
Next Steps: Begin Phase 1 - Core UI Widget Separation