Ecclesiam
Um horário errado é pior do que horário nenhum.
309
requisitos
1034
cláusulas de casos-limite
94
invariantes de domínio
95%
cobertura, 2534 testes
Por que existe
Eu queria um lugar só que respondesse a que horas é a missa. E a adoração ao Santíssimo, a confissão, os retiros, o que a paróquia tem nesta semana — de todas as paróquias católicas, de onde quer que você esteja. Essa resposta existe hoje, espalhada entre o telefone da secretaria, um cartaz na porta da igreja e uma página do Facebook que ninguém atualiza desde 2019, o que na prática significa que ela não existe.
Em volta disso ficam três coisas. O padre consegue avisar quem acompanha a paróquia. A paróquia mantém as próprias informações em dia. E doar para ela é um copia e cola, não um telefonema para o qual você precisa criar coragem. Para o que a plataforma serve de verdade é proximidade: colocar os fiéis, os padres e as paróquias em uma superfície só, acessível a todos.
O problema
Alguém quer saber a que horas é a missa. Hoje isso significa ligar para a secretaria paroquial, ler um cartaz na porta da igreja ou achar uma página no Facebook atualizada pela última vez em 2019. O horário existe — só não está em lugar nenhum onde dê para consultar.
A parte difícil nunca foi publicar um horário. É publicar o correto: o domingo em que foi cancelada, a que mudou para as 10h, o dia santo que acrescentou uma celebração. Esse único requisito determinou a maior parte da arquitetura.
Arquitetura
Quatro repositórios, três domínios de confiança, um backend Django dono de todas as regras.
A API pública não exige credencial e é somente leitura. O painel da paróquia autentica com um JWT do Supabase e é limitado por capacidades. O painel de superadmin fica atrás de senha, TOTP e Tailscale, com uma allowlist de IP no Caddy que roda no middleware antes da autenticação do DRF — um token vazado é inerte fora da rede, e um JWT válido de superusuário do painel não carrega privilégio algum ali.
A paróquia é o tenant, mas não há coluna de tenant nem schema por tenant. O isolamento resolve o conjunto de paróquias que a pessoa administra e filtra toda consulta contra ele. A paróquia em ação vem sempre da URL, nunca do payload.
Decisões que merecem explicação
- 01
As ocorrências de missa são calculadas, nunca armazenadas. Um único motor de expansão serve a API pública, o calendário do painel, o feed iCal e o app — então uma mudança de horário não pode estar correta numa superfície e desatualizada em outra.
- 02
Leituras fora de escopo retornam 404, não 403. Quem testa identificadores não descobre nada sobre quais paróquias existem em outra diocese.
- 03
Toda regra é aplicada três vezes: serializer, model.clean() e um CheckConstraint no banco. Uma regra que vive só no serializer não é invariante, é validação de formulário.
- 04
O repositório de documentação também é um servidor MCP, e seu verificador falha se qualquer link, identificador, citação de arquivo, número de linha ou nome de constraint deixar de resolver. Documentação que pode envelhecer em silêncio é pior do que nenhuma.
- 05
Check-in e confirmação de presença foram entregues e depois deliberadamente removidos após uma revisão de privacidade. O que sobrou é uma migração que derruba as tabelas. Reconstruir seria decisão de produto e conformidade, não de engenharia.
Stack
Situação
No ar e ainda em desenvolvimento ativo. Backend, painel e site público estão em produção e continuam sendo construídos — o que está descrito aqui é o estado atual, não um estado final. O console de superadmin roda em rede privada. O app mobile tem assinatura de release pronta, mas nunca foi publicado em loja, e o piloto é deliberadamente uma única paróquia — não há números de adoção a citar.