Por qué importan los módulos
Cada funcionalidad de tu bot pertenece exactamente a un módulo. Cada módulo declara lo que provee, lo que importa y lo que expone. Ese límite te permite escalar el bot agregando módulos nuevos sin tocar los existentes.
Arquitectura de módulos recomendada
La estructura estándar aísla cada funcionalidad detrás de un límite de módulo con su propia carpeta que contiene, como mínimo, un archivo de módulo y un archivo de servicio. Los módulos evolucionan de forma independiente entre sí, y el contenedor de DI se encarga de todo el wiring entre ellos en el arranque sin configuración manual ni funciones factory.
Declara el módulo raíz
El archivo de bootstrap main.ts es el punto de entrada donde validas el entorno, creas la instancia de aplicación, cargas el módulo raíz y empiezas a escuchar eventos de Discord. La llamada app.useModule(AppModule) es el punto de entrada de composición, y desde ahí Spraxium carga todos los módulos importados de forma recursiva, resuelve providers mediante inyección de dependencias y enlaza automáticamente cada listener registrado al cliente de Discord.
import { IntentPreset, Logger, SpraxiumFactory } from '@spraxium/core';
import { EnvValidator } from '@spraxium/env';
import { AppEnv } from './app.env';
import { AppModule } from './app.module';
async function main() {
const logger = new Logger('Main');
const environment = EnvValidator.validate(AppEnv);
const app = await SpraxiumFactory.create({ token: environment.token });
app.useModule(AppModule);
app.intents(IntentPreset.Standard);
logger.info('Starting application...');
await app.listen();
}
main();Construye la raíz de composición
El módulo raíz AppModule compone funcionalidades importando otros módulos, pero nunca debería contener lógica funcional por sí mismo. Agrega un dominio nuevo creando un módulo de funcionalidad e importándolo aquí.
import { Module } from '@spraxium/common';
import { AnalyticsModule } from '@spraxium/analytics';
import { ModuleNameModule } from './modules/module-name/module-name.module';
@Module({
imports: [AnalyticsModule, ModuleNameModule],
})
export class AppModule {}Referencia de propiedades del módulo
Módulos globales
Por defecto, los providers de un módulo solo están disponibles para los módulos que lo importan explícitamente, que es el comportamiento deseado para la mayoría de módulos funcionales porque mantiene las dependencias visibles y trazables. Marcar un módulo con @Global() hace que sus exports estén disponibles en toda la aplicación sin imports explícitos, pero esto debe reservarse exclusivamente para preocupaciones transversales como logging, analytics o servicios compartidos de configuración que realmente necesiten ser accedidos desde cualquier parte del código.
Usa @Global() con moderación
Marcar demasiados módulos como globales evita la encapsulación que hace valioso al sistema de módulos y dificulta rastrear dependencias conforme crece el proyecto. Reserva @Global() para infraestructura que todos los módulos necesiten de verdad, como logging o analytics, y mantén los servicios específicos de funcionalidades dentro de su propio módulo con exports explícitos.
import { Global, Module } from '@spraxium/common';
import { AnalyticsService } from './analytics.service';
@Global()
@Module({
providers: [AnalyticsService],
exports: [AnalyticsService],
})
export class AnalyticsModule {}Usa módulos globales con moderación porque evitan los límites de encapsulación que hacen valioso al sistema de módulos desde el principio. Los servicios específicos de cada funcionalidad deben permanecer siempre locales a su módulo con exports explícitos, y solo la infraestructura verdaderamente universal debería marcarse como global. Si te descubres marcando varios módulos como globales, normalmente indica que los límites de tus módulos deben rediseñarse en lugar de saltarse.
Reglas para mantener módulos mantenibles
Un límite de negocio por carpeta de módulo. Exporta solo lo que otros módulos deban consumir. Separa declaraciones de comandos y listeners de los internos de servicios. Prefiere muchos módulos pequeños y enfocados, compuestos por AppModule, en lugar de unos pocos módulos grandes y compartidos.
Cuando un dominio crece más allá de su alcance original, divídelo en dos módulos enfocados. El sistema de módulos hace esto sencillo porque cada módulo ya posee su propia carpeta y dependencias.