Module Creation Guide

Comprehensive guide to creating modules using visual builder or code-first approach

๐Ÿ› ๏ธ Module Creation Guide

GoGrab Space offers TWO powerful ways to create production-ready modules: Visual Builder and Code-First.


๐ŸŽฏ Choose Your Approach

๐ŸŽจ Visual Builder (NEW - Recommended)

Use the Module Workbench - A groundbreaking visual tool that guides you through module creation step-by-step and generates production-ready code.

Best For:

Access: Navigate to /modularity in GoGrab Space


๐Ÿ’ป Code-First (Traditional)

Write the code directly - Full control over implementation details.

Best For:


๐ŸŽจ Method 1: Visual Builder (Modularity-Lib)

Overview

The Module Workbench is a revolutionary visual tool that enables creating complex, production-ready modules through a guided, step-by-step interface.

Location: libs/libs-structural/modularity-lib Route: /space/:spaceSlug/modularity

Features

The 6-Step Workflow

Step 1: Models

Define your data entities (e.g., User, Product, Order).

Step 2: State

Configure state management for your entities.

Step 3: Actions

Create module operations (CRUD, queries, mutations).

Step 4: UI

Design embeddable components (widgets).

Step 5: Test

Test your module with mock data.

Step 6: Deploy

Export production-ready code.

Code Generation

The Module Export Service generates:

my-module/
โ”œโ”€โ”€ index.ts                          # Barrel exports
โ”œโ”€โ”€ my-module.module.ts              # BrowserModuleContract implementation
โ”œโ”€โ”€ my-module.manifest.ts            # ModuleManifest
โ”œโ”€โ”€ models/
โ”‚   โ””โ”€โ”€ my-entity.model.ts           # TypeScript interfaces
โ”œโ”€โ”€ actions/
โ”‚   โ””โ”€โ”€ my-action.action.ts          # @PublicAction classes
โ””โ”€โ”€ components/
    โ””โ”€โ”€ my-widget/
        โ”œโ”€โ”€ my-widget.component.ts
        โ”œโ”€โ”€ my-widget.component.html
        โ””โ”€โ”€ my-widget.component.scss

Example: Creating a Product Catalog Module

  1. Navigate to /modularity/workbench
  2. Define Entity: Product (name, price, description, category)
  3. Auto-Generate: 5 CRUD actions (getProducts, getProductById, createProduct, updateProduct, deleteProduct)
  4. Customize Actions: Open Action Flow Builder for createProduct, add validation logic
  5. Add Widgets: Product List Widget, Product Card Widget
  6. Export Code: Click "Export as TypeScript" - Production-ready code generated!

๐Ÿ’ป Method 2: Code-First (Traditional)

๐Ÿ—๏ธ Module Architecture

Monorepo Structure

libs/
โ”œโ”€โ”€ core/                    # Core system libraries (@libs-core/*)
โ””โ”€โ”€ modules/                 # Reusable business modules (@modules/*)
    โ”œโ”€โ”€ user-management/     # @modules/user-management
    โ”œโ”€โ”€ product-catalog/     # @modules/product-catalog
    โ””โ”€โ”€ analytics/           # @modules/analytics

Key Benefits


๐Ÿš€ Code-First: Step-by-Step Creation

When you choose the code-first approach, follow these steps:

1. Generate Nx Library

Use the Nx generator to create a new standalone library.

# Generate new module library
npx nx g @nx/angular:lib <module-name> --directory=libs/modules --standalone --changeDetection=OnPush

# Example: User Management
npx nx g @nx/angular:lib user-management --directory=libs/modules --standalone --changeDetection=OnPush

2. Directory Structure

Organize your module following this standard structure:

libs/modules/user-management/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ lib/
โ”‚   โ”‚   โ”œโ”€โ”€ components/         # UI Components
โ”‚   โ”‚   โ”œโ”€โ”€ services/           # Module-specific Services
โ”‚   โ”‚   โ”œโ”€โ”€ models/             # Interfaces & Types
โ”‚   โ”‚   โ”œโ”€โ”€ actions/            # Public Actions
โ”‚   โ”‚   โ”œโ”€โ”€ mock/               # Mock Data
โ”‚   โ”‚   โ””โ”€โ”€ user-management.module.ts  # Main Module Class
โ”‚   โ”œโ”€โ”€ index.ts                # Barrel exports
โ”‚   โ””โ”€โ”€ test-setup.ts
โ”œโ”€โ”€ project.json
โ”œโ”€โ”€ tsconfig.json
โ””โ”€โ”€ README.md

3. Implement Module Contract

The heart of your module is the class implementing BrowserModuleContract.

File: libs/modules/user-management/src/lib/user-management.module.ts

import { Injectable, inject } from '@angular/core';
import { Observable, of, delay } from 'rxjs';
import { BrowserModuleContract, ModuleManifest, ModuleDecorator } from '@libs-core/module-base';
import { LoggerService } from '@libs-core/log-system';
import { EventBusService } from '@libs-core/event-system';

@ModuleDecorator({
  id: 'user-management',
  version: '1.0.0',
  name: 'User Management',
  description: 'User management and RBAC system',
  permissions: ['users:read', 'users:write']
})
@Injectable({ providedIn: 'root' })
export class UserManagementModule implements BrowserModuleContract {
  private readonly logger = inject(LoggerService);
  private readonly eventBus = inject(EventBusService);

  // Manifest must match decorator
  readonly manifest: ModuleManifest = {
    id: 'user-management',
    version: '1.0.0',
    name: 'User Management',
    description: 'User management and RBAC system',
    permissions: ['users:read', 'users:write'],
    // Define your public actions here
    publicActions: [],
    // Define your embeddable widgets here
    embeddableComponents: []
  };

  configure<T = Record<string, unknown>>(config: T): Observable<void> {
    this.logger.info('UserManagementModule', 'Configuring...', config);
    return of(void 0);
  }

  initialize(): Observable<void> {
    this.logger.info('UserManagementModule', 'Initializing...');
    // Setup services, connections, etc.
    return of(void 0);
  }

  start(): Observable<void> {
    this.logger.info('UserManagementModule', 'Starting...');
    this.eventBus.emit({ type: 'MODULE_STARTED', payload: { moduleId: this.manifest.id } });
    return of(void 0);
  }

  stop(): Observable<void> {
    this.logger.info('UserManagementModule', 'Stopping...');
    return of(void 0);
  }

  destroy(): Observable<void> {
    this.logger.info('UserManagementModule', 'Destroying...');
    return of(void 0);
  }
}

4. Define Models (Shared Models First)

Always prioritize using shared models before creating local types.

File: libs/modules/user-management/src/lib/models/user.types.ts

import { UserProfile, BaseEntity, SystemRoles } from '@libs-core/shared-models';

// โœ… Extend base types (Tenant ID is handled by context, omit if redundant)
export interface User extends Omit<UserProfile, 'tenantId'> {
  status: UserStatus;
  primaryRole: SystemRoles;
}

export type UserStatus = 'active' | 'inactive';

5. Create Context-Aware Services

Services should use LoggerService and EventBusService which are already tenant-aware.

File: libs/modules/user-management/src/lib/services/user.service.ts

@Injectable({ providedIn: 'root' })
export class UserService {
  private readonly http = inject(HttpClient);
  private readonly logger = inject(LoggerService);

  getUsers(): Observable<User[]> {
    // Logger automatically includes context
    this.logger.debug('UserService', 'Fetching users...');
    return this.http.get<User[]>('/api/users');
  }
}

6. Main Component

Create a standalone component as the entry point for your module's UI (if applicable).

File: libs/modules/user-management/src/lib/components/user-management.component.ts

@Component({
  selector: 'lib-user-management',
  standalone: true,
  imports: [CommonModule],
  template: `
    <div class="module-container">
      <h2>User Management</h2>
      <!-- Module content -->
    </div>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserManagementComponent {}

7. Export the Module

Expose your module class and public assets.

File: libs/modules/user-management/src/index.ts

export * from './lib/user-management.module';
export * from './lib/components/user-management.component';
export * from './lib/models';
// Do NOT export internal services

๐Ÿ”„ Hybrid Approach: Visual Builder + Code Refinement

The Power Workflow: Use both methods together!

  1. Start Visual: Use Module Workbench to scaffold the module structure
  2. Export Code: Generate production-ready TypeScript code
  3. Refine Manually: Add complex business logic, custom validation
  4. Integrate: Import into your application as an Nx library

When to Use Hybrid


๐Ÿงช Testing

Every module must include tests.

describe('UserManagementModule', () => {
  let module: UserManagementModule;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        UserManagementModule,
        { provide: LoggerService, useValue: mockLogger },
        { provide: EventBusService, useValue: mockEventBus }
      ]
    });
    module = TestBed.inject(UserManagementModule);
  });

  it('should implement lifecycle methods', () => {
    expect(module.configure).toBeDefined();
    expect(module.initialize).toBeDefined();
    // ...
  });
});

โœ… Best Practices

General

  1. Independence: Modules must be self-contained.
  2. Contracts: Always implement BrowserModuleContract.
  3. Logging: Use LoggerService exclusively.
  4. Events: Emit lifecycle events.
  5. OnPush: Use ChangeDetectionStrategy.OnPush.

Multi-Tenancy

  1. Context: Rely on application context for tenant ID.
  2. Shared Models: Use @libs-core/shared-models.
  3. Clean Events: Avoid redundant tenant IDs in payloads.

Mocking

  1. Requirement: Create realistic mock data for development.
  2. Volume: Use 50+ records for realistic testing.
  3. Types: Use shared model types for mocks.

๐ŸŽฏ Quick Decision Matrix

Requirement Visual Builder Code-First Hybrid
Speed โšกโšกโšก Very Fast โšก Slower โšกโšก Fast
Control ๐Ÿ”ง๐Ÿ”ง Good ๐Ÿ”ง๐Ÿ”ง๐Ÿ”ง Full ๐Ÿ”ง๐Ÿ”ง๐Ÿ”ง Full
Learning Curve ๐Ÿ“š Gentle ๐Ÿ“š๐Ÿ“š๐Ÿ“š Steep ๐Ÿ“š๐Ÿ“š Moderate
AI Assistance โœ… Built-in โŒ Manual โœ… Partial
CRUD Modules โœ… Perfect โš ๏ธ Tedious โœ… Excellent
Complex Logic โš ๏ธ Limited โœ… Perfect โœ… Perfect
Code Quality โœ… Consistent โš ๏ธ Varies โœ… Best of Both

Recommendation: Start with Visual Builder for 95% of modules. Use Code-First only for highly specialized cases. Use Hybrid for complex modules.


๐Ÿ“š Related Documentation


Last Updated: December 3, 2025 - 9:45 PM EST Session ID: 3 Status: โœ… Reflects Hybrid Visual + Code-First Approach