Crear un módulo¶
Guía completa para desarrollar un módulo first-party de Didacta. La plantilla de referencia es modules/hello-world — cópiala y adapta.
Anatomía de un módulo¶
Un módulo first-party se reparte en capas con responsabilidades claras:
| Capa | Ruta | Qué contiene |
|---|---|---|
| Paquete del módulo | modules/<slug>/ |
Lógica de dominio pura: manifest, schemas Zod, servicios sin NestJS ni Prisma. Testeable de forma aislada. |
| Host NestJS | apps/api/src/modules/<slug>/ |
Controllers, services con Prisma, bridges de eventos, workers. |
| Tablas | packages/database/prisma/schema.prisma |
Modelos con @@map("mod_<slug>_…") + migración versionada. |
| UI | apps/web/src/modules/<slug>/ + páginas en apps/web/src/app/(app)/ |
Extensión web (menú, tabs de configuración) y páginas Next.js. |
Estructura mínima del paquete¶
modules/mi-modulo/
├── module.json # manifest para el linter (module-doctor)
├── package.json # @didacta/mod-mi-modulo
├── README.md # con las 9 secciones obligatorias
├── tsconfig.json # extends ../../tsconfig.base.json
├── vitest.config.ts
├── src/
│ ├── manifest.ts # parseModuleManifest(...) → export const manifest
│ ├── service.ts # lógica de dominio
│ └── index.ts # export const miModulo: DidactaModule
└── tests/
└── contract.test.ts
package.json del paquete (patrón a copiar):
{
"name": "@didacta/mod-mi-modulo",
"version": "1.0.0",
"private": true,
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": ["dist"],
"scripts": {
"build": "tsc -p tsconfig.json",
"typecheck": "tsc -p tsconfig.json --noEmit",
"test": "vitest run"
},
"dependencies": { "@didacta/core-kernel": "workspace:*" },
"devDependencies": { "@didacta/core-registry": "workspace:*", "vitest": "^2.1.8", "typescript": "^5.7.2" }
}
Checklist completo¶
- Crea
modules/<slug>/con la estructura de arriba (el workspace pnpm ya incluyemodules/*). - Escribe el manifest en
src/manifest.tsconparseModuleManifest(...). - Exporta el contrato
DidactaModuledesdesrc/index.ts. - Regístralo en el array de
registry.register([...])deapps/api/src/modules/module-registry.service.ts(el orden no importa: hay orden topológico automático). - Crea el host NestJS en
apps/api/src/modules/<slug>/y decláralo enapps/api/src/modules/modules.module.ts. - Añade las tablas al schema de Prisma con prefijo
mod_<slug>_+tenant_id, y genera la migración versionada. - Crea la extensión de UI en
apps/web/src/modules/<slug>/index.tsy regístrala enapps/web/src/modules/index.ts. - Completa
module.jsony elREADME.mdcon las 9 secciones, y pasa las validaciones.
Las reglas de oro¶
Del contrato de módulo (reglas completas):
- Nunca importes código de otro módulo.
- Nunca escribas en tablas de otro módulo (leer sí, declarando la dependencia y filtrando por
tenant_id). - Nunca modifiques el core para una feature de tu módulo.
- Nunca emitas eventos sin declararlos en el manifest.
- Nunca crees FKs hacia tablas de otro módulo.
- Nunca metas lógica de negocio en controllers.
- Nunca gatees un módulo por licencia: todos los módulos son Community.
Guía paso a paso¶
- El manifest — el contrato declarativo del módulo.
- Base de datos — tablas, RLS y migraciones.
- Backend — el
DidactaModule, elModuleContexty el host NestJS. - Interfaz de usuario — menú, páginas y tabs de configuración.
- Eventos y hooks — comunicación con otros módulos.
- Validación y tests — module-doctor, README y suites.