Plataforma de Integração¶
A Plataforma de Integração é como os dados se sincronizam dentro do ecossistema X-Adm — trazer dados do ERP para a nuvem, devolvê-los ao ERP, ou enviar dados a terceiros.
- Tem como seu ponto central a aplicação tipo Servidor, rodando na nuvem, onde o banco de dados espelha o banco de dados do X-Adm (apenas tabelas e colunas necessárias, não um espelhamento 100% completo). Toda a integração de dados passa por esse servidor, onde cada cliente tem o seu servidor com seu banco de dados.
- Aliado a isso, cada cliente ou terceiro pode ter seu aplicativo próprio, desenvolvido de acordo com a sua necessidade.
Norma × detalhe
A norma está na constituição §8. Aqui, o contrato operável. O desenho concreto (inventário, roadmap, decisões D0–D13) e o que ainda está em fluxo vivem na arquitetura-alvo, no repo do integrador.
Topologia¶
Na figura e na taxonomia, Plataforma de Integração nomeia o serviço central por cliente
(int.<cliente>).
A figura é a norma em 4 grupos: cliente (servidor X-Adm no cliente: ERP X-Adm + Integrador Cliente, que faz a ponte com a nuvem) — nuvem X-Adm (Wiechert) (Plataforma de Integração, apps específicas, apps compartilhados, banco por cliente) — terceiros (parceiros externos) — usuários (apps consumidor Web e Mobile, que rodam no dispositivo do usuário final, não na nuvem).
¹ Um banco de dados por cliente.
Nota: apps consumidor (Web e Mobile) bem como o programa Integrador Cliente escrevem de volta à
Plataforma de Integração via write-back do PowerSync (campo editável → uploadData →
connector → a Plataforma de Integração grava nas tabelas que ela possui) — é a aresta
write-back da figura, correndo por fora.
Fonte da figura (Mermaid-base)
A figura acima é um SVG desenhado à mão (assets/topologia-integracao.svg) derivado deste
Mermaid, que é a fonte semântica: mudou a topologia, atualize AQUI primeiro e espelhe no SVG.
block-beta
columns 3
space
block:cli
columns 1
clit["Servidor X-Adm Cliente"]
erp["ERP X-Adm"]
intc["Integrador Cliente"]
end
space
block:ter
columns 1
tert["Terceiros"]
pi["PIED"]
ec["E-commerce"]
sa["Sascar"]
end
block:nuv:2
columns 2
nuvt["Nuvem X-Adm (Wiechert)"]:2
vert["Apps Específicas<br/>pied.<cliente>.xadm.biz<br/>excel.<cliente>.xadm.biz<br/>ecommerce.<cliente>.xadm.biz"]
hub["Plataforma de Integração<br/>int.<cliente>.xadm.biz<br/>ps.<cliente>.xadm.biz"]
vs["Apps Compartilhados<br/>sascar.xadm.biz"]
pg[("PostgreSQL Cliente ¹")]
end
space
block:usr
columns 2
usrt["Usuários"]:2
appweb["App Web<br/>bi.<cliente>.xadm.biz"]
appmob["App Mobile<br/>App Android/Apple"]
end
space
erp <-- " " --> intc
intc -- "push tempo real + write-back" --> hub
intc -- "batch XLSX" --> vert
pi -- "webhook + pull" --> vert
sa -- "pull (MDF-e, odômetro)" --> vs
vert -- "push" --> ec
hub <-- "REST" --> vert
hub <-- "REST (baixa MDF-e, odômetro)" --> vs
hub <-- " " --> pg
vert <-- " " --> pg
vs <-- " " --> pg
pg -- "PowerSync" --> usr
pg -- "PowerSync" --> intc
usr -- "write-back" --> hub
Fluxos principais¶
Três fluxos contam a plataforma em movimento — cada um com como acompanhar: o mecanismo pelo qual um humano vê se o fluxo rodou ou falhou.
Fonte das figuras (Mermaid-base)
Mesma regra da topologia: mudou um fluxo, atualize AQUI primeiro e espelhe no SVG do
fluxo (assets/fluxo-saida.svg, assets/fluxo-entrada.svg, assets/fluxo-ciclo-mdfe.svg).
flowchart TB
subgraph f1["Saída — X-Adm → Usuários"]
direction LR
erp1["ERP X-Adm"] --> int1["Integrador Cliente"]
int1 -- "tempo real" --> plat1["Plataforma de Integração"]
int1 -- "batch XLSX" --> excel1["excel.<cliente>"]
plat1 --> pg1[("PostgreSQL")]
excel1 --> pg1
pg1 -- "PowerSync" --> web1["App Web"]
pg1 -- "PowerSync" --> mob1["App Mobile"]
end
subgraph f2["Entrada — Externo → X-Adm"]
direction LR
pied2["PIED (parceiro)"] -- "webhook + pull" --> app2["pied.<cliente>"]
app2 -- "grava PEDIDO" --> pg2[("Plataforma de Integração<br/>(PostgreSQL Cliente)<br/>estado-desejado")]
pg2 -- "PowerSync" --> int2["Integrador Cliente"]
int2 -- "importa (zimrtmu)" --> erp2["ERP X-Adm"]
int2 -. "devolve status IMPORTADO/ERRO" .-> pg2
end
subgraph f3["Ciclo completo — MDF-e"]
direction LR
erp3["ERP X-Adm"] --> int3["Integrador Cliente"]
int3 -- "push" --> plat3["Plataforma de Integração"]
plat3 -- "MDF-e aberto (chave, placa)" --> sas3["sascar.xadm.biz"]
sas3 -- "polling" --> ter3["Sascar (parceiro)"]
sas3 -. "devolve encerrado" .-> plat3
plat3 -. "espelho atualizado → PowerSync" .-> int3
int3 -. "importa no ERP" .-> erp3
end
f1 ~~~ f2
f2 ~~~ f3
Organiza-se por tipo de fluxo, não por cliente¶
A lógica é que tudo o que é espelho do X-Adm segue o padrão para todos os clientes. O que diverge
(aplicações específicas para cliente, integrações com terceiros) fica em aplicativo dedicado. Desta
forma mantemos a plataforma central (int.<cliente>) independente, sendo possível evoluir tanto a
plataforma como desenvolver aplicações específicas de maneira independente umas das outras.
Taxonomia¶
| Papel | O que é | Recebe de fora? | Dono de | Exemplos |
|---|---|---|---|---|
| Plataforma de Integração | A cópia fiel do banco do X-Adm por cliente (réplica do push + dado bruto do ERP) e o connector do PowerSync. Uma por cliente. | Só o X-Adm (push/agente) | réplica + auditoria | int.<cliente> (o integrador, estreitado a este papel) |
| App específico | Serviço específico que recebe de fora, faz o específico do cliente e escreve as suas tabelas. Pode enviar dados para um terceiro ou para o X-Adm. Um por cliente. | Sim | suas tabelas (bi_*, estado-desejado) |
excel.<cliente> (XLS), pied.<cliente> |
| App compartilhado | Serviço multi-tenant — 1 instância, N clientes; roteia por cliente na entrada. Nasce quando o parceiro é o mesmo para todos (não faz sentido replicar por cliente). Não escreve no barramento diretamente — conversa com a Plataforma de Integração, que grava no espelho do cliente certo. Detalhe em decisão 0018. | Sim (webhook do parceiro + chamadas da Plataforma de Integração de cada cliente) | próprio banco de trabalho (cadastro por cliente, credenciais, log de polling) | sascar.xadm.biz |
| App consumidor | O que o usuário final usa (Web ou Mobile); lê via PowerSync, escreve só campos editáveis (uploadData → connector da Plataforma de Integração). |
Não (não é integração) | nada / write-back de campo | bi.<cliente> (Web), Mobile App do cliente |
Os 4 tipos de fluxo¶
A Plataforma de Integração recebe só o tipo 1 (a cópia fiel). Os tipos 2 e 3 entram pelo
app específico. O tipo 4 sai de um app específico que recebe da Plataforma
de Integração via REST e faz POST no parceiro.
- Push X-Adm em tempo real — o X-Adm envia eventos (nota, BL, pedido) por push HTTP direto à Plataforma de Integração, que aplica na réplica. Genérico, igual para todos. (hoje: o integrador.)
- Batch de arquivo (XLSX/CSV) — o X-Adm exporta um relatório; o agente entrega o arquivo ao
app específico dono (
excel.<cliente>), que faz a recepção (dedupe/envelope), parseia e escreve as suas tabelas (bi_*). Divergente por cliente. (hoje: os-xls.) - Pull/webhook de API externa → formato X-Adm (entrada) — o app específico (
pied.<cliente>) recebe webhook + faz polling na API na sua porta, transforma para o formato do ERP e grava o estado-desejado (tabelas sem prefixo, com máquina de status por linha). Um cliente Java do lado do ERP importa e devolve o status. (novo: PIED.) - Push para API externa (saída) — um app específico (
ecommerce.<cliente>) recebe da Plataforma de Integração via REST (POST /sync/erpno contrato do app), transforma e fazPOSTnuma API de terceiro; é dono da sua tabela de status (idempotência por chave natural). (novo: thoms → WebStorm.)
Combinação ③+④ num app compartilhado. Quando o parceiro é global (mesmo endpoint para
todos os clientes), os dois tipos convivem num único app multi-tenant — recebe da Plataforma de
Integração (dado que vai para o parceiro) e devolve a ela o retorno do parceiro. A Plataforma de
Integração escreve no espelho do cliente certo; o app compartilhado nunca escreve no barramento
(para não virar segundo dono). (novo: Sascar — a Plataforma de Integração envia MDF-es abertos
com chave/placa; o app compartilhado faz polling na Sascar do cliente com credenciais próprias;
quando o motorista chega ao destino, devolve encerrado à Plataforma de Integração, que atualiza
o status do MDF-e; o cliente Java lê via PowerSync e importa no ERP. Ver
decisão 0018.)
Reator — reservado para uso futuro
Uma versão anterior desta norma listava Reator como 5º papel: serviço que não recebia de
fora e consumia o banco via PowerSync para enviar a terceiros. O único caso concreto — thoms
→ e-commerce — não usa PowerSync (o servidor não o consome; o transporte é POST /sync/erp da
Plataforma de Integração para o próprio app), então virou app específico
(ecommerce.<cliente>). O papel Reator
fica reservado para casos futuros de notificação (email, push, alertas Telegram) — quando
aparecer, volta à taxonomia com definição própria.
Fronteiras e owner-writes¶
O Postgres por cliente é o barramento: cada peça escreve as suas tabelas e lê o resto via PowerSync. Um dono por tabela (quem roda o Flyway e escreve) — o ponto de integração é o banco, não um dispatcher na Plataforma de Integração. O invariante server-side está em Java/Micronaut §Banco.
A convenção de nome de tabela é a propriedade do dado:
| Prefixo | Significa | Sincroniza p/ apps? | Dono típico |
|---|---|---|---|
| (sem prefixo) | dado do ERP (é, ou vira, dado do X-Adm) | Sim | Plataforma de Integração (réplica) · app específico (estado-desejado) |
<dominio>_ |
derivado do processamento, consumido por app | Sim | app específico (bi_*) |
<app>_ |
controle interno (staging, tabela de status por chave natural) | Não | app específico (xls_*, thoms_envio) |
Um app específico que envia para fora (tipo ④) nunca marca estado numa coluna da tabela-espelho
(isso daria dois donos à réplica) — tem a sua tabela de status (<app>_envio), separada.
Dentro da tabela-espelho, a fidelidade é por coluna. O prefixo diz de quem é a tabela; dentro
de uma tabela-espelho (sem prefixo), o que rege cada coluna é: o espelho modela a entidade do
X-Adm, não a do parceiro. A identidade (chave de negócio, critério de join) vive sempre em
coluna nativa do X-Adm, conferida contra a spec de entidades do ERP. Um campo que só existe no
vocabulário da fonte externa (ex. codigo_alt, x_ped de um parceiro) entra prefixado pela origem
e é só rastreabilidade:
| Coluna | Origem | Papel | Vira identidade/join? |
|---|---|---|---|
| (sem prefixo, nativa) | modelo do X-Adm | identidade, join, negócio | Sim |
<origem>_<campo> |
sistema externo (ex. pied_x_ped) |
rastreabilidade / transporte | Não |
A coluna <origem>_ sincroniza como o resto da tabela (a tabela é sem prefixo), mas o consumidor a
lê para auditar, nunca para casar registros. Deixar a chave do parceiro virar identidade de 1ª
classe acopla o espelho ao vocabulário de um terceiro — o oposto de "cópia fiel do X-Adm"
(decisão 0009).
Transporte X-Adm↔nuvem (padrão único por direção)¶
Muda o processamento e o destino, nunca o transporte:
- Saída — tempo real: push HTTP direto à Plataforma de Integração (o
/api/v1/xadmde hoje). Contrato legado: responde sempre 200, erro no corpo. - Saída — arquivo/lote: o X-Adm grava numa outbox local; um agente
.jargenérico observa a pasta (~1 min) e envia à nuvem, roteando por tipo (config, não código): dado bruto do ERP → a Plataforma de Integração; relatório → o app específico dono. O X-Adm fica desacoplado do destino. - Entrada no ERP: a nuvem grava tabelas-espelho (sem prefixo, com status
PENDENTE→PROCESSANDO→IMPORTADO→ERRO) no banco do cliente; um cliente Java do lado do ERP conecta via PowerSync, lê oPENDENTE, importa chamando ozimrtmu.exe(runtime do ZIM) e escreve o status de volta. O mesmo contrato para qualquer fonte de entrada.
O transporte é PowerSync bidirecional (connector na Plataforma de Integração) para os apps consumidor (Web e Mobile) e para o cliente Java do lado do ERP; entre a Plataforma de Integração e apps específicos que enviam para fora, o transporte é REST (o servidor Java não consome PowerSync — ver 0018 e §Os 4 tipos, tipo ④). A tech (connector, write-back, auth, config do PowerSync) está em PowerSync.
Na direção inversa — quando um app chama outro via REST (o poke "algo mudou, vá puxar"; o
integrador ao app é o caso comum) — a rota do lado do chamado segue /api/<origem>/<recurso>, com
<origem> = o app chamador (/api/integrador/produto): auth uniforme (ROLE_API no /api/**) e
caminho previsível. E a env de auth/URL de cada aresta se nomeia pelo destino — <APP>_URL +
<APP>_API_TOKEN, um token por app chamado, mesmo valor no validador e em todos os callers — para
o mapa de segredo não colidir num app que é chamador e chamado ao mesmo tempo
(Segurança §Segredos ·
Java/Micronaut §Específico).
Arestas concretas (call-graph)¶
O diagrama e os fluxos acima nomeiam as famílias de aresta; esta tabela é o call-graph concreto server-server que a auditoria levantou — caller → callee, transporte, endpoint e auth por linha. Não é a topologia (essa é a figura); é o inventário do que fala com o quê hoje.
| Caller | Callee | Transporte | Endpoint (no callee) | Auth |
|---|---|---|---|---|
| ERP X-Adm (push) | Plataforma de Integração (int.<cliente>) |
HTTP push | PUT/DELETE /api/v1/xadm |
Bearer, 1 token por instância |
| Plataforma de Integração | app compartilhado (sascar.xadm.biz) |
REST | POST /api/integrador/mdfe/watch |
Bearer M2M (<CALLEE>_API_TOKEN) |
| app compartilhado (Sascar) | Plataforma de Integração | REST | POST /api/sascar/encerramento |
Bearer M2M, token-tenant (0018) |
| App novo (bootstrap) | Central (broker de setup) | REST | POST /api/setup/provision |
Bearer, token de serviço do broker |
| Integrador Cliente | pAbast (parceiro) | dXp (dXpEnvio/dXpRetorno) |
— (protocolo do parceiro) | credencial do parceiro |
Notas:
/api/<origem>/<recurso>— o poke leva o chamador no prefixo:/api/integrador/…é rota no app compartilhado, chamada pela Plataforma de Integração;/api/sascar/…é rota na Plataforma, chamada pelo app compartilhado (§Transporte, direção inversa · Java/Micronaut §Específico).- Status por caso — a aresta de push do ERP responde sempre 200 (erro no corpo, contrato legado que a fila exige); par app↔app novo sem PowerSync usa status HTTP real (decisão 0020).
- O detalhe exato de cada endpoint (schema do corpo, contrato) vive no repo dono do callee (§1.9) — aqui fica o mapa, não o contrato. A dXp/pAbast é da Fase 5 (integrador-client, amarrado ao ERP), fora deste escopo.
Concreto, roadmap e decisões¶
O inventário de projetos, os diagramas de ponta a ponta, o roadmap de migração e as decisões D0–D13 vivem na arquitetura-alvo do integrador — é o desenho volátil, que evolui no repo da integração sem tocar a constituição.