PowerSync — o transporte praticado¶
Status: Aprovado · Responsável: Gustavo Madruga · Atualizado em: 2026-07-07
O PowerSync é o transporte bidirecional entre o Postgres por cliente (o barramento) e as pontas. O connector vive na Plataforma de Integração; o PowerSync serve dois consumos: os apps consumidor Web e Mobile (saída X-Adm→app) e o cliente Java do ERP (entrada nuvem→ERP). Apps específicos que enviam para fora (tipo ④) NÃO consomem PowerSync — o transporte com a Plataforma de Integração é REST. Esta página é só o praticado — o padrão provado nos pilotos, não o aspiracional.
Norma × detalhe
A norma de integração está na constituição §8 e o desenho em Plataforma de Integração. Aqui, a tech.
Cliente (a face do app)¶
- Sync read-only por padrão. O app lê o SQLite local que o PowerSync mantém; não escreve direto no Postgres.
- Write-back só via
uploadData. Campo editável (ex. nome-curto nonavarro_app) sobe pelouploadDatado connector →POSTna Plataforma de Integração, que grava nas tabelas que ela possui. O app nunca fala com o banco; a autoridade da escrita é do dono da tabela (owner-writes, §8).
Connector (server-side, na Plataforma de Integração)¶
- Dono do write-back. O connector aplica os write-backs dos apps nas tabelas da Plataforma de Integração (a réplica).
- Campo de app nunca é sobrescrito pelo ERP. O push do X-Adm reidrata a réplica; os campos que o app edita (nome-curto, status) são preservados — o apply do push não pisa neles. É invariante: dois donos lógicos na mesma linha (o ERP e o app) exigem que o merge respeite a coluna de cada um.
Auth (o consumidor decide o modo)¶
Duas classes de consumidor, dois modos — quem tem usuário vs quem é máquina:
- App com usuário real — o PowerSync valida o JWT do usuário pelo JWKS do
auth.xadm.biz(ou pelojwks_urido Google, nos apps que autenticam por Firebase). - Cliente máquina-a-máquina (o cliente Java do ERP na entrada — sem humano) —
nasce self-signed + JWK inline: o cliente assina o próprio JWT com uma key privada em env e o
PowerSync valida contra o JWK público inline na config. É o mais simples e não acrescenta peça
(sem broker, sem IdP) — reserve Firebase/pAbast para quem tem usuário de verdade. A key privada é
segredo de env (nunca em repo/log) e o algoritmo é público — é Kerckhoffs,
não fórmula-em-claro. Cuide do
kid/audiencena config para o PowerSync casar o JWK certo. (Não confunda com o M2M do broker de setup, que emite token de serviço — lá quem assina é oauth, aqui é o próprio cliente.) - JWKS inline
>jwks_uri— vale para os dois modos. Preferir a chave inline na config do PowerSync a apontar umjwks_uri: a busca remota tem timeout de ~3s e sofre com NAT hairpin (o container batendo no próprio domínio público via Traefik) → falha intermitente de auth (recorrente em produção, em mais de um cliente). Inline elimina a ida à rede — e o self-sign do M2M já nasce inline por construção. Exceção: o Firebase usa ojwks_urido Google (chaves rotativas, sem inline) — a regra inline vale para JWK próprio (authou self-sign), não para o do Google.
Config (as pegadinhas)¶
edition: 3é obrigatório nosync_config. Sem ele, o PowerSync cai num fallback legacy silencioso — funciona no happy-path e diverge sutilmente depois, sem erro visível. Fixe a edição.- Callback sempre-200. O endpoint de upload/callback (write-back
uploadData) responde HTTP 200 com o resultado no corpo (sucesso/erro), nunca um não-2xx para erro de negócio — senão a fila do cliente trava e reenvia em loop. É o mesmo contrato do push do X-Adm (erro vai no corpo, não no status). Este é o caso que exige o 200-sempre no status-por-caso do contrato app↔app: onde há PowerSync ou fila no meio, 200 é obrigatório e não muda; par app↔app novo sem fila usa status HTTP real.
Deploy (verificar antes do release)¶
O PowerSync self-hosted é uma stack Docker Compose (imagem journeyapps/powersync-service
pull, config + sync rules em volume). docker build não o exercita — sem Dockerfile próprio,
não há o que buildar; bootstrap (load de sync rules, migração) e healthcheck só rodam no up, e o
primeiro a subir a stack de verdade é o Coolify, em produção. Antes de taggar, suba a stack
efêmera com volume novo e espere os healthchecks — a /xadm-release faz isso no pré-flight (bloco
Docker Compose em Particularidades): docker compose -p <slug>-preflight up -d --wait +
down -v. --wait reprova se um serviço fica unhealthy ou um container de bootstrap sai ≠0.
Servidor-consumidor (ponteiro)¶
Consumir PowerSync em Java (hoje: o cliente do ERP na entrada) exige uma bridge Kotlin
(PsBridge.kt, ~190 linhas). A base de consumo (idempotência + tabela de status) e o desenho de cada
tipo de fluxo vivem em
Plataforma de Integração e, no concreto, na
arquitetura-alvo do integrador.
De olho no repo do PowerSync: uma API Java pura deve eliminar a bridge.