Module Base Plan

Ecosistema completo para organización y gestión de contenido con interfaces espaciales

Plan de Desarrollo - Librería Module Base

Estado Actual

Cambios de Arquitectura

Dependencias Fundamentales Verificadas

Plan de Implementación por Pasos

Paso 1: Estructura Base del Proyecto

1.1 Crear estructura de directorios

src/lib/
├── contracts/           # Contratos principales
├── actions/             # Sistema de acciones
├── state/               # Gestión de estado
├── components/          # Componentes base
├── services/            # Servicios base
├── models/              # Modelos y tipos
├── decorators/          # Decoradores
└── utils/               # Utilidades específicas

1.2 Configurar dependencias del proyecto (solo revisar ya debe estar implementado)

Paso 2: Modelos y Tipos Fundamentales

2.1 Modelos base

2.2 Inyección de configuración

Paso 3: Contratos Principales

3.1 Contratos base

3.2 Contratos de configuración y registro

Paso 4: Servicios Base del Sistema

4.1 Registro y descubrimiento

4.2 Comunicación y validación

Paso 5: Sistema de Estado y Acciones

5.1 Gestión de estado

5.2 Sistema de acciones

Paso 6: Componentes Base

6.1 Componentes principales

Paso 7: Servicios Base de Módulos

7.1 Servicio base

Paso 8: Decoradores y Utilidades

8.1 Decoradores principales

8.2 Utilidades (mínimas)

Paso 9: Eventos del Ciclo de Vida

9.1 Eventos base

Paso 10: Testing Comprehensivo

10.1 Tests unitarios

10.2 Tests de integración

Paso 11: Integración Angular 20 y Browser APIs

11.1 Features Angular 20

11.2 Browser APIs

11.3 Integración NGXS

Paso 12: Finalización e Integración

12.1 Integración final

12.2 Documentación

12.3 Validación final

Estructura Detallada del Paquete

src/lib/
├── contracts/
│   ├── module-contract.ts              # BrowserModuleContract
│   ├── module-manifest.ts              # ModuleManifest y tipos relacionados
│   ├── action-contract.ts              # ActionContract
│   ├── state-contract.ts               # StateContract
│   ├── component-contract.ts           # ComponentContract
│   ├── service-contract.ts             # ServiceContract
│   ├── registration-contract.ts        # ModuleRegistrationContract
│   └── module-configuration-contract.ts # ModuleConfigurationContract
├── actions/
│   ├── module-actions.ts               # ModuleActions
│   ├── action-metadata.ts              # ActionMetadata
│   ├── public-actions.base.ts          # Acciones base del sistema
│   └── action-registry.ts              # ActionRegistry
├── state/
│   ├── base-module-state.ts            # BaseModuleState
│   ├── module-state-actions.ts         # ModuleStateActions
│   ├── module-state.service.ts         # ModuleStateService
│   └── state-selectors.base.ts         # Selectores base
├── components/
│   ├── base-module.component.ts        # BaseModuleComponent
│   ├── module-layout.component.ts      # ModuleLayoutComponent
│   ├── module-router-outlet.ts         # ModuleRouterOutlet
│   └── component-base.ts               # ComponentBase
├── services/
│   ├── base-module.service.ts          # BaseModuleService
│   ├── module-config.service.ts        # ModuleConfigService (para obtener config por moduleId)
│   ├── module-communication.service.ts # ModuleCommunicationService
│   ├── module-configuration.service.ts # ModuleConfigurationService
│   ├── module-discovery.service.ts     # ModuleDiscoveryService
│   ├── module-registry.service.ts      # ModuleRegistryService
│   ├── service-base.ts                 # ServiceBase
│   └── base-module.ts                  # BaseModule
├── models/
│   ├── module-types.ts                 # Tipos y enums
│   ├── module-events.ts                # Eventos del ciclo de vida
│   ├── module-permissions.ts           # Permisos básicos
│   └── lifecycle-states.ts             # Estados del ciclo de vida
├── decorators/
│   ├── module.decorator.ts             # @ModuleDecorator (incluye auto-registro)
│   └── public-action.decorator.ts      # @PublicAction
├── browser/
│   ├── service-worker.service.ts      # ServiceWorkerService
│   └── performance-monitor.service.ts # PerformanceMonitorService
└── utils/
    └── contract-implementation.helper.ts # ContractImplementationHelper

Dependencias Técnicas

Dependencias de Desarrollo

{
  "@gograb-space/utilities": "^1.0.0",
  "@libs-core/log-system": "^1.0.0",
  "@libs-core/event-system": "^1.0.0",
  "@libs-core/action-registry": "^1.0.0",
  "@libs-core/data-access": "^1.0.0",
  "@libs-core/security": "^1.0.0",
  "@angular/core": "^20.0.0",
  "rxjs": "^7.8.0",
  "@ngxs/store": "^3.8.1"
}

Peer Dependencies

{
  "@angular/common": "^20.0.0",
  "@angular/core": "^20.0.0",
  "rxjs": "^7.8.0"
}

Cronograma de Implementación

Fase 1: Fundamentos (Pasos 1-3)

Fase 2: Servicios y Estado (Pasos 4-5)

Fase 3: Componentes y UI (Pasos 6-7)

Fase 4: Herramientas (Pasos 8-9)

Fase 5: Testing y Finalización (Pasos 10-12)

Consideraciones Técnicas

Angular 20 Features

Performance

Security

Browser Compatibility

Configuración Específica por Módulo

Enfoque simplificado: Pasar configuración directamente al módulo, sin tokens de Angular:

// Contrato base con método configure que recibe configuración específica
export interface BrowserModuleContract {
  readonly manifest: ModuleManifest;

  configure<T = ModuleConfig>(config: T): Promise<void>;
  initialize(): Promise<void>;
  start(): Promise<void>;
  stop(): Promise<void>;
  destroy(): Promise<void>;
}

// Servicio para resolver configuración por módulo desde API
@Injectable({ providedIn: 'root' })
export class ModuleConfigService {
  constructor(private authService: AuthService) {}

  async getModuleConfig<T = ModuleConfig>(moduleId: string): Promise<T | undefined> {
    const tenantContext = this.authService.getCurrentTenantContext();
    return await this.loadConfigForModule(moduleId, tenantContext?.tenantId);
  }
}

Uso en Módulos:

// Interface específica del módulo
interface UserModuleConfig {
  enableAdvancedSearch: boolean;
  maxUsers: number;
  features: string[];
}

@ModuleDecorator({
  id: 'user-management',
  version: '1.0.0',
})
export class UserManagementModule implements BrowserModuleContract {
  private config: UserModuleConfig | null = null;

  constructor(private authService: AuthService) {}

  async configure<UserModuleConfig>(config: UserModuleConfig): Promise<void> {
    this.config = config;
    console.log('User module configured with:', this.config);
  }

  async initialize(): Promise<void> {
    if (!this.config) {
      throw new Error('Module must be configured before initialization');
    }

    // Usar configuración específica del módulo
    if (this.config.enableAdvancedSearch) {
      await this.initializeAdvancedSearch();
    }

    // Configuración diferente para cada módulo:
    // - user-management: { enableAdvancedSearch: true, maxUsers: 1000 }
    // - product-catalog: { enableRecommendations: false, maxProducts: 1000 }
    // - order-management: { allowCancelation: true, timeoutMinutes: 30 }
  }

  async start(): Promise<void> {
    // Lógica de inicio usando this.config
  }
}

Integración con Security para Multitenancy

Module-base ahora consume directamente los servicios de multitenancy desde @libs-core/security. Todos los tokens relacionados con tenant (incluyendo API_BASE_URL_TOKEN) están en security porque cada tenant puede tener su propia configuración de API:

// Los módulos consumen tenant context desde security
@ModuleDecorator({
  id: 'user-management',
  version: '1.0.0',
})
export class UserManagementModule implements BrowserModuleContract {
  constructor(
    private authService: AuthService, // Desde @libs-core/security
    private logSystem: LogSystem,
    private eventSystem: EventSystem
  ) {}

  async initialize(): Promise<void> {
    // Obtener contexto de tenant desde security
    const tenantContext = this.authService.getCurrentTenantContext();

    if (tenantContext) {
      this.logSystem.info('Module initialized for tenant', {
        tenantId: tenantContext.tenantId,
      });

      await this.loadTenantSpecificConfiguration(tenantContext);
    }
  }

  private async loadTenantSpecificConfiguration(context: TenantContext): Promise<void> {
    // La configuración específica del tenant viene desde security
    const permissions = this.authService.getCurrentPermissions();
    // Configurar módulo basado en permisos del tenant actual
  }
}

Sistema de Auto-Registro y Configuración API

Auto-Registro Simplificado (Carga Estática)

// Decorador para auto-registro con carga nativa de Angular
@ModuleDecorator({
  id: 'user-management',
  version: '1.0.0',
  autoRegister: true, // Auto-registro al cargar la aplicación
})
export class UserManagementModule implements BrowserModuleContract {
  constructor(private authService: AuthService) {}

  async initialize(): Promise<void> {
    // Inicialización del módulo
    const tenantContext = this.authService.getCurrentTenantContext();
    if (tenantContext) {
      await this.loadTenantSpecificConfiguration(tenantContext);
    }
  }
}

// Servicio de registro central
@Injectable({ providedIn: 'root' })
export class ModuleRegistryService {
  private readonly registry = new Map<string, BrowserModuleContract>();

  registerModule(module: BrowserModuleContract): void {
    this.registry.set(module.manifest.id, module);
    this.eventSystem.emit(new ModuleRegisteredEvent(module.manifest.id));
  }

  getModules(): BrowserModuleContract[] {
    return Array.from(this.registry.values());
  }

  getModule(moduleId: string): BrowserModuleContract | undefined {
    return this.registry.get(moduleId);
  }
}

Configuración API con Tokens Específicos

// Servicio de configuración que resuelve configs específicas por módulo
@Injectable({ providedIn: 'root' })
export class ModuleConfigurationService {
  constructor(
    private configService: AppConfigService,
    private authService: AuthService // Para obtener tenant context desde security
  ) {}

  async getModuleConfiguration(): Promise<Record<string, ModuleConfig>> {
    const tenantContext = this.authService.getCurrentTenantContext();
    return await this.configService.getModuleConfiguration(tenantContext?.tenantId);
  }

  async getModuleConfig<T = ModuleConfig>(moduleId: string): Promise<T | undefined> {
    const config = await this.getModuleConfiguration();
    return config[moduleId] as T;
  }
}

// Ejemplo: Diferentes configuraciones por módulo y tenant
// Tenant A - user-management: { enableAdvancedSearch: true, maxUsers: 1000 }
// Tenant A - product-catalog: { enableRecommendations: true, maxProducts: 10000 }
// Tenant B - user-management: { enableAdvancedSearch: false, maxUsers: 100 }
// Tenant B - product-catalog: { enableRecommendations: false, maxProducts: 1000 }

Integración con Module Integrator

// Module Integrator simplificado - multitenancy manejado por security
@Injectable({ providedIn: 'root' })
export class ModuleIntegratorService {
  constructor(
    private configService: AppConfigService,
    private registry: ModuleRegistryService,
    private authService: AuthService, // Security maneja tenant context
    private eventSystem: EventSystem,
    private logSystem: LogSystem
  ) {}

  async initializeApplication(): Promise<void> {
    this.eventSystem.emit(new ApplicationInitializingEvent());

    try {
      // 1. Cargar configuración de módulos
      const moduleConfig = await this.configService.getModuleConfiguration();

      // 2. Obtener módulos registrados
      const registeredModules = this.registry.getModules();

      // 3. Gestionar ciclo de vida de módulos
      for (const module of registeredModules) {
        const config = moduleConfig[module.manifest.id];
        await this.manageModuleLifecycle(module, config);
      }

      this.eventSystem.emit(new ApplicationInitializedEvent());
      this.logSystem.info('Application initialized successfully');
    } catch (error) {
      this.logSystem.error('Failed to initialize application', { error });
      throw error;
    }
  }

  private async manageModuleLifecycle(module: BrowserModuleContract, config: ModuleConfig): Promise<void> {
    try {
      if (config?.enabled && this.validateModuleAccess(module)) {
        this.logSystem.debug(`Activating module: ${module.manifest.id}`);

        // 1. Configurar módulo con su configuración específica
        await module.configure(config);

        // 2. Inicializar módulo (tenant context viene desde security)
        await module.initialize();

        // 3. Iniciar módulo
        await module.start();

        this.eventSystem.emit(new ModuleActivatedEvent(module.manifest.id));
      }
    } catch (error) {
      this.logSystem.error(`Failed to manage module lifecycle: ${module.manifest.id}`, { error });
    }
  }

  private validateModuleAccess(module: BrowserModuleContract): boolean {
    // Validación de acceso usando security service
    return this.authService.hasModulePermission(module.manifest.id);
  }
}

Integración con Librerías Core

// Ejemplo simplificado: Módulo con configuración directa (sin tokens)
interface UserModuleConfig {
  enableAdvancedSearch: boolean;
  maxUsers: number;
  allowBulkOperations: boolean;
}

@ModuleDecorator({
  id: 'user-management',
  version: '1.0.0',
})
export class UserManagementModule implements BrowserModuleContract {
  private config: UserModuleConfig | null = null;

  constructor(
    private logSystem: LogSystem,
    private eventSystem: EventSystem,
    private actionRegistry: ActionRegistryService,
    private dataAccess: DataAccessService,
    private authService: AuthService, // Todo el contexto tenant viene de security
    private utilities: ValidationUtils
  ) {}

  async configure(config: UserModuleConfig): Promise<void> {
    this.config = config;
    this.logSystem.debug('User module configured', { config });
  }

  async initialize(): Promise<void> {
    if (!this.config) {
      throw new Error('Module must be configured before initialization');
    }

    // Obtener contexto tenant desde security
    const tenantContext = this.authService.getCurrentTenantContext();

    if (tenantContext) {
      // Registrar acciones basadas en configuración
      this.actionRegistry.registerActions(this.getModuleActions());

      // Configurar listeners de eventos
      this.eventSystem.subscribe('user-created', this.handleUserCreated.bind(this));

      // Verificar permisos usando security
      if (!this.authService.hasPermission('users:manage')) {
        throw new Error('Insufficient permissions for user management');
      }

      this.logSystem.info('UserManagement module initialized', {
        tenantId: tenantContext.tenantId,
        config: this.config,
      });
    }
  }

  private getModuleActions(): ActionConfig[] {
    const actions = [
      {
        id: 'create-user',
        action: this.createUser.bind(this),
        permissions: ['users:write'],
        validation: this.utilities.validateUserData.bind(this),
      },
    ];

    // Agregar acciones basadas en configuración
    if (this.config?.allowBulkOperations) {
      actions.push({
        id: 'bulk-create-users',
        action: this.bulkCreateUsers.bind(this),
        permissions: ['users:bulk-write'],
      });
    }

    return actions;
  }

  @PublicAction()
  async createUser(userData: UserData): Promise<User> {
    // Validar límites basados en configuración
    if (this.config?.maxUsers && (await this.getUserCount()) >= this.config.maxUsers) {
      throw new Error('Maximum user limit reached');
    }

    // El tenant context es manejado automáticamente por security
    return this.dataAccess.create<User>('users', userData);
  }
}

Métricas de Éxito

Funcionalidad Core

Calidad y Performance

Compatibilidad

Consideraciones de Implementación

Prioridades de Desarrollo

  1. Paso 1-3: Contratos sólidos y modelos fundamentales
  2. Paso 4-6: Servicios base, estado y componentes
  3. Paso 7-9: Decoradores, utilidades y eventos
  4. Paso 10-12: Integración Angular 20 y testing exhaustivo

Criterios de Calidad

Próximos Pasos Inmediatos

  1. Crear estructura base según Paso 1
  2. Implementar modelos fundamentales según Paso 2
  3. Definir contratos principales según Paso 3
  4. Coordinar con @libs-core/security para tokens de multitenancy (API_BASE_URL_TOKEN, etc.)
  5. Configurar testing environment con integración a @libs-core/security
  6. Establecer CI/CD pipeline con validación de contratos

Comandos de Desarrollo

# Desarrollo y testing
nx test module-base --watch
nx lint module-base
nx build module-base

# Análisis de dependencias
nx graph --focus=module-base

# Testing de integración con security
nx test module-base --grep="security"

Este plan proporciona una base sólida para implementar module-base como una librería de contratos y clases base ultra-simplificada con configuración directa por módulo (sin tokens, factory functions ni Module Federation), usando únicamente carga nativa de Angular, delegando toda la funcionalidad de multitenancy a @libs-core/security, manteniendo la consistencia arquitectónica y la máxima simplicidad en el ecosistema GoGrab Space.