Base de datos del módulo¶
Las tablas de un módulo first-party viven en el schema Prisma del host (packages/database/prisma/schema.prisma), no en el módulo. El módulo declara su territorio con el tablePrefix del manifest.
Convenciones obligatorias¶
- Prefijo
mod_<slug>_en toda tabla, con_en lugar de-(mod.access-groups→mod_access_groups_). tenant_iden toda tabla. Sin excepciones para módulos.- Cero foreign keys hacia tablas de otro módulo o del core de otro dominio.
- Cambios de schema siempre en migración versionada (
prisma migrate devgenera;migrate deployaplica en producción).
Declarar una tabla¶
model AccessGroup {
id String @id @default(uuid()) @db.Uuid
tenantId String @map("tenant_id") @db.Uuid
name String
createdAt DateTime @default(now()) @map("created_at")
@@index([tenantId])
@@map("mod_access_groups_group")
}
@@map es lo que materializa la convención de prefijo: el nombre del modelo Prisma es libre, el de la tabla no.
RLS gratis¶
No tienes que escribir políticas de Row-Level Security: el script rls.sql del host autodescubre toda tabla de public con columna tenant_id y le aplica la política tenant_isolation (ver Base de datos). Tu única obligación es que la tabla lleve tenant_id; tras la migración, ejecuta pnpm db:rls (en producción lo hace el entrypoint en cada arranque).
Flujo de trabajo en desarrollo¶
# 1. Edita packages/database/prisma/schema.prisma
# 2. Genera la migración versionada
pnpm db:migrate # prisma migrate dev — te pedirá nombre
# 3. Regenera el cliente
pnpm db:generate
# 4. Reaplica RLS (las tablas nuevas la reciben aquí)
pnpm db:rls
Nombra la migración con el prefijo del módulo (mod_access_groups_membership_source, mod_member_registration_datos…) — es la convención del historial real del repo.
Leer datos de otro módulo (vía B del ADR-016)¶
Un módulo first-party puede leer tablas de otro módulo si — y solo si —:
- Declara la dependencia en el manifest (
dependencies.modulesuoptionalModules). - Filtra siempre por
tenant_id. - Jamás escribe en esas tablas ni les crea FKs.
La alternativa preferible cuando existe (vía A) es consumir el service público del otro módulo, inyectado por el host: por ejemplo, mod.messaging obtiene los espacios de mod.community llamando a community.listSpaces(tenantId) en lugar de leer sus tablas.
Datos al desactivar / desinstalar¶
onDisableconserva los datos: desactivar un módulo es reversible.onUninstallarchiva, no borra: la disciplina del producto es no destruir datos de tenant por su cuenta.