AI RULES
Comprehensive guidelines for AI-assisted development within the Editor platform
AI Code Generation Rules - editor2 Platform
Critical Rules for AI Code Generators These rules MUST be followed when generating code for the editor2 platform.
Last Updated: December 27, 2025
Source: Adapted from gograb-modules + editor2 enhancements
Session: 14
Priority Levels
| Priority | Meaning | Action |
|---|---|---|
| MUST | Mandatory | Violation breaks the system |
| SHOULD | Strongly recommended | Violation reduces quality |
| MAY | Optional | Enhancement when applicable |
| NEVER | Forbidden | Causes critical issues |
Framework Rules (MUST)
Angular 20 Compliance
MUST_USE:
- standalone: true # All components standalone
- changeDetection: OnPush # Always OnPush
- inject(): true # Use inject() function, NOT constructor injection
- signals: true # Prefer Signals over Observables for local state
- Separate files: true # .ts, .html, .scss files (best practice)
NEVER_USE:
- NgModules # No module declarations
- setTimeout # Use RxJS timer/delay instead (except tests)
- Promises # Use RxJS Observables
- any # Use SafeAny if absolutely necessary
- Constructor injection # Use inject() function
- Inline templates # Use separate .html files (maintainability)
State Management Hierarchy
ORDER_OF_PREFERENCE:
1: Signals # Local component state, computed values
2: autoFlashState # Persistent state with flash-persistence
3: RxJS # Async operations, HTTP, events
4: NGXS # High-level module state ONLY
SIGNALS_FOR:
- Component local state
- Derived/computed values
- Service-level simple state
AUTO_FLASH_STATE_FOR:
- User preferences
- UI state that should persist
- Module configuration
- Draft data
RXJS_FOR:
- HTTP requests
- Event streams
- Time-based operations
- Complex async workflows
NGXS_FOR:
- Global application state
- Cross-module state
- High-level module state
editor2-Specific Rules (MUST)
Intelligence Pyramid Integration
BEFORE_GENERATION:
- MUST call preflight({ task: "description" })
- Returns: Past decisions, conventions, warnings, patterns
- Use returned context to inform generation
DURING_GENERATION:
- SHOULD call find_similar({ query: "similar task" })
- Use patterns from successful past generations
AFTER_GENERATION:
- MUST call log_decision({
type: "implementation",
question: "What was decided?",
chosen: "Selected approach",
reasoning: "Why this approach",
confidence: 0.9,
files: ["affected files"]
})
Three-Tier AI Architecture
TIER_1_DEVELOPMENT_AI:
- Location: Cursor IDE with MCP
- Purpose: Help developers during coding
- Tools: preflight, log_decision, find_similar
- Memory: .cursor/ai-memory/
TIER_2_PLATFORM_AI:
- Location: backend-ai-api (port 3001)
- Purpose: Generate modules and platforms
- Services: WorkflowService, AgentProcessService
- Memory: MongoDB ai-* databases
TIER_3_TENANT_AI:
- Location: Per-space sandboxed
- Purpose: Help end-users build spaces
- Services: SpaceAgentOrchestrator
- Memory: Per-tenant isolated data
Flash Persistence Integration (MUST)
FOR_PERSISTENT_STATE:
- MUST use autoFlashState from @storage-system
- Automatically syncs to IndexedDB
- Automatically handles tenant context
- Automatically handles conflicts
EXAMPLE:
readonly settings = autoFlashState('user-settings', {
theme: 'dark',
layout: 'grid'
});
NEVER:
- Manual localStorage usage
- Manual sessionStorage usage
- Custom persistence logic
Theme System Integration (MUST)
FOR_ALL_STYLING:
- MUST use CSS variables from theme-system
- NEVER hardcode colors
- NEVER hardcode fonts
- ALWAYS use glassmorphism patterns
CORRECT:
background: var(--ux-surface);
color: var(--ux-text-primary);
backdrop-filter: blur(16px);
background: rgba(var(--ux-surface-rgb), 0.8);
WRONG:
background: #ffffff; # ❌ Hardcoded color
color: black; # ❌ Hardcoded color
font-family: Arial; # ❌ Not from theme
Library Integration Rules (MUST)
Import Order for editor2
// 1. Angular core
import { Injectable, inject, signal, computed } from '@angular/core';
import { Observable, of } from 'rxjs';
// 2. editor2 core libraries (in this order)
import { BrowserModuleContract, ModuleManifest, ModuleDecorator } from '@libs-core/module-base';
import { LoggerService } from '@libs-core/log-system';
import { EventBusService, DomainEvent } from '@libs-core/event-system';
import { authGuard, permissionGuard, roleGuard, ContextService } from '@libs-core/security';
import { BaseEntity, AuditFields, ApiResponse, Permission, SystemRoles } from '@libs-core/shared-models';
import { PublicAction, ExecutableAction, ActionContext, ActionParams } from '@libs-core/action-registry';
import { BaseRepository } from '@libs-core/data-access';
// 3. editor2 foundational libraries
import { autoFlashState, GgStorage } from '@storage-system';
// 4. Module local imports
import { moduleRoutes } from './module.routes';
import { EntityRepository } from './data/repositories';
Library Usage Patterns
@libs-core/module-base:
- MUST implement BrowserModuleContract
- MUST use @ModuleDecorator
- MUST define ModuleManifest
@libs-core/log-system:
- MUST use LoggerService.child() for scoped logging
- Logger is tenant-aware automatically
@libs-core/security:
- MUST protect all routes with authGuard
- MUST use permissionGuard for resource access
@libs-core/shared-models:
- MUST use BaseEntity for all entities
- MUST check shared-models BEFORE creating local types
@libs-core/action-registry:
- MUST use @PublicAction decorator
- MUST implement ExecutableAction<T> interface
@libs-core/data-access:
- MUST extend BaseRepository<T>
- MUST use findAll(), findById(), create(), update(), delete()
@storage-system:
- MUST use autoFlashState for persistent state
- NEVER use localStorage directly
@theme-system:
- MUST use CSS variables (var(--ux-*))
- MUST use glassmorphism patterns
- NEVER hardcode colors
Naming Conventions (MUST)
File Naming
Pattern: kebab-case
Examples:
- user-management.module.ts
- product-catalog.routes.ts
- navigate-to-user.action.ts
- user.repository.ts
- user-list.component.ts
- user-list.component.html # Separate HTML file
- user-list.component.scss # Separate SCSS file
Class Naming
Pattern: PascalCase
Examples:
Module: UserManagementModule
Action: NavigateToUserAction
Repository: UserRepository
Component: UserListComponent
Service: UserManagementService
Event: UserCreatedEvent
Permission Naming
Pattern: <resource>:<action>
Examples:
- users:read
- users:create
- users:update
- users:delete
- users:manage
Action ID Naming
Pattern: <resource>:<action-verb>
Examples:
- users:navigate-to-user
- users:create-user
- users:update-user
- users:delete-user
- products:navigate-to-product
Component Rules (MUST)
File Structure (CRITICAL - Best Practice)
MUST_USE_SEPARATE_FILES:
reason: "Best practice for maintainability, team collaboration, editor support"
structure: |
component-name/
├── component-name.component.ts # Logic
├── component-name.component.html # Template
└── component-name.component.scss # Styles
CORRECT:
templateUrl: './component-name.component.html' # ✅ Separate file
styleUrl: './component-name.component.scss' # ✅ Separate file
WRONG:
template: `...` # ❌ Inline template
styles: [`...`] # ❌ Inline styles
Component Template (.ts file)
// component-name/component-name.component.ts
import { Component, inject, signal, computed, input, output, OnInit, ChangeDetectionStrategy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LoggerService } from '@libs-core/log-system';
@Component({
selector: 'lib-component-name',
standalone: true,
imports: [CommonModule],
templateUrl: './component-name.component.html', // MUST use separate file
styleUrl: './component-name.component.scss', // MUST use separate file
changeDetection: ChangeDetectionStrategy.OnPush, // MUST be OnPush
})
export class ComponentNameComponent implements OnInit {
// MUST use inject() for dependencies
private readonly logger = inject(LoggerService).child({ source: 'ComponentNameComponent' });
// MUST use signals for local state
readonly loading = signal(false);
readonly data = signal<Data[]>([]);
readonly error = signal<string | null>(null);
// MUST use computed for derived values
readonly isEmpty = computed(() => this.data().length === 0);
readonly hasError = computed(() => this.error() !== null);
// MUST use input() for inputs (Angular 20 style)
readonly limit = input<number>(10);
readonly showHeader = input<boolean>(true);
// MUST use output() for outputs
readonly itemSelected = output<Item>();
ngOnInit(): void {
this.loadData();
}
private loadData(): void {
this.loading.set(true);
// Implementation
}
}
Component HTML Template
<!-- component-name/component-name.component.html -->
<div class="component-container">
<header class="component-header" *ngIf="showHeader()">
<h2>{{ title }}</h2>
</header>
@if (loading()) {
<div class="loading-state">
<p>Loading...</p>
</div>
} @else if (hasError()) {
<div class="error-state">
<p>{{ error() }}</p>
</div>
} @else {
@if (isEmpty()) {
<div class="empty-state">
<p>No items found</p>
</div>
} @else {
<div class="data-grid">
@for (item of data(); track item.id) {
<div class="data-item" (click)="onItemClick(item)">
<h3>{{ item.name }}</h3>
<p>{{ item.description }}</p>
</div>
}
</div>
}
}
</div>
Component SCSS Styles
// component-name/component-name.component.scss
.component-container {
padding: var(--spacing-4);
backdrop-filter: blur(16px);
background: rgba(var(--ux-surface-rgb), 0.8);
border-radius: var(--radius-lg);
}
.component-header {
margin-bottom: var(--spacing-4);
h2 {
color: var(--ux-text-primary);
font-size: var(--font-size-xl);
font-weight: 600;
}
}
.loading-state,
.error-state,
.empty-state {
padding: var(--spacing-8);
text-align: center;
color: var(--ux-text-secondary);
}
.error-state {
color: var(--ux-error);
}
.data-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: var(--spacing-4);
}
.data-item {
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);
border-color: var(--ux-primary);
}
h3 {
margin: 0 0 var(--spacing-2) 0;
color: var(--ux-text-primary);
font-size: var(--font-size-lg);
}
p {
margin: 0;
color: var(--ux-text-secondary);
font-size: var(--font-size-sm);
}
}
Repository Rules (MUST)
BaseRepository Methods (CRITICAL)
INHERITED_METHODS_FROM_BASE_REPOSITORY:
findById(id: string): Observable<T | null> # Get single entity by ID
findAll(): Observable<T[]> # Get all entities
create(entity: Partial<T>): Observable<T> # Create new entity
update(id: string, entity: Partial<T>): Observable<T> # Update entity
delete(id: string): Observable<boolean> # Delete entity
CORRECT_USAGE:
repository.findAll() # ✅ Correct
repository.findById(id) # ✅ Correct
repository.create(data) # ✅ Correct
WRONG_USAGE:
repository.getAll() # ❌ WRONG - method does NOT exist
repository.get(id) # ❌ WRONG - use findById()
repository.save(data) # ❌ WRONG - use create() or update()
Repository Template
// data/repositories/entity.repository.ts
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
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 EntityRepository extends BaseRepository<Entity> {
private readonly http = inject(HttpClient);
private readonly logger = inject(LoggerService).child({ source: 'EntityRepository' });
// MUST define static ENTITY_NAME
static readonly ENTITY_NAME = 'entity';
// MUST define protected properties
protected entityName = 'entity';
protected baseUrl = '/api/entities';
// Inherited methods from BaseRepository:
// - 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 if needed:
findByStatus(status: string): Observable<Entity[]> {
this.logger.debug('Finding entities by status', { status });
return this.http.get<Entity[]>(`${this.baseUrl}/by-status/${status}`);
}
}
Route Rules (MUST)
Route Protection
// Every route MUST have guards:
canActivate: [authGuard, permissionGuard('resource:action')]
// Admin routes MUST include roleGuard:
canActivate: [authGuard, roleGuard(SystemRoles.ADMIN), permissionGuard('resource:manage')]
Route Data
// Every route MUST include data:
data: {
title: 'Page Title',
breadcrumb: 'Breadcrumb Text',
permissions: ['resource:action'],
animation: 'fade', // Use flash-animations
animationSpeed: 'fast'
}
Lazy Loading
// MUST use loadComponent for lazy loading:
{
path: 'users',
loadComponent: () => import('./components/user-list/user-list.component')
.then(m => m.UserListComponent),
data: { title: 'Users', permissions: ['users:read'] }
}
Module Structure (MUST)
Directory Structure
libs/libs-modules/<module-name>/
├── src/
│ ├── lib/
│ │ ├── actions/ # Public actions
│ │ │ ├── index.ts
│ │ │ ├── navigate-to-entity.action.ts
│ │ │ ├── create-entity.action.ts
│ │ │ ├── update-entity.action.ts
│ │ │ └── delete-entity.action.ts
│ │ ├── components/ # UI Components (separate files!)
│ │ │ ├── index.ts
│ │ │ ├── entity-list/
│ │ │ │ ├── entity-list.component.ts
│ │ │ │ ├── entity-list.component.html
│ │ │ │ └── entity-list.component.scss
│ │ │ ├── entity-detail/
│ │ │ │ ├── entity-detail.component.ts
│ │ │ │ ├── entity-detail.component.html
│ │ │ │ └── entity-detail.component.scss
│ │ │ └── entity-form/
│ │ │ ├── entity-form.component.ts
│ │ │ ├── entity-form.component.html
│ │ │ └── entity-form.component.scss
│ │ ├── data/ # Data access
│ │ │ ├── repositories/
│ │ │ │ ├── index.ts
│ │ │ │ └── entity.repository.ts
│ │ │ └── index.ts
│ │ ├── embeddables/ # Widget components
│ │ │ ├── index.ts
│ │ │ └── entity-widget/
│ │ │ ├── entity-widget.component.ts
│ │ │ ├── entity-widget.component.html
│ │ │ └── entity-widget.component.scss
│ │ ├── events/ # Domain events
│ │ │ ├── index.ts
│ │ │ └── entity.events.ts
│ │ ├── models/ # Interfaces
│ │ │ ├── index.ts
│ │ │ ├── entity.model.ts
│ │ │ └── entity-filters.model.ts
│ │ ├── services/ # Module services
│ │ │ ├── index.ts
│ │ │ └── entity-api.service.ts
│ │ ├── <module-name>.module.ts # Main module class
│ │ └── <module-name>.routes.ts # Angular routes
│ └── index.ts # Barrel exports
├── project.json
├── tsconfig.json
├── tsconfig.lib.json
└── README.md
Barrel Exports (MUST)
// 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';
Generation Workflow Integration (MUST)
Entry Points (MUST Know)
FOR_COMPLETE_PLATFORMS:
- Route: /modularity/ai-platform
- Service: WorkflowService (backend-ai-api)
- Method: 5-phase workflow with SSE streaming
- Output: Complete universe with multiple modules
FOR_SINGLE_MODULES:
- Route: /modularity/workbench
- Service: AgentProcessService (backend-ai-api)
- Method: 6-step guided creation or 8-phase agent
- Output: Single Nx library module
FOR_QUICK_MODULES:
- Route: /modularity/ai-builder
- Service: AIModuleGeneratorService
- Method: Direct generation
- Output: Module definition (can export to Nx library)
FOR_VISUAL_UNIVERSE_BUILDING:
- Route: /modular-universe
- Service: AI Panel + UniverseModuleService
- Method: Drag-drop AI-generated modules
- Output: Visual universe structure
Validation Requirements (MUST)
AFTER_GENERATION:
- MUST validate file structure
- MUST validate theme-system usage
- MUST validate flash-persistence usage
- MUST validate BrowserModuleContract implementation
- MUST validate import order
- MUST validate naming conventions
- MUST provide auto-fix suggestions
VALIDATION_TOOLS:
- MCP: validate_module tool
- Service: ValidationService
- Display: Real-time in UI with auto-fix buttons
Anti-Patterns (NEVER)
Code Anti-Patterns
NEVER:
- NgModules (use standalone: true)
- Constructor injection (use inject())
- setTimeout in production (use RxJS timer/delay)
- Promises (use RxJS Observables)
- any type (use SafeAny if needed)
- Inline templates (use separate .html files)
- Inline styles (use separate .scss files)
- Hardcoded colors (use CSS variables)
- Direct localStorage (use autoFlashState)
- Duplicate auth logic (use @libs-api/auth-core)
- Hardcode database names (use constants)
Architecture Anti-Patterns
NEVER:
- Create new storage systems (use @storage-system)
- Create new theme systems (use @theme-system)
- Bypass guards on routes
- Skip Intelligence Pyramid (preflight, log_decision)
- Generate code without validation
- Deploy without testing
Quality Checklist
Before marking generation complete:
Code Quality
- All components use separate .ts, .html, .scss files
- All components use standalone: true
- All components use OnPush change detection
- All components use inject() for DI
- All state uses signals or autoFlashState
- All async uses RxJS (no Promises, no setTimeout)
Integration Quality
- Uses @storage-system for persistent state
- Uses @theme-system CSS variables
- Uses @libs-core libraries appropriately
- Repository extends BaseRepository correctly
- Routes have proper guards
- Module implements BrowserModuleContract
Documentation Quality
- Barrel exports complete in index.ts
- README.md explains module purpose
- All public APIs documented
Intelligence Pyramid
- Called preflight() before generation
- Logged decision with log_decision()
- Used patterns from find_similar()
Reference Implementation
User Management Module: libs/core/user-management/
Use this as the gold standard for:
- Module structure
- Component patterns
- Repository patterns
- Action patterns
- Integration with core libraries
Related Documentation
- MODULE-TEMPLATE.md - Complete module structure template
- QUICK-REFERENCE.md - Copy-paste ready snippets
- WORKFLOW-GUIDE.md - Using WorkflowService
- AGENT-GUIDE.md - Using AgentProcessService
- INTELLIGENCE-PYRAMID-GUIDE.md - MCP tools usage
Version: 1.0.0
Last Updated: December 27, 2025
Maintained By: editor2 development team