Pular para conteúdo

Documentação Completa — Integrador

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

O desenho do sistema no estado atual: o que é, como os dados fluem do ERP até o celular, quais são as entidades e como se autentica. Runbooks de operação estão em Operação; detalhes de código, em Dev; o histórico das decisões, em Decisões.

Sem manual de usuário — por quê

O Integrador é um serviço de integração backend (API REST + telas administrativas internas). Não há docs/manual/ (manual de usuário final) de propósito: o produto voltado ao usuário é o app móvel (repositório próprio), que consome este serviço via PowerSync/API. A experiência de usuário final é documentada lá, não aqui.

Componentes

  • X-Adm — ERP de mesa (base Zim) onde todos os dados nascem: o sistema-fonte da integração.
  • X-Adm Integração Java — agente on-premises que lê os arquivos JSON exportados pelo X-Adm e os encaminha via REST/HTTPS (com retry) ao Integrador.
  • Integrador — este repositório: servidor Micronaut / Java 25, uma instância por cliente (subdomínio por tenant atrás do Coolify/Traefik, porta 8080). Recebe REST, persiste no Postgres, emite push (FCM) e alimenta o PowerSync.
  • PostgreSQL por cliente — banco dedicado por tenant (Postgres 18+, uuidv7).
  • PowerSync (self-hosted) — Docker Compose por cliente (powersync/<cliente>/), cada um com seu MongoDB; lê o WAL do Postgres (replicação lógica, publicação powersync) e replica para o SQLite do app.
  • central-backend (central-backend.xadm.biz; auth.xadm.biz é o nome antigo, mantido como issuer/JWKS) — serviço central da casa: autenticação + JWKS (o Integrador não emite JWT próprio — ver decisão 0001) e destino do heartbeat do integrador-client que esta instância repassa (§ Heartbeat).
  • integrador-client (repositório próprio) — jar on-premise do cliente que faz o write-back pelo PowerSync e manda o heartbeat a esta instância (docs).
  • FCM (Firebase Admin Java) — push para o aplicativo.
  • Aplicativo Flutter (repositório separado) — SQLite/Drift local via PowerSync; mescla empresas no cliente.

Fluxo de dados

  1. O usuário age no X-Adm → o X-Adm gera um arquivo JSON, marcado com um código de Origem (PPEDAMX, PPEDIDO, PBLDI, PNOTAI, PNOTAD, PCSTPROD, PREQUIS).
  2. O agente X-Adm Integração Java envia a PUT/DELETE /api/v1/xadm com Authorization: Bearer <INTEGRADOR_API_TOKEN>. (Esse é o fluxo de saída, X-Adm → apps. Há também o fluxo de entrada — fonte externa PIED, Origem = INT-PIED, dado que volta ao X-Adm — no mesmo endpoint; ver decisão 0013.)
  3. O Integrador faz o parse e persiste no Postgres. Para JSON válido o endpoint sempre responde HTTP 200; o resultado vai no corpo ({requestId, resultado: SUCESSO|ERRO, mensagem}). HTTP 400 só para JSON malformado. Detalhe em tratamento de erros.
  4. Todo apply do XADM é serializado por um ReentrantLock(fair=true) global, para preservar a ordem DELETE→PUT do ERP e evitar deadlock no Postgres (40P01). Cada requisição é auditada na tabela request.
  5. O PowerSync acompanha o WAL e replica para o SQLite do celular (offline-first).
  6. Em notas de venda/entrada, o Integrador envia push FCM (ver payload FCM).
  7. Checagem de "banco parado": o app consulta o endpoint público GET /api/v1/powersync/lastchange.

Heartbeat do integrador-client

Uma instalação do integrador-client que para (máquina desligada, jar travado) só aparecia horas depois, como "a integração parou". O heartbeat torna isso visível sem acesso à máquina, passando por esta instância — o único destino que o firewall do cliente já libera:

  1. O integrador-client manda POST /api/v1/heartbeat (versão, fluxos, hostname) no startup e a cada 60 min, com o mesmo Bearer INTEGRADOR_API_TOKEN do write-back.
  2. Esta instância valida o corpo, carimba o cliente_id (env CLIENTE_ID — identidade do contexto, nunca do corpo) e repassa ao central-backend em POST {CENTRAL_URL}/api/integrador/heartbeat, Bearer CENTRAL_API_TOKEN. Não grava nada aqui.
  3. O central registra a instalação, alerta no GlitchTip quando ela passa de 6 horas úteis sem sinal e a mostra na aba Deploy do central-ui.

Contrato do salto client → aqui: heartbeat. O porquê (rota em dois saltos, contrato congelado, alerta por horas úteis): a decisão local 0028 do central-backend. Configuração: heartbeat na configuração.

Modelo de dados

As entidades de negócio e as tabelas de infraestrutura (request, pushenviada, pabast_*) estão descritas em Modelagem de dados. Toda tabela de negócio carrega a chave de negócio do X-Adm e um id UUID v7 surrogate, além de soft-delete (deleted, deleted_at).

Modelo de autenticação

  • /api/** → Bearer estático (INTEGRADOR_API_TOKEN no ambiente; sem fallback para o antigo API_BEARER_TOKEN); 401 se errado. Exceção pública: GET /api/v1/powersync/lastchange (sem PII, exigido no cold boot do app). Ver Segurança e /health.
  • Views server-side (/, MVC server-render JTE) → login Google/Firebase (domínio @xadm.com.br), SessionAuthenticationFetcher (lib xadm-seguranca) + ViewSecurityRule (policy local, micronaut-security) + cookie xadm_session (JWT HS256, 8h) e CSRF double-submit. /login, /health, /swagger/** públicos. Ver login Google e decisão 0005.
  • Nenhum JWT é emitido por este JAR (o login/JWT do pAbast foi removido — ver decisão 0001); o JWKS do PowerSync aponta para auth.xadm.biz.
  • Botões de edição da UI e /debug só ligam sob os perfis dev/test; em produção a UI é somente-leitura. Ver perfis Micronaut.

Configuração

application.yml (defaults de produção) + ENV do Coolify; application-dev.yml só com MICRONAUT_ENVIRONMENTS=dev (Postgres local :5432, Flyway clean-schema); testes usam application-test.yml. Não há application-prod.yml. O Sentry só inicializa com DSN válido em ambiente não-dev/test. Detalhe em Configuração.