Reset — recomeçar a integração do zero (Maxsul)¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-09-04
O que é¶
Procedimento para zerar a integração PIED → X-Adm e recomeçar limpo, sem inundar o X-Adm com inserts/updates. Serve quando uma mudança de identidade canônica ou de contrato exige recomeçar a base — ex.: a adoção do cliente do Faturamento (decisão 0009), que entra sem backfill nem re-envio dos pedidos existentes.
O desenho (arquitetura, fluxo) é do livro do projeto; como subir e desligar no dia a dia é de Implantação. Aqui está só o reset.
Por que não é só "apagar as tabelas"¶
O PowerSync sincroniza as 5 tabelas espelho (contratos, propriedades, fones, itensped,
estoque) para o cliente do X-Adm. Um resync completo re-snapshota a fonte: se a fonte ainda
tiver linhas velhas quando o PowerSync subir, elas viram um flood de escrita no X-Adm. Também há o
lixo do espelho antigo — propriedade/estoque/fone sem contrato no X-Adm não vem do
maxsul-pied (que só envia por pedido, no PushService.enviarPedido), e sim de um snapshot
anterior que não foi esvaziado.
Chave anti-flood: esvaziar a fonte ANTES de o PowerSync subir fresh, com o cliente do X-Adm parado. Fonte vazia + cliente parado = zero flood.
Pré-requisitos¶
- Acesso ao Coolify da Maxsul (recursos
pied.maxsul,integrador.maxsul,powersync.maxsul+ o Postgres compartilhado). - Acesso ao repo do PowerSync (
maxsul/powersync) e ao cliente do X-Adm (integrador-client). - Secrets no cofre da X-Adm (nunca neste doc):
PS_*,MONGO_ROOT_*, credenciais do Postgres. - Backup antes de apagar (
pg_dumpdo banco do cliente).
Topologia (o que existe)¶
- 1 Postgres compartilhado, 1 banco por cliente. O do Maxsul contém
pied_*e as tabelas espelho do Integrador (schemapublic), com dois históricos Flyway (o do pied e o do Integrador). - PowerSync (Maxsul): storage em MongoDB (dois volumes: estado do bucket + metadados). A config está assada na imagem — matar o disco do Mongo não perde config. Lê da fonte via replication slot + publication no Postgres (o slot vive no Postgres, não no Mongo). Sincroniza só as 5 espelho.
- Cliente do X-Adm =
integrador-client: consome o PowerSync e escreve no ZIM em lotes.
Passo a passo¶
Ordem importa — cada passo evita um modo de flood do seguinte.
- Parar quem escreve. Pare o
pied.maxsule ointegrador.maxsul(para o push por pedido) e pare o clienteintegrador-client(para a escrita no ZIM). - Backup.
pg_dumpdo banco do cliente (fonte da verdade antes de apagar). - Parar o PowerSync (
powersync.maxsul). - Esvaziar a fonte com
DELETE, nuncaTRUNCATE(por quê no fim deste doc): as 5 tabelas espelho + aspied_*.DELETE, nãoDROP TABLE— o drop quebra a publication e o Flyway do Integrador sem ganho. ⚠️ Reseede os singletons logo em seguida (abaixo): há tabelapied_*cuja linha única é semeada pela migration, e oDELETEa leva junto. - Matar o storage do PowerSync (
docker compose down -v, ou remover só os volumes do Mongo se o Coolify já removeu o container no Stop). Não exclua o recurso Coolify — isso perde os secretsPS_*/MONGO_ROOT_*. - Dropar o replication slot órfão no Postgres, de forma idempotente — só os inativos:
SELECT pg_drop_replication_slot(slot_name) FROM pg_replication_slots WHERE database = '<banco_do_cliente>' AND NOT active; - Subir apps + PowerSync fresh. Suba
pied.maxsul/integrador.maxsule redeploy dopowersync.maxsul(Mongo vazio → snapshot de uma fonte vazia, sem flood). - Semear o cursor da PIED para não re-puxar o histórico:
pied_cursorcom a data de hoje. E reseedar os singletons apagados no passo 4 (ver abaixo). - Zerar o cliente do X-Adm.
disconnectAndClearnointegrador-client(limpa o SQLite local) e religue.
Singletons semeados por migration (reseedar depois do DELETE)¶
Nem toda tabela pied_* é só dado: algumas têm uma linha fixa semeada pela migration, e o código
a atualiza com UPDATE ... WHERE id = 1. Se o DELETE do passo 4 leva a linha e ninguém reseeda, o
UPDATE afeta 0 linhas — falha silenciosa, sem erro no log.
-- pied_integracao_estado (V4): corte go-forward. Reseedar após o DELETE das pied_*.
INSERT INTO pied_integracao_estado (id) VALUES (1) ON CONFLICT (id) DO NOTHING;
Hoje é inerte, não deixe enganar. Desde a revisão do gate (2026-08-07) quem manda no envio é a transição de pagamento no upsert; o corte go-forward ficou sem chamador, e o código que o gravava saiu na migração para
micronaut-data(2026-09-11). A tabela ficou — só oGET /dados/estadoa lê; dropá-la é DDL destrutivo, decisão à parte (expand/contract). A linha ausente não trava envio nenhum — mas deixaGET /dados/estadovazio, o que atrapalha o diagnóstico (já custou uma investigação, 2026-09-04). Reseede.
Ao criar um singleton novo (INSERT ... VALUES (1) numa migration), acrescente-o aqui no mesmo
PR — senão o próximo reset o apaga em silêncio.
Variante: reset só-envio (mantém o raw)¶
Usada na ida pra produção (2026-09-04): recomeçar o envio do zero sem perder a captura
raw já feita (evita re-puxar meses de PIED). Zera o lado X-Adm e a fila, mantém
pied_webhook, pied_rest, pied_cliente, pied_produto e o payload do pied_pedido. É o
reset total menos o DELETE das pied_* — no lugar dele, reseta a máquina de entrega.
Mesma ordem e mesmos cuidados do passo a passo acima (parar escritores → backup → parar PowerSync →
mexer no Postgres → matar Mongo → dropar slot → subir fresh → disconnectAndClear). Só o passo 4
muda, e o passo 8 (semear cursor) não se aplica — mantendo o raw, o cursor continua de onde
parou (reseedar arriscaria pular pedidos atualizados no intervalo).
Passo 4 (variante) — DELETE nunca TRUNCATE:
BEGIN;
-- (a) Espelho X-Adm: esvazia a FONTE antes do PowerSync subir fresh (anti-flood).
DELETE FROM estoque; DELETE FROM itensped; DELETE FROM fones;
DELETE FROM propriedades; DELETE FROM contratos;
-- (b) Outbox M2M: mata o dispatch pendente/enviado do push. 'xadm-push' é o ÚNICO tipo do PIED
-- (PushEnviador.TIPO); o write-back do X-Adm volta na resposta HTTP, NÃO cria linha ENTRADA.
DELETE FROM mensagem_m2m WHERE tipo = 'xadm-push';
-- (c) Reset da máquina de entrega no pied_pedido — MANTÉM linha e payload (raw).
-- payment_status_anterior := payment_status => já-pago NÃO refira o gate (sem transição
-- testemunhada), senão o backlog inteiro despejaria no X-Adm.
UPDATE pied_pedido SET
status = 'CAPTURADO',
content_hash = NULL,
cod_retorno = NULL,
msg_retorno = NULL,
chave_xadm = NULL,
enviado_em = NULL,
payment_status_anterior = payment_status,
atualizado_em = now();
COMMIT;
O gate manda no "só pedidos novos". O disparo do envio é a transição payment_status
não-received → received num pedido CAPTURADO (upsert ON CONFLICT, V6__gate_pagamento.sql +
PiedPedidoRepository.upsert). Ao setar payment_status_anterior = payment_status, os já-received
não refira; só quem pagar depois do reset entra na fila. Pedido que reaparece por webhook é
INSERT (1ª captura) — já-pago no INSERT nunca dispara.
Opção — começar do zero de verdade (usada em 2026-09-04): os já-pagos de teste eram ruído;
apagamos em vez de deixar parados em CAPTURADO. Mantém só os pendentes reais, que vão pro X-Adm
quando pagarem:
DELETE FROM pied_pedido WHERE payment_status = 'received';
Verificação (antes de ligar a Fase 2):
SELECT status, count(*) FROM pied_pedido GROUP BY status; -- só CAPTURADO
SELECT count(*) FROM mensagem_m2m WHERE tipo='xadm-push'; -- 0
SELECT count(*) FROM contratos; -- 0 (idem as outras 4 espelho)
SELECT count(*) FROM pied_webhook; -- >0 (raw intacto)
Por que DELETE e não TRUNCATE¶
Este banco tem PowerSync com replicação lógica; TRUNCATE não se comporta bem com a publication
usada pelo slot. Use DELETE nas tabelas espelho e pied_*. (Regra do repo — nunca TRUNCATE
onde há PowerSync.)
Depois do reset¶
- Confira que o X-Adm não recebeu escrita durante o procedimento (cliente parado).
- Religue a Fase 2 conforme Implantação só quando a fonte estiver populada de novo pelos pedidos correntes.
- Runbooks operacionais do PowerSync em si (Mongo, slot, docker) vivem nos repos donos
(
maxsul/powersynceintegrador-server); aqui fica só a fatia do maxsul-pied.