QUICK REFERENCE

Comprehensive guidelines for AI-assisted development within the Editor platform

Quick Reference - editor2 Module Generation

Code Snippets for Rapid Module Generation Copy-paste ready templates optimized for AI code generation

Last Updated: December 27, 2025
Platform: editor2


Generation Variables

Placeholder Example Description
<module-name> product-catalog Module folder name (kebab-case)
<ModuleName> ProductCatalog Module class prefix (PascalCase)
<moduleName> productCatalog Module variable name (camelCase)
<Entity> Product Main entity (PascalCase)
<entity> product Entity lowercase
<entities> products Entity plural lowercase
<Entities> Products Entity plural (PascalCase)
<base-path> products URL base path
<resource> products Permission resource

1. Component Files (Separate Files - Best Practice)

Component TypeScript

// <entity>-list/<entity>-list.component.ts
import { Component, inject, signal, computed, OnInit, ChangeDetectionStrategy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { LoggerService } from '@libs-core/log-system';
import { autoFlashState } from '@storage-system';
import { <Entity>Repository } from '../../data/repositories/<entity>.repository';
import { <Entity>, <Entity>Filters } from '../../models';
import { firstValueFrom } from 'rxjs';

@Component({
  selector: 'lib-<entity>-list',
  standalone: true,
  imports: [CommonModule, RouterModule],
  templateUrl: './<entity>-list.component.html',
  styleUrl: './<entity>-list.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class <Entity>ListComponent implements OnInit {
  private readonly repository = inject(<Entity>Repository);
  private readonly logger = inject(LoggerService).child({ source: '<Entity>ListComponent' });

  readonly entities = signal<<Entity>[]>([]);
  readonly loading = signal(false);
  readonly error = signal<string | null>(null);
  readonly filters = autoFlashState<<Entity>Filters>('<module-name>-filters', {
    status: 'all',
    searchTerm: '',
  });

  readonly filteredEntities = computed(() => {
    const filters = this.filters();
    let result = this.entities();
    if (filters.status !== 'all') {
      result = result.filter(e => e.status === filters.status);
    }
    if (filters.searchTerm) {
      const term = filters.searchTerm.toLowerCase();
      result = result.filter(e => e.name.toLowerCase().includes(term));
    }
    return result;
  });

  ngOnInit(): void {
    this.loadEntities();
  }

  private async loadEntities(): Promise<void> {
    this.loading.set(true);
    try {
      const entities = await firstValueFrom(this.repository.findAll());
      this.entities.set(entities);
    } catch (err) {
      this.error.set(err instanceof Error ? err.message : 'Unknown error');
    } finally {
      this.loading.set(false);
    }
  }
}

Component HTML

<!-- <entity>-list/<entity>-list.component.html -->
<div class="page-container">
  <header class="page-header">
    <h1><Entities></h1>
    <button (click)="onCreate()">Create New</button>
  </header>

  @if (loading()) {
    <div class="loading-state">Loading...</div>
  } @else if (error()) {
    <div class="error-state">{{ error() }}</div>
  } @else if (filteredEntities().length === 0) {
    <div class="empty-state">No <entities> found</div>
  } @else {
    <div class="data-grid">
      @for (entity of filteredEntities(); track entity.id) {
        <div class="data-card" (click)="onEntityClick(entity)">
          <h3>{{ entity.name }}</h3>
          <p>{{ entity.description }}</p>
        </div>
      }
    </div>
  }
</div>

Component SCSS

// <entity>-list/<entity>-list.component.scss
.page-container {
  padding: var(--spacing-4);
  backdrop-filter: blur(16px);
  background: rgba(var(--ux-surface-rgb), 0.8);
  border-radius: var(--radius-lg);
}

.page-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--spacing-4);

  h1 {
    margin: 0;
    color: var(--ux-text-primary);
    font-size: var(--font-size-2xl);
  }

  button {
    padding: var(--spacing-2) var(--spacing-4);
    background: var(--ux-primary);
    border: none;
    border-radius: var(--radius-md);
    color: white;
    cursor: pointer;
  }
}

.data-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: var(--spacing-4);
}

.data-card {
  padding: var(--spacing-4);
  backdrop-filter: blur(8px);
  background: rgba(var(--ux-surface-rgb), 0.6);
  border: 1px solid var(--ux-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: all 0.2s ease;

  &:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-lg);
  }
}

2. Module Class

// <module-name>.module.ts
import { Injectable, inject } from '@angular/core';
import { Observable, of } 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: '<module-name>',
  version: '1.0.0',
  name: '<Module Name>',
  description: '<Module description>',
  permissions: ['<resource>:read', '<resource>:write']
})
@Injectable({ providedIn: 'root' })
export class <ModuleName>Module implements BrowserModuleContract {
  private readonly logger = inject(LoggerService).child({ source: '<ModuleName>Module' });
  private readonly eventBus = inject(EventBusService);

  readonly manifest: ModuleManifest = {
    id: '<module-name>',
    version: '1.0.0',
    name: '<Module Name>',
    description: '<Module description>',
    permissions: ['<resource>:read', '<resource>:write'],
    publicActions: [/* actions here */],
    embeddableComponents: [/* widgets here */],
  };

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

  initialize(): Observable<void> {
    this.logger.info('Initializing');
    return of(void 0);
  }

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

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

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

3. Repository

// data/repositories/<entity>.repository.ts
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BaseRepository } from '@libs-core/data-access';
import { LoggerService } from '@libs-core/log-system';
import { <Entity> } from '../models/<entity>.model';

@Injectable({ providedIn: 'root' })
export class <Entity>Repository extends BaseRepository<<Entity>> {
  private readonly http = inject(HttpClient);
  private readonly logger = inject(LoggerService).child({ source: '<Entity>Repository' });

  static readonly ENTITY_NAME = '<Entity>';
  protected entityName = '<Entity>Repository.ENTITY_NAME;
  protected baseUrl = '/api/<entities>';

  // Inherited methods (DO NOT redefine):
  // - findAll(): Observable<<Entity>[]>
  // - findById(id: string): Observable<<Entity> | null>
  // - create(entity: Partial<<Entity>>): Observable<<Entity>>
  // - update(id: string, entity: Partial<<Entity>>): Observable<<Entity>>
  // - delete(id: string): Observable<boolean>

  // Add custom methods:
  findByStatus(status: string): Observable<<Entity>[]> {
    return this.http.get<<Entity>[]>(`${this.baseUrl}/by-status/${status}`);
  }
}

4. Routes

// <module-name>.routes.ts
import { Routes } from '@angular/router';
import { authGuard, permissionGuard } from '@libs-core/security';

export const <moduleName>Routes: Routes = [
  {
    path: '',
    redirectTo: 'list',
    pathMatch: 'full',
  },
  {
    path: 'list',
    loadComponent: () => import('./components/<entity>-list/<entity>-list.component')
      .then(m => m.<Entity>ListComponent),
    canActivate: [authGuard, permissionGuard('<resource>:read')],
    data: {
      title: '<Entities>',
      permissions: ['<resource>:read'],
      animation: 'fade',
    },
  },
  {
    path: 'create',
    loadComponent: () => import('./components/<entity>-form/<entity>-form.component')
      .then(m => m.<Entity>FormComponent),
    canActivate: [authGuard, permissionGuard('<resource>:create')],
    data: {
      title: 'Create <Entity>',
      permissions: ['<resource>:create'],
      mode: 'create',
    },
  },
  {
    path: ':id',
    loadComponent: () => import('./components/<entity>-detail/<entity>-detail.component')
      .then(m => m.<Entity>DetailComponent),
    canActivate: [authGuard, permissionGuard('<resource>:read')],
    data: {
      title: '<Entity> Detail',
      permissions: ['<resource>:read'],
    },
  },
];

5. Barrel Exports

Main Index

// src/index.ts
export * from './lib/<module-name>.module';
export * from './lib/<module-name>.routes';
export * from './lib/models';
export * from './lib/services';
export * from './lib/data';
export * from './lib/components';
export * from './lib/embeddables';
export * from './lib/actions';
export * from './lib/events';

Sub-folder Indexes

// actions/index.ts
export * from './navigate-to-<entity>.action';
export * from './create-<entity>.action';
export * from './update-<entity>.action';
export * from './delete-<entity>.action';

// components/index.ts
export * from './<entity>-list/<entity>-list.component';
export * from './<entity>-detail/<entity>-detail.component';
export * from './<entity>-form/<entity>-form.component';

// embeddables/index.ts
export * from './<entity>-widget/<entity>-widget.component';

// models/index.ts
export * from './<entity>.model';
export * from './<entity>-filters.model';

// services/index.ts
export * from './<entity>-api.service';

// data/index.ts
export * from './repositories';

// data/repositories/index.ts
export * from './<entity>.repository';

// events/index.ts
export * from './<entity>.events';

6. Action Template

// actions/navigate-to-<entity>.action.ts
import { Injectable, inject } from '@angular/core';
import { Router } from '@angular/router';
import { Observable, of } from 'rxjs';
import { tap } from 'rxjs/operators';
import { PublicAction, ExecutableAction, ActionContext, ActionParams } from '@libs-core/action-registry';
import { LoggerService } from '@libs-core/log-system';

export interface NavigateTo<Entity>Input extends ActionParams {
  <entity>Id: string;
  mode?: 'detail' | 'edit';
}

export interface NavigateTo<Entity>Output {
  success: boolean;
  targetRoute: string;
}

@PublicAction({
  id: '<resource>:navigate-to-<entity>',
  name: 'Navigate to <Entity>',
  description: 'Navigate to <entity> page',
  permissions: ['<resource>:read'],
  tags: ['navigation'],
  parameters: [
    { name: '<entity>Id', type: 'string', required: true, description: '<Entity> ID' },
    { name: 'mode', type: 'string', required: false, default: 'detail' },
  ],
  config: { category: 'navigation', module: '<module-name>' },
})
@Injectable({ providedIn: 'root' })
export class NavigateTo<Entity>Action implements ExecutableAction<NavigateTo<Entity>Output> {
  readonly metadata = {
    id: '<resource>:navigate-to-<entity>',
    name: 'Navigate to <Entity>',
    description: 'Navigate to <entity> page',
    requiredPermissions: ['<resource>:read'] as const,
    category: 'navigation',
    enabled: true,
  };

  private readonly router = inject(Router);
  private readonly logger = inject(LoggerService).child({ source: 'NavigateTo<Entity>Action' });

  execute(params: NavigateTo<Entity>Input, context: ActionContext): Observable<NavigateTo<Entity>Output> {
    const route = params.mode === 'edit'
      ? ['/<base-path>', params.<entity>Id, 'edit']
      : ['/<base-path>', params.<entity>Id];

    return of({ success: true, targetRoute: route.join('/') }).pipe(
      tap(() => this.router.navigate(route))
    );
  }

  validate(params: NavigateTo<Entity>Input): Observable<boolean> {
    return of(!!params.<entity>Id);
  }

  cleanup(): void {}
}

7. Event Template

// events/<entity>.events.ts
import { DomainEvent, DomainEventPayload } from '@libs-core/event-system';
import { <Entity> } from '../models/<entity>.model';

export interface <Entity>CreatedPayload extends DomainEventPayload {
  <entity>: <Entity>;
  createdBy: string;
}

export class <Entity>CreatedEvent extends DomainEvent<<Entity>CreatedPayload> {
  static readonly TYPE = '<entity>.created';
  constructor(payload: <Entity>CreatedPayload) {
    super(<Entity>CreatedEvent.TYPE, '<module-name>', payload);
  }
}

8. Model Template

// models/<entity>.model.ts
import { BaseEntity } from '@libs-core/shared-models';

export type <Entity>Status = 'active' | 'inactive' | 'pending';

export interface <Entity> extends BaseEntity {
  name: string;
  description: string;
  status: <Entity>Status;
}

export interface <Entity>Filters {
  status?: <Entity>Status | 'all';
  searchTerm?: string;
  page?: number;
  pageSize?: number;
}

9. Flash Persistence Usage

// For persistent UI state
readonly viewMode = autoFlashState('<module-name>-view-mode', 'grid' as 'grid' | 'list');

// For complex objects
readonly settings = autoFlashState('<module-name>-settings', {
  sortBy: 'name',
  sortDirection: 'asc',
  itemsPerPage: 20,
});

// Update state
this.settings.update(current => ({ ...current, sortBy: 'date' }));

// Read state
const currentSort = this.settings().sortBy;

10. Theme System Usage

// Always use CSS variables
.my-component {
  // Colors
  background: var(--ux-surface);
  color: var(--ux-text-primary);
  border-color: var(--ux-border);
  
  // Glassmorphism
  backdrop-filter: blur(16px);
  background: rgba(var(--ux-surface-rgb), 0.8);
  
  // Spacing
  padding: var(--spacing-4);
  gap: var(--spacing-3);
  margin: var(--spacing-2);
  
  // Border radius
  border-radius: var(--radius-lg);
  
  // Font sizes
  font-size: var(--font-size-lg);
  
  // Shadows
  box-shadow: var(--shadow-lg);
  
  // States
  &:hover {
    background: var(--ux-primary-hover);
  }
}

11. Intelligence Pyramid Integration

// Before generation
const context = await mcp.preflight({
  task: 'Generate <module-name> module',
  categories: ['angular', 'modules']
});

// Use context in generation
// ...

// After generation
await mcp.log_decision({
  type: 'implementation',
  question: 'How to implement <module-name> module?',
  options: ['Approach A', 'Approach B'],
  chosen: 'Approach A',
  reasoning: 'Because...',
  confidence: 0.9,
  files: ['<module-name>.module.ts', '<entity>.repository.ts'],
});

12. Project Configuration

project.json

{
  "name": "<module-name>",
  "$schema": "../../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "libs/libs-modules/<module-name>/src",
  "prefix": "lib",
  "projectType": "library",
  "tags": ["type:module", "scope:business"],
  "targets": {
    "build": {
      "executor": "nx:run-commands",
      "outputs": ["{workspaceRoot}/dist/libs/libs-modules/<module-name>"],
      "options": {
        "command": "node tools/scripts/build/build-angular-library.js libs/libs-modules/<module-name>"
      }
    },
    "test": {
      "executor": "@nx/vite:test",
      "options": {
        "config": "libs/libs-modules/<module-name>/vite.config.mts"
      }
    },
    "lint": {
      "executor": "@nx/eslint:lint"
    }
  }
}

tsconfig.lib.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "../../../dist/libs/libs-modules/<module-name>"
  },
  "include": ["src/**/*.ts"],
  "exclude": ["src/**/*.spec.ts", "src/test-setup.ts"]
}

13. Common Patterns

Loading Pattern

readonly loading = signal(false);
readonly data = signal<T[]>([]);
readonly error = signal<string | null>(null);

async loadData() {
  this.loading.set(true);
  this.error.set(null);
  try {
    const data = await firstValueFrom(this.service.getData());
    this.data.set(data);
  } catch (err) {
    this.error.set(err instanceof Error ? err.message : 'Unknown error');
  } finally {
    this.loading.set(false);
  }
}

Filtering Pattern

readonly filters = autoFlashState('filters', { status: 'all', search: '' });
readonly filteredItems = computed(() => {
  const f = this.filters();
  return this.items().filter(item => {
    if (f.status !== 'all' && item.status !== f.status) return false;
    if (f.search && !item.name.toLowerCase().includes(f.search.toLowerCase())) return false;
    return true;
  });
});

Form Pattern

readonly formData = signal<CreateEntityRequest>({ name: '', description: '' });

async onSubmit() {
  const data = this.formData();
  const result = await firstValueFrom(this.repository.create(data));
  this.router.navigate(['/<base-path>', result.id]);
}

14. Validation Integration

MCP Validation

// After generating module files
const validation = await mcp.executeToolCall({
  server: 'gograb-mcp-server',
  tool: 'validate_module',
  arguments: {
    modulePath: 'libs/libs-modules/<module-name>',
    strictMode: true
  }
});

if (!validation.valid) {
  // Handle validation issues
  for (const issue of validation.issues) {
    if (issue.autoFixable) {
      await autoFix(issue);
    }
  }
}

15. Testing Template

// <entity>.repository.spec.ts
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { <Entity>Repository } from './<entity>.repository';
import { LoggerService } from '@libs-core/log-system';

describe('<Entity>Repository', () => {
  let repository: <Entity>Repository;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      providers: [
        <Entity>Repository,
        { provide: LoggerService, useValue: { child: () => ({ debug: vi.fn(), info: vi.fn(), error: vi.fn() }) } }
      ]
    });
    repository = TestBed.inject(<Entity>Repository);
  });

  it('should be created', () => {
    expect(repository).toBeTruthy();
  });

  it('should have correct entity name', () => {
    expect(<Entity>Repository.ENTITY_NAME).toBe('<Entity>');
  });
});

Version: 1.0.0
Last Updated: December 27, 2025
Platform: editor2