Pular para o conteúdo principal

Banco de Dados

A API do ChurchApps usa uma arquitetura de banco de dados por módulo. Cada um dos seis módulos de dados tem seu próprio banco de dados MySQL com um pool de conexões independente, proporcionando limites de dados claros mantendo tudo dentro de uma única implantação.

Antes de Começar

Visão Geral da Arquitetura

Api
├── membership_db ← Pessoas, grupos, permissões
├── attendance_db ← Serviços, sessões, registros
├── content_db ← Páginas, seções, elementos
├── giving_db ← Doações, fundos, pagamentos
├── messaging_db ← Conversas, notificações
└── doing_db ← Tarefas, planos, atribuições

Principais Decisões de Design

  • Um banco de dados por módulo -- Cada módulo mantém seu próprio banco de dados MySQL com um pool de conexões dedicado (gerenciado por KyselyPool). Isso mantém os módulos desacoplados e permite a evolução independente do esquema.
  • Propriedade exclusiva -- As tabelas de um módulo são lidas e escritas apenas pelo código do próprio módulo. Quando outro módulo precisa dos dados, ele chama o gateway do módulo proprietário em vez de consultar as tabelas diretamente -- veja Comunicação Entre Módulos.
  • Padrão de repositório sem ORM -- Todo acesso a dados passa por classes de repositório que constroem SQL tipado com o construtor de consultas Kysely sobre o esquema do módulo. Isso proporciona controle total sobre o desempenho e o comportamento das consultas.
  • Multi-inquilino por design -- Toda consulta é restrita por churchId. Todas as tabelas incluem uma coluna churchId, e a camada de repositório aplica o isolamento entre inquilinos automaticamente.

Strings de Conexão

A conexão de banco de dados de cada módulo é configurada no .env usando o formato padrão de string de conexão MySQL:

mysql://user:password@host:port/database

Por exemplo, uma configuração de desenvolvimento local pode ser assim:

Cada módulo lê sua conexão a partir de uma variável de ambiente chamada <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
Info

Em produção, as strings de conexão são armazenadas no AWS SSM Parameter Store e lidas pela classe Environment na inicialização.

Scripts de Esquema

Os esquemas de tabela são definidos como migrações Kysely no diretório tools/migrations/, organizados por módulo:

tools/migrations/
├── membership/
├── attendance/
├── content/
├── giving/
├── messaging/
└── doing/

As migrações definem a criação de tabelas, índices e alterações de esquema. O diretório tools/dbScripts/ contém dados de demonstração e de seed que podem ser carregados sobre o esquema.

Inicialização do Banco de Dados

Inicializar todos os bancos de dados

npm run initdb

Isso cria todos os seis bancos de dados e executa as migrações para cada um.

Inicializar um único módulo

npm run initdb -- --module=membership
Dica

Ao trabalhar em um módulo específico, você pode reinicializar apenas o banco de dados desse módulo sem afetar os demais.

Padrão de Acesso a Dados

Os repositórios constroem consultas com o construtor de consultas Kysely sobre o esquema de banco de dados tipado do módulo, obtido por meio da função getDb() do módulo. Um método típico de repositório se parece com isto:

public async loadAll(churchId: string) {
return getDb().selectFrom("people").selectAll()
.where("churchId", "=", churchId)
.execute();
}

Os repositórios são obtidos via RepoManager:

const repos = await RepoManager.getRepos<Repos>("membership");
const people = await repos.person.loadAll(churchId);
Aviso

Sempre inclua churchId em suas consultas para manter o isolamento multi-inquilino. Nunca consulte entre inquilinos a menos que tenha uma razão específica e autorizada para fazê-lo.

Referências Entre Módulos

Como os dados de cada módulo residem em um banco de dados separado, não há chaves estrangeiras nem junções SQL entre limites de módulo. Um registro que se relaciona com dados de outro módulo armazena o id desse registro -- por exemplo, uma doação no banco de dados de doações carrega o personId de uma pessoa no banco de dados de membros -- e qualquer composição entre módulos acontece no código da aplicação.

Essa restrição é o que torna os limites de módulo reais: cada esquema pode evoluir independentemente, o banco de dados de um módulo pode ser movido para seu próprio servidor, e um módulo poderia até ser extraído para um serviço independente sem desemaranhar tabelas compartilhadas ou consultas entre bancos de dados.

Artigos Relacionados