Base de Datos
La API de ChurchApps utiliza una arquitectura de base de datos por módulo. Cada uno de los seis módulos de datos tiene su propia base de datos MySQL con un grupo de conexiones independiente, proporcionando límites de datos claros mientras se mantiene todo dentro de una única implementación.
Antes de comenzar
- Instala MySQL 8.0+ -- consulta Requisitos Previos
- Configura las cadenas de conexión de base de datos en tu archivo
.env-- consulta Variables de Entorno
Descripción General de la Arquitectura
Api
├── membership_db ← Personas, grupos, permisos
├── attendance_db ← Servicios, sesiones, registros
├── content_db ← Páginas, secciones, elementos
├── giving_db ← Donaciones, fondos, pagos
├── messaging_db ← Conversaciones, notificaciones
└── doing_db ← Tareas, planes, asignaciones
Decisiones Clave de Diseño
- Una base de datos por módulo -- Cada módulo mantiene su propia base de datos MySQL con un grupo de conexiones dedicado (gestionado por
KyselyPool). Esto mantiene los módulos desacoplados y permite la evolución independiente del esquema. - Propiedad exclusiva -- Las tablas de un módulo son leídas y escritas solo por el código de ese módulo. Cuando otro módulo necesita los datos, llama a la puerta de enlace del módulo propietario en lugar de consultar las tablas directamente -- consulta Comunicación entre Módulos.
- Patrón de repositorio sin un ORM -- Todo el acceso a datos va a través de clases de repositorio que construyen SQL tipado con el generador de consultas Kysely contra el esquema del módulo. Esto da control total sobre el rendimiento y comportamiento de la consulta.
- Multi-inquilino por diseño -- Cada consulta está limitada por
churchId. Todas las tablas incluyen una columnachurchId, y la capa del repositorio aplica el aislamiento del inquilino automáticamente.
Cadenas de Conexión
Cada conexión de base de datos del módulo se configura en .env usando el formato de cadena de conexión MySQL estándar:
mysql://user:password@host:port/database
Por ejemplo, una configuración de desarrollo local podría verse así:
Cada módulo lee su conexión desde una variable de entorno llamada <MODULE>_CONNECTION_STRING:
MEMBERSHIP_CONNECTION_STRING=mysql://root:password@localhost:3306/churchapps_membership
ATTENDANCE_CONNECTION_STRING=mysql://root:password@localhost:3306/churchapps_attendance
CONTENT_CONNECTION_STRING=mysql://root:password@localhost:3306/churchapps_content
GIVING_CONNECTION_STRING=mysql://root:password@localhost:3306/churchapps_giving
MESSAGING_CONNECTION_STRING=mysql://root:password@localhost:3306/churchapps_messaging
DOING_CONNECTION_STRING=mysql://root:password@localhost:3306/churchapps_doing
En producción, las cadenas de conexión se almacenan en AWS SSM Parameter Store y son leídas por la clase Environment al iniciar.
Scripts de Esquema
Los esquemas de tabla se definen como migraciones de Kysely en el directorio tools/migrations/, organizadas por módulo:
tools/migrations/
├── membership/
├── attendance/
├── content/
├── giving/
├── messaging/
└── doing/
Las migraciones definen la creación de tablas, índices, y cambios de esquema. El directorio tools/dbScripts/ contiene datos de demostración y semilla que se pueden cargar sobre el esquema.
Inicialización de Base de Datos
Inicializar todas las bases de datos
npm run initdb
Esto crea las seis bases de datos y ejecuta las migraciones para cada una.
Inicializar un solo módulo
npm run initdb -- --module=membership
Cuando trabajes en un módulo específico, puedes reinicializar solo la base de datos de ese módulo sin afectar a los demás.
Patrón de Acceso a Datos
Los repositorios construyen consultas con el generador de consultas Kysely contra el esquema de base de datos tipado del módulo, obtenido a través de la función getDb() del módulo. Un método típico de repositorio se ve así:
public async loadAll(churchId: string) {
return getDb().selectFrom("people").selectAll()
.where("churchId", "=", churchId)
.execute();
}
Los repositorios se obtienen a través de RepoManager:
const repos = await RepoManager.getRepos<Repos>("membership");
const people = await repos.person.loadAll(churchId);
Siempre incluye churchId en tus consultas para mantener el aislamiento multi-inquilino. Nunca consultes entre inquilinos a menos que tengas una razón específica y autorizada para hacerlo.
Referencias entre Módulos
Debido a que los datos de cada módulo viven en una base de datos separada, no hay claves foráneas ni uniones SQL a través de los límites del módulo. Un registro que se relaciona con los datos de otro módulo almacena el id de ese registro -- por ejemplo, una donación en la base de datos de donaciones lleva el personId de una persona en la base de datos de membresía -- y cualquier composición entre módulos ocurre en el código de aplicación.
Esta restricción es lo que hace que los límites del módulo sean reales: cada esquema puede evolucionar independientemente, la base de datos de un módulo puede moverse a su propio servidor, e incluso un módulo podría extraerse en un servicio independiente sin desenredar tablas compartidas o consultas entre bases de datos.
Artículos Relacionados
- Estructura del Módulo -- Cómo se organizan los controladores y repositorios dentro de cada módulo
- Configuración Local de API -- Guía completa paso a paso para la instalación