Implantação — integração Maxsul (PIED)¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-09-08
Como os quatro componentes da integração PIED → X-Adm da Maxsul ficam de pé, como se confere que subiram e como se desligam — hoje em staging. Traz também a config para um dev da XADM rodar os clientes no VSCode.
O desenho — arquitetura, fluxo de processamento, modelo de dados, contratos — é do livro: Documentação Completa, e o porquê do fluxo de entrada está na decisão 0013. Aqui não se repete: o que é daqui é o que subir, com que variáveis, como conferir e como desligar.
Topologia de operação¶
PIED ──webhook/REST──▶ int-pied ──PUT/DELETE /api/v1/xadm──▶ Integrador
pied.maxsul.xadm.biz ◀──GET /api/v1/xadm/retorno── int.maxsul.xadm.biz
│ grava Postgres (db_maxsul)
▼
PowerSync ◀──replicação lógica── Postgres
ps.maxsul.xadm.biz
│ SQLite streaming
▼
clientes ps-java / ps-dart (réplica no ERP)
└──write-back status──▶ POST /api/v1/powersync (Integrador)
| Componente | Host | Recurso Coolify | Repo |
|---|---|---|---|
| Integrador | int.maxsul.xadm.biz |
App (Dockerfile) | integracao/integrador |
| int-pied | pied.maxsul.xadm.biz |
App (Dockerfile) | clientes/maxsul/int-pied |
| PowerSync | ps.maxsul.xadm.biz |
Docker Compose | clientes/maxsul/powersync |
| Clientes | — (rodam no ERP / na máquina do dev) | — | clientes/maxsul/ps-java, ps-dart |
Banco: um Postgres, database db_maxsul (Postgres 18+ — o int-pied usa uuidv7()
nativo). Três papéis de conexão:
user_maxsul— usuário da aplicação; Integrador e int-pied conectam com ele e escrevem (o int-pied gerencia as tabelaspied_*com histórico Flyway próprioflyway_schema_history_pied; o Integrador é dono das tabelas-espelho e do Flyway principal). Ambos partilham o schemapublic.powersync_role— só leitura, com privilégio de replicação (WAL) — ver preparação do Postgres.
Convenção: staging agora, produção depois¶
Hoje estamos em staging: o operador entra no /console do int-pied e libera cada pedido à mão.
A promoção para produção é um conjunto de flags a virar — reunidas em
Promoção para produção. Todo passo abaixo já traz a coluna staging e a
nota do que muda em produção.
1. Integrador — int.maxsul.xadm.biz¶
Recurso App no Coolify, build do Dockerfile do repo integracao/integrador (Forgejo → Coolify).
Detalhe da config: application-config.md e deploy-coolify.md.
Coolify: porta interna 8080 · domínio int.maxsul.xadm.biz (TLS automático) · health check
GET /health.
Variáveis de ambiente:
| Variável | Valor (staging) | Nota |
|---|---|---|
CLIENTE |
maxsul |
Vira a tag cliente de todo evento GlitchTip (separa o tenant no projeto único). |
DATASOURCES_DEFAULT_URL |
jdbc:postgresql://<host>:5432/db_maxsul |
JDBC. |
DATASOURCES_DEFAULT_USERNAME |
user_maxsul |
Usuário-app da Maxsul. |
DATASOURCES_DEFAULT_PASSWORD |
(secret) | |
INTEGRADOR_API_TOKEN |
(secret — gerar 1 segredo forte) | Bearer estático de /api/**. Mesmo valor usado pelo int-pied e pelos clientes (uploadToken). Nome por destino (quem valida é o integrador), norma da constituição em engenharia/seguranca.md; detalhe local em Segurança. O nome antigo API_BEARER_TOKEN não é lido: app.api-token: ${INTEGRADOR_API_TOKEN:} não tem fallback, e setar só o antigo deixa o validador dormente (/api/** aberto) ou o boot recusado pela guarda da xadm-seguranca. |
SENTRY_DSN |
https://77e5b71d9213456caea902ec36aae742@bug.xadm.biz/16 |
DSN do projeto GlitchTip integrador (fonte: docs/app.json; igual em todo cliente). |
SENTRY_ENVIRONMENT |
staging |
Em produção → production. |
Sem MICRONAUT_ENVIRONMENTS (produção = application.yml + ENV). PUSH_* ficam desligados
(default false) — a Maxsul não usa FCM.
Migrations: o Flyway roda no start; garanta que o user_maxsul tem permissão de DDL no public.
2. int-pied — pied.maxsul.xadm.biz (staging)¶
Recurso App no Coolify, build do Dockerfile do repo clientes/maxsul/int-pied.
Config detalhada: clientes/maxsul/int-pied/docs/operacao/configuracao.md; modo staging:
ADR 0004-modo-staging-gate-manual.md do mesmo repo.
Coolify: porta interna 8080 · domínio pied.maxsul.xadm.biz · health GET /health.
Variáveis de ambiente:
| Variável | Valor (staging) | Nota |
|---|---|---|
DATASOURCES_DEFAULT_URL |
jdbc:postgresql://<host>:5432/db_maxsul |
Mesmo banco do Integrador (schema public, tabelas pied_*). |
DATASOURCES_DEFAULT_USERNAME |
user_maxsul |
|
DATASOURCES_DEFAULT_PASSWORD |
(secret) | |
PIED_TOKEN |
(secret — token da PIED) | Bearer da API PIED. Necessário para o poll e para as ações do /console que buscam na PIED. |
PIED_WEBHOOK_HABILITADO |
true |
Liga POST /webhook/pied. |
PIED_WEBHOOK_SECRET |
(secret do painel PIED, ou vazio) | Vazio = aceita sem validar (MVP). Cadastro do webhook na PIED é manual (ver abaixo). |
PIED_POLL_HABILITADO |
false |
Staging opera por webhook + console. Ligar (true) só com PIED_TOKEN válido. |
PIED_INTEGRACAO_HABILITADA |
true |
Liga a Fase 2 (transform + push ao Integrador). |
PIED_INTEGRACAO_MODO |
STAGING |
Chave do staging: transforma e enfileira (NA_FILA); nada vai ao Integrador até o operador liberar no /console. |
INTEGRADOR_BASE_URL |
https://int.maxsul.xadm.biz |
Base do Integrador (item 1). |
INTEGRADOR_API_TOKEN |
(o mesmo secret do item 1) | Bearer que o int-pied manda ao Integrador (integrador.token). Nome pelo destino, e é o mesmo nome dos dois lados: aqui é para quem eu falo, no item 1 é quem eu valido. |
PORT |
8080 |
(default) |
Não setar
SENTRY_DSN: o entrypoint do container lêdocs/app.json(projeto GlitchTip15) e exporta sozinho. Setar à mão fura a fonte única.
Cadastro do webhook na PIED (manual, uma vez): no painel da PIED, apontar o webhook para
https://pied.maxsul.xadm.biz/webhook/pied (com o header X-Pied-Secret = PIED_WEBHOOK_SECRET, se
definido).
Segurança:
/console,/capturae/test/glitchtipestão abertos, sem auth, e expõem PII e ações ao vivo (push ao X-Adm, fetch na PIED). Proteger (basic-auth do Coolify ou allowlist de IP) antes de expor fora da rede.
Operação em staging (o passo do operador): com pedidos na fila, abrir
https://pied.maxsul.xadm.biz/console e usar Processar próximo (libera 1, inspeção item a item)
ou Processar todos os pendentes. Cada item liberado vira PUT /api/v1/xadm no Integrador.
3. PowerSync — ps.maxsul.xadm.biz¶
Recurso Docker Compose no Coolify, repo clientes/maxsul/powersync (imagem
journeyapps/powersync-service:1.20.5, config assada na imagem — mudar powersync.yaml = rebuild).
Operação do dia a dia: clientes/maxsul/powersync/docs/operacao/runbook.md. Conceitos (volumes,
publicação, replica identity): powersync-docker.md e
powersync-runbook.md.
3.1. Preparar o Postgres origem (uma vez)¶
No db_maxsul, habilitar replicação lógica e criar o papel de leitura (detalhe completo e
pg_hba.conf em powersync-docker.md):
-- cluster (superusuário), uma vez
ALTER SYSTEM SET wal_level = logical; -- exige restart do Postgres
CREATE ROLE powersync_role WITH REPLICATION BYPASSRLS LOGIN PASSWORD '<senha_forte>';
-- em db_maxsul
GRANT CONNECT ON DATABASE db_maxsul TO powersync_role;
\c db_maxsul
GRANT USAGE ON SCHEMA public TO powersync_role;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO powersync_role;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO powersync_role;
CREATE PUBLICATION powersync FOR TABLE contratos, propriedades, fones, itensped, estoque, formulas,
integracao_remessa, integracao_remessa_item;
As tabelas-espelho nascem na Fase 2 do int-pied e as duas do manifesto de remessa na V27 do Integrador; até existirem, o PowerSync loga "tabela ausente" — não é incidente.
Instalação que já existe (
FOR TABLEcom lista antiga): o deploy da V27 exige um passo manual. Nenhuma migration toca a publication. Com lista explícita, as tabelas que a V27 cria ficam fora: o PowerSync nunca vêintegracao_remessa/_item, ointegrador-clientrecebe manifesto vazio, cai no caminho por presença — e a correção do "filho sem pai" fica inerte sem erro nenhum. Depois da V27 aplicada:-- confira primeiro: 't' = FOR ALL TABLES (nada a fazer; as tabelas novas entram sozinhas) SELECT puballtables FROM pg_publication WHERE pubname = 'powersync'; -- se 'f', veja a lista e adicione o que faltar SELECT tablename FROM pg_publication_tables WHERE pubname = 'powersync'; ALTER PUBLICATION powersync ADD TABLE integracao_remessa, integracao_remessa_item;(
ADD TABLEnuma publicationFOR ALL TABLESdá erro — por isso a conferência vem antes.) É o mesmo passo quebaixa-mdfe-sascar.mdjá manda para a tabelamdf. Esta lista também estava semformulas, que produção comprovadamente replica (os logs do incidente de 08/09 mostram o coletor processandoformulas) — ou seja, produção não está como este doc dizia; a conferência acima é o que vale, não o doc. Ostaging/e2e-maxsul-pied(tests) mede isso sozinho:0-pull-dump -Checarreporta a publication de produção e o3-verifyreprova se o manifesto estiver fora. Tabelas sem PK que entram na publicação precisam deREPLICA IDENTITY(ver powersync-docker.md).
3.2. Variáveis de ambiente (secrets do recurso Coolify)¶
| Variável | Valor | Nota |
|---|---|---|
PS_DATA_SOURCE_URI |
postgresql://powersync_role:<senha>@<host>:5432/db_maxsul |
URI postgresql:// completa (não JDBC); @ na senha → %40. |
PS_MONGO_URI |
mongodb://psadmin:<senha>@mongo-maxsul:27017/powersync_maxsul?authSource=admin&directConnection=true |
Host = nome do serviço (mongo-maxsul); senha SEM @ nem :. |
MONGO_ROOT_USER |
psadmin |
Igual ao user embutido em PS_MONGO_URI. |
MONGO_ROOT_PASSWORD |
(secret) | Igual à senha embutida em PS_MONGO_URI. |
SERVICE_FQDN_POWERSYNC / SERVICE_URL_POWERSYNC |
ps.maxsul.xadm.biz |
Magic vars do Coolify → domínio + labels Traefik. |
A auth dos clientes (client_auth com JWK inline) já vem no powersync.yaml — ver item 4.4.
3.3. Subir¶
Pelo Coolify (deploy do recurso) ou, no servidor:
docker compose up -d --build # config assada na imagem → sempre --build
docker compose logs -f powersync
Nunca docker compose down -v em produção (apaga mongo_storage/mongo_meta → resync total).
4. Clientes ps-java / ps-dart — rodar no VSCode¶
Não são apps de UI: são CLIs daemon que mantêm a réplica SQLite e fazem write-back. Ambos rodam
a partir de dist/ (onde estão a config *.properties e a chave maxsul-private.pem) — rodar de
outro diretório quebra o carregamento da chave. Guias no repo: LEIAME.md (operador) e
DESENVOLVIMENTO.md (dev).
4.1. ps-java (JDK 21+)¶
# extensão VSCode: "Extension Pack for Java"; deixar o Gradle sync rodar
./gradlew shadowJar # gera e copia o jar para dist/
cd dist && ./rodar.sh # (rodar.bat no Windows)
./gradlew run não funciona out-of-box (cwd errado, não acha a chave). Para debugar no VSCode,
criar um launch para a main br.com.xadm.maxsul.ps.Main com working directory = dist/.
4.2. ps-dart (Dart SDK ≥ 3.7, não Flutter)¶
# extensão VSCode: "Dart"
dart pub get
dart build cli -o dist/build # NÃO use `dart compile exe` (native assets do PowerSync)
cd dist && ./rodar.sh # ou, do fonte: cd dist && dart run ../bin/ps_dart.dart
Cópia Windows (
C:\Work\Xadm\ps-dart): o bundle fica emdist\bundle\e roda pordist\rodar.bat. Odist\ps-dart.propertieslá vai com os valores descomentados (override ativo) para ops_dart.exejá compilado funcionar sem recompilar.
4.3. Configuração (ps-java.properties / ps-dart.properties em dist/)¶
| Chave | Valor de produção | Nota |
|---|---|---|
powersync.syncUrl |
https://ps.maxsul.xadm.biz |
PowerSync (item 3). |
powersync.uploadUrl |
https://int.maxsul.xadm.biz/api/v1/powersync |
Write-back no Integrador. |
powersync.uploadToken |
(o INTEGRADOR_API_TOKEN do item 1) |
Bearer do POST de upload. |
powersync.privateKeyPath |
maxsul-private.pem |
Chave que assina o JWT (ver 4.4). Já é default. |
jwt.kid / jwt.audience |
maxsul-ps-v1 / maxsul |
Batem com o client_auth do PowerSync. Já são default. |
4.4. Autenticação dos clientes — JWT self-signed¶
Os clientes são programas sem usuário nem senha: não "logam", provam posse de uma chave. O
cliente assina um JWT curto com a chave privada maxsul-private.pem; o PowerSync valida contra a
chave pública correspondente, embutida inline no client_auth do powersync.yaml. Sem serviço
de auth, sem login — a chave privada é a credencial (como uma API key / service account). É o
padrão máquina-a-máquina, e já vem configurado por default nos dois clientes.
Como está montado (já feito):
- Par de chaves:
maxsul-private.pem(RSA 2048 PKCS#8) entregue nodist/de cada cliente, fora do git (.gitignore); a pública emclientes/maxsul/powersync/keys/maxsul-public.pem. - PowerSync (
clientes/maxsul/powersync/powersync.yaml) —client_auth.jwkscom a pública inline (kid: maxsul-ps-v1,audience: ['maxsul']). Inline em vez dejwks_uride propósito: o fetch por URL doauth.xadm.bizdeu bug de rede em outras instâncias (vantroba/onpetro). - Clientes — defaults já apontam para a chave e os claims certos (
powersync.privateKeyPath=maxsul-private.pem,jwt.kid=maxsul-ps-v1,jwt.audience=maxsul,jwt.issuer=maxsul-ps,jwt.subject=maxsul-ps-{java,dart}).
O que o operador/dev precisa fazer: garantir que a maxsul-private.pem está no dist/ do cliente
(entregue fora do git) e que o PowerSync foi rebuildado com o powersync.yaml atual
(docker compose up -d --build — config assada na imagem). Rodar o cliente → sincroniza sem 401.
Rotação de chave: gerar novo par
(openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048), trocar o n e o kid no
powersync.yaml, atualizar maxsul-private.pem/jwt.kid no cliente, rebuild do PowerSync. Sintoma de
chave/audience errados: 401 PSYNC_S2101 no cliente.
Segurança: quem tiver a
maxsul-private.pememite token válido. Mantê-la fora do git (já no.gitignore), entregar por canal seguro, rotacionar okidse vazar.
Superfície de operação¶
O que o operador olha, depois de implantado:
https://pied.maxsul.xadm.biz/console— a fila de pedidos: o que foi capturado, o que estáNA_FILA, o que foiENVIADO/confirmado, e as ações (liberar, reenviar, reconciliar).https://pied.maxsul.xadm.biz/console/{code}— detalhe de um pedido, com o de-para dry-run.https://int.maxsul.xadm.biz/— as telas do integrador (tabelas-espelho, requests, debug).GET /healthnos três serviços; logs do PowerSync no Coolify.
Pedido preso em 1XX (erro terminal) — re-armar¶
1XX é terminal: o integrador-client só coleta linha com cod_retorno em 000 ou 9XX, e o
upsert do PUT preserva o retorno por regra (mão única — senão o re-push de rotina apagaria o
retorno de pedido já gravado no ERP). Resultado: Reimportar no painel do PIED não destrava um
1XX, por mais vezes que se clique — os pushes chegam e são aplicados, e o cod_retorno continua
o mesmo.
O botão Reimportar do painel do int-pied já faz o certo desde 2026-09-08: push do pedido
primeiro (dado fresco no espelho), re-armar depois. Use-o. O curl abaixo é o mesmo comando na
mão, para diagnóstico ou quando o painel está fora do ar — e sempre depois de o dado
corrigido já ter subido, senão o cliente coleta a linha com o valor velho.
curl -fsS -X POST \
-H "Authorization: Bearer $INTEGRADOR_API_TOKEN" \
"https://int.maxsul.xadm.biz/api/v1/xadm/retorno/pedido/reenfileirar?chave=260079421"
# → {"xPed":"260079421","contratos":1,"itensped":3,"formulas":2,"total":6}
Volta a 000 todos os itens em 1XX da remessa daquele pedido — as seis tabelas, inclusive o
pai (propriedades/fones/estoque). 006 (já no ERP) e 9XX (retenta sozinho) ficam
intactas, e linha soft-deletada não entra na conta.
O parâmetro passou a ser chave (o xPed segue valendo como alias), e ele aceita também o
cgc_cpf de uma remessa de cadastro de cliente. Consulte antes o que está travado:
curl -fsS -H "Authorization: Bearer $INTEGRADOR_API_TOKEN" "https://int.maxsul.xadm.biz/api/v1/integracao/remessas?origem=INT-PIED&status=TRAVADA"
A resposta traz, por remessa travada, os itens em 1XX com bloqueado. A causa real é a mensagem
do item NÃO bloqueado — os bloqueados são colaterais do pai morto, e reportá-los faz o operador
perseguir o sintoma errado. total: 0 significa
"não havia nada preso", não falha. Confirmar no ciclo seguinte pelo dXpEnvio novo no
integrador-client.log. Contrato completo em
Contratos do integrador.
Se total vier certo mas a linha voltar para 1XX no ciclo seguinte, não é o re-armar que falhou:
é o write-back do cliente carimbando o mesmo erro de novo — o dado na origem continua errado.
Não é mais fora de escopo: propriedades/fones/estoque presas em 1XX são alcançadas pelo
re-arme desde o manifesto de remessa — era o beco que deixava pedido travado sem saída.
Cadastro em 006 com dado corrigido — re-arme manual (caso 260081441)¶
Desde a revisão 2026-09-17 da decisão 0023, um
PUT com dado diferente rearma sozinho a linha 006 de propriedades/fones/estoque.
Mas PUT passado não se repete (caminho só de ida): para a linha que já está corrigida no espelho e
parada no 006 — como a do cliente abaixo — o re-arme é SQL na mão, depois de alinhar com a
equipe X-Adm o que o pAbast faz com o código 0 existente:
UPDATE propriedades
SET cod_retorno = '000', msg_retorno = NULL, updated_at = now()
WHERE TRIM(cgc_cpf) = '34586067934' AND TRIM(cod_retorno) = '006';
No ciclo seguinte o client coleta a linha e o dXpEnvio sai com o endereço corrigido. Conferir
pelo integrador-client.log (envio N: | ...propriedades ...).
Pedido lançado à mão no X-Adm — fechar a remessa¶
Há travamento que reenviar não resolve: o produto-kit que o ERP não criou, por exemplo. O operador
lança o pedido direto no X-Adm, e a remessa tem de ser fechada, não re-armada. O botão
"Importado manualmente" do painel do maxsul-pied faz isso. O curl abaixo é o mesmo comando na
mão:
curl -fsS -X POST \
-H "Authorization: Bearer $INTEGRADOR_API_TOKEN" -H "Content-Type: application/json" \
-d '{"observacao":"Lançado manualmente no X-Adm: kit sem produto.","operador":"fulano"}' \
"https://int.maxsul.xadm.biz/api/v1/integracao/remessas/resolver-manual?origem=INT-PIED&chave=260079421"
# → {"chave":"260079421","resolvidas":1}
A remessa vai de TRAVADA a RESOLVIDA_MANUAL, e a observação fica gravada nela. As linhas 1XX
não mudam. Só TRAVADA pode ser fechada: ABERTA dá 409, porque ainda está em entrega.
Depois disso, o re-arme daquela chave responde 409, porque reenviaria ao ERP o que já foi
lançado. Não há comando que desfaça a resolução; se precisar, é SQL na mão. Decisão:
0025.
Verificações pós-deploy¶
Cada passo declara o resultado esperado conferido no código, não o que parece razoável.
| Host | Como verificar | GlitchTip |
|---|---|---|
int.maxsul.xadm.biz |
GET /health → {"status":"UP","versao":"X.Y.Z"} (shape do HealthController; o status:"ok" é do /api/health, outro endpoint — não confundir). Provocar um erro controlado (requisição inválida a /api/** que gere log.error) e conferir o evento no projeto integrador filtrando pela tag cliente=maxsul. |
✅ projeto 16 |
pied.maxsul.xadm.biz |
GET /health → 200. Smoke do GlitchTip: POST https://pied.maxsul.xadm.biz/test/glitchtip → evento no projeto 15. |
✅ projeto 15 |
ps.maxsul.xadm.biz |
GET /probes/liveness → 200 + docker compose logs -f powersync sem erro de conexão. |
⚠️ não reporta — a imagem journeyapps não tem GlitchTip (glitchtip.enabled:false). Verificação é liveness + logs, por decisão. |
Fumaça do fluxo de entrada (staging): liberar um pedido no /console → o int-pied dá
PUT /api/v1/xadm no integrador → o pedido vira ENVIADO e a linha aparece na tabela-espelho.
Repetir o envio do mesmo pedido, sem mudança, → resultado PULADO, não um novo PUT: o
PushService compara o content_hash do payload antes de enviar (dirty-check de conteúdo). Um
segundo PUT aqui seria sintoma, não normalidade.
Reversão — desligar a integração sem derrubar o X-Adm¶
O int-pied descobre pedido por duas vias independentes (webhook e poll) e empurra ao integrador
por três caminhos: os dois jobs @Scheduled (transform e reconciliação) e o clique do
operador no /console. Desligar uma flag não para os envios:
| Caminho | Efeito |
|---|---|
| Parar o container do int-pied (Coolify) | Para tudo. Mais simples e garantido — prefira este |
PIED_INTEGRACAO_HABILITADA=false |
Para os dois jobs (TransformJob, ReconciliacaoJob). ⚠️ Não para o /console: POST /console/{code}/enviar, /reenviar e /enviar-todos chamam o PushService sem passar pela flag — e o /console está aberto, sem auth. Um clique ainda empurra ao X-Adm |
PIED_WEBHOOK_HABILITADO=false |
⚠️ Não desliga — corta só a recepção pelo webhook; o que já está capturado segue processável, e o poll (se ligado) segue trazendo pedido novo |
PIED_POLL_HABILITADO=false |
⚠️ Não desliga — o webhook segue recebendo (é o default true) |
PIED_INTEGRACAO_MODO=STAGING |
⚠️ Não desliga — só troca envio automático por manual; o operador segue empurrando pelo /console |
| Parar o container do integrador | Para a entrada no X-Adm, mas o int-pied segue capturando e acumulando falha de push (ERRO) |
Desligar de verdade, mantendo as telas no ar: PIED_INTEGRACAO_HABILITADA=false e bloquear
o /console (auth/allowlist no Coolify). Sem as duas, a via manual continua aberta.
Em qualquer caso a PIED segue postando no webhook (ou o poll acumula), e o atraso sai quando religar — nada se perde.
Reverter versão: redeploy da tag anterior no Coolify. As migrations do int-pied (pied_*, com
histórico Flyway próprio) e as do integrador são aditivas — reverter o container não desfaz schema.
Promoção para produção¶
Quando sair de staging, virar (na ordem):
- int-pied —
PIED_INTEGRACAO_MODO=PRODUCAO(push automático, sem gate no/console);PIED_POLL_HABILITADO=true(comPIED_TOKENválido) se quiser o backstop REST; confirmarPIED_WEBHOOK_SECRETreal com a PIED. - int-pied — proteger
/console,/captura,/test/glitchtip(auth/allowlist). Não é só PII: enquanto o/consoleestá aberto, ele é uma via de push ao X-Adm que nenhuma flag corta (§ Reversão). - Integrador —
SENTRY_ENVIRONMENT=production. - Clientes —
maxsul-private.pemde produção entregue nodist/e PowerSync rebuildado com o JWK inline (item 4.4). Trocar a chave dev-only por uma chave de produção, se ainda não feito.
Pares que têm de casar (segredos compartilhados — não commitar)¶
Valor que existe nos dois lados e diverge em silêncio é falha de implantação que só aparece depois, em produção. Enumerados:
| Ponta A | Ponta B | Sintoma se divergirem |
|---|---|---|
INTEGRADOR_API_TOKEN (integrador, define) |
INTEGRADOR_API_TOKEN (int-pied) |
PUT /api/v1/xadm responde 401; o pedido fica ERRO no /console, nada entra no espelho |
INTEGRADOR_API_TOKEN (integrador) |
powersync.uploadToken (ps-java / ps-dart) |
write-back do status responde 401; o ERP replica mas nunca confirma — o pedido trava em ENVIADO |
Senha do powersync_role (Postgres) |
PS_DATA_SOURCE_URI |
PowerSync não conecta na origem; sem replicação, cliente não recebe nada |
MONGO_ROOT_PASSWORD |
senha embutida em PS_MONGO_URI |
PowerSync sobe e falha no storage; /probes/liveness denuncia |
maxsul-private.pem (dist/ dos clientes) |
JWK público inline no powersync.yaml |
401 PSYNC_S2101 no cliente (ver 4.4) |
PIED_WEBHOOK_SECRET (int-pied) |
header X-Pied-Secret cadastrado no painel PIED |
webhook rejeitado — a PIED para de entregar e a captura fica só no poll (se ligado) |
A chave privada maxsul-private.pem fica fora do git (.gitignore) e é entregue por canal
seguro; quem a tiver emite token válido.
Referências¶
- Config do Integrador: application-config.md · deploy-coolify.md
- Observabilidade (tag
cliente): observabilidade.md - PowerSync (Postgres/volumes): powersync-docker.md · powersync-runbook.md
- int-pied:
clientes/maxsul/int-pied/docs/operacao/configuracao.md· ADR0004-modo-staging-gate-manual.md - PowerSync Maxsul:
clientes/maxsul/powersync/docs/operacao/runbook.md - Clientes:
clientes/maxsul/ps-java/DESENVOLVIMENTO.md·clientes/maxsul/ps-dart/DESENVOLVIMENTO.md