Guia do código¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-09-21
Para quem vai mexer no código. O porquê das escolhas está nas decisões; os contratos com o ZIM estão em contrato pAbast. Aqui fica o mapa: onde cada coisa mora. Como rodar na sua máquina está em como rodar.
Princípio de leitura¶
O público deste código é a equipe que desenvolve em ZIM e sabe pouco Java. Por isso: sem framework, sem injeção de dependência, wiring manual e explícito, e duplicidade aceita em prol da leitura. Antes de extrair uma abstração "porque repete", pergunte se ela facilita a vida de quem lê — normalmente não facilita.
Exceção única de linguagem: uma classe Kotlin embrulha o SDK PowerSync (Kotlin
Multiplatform, com suspend/Flow, inviável de Java 8 puro). Nenhuma lógica de negócio
mora nela — só a ponte.
Mapa dos pacotes¶
Base: br.com.xadm.integradorclient.
| Pacote | Papel |
|---|---|
| (raiz) | ponto de entrada e trava de instância: parsing das flags, wiring manual de tudo, guarda de uma execução por pasta de dados |
config |
leitura e validação do .properties, com erro que nomeia a chave faltante |
auth |
JWT auto-assinado (RS256) que autentica o cliente no PowerSync da nuvem |
powersync |
o espelho local: declaração do schema das tabelas, o wrapper Kotlin do SDK, o write-back HTTP do status e o envio do heartbeat (EnvioHeartbeat) |
processo |
o miolo: um processador por fluxo, o agendador serial que os roda, a coleta coerente por remessa, a máquina de status, os avisos e o heartbeat periódico (BatimentoPeriodico) |
zim |
a fronteira com o ERP: os fluxos conhecidos, a escrita do arquivo de envio fixed-width, a leitura do retorno e a execução do zimrtmu.exe |
Quatro pontos que costumam surpreender quem chega:
- Um lote carrega as tabelas de UM fluxo só. O fluxo é que define quais tabelas viajam e qual literal de handshake o ZIM vai ler para saber o que chegou.
- O arquivo de envio e o contrato andam juntos. Mudou uma largura de campo no layout, muda o contrato no mesmo PR — o gate não compara os dois por você.
- O que roda a cada volta do laço não pode lançar. O
Agendadorchama o vigia do write-back e o heartbeat periódico sem try/catch; uma exceção ali derrubaria o daemon. Por issoEnvioHeartbeateBatimentoPeriodicoengolem atéRuntimeExceptione só logam WARN. OBatimentoPeriodicorecebe o envio comoConsumer—processonão conhece o HTTP, e o teste usa um consumidor fake. - O nível do log decide o que abre incidente. Um
LOG.warnouLOG.errornovo vira issue no GlitchTip sozinho, pelo appender do Logback — não há (nem se deve criar) chamada ao SDK no call-site. O que é ação do operador na ponta, e não falha do app, sai pelo logger…integradorclient.operador; o eco do dXp sai pelo…integradorclient.eco. Os dois ficam fora do appender, e oObservabilidadeLogbackTesttrava isso (decisão 0006).
Como compilar e testar localmente¶
Pré-requisitos, comandos do gate e recomendações de ambiente estão em como rodar.
Onde NÃO mexer sem ler antes¶
- Layout fixed-width (
zim): cada campo tem largura e escala fechadas com a equipe ZIM; os testes golden travam byte a byte. Mudança aqui é mudança de contrato. - Casamento envio↔retorno (
processo): por posição de linha no fluxo pied, por contador no encerramento de MDF-e. Divergência invalida o lote inteiro de propósito — nunca aplique resultado desalinhado. Duas tolerâncias, ambas para defeitos dopAbastem conflito: os começos de tentativa abortada que ele deixa antes da rodada final e o eco da linha de continuação no fim do retorno (contrato §4, salvaguardas do reinício e do eco) — não as alargue sem a equipe ZIM. - Coleta por remessa (
processo): o cliente lê as flags que o servidor calcula; ele não deduz dependência entre tabelas (decisão 0004).