Pular para conteúdo

Guia do código

Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-09-15

Audiência: dev que abriu o repositório e quer entender como o código está organizado antes de ler classe a classe. O desenho do sistema está na Documentação Completa; o porquê da organização, nas decisões 0010, 0011 e 0012; rodar e testar, em Como rodar.

O retrato em uma frase

O ERP X-Adm do cliente exporta cada mudança como JSON, o agente on-premises a envia à API de ingestão (/api/v1/xadm), o Integrador grava no Postgres da instância e o PowerSync replica o banco para o app móvel. Em volta desse fio ficam a API CRUD /api/v1/*, as telas JTE de consulta, o push FCM das notas e as mensagens de saída pelo outbox (watch de MDF-e para o int-sascar, poke para o tradutor da Thoms).

flowchart TB
  ERP["ERP X-Adm"] -->|JSON| Agente["agente on-premises"]
  Agente -->|"/api/v1/xadm"| Ingest["ingest — parser e handlers por tabela"]
  Ingest --> Banco[("Postgres da instância")]
  Banco --> PowerSync["PowerSync"] --> App["app móvel"]
  Ingest -->|NotaAplicadaEvent| Push["push — FCM"]
  Ingest -->|outbox| Webhook["webhook — watch e poke"]
  Api["api — CRUD /api/v1/*"] --> Banco
  Views["views — telas JTE"] --> Banco

Como o código é organizado

Organização package-by-feature sob br.com.xadm, sobre uma fundação de dados (core) e um kernel (comum). O mapa abaixo é o de mais alto nível; o papel de cada pacote em detalhe, as camadas e a escrita por chave natural estão em Estrutura de código.

Pacote É Responsabilidade
core base entidades, repositórios, enums e eventos de domínio; não depende de nada do app
comum base config, regras de acesso de /api/** e das telas, erros RFC 7807, observabilidade, /health; depende só de core
ingest feature-motor ingestão do payload XADM, o manifesto de remessa e a leitura do retorno do X-Adm
powersync feature-motor rotas do PowerSync: write-back, reset e lastchange
push feature-motor push FCM disparado pela nota aplicada
export feature-motor exportação de tabela para XLS
heartbeat feature-motor repasse do heartbeat do integrador-client ao central-backend
sascar feature callback de encerramento de MDF-e vindo do int-sascar
webhook feature mensagens de saída pelo outbox da xadm-mensageria: watch de MDF-e ao int-sascar e poke ao tradutor da Thoms
api edge controllers CRUD por entidade em /api/v1/*
views edge telas JTE de consulta, a home e a tela de debug

A infra idêntica entre apps vem das libs da casa: login e sessão da xadm-seguranca, /health e Sentry da xadm-comum-web, outbox e relay M2M da xadm-mensageria.

As camadas

A ingestão entra pelo XadmController; o XadmService serializa as aplicações sob um lock e descarta payload vazio; o XadmApplyService percorre o XadmTableRegistry e aplica cada XadmTableHandler na ordem que respeita as chaves estrangeiras. A escrita por chave natural (upsert com revive de soft-delete) tem um ponto único, o EscritaPorChaveNatural, que os controllers CRUD de api também usam.

Nas edges, o controller só traduz HTTP: api responde JSON e views monta o modelo e renderiza o JTE dentro do kit/layout.jte (UI das telas). O acesso é decidido por duas regras de comum: o ApiBearerSecurityRule exige o Bearer em /api/** e o ViewSecurityRule exige login nas telas (Segurança).

ingest não conhece push: a nota aplicada publica um NotaAplicadaEvent (em core) e o listener de push reage (decisão 0011).

Travas de arquitetura

O ArchitectureTest roda no ./gradlew check e guarda as fronteiras descritas em Estrutura de código: core puro, comum dependendo só de core, features-motor independentes entre si e nenhum ciclo entre pacotes. sascar e webhook não constam das listas de pacotes do teste.

Por onde começar a ler

  1. Application — inicializa o Sentry antes do Micronaut e declara o OpenAPI com o Bearer.
  2. ingest.XadmController → ingest.XadmService → ingest.XadmApplyService — o fio da ingestão.
  3. ingest.XadmTableRegistry e dois handlers: um simples (ingest.MunicipioHandler) e um com regra própria (ingest.ContratosHandler).
  4. comum.ApiBearerSecurityRule e comum.ViewSecurityRule — quem entra em /api/** e nas telas.
  5. src/main/resources/db/migration/ — o schema, migration a migration; o modelo consolidado está em Modelagem de dados.