Voltar aos trabalhos
No ar
Em desenvolvimento ativo

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

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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

Django
PostgreSQL
Next.js
React Native
Expo

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.