Package br.com.xadm.comum.mensageria


package br.com.xadm.comum.mensageria
xadm-mensageria — entrega garantida M2M via outbox transacional (ADR 0019, raiz/004, Fase 3 da iniciativa libs+contrato). Generaliza o padrão bom do encerramento (int-sascar) em capacidade reusável da casa: uma tabela genérica (MensagemM2m), um relay @Scheduled com backoff/teto/PAUSADO (RelayM2m), uma SPI de envio tipado (EnviadorMensagem) que cada app implementa chamando o @Client gerado do OpenAPI, e uma tela /admin/mensageria (MensageriaController) restrita a admin @xadm.com.br (MensageriaAdminRule).

O motor é agnóstico de domínio; o dispatch é tipado (um bean EnviadorMensagem por tipo, no app). Semântica AT-LEAST-ONCE: sob N instâncias do MESMO app o relay pode despachar em dobro — o receptor deduplica por chave natural de negócio (a lib não faz dedup nem lock de linha).

N apps DIFERENTES numa mesma mensagem_m2m (mesmo DB/schema — ex.: integrador + int-pied dividindo db_maxsul_pied): dois ownerships distintos. (1) Tabela (DDL): um app cria; os outros consomem (migração test-only pros testes standalone) — nunca dois CREATE. (2) Mensagem (roteamento): cada RelayM2m reivindica só os tipo que registra (RoteadorEnviadores.tiposRegistrados()) — app sem enviador é no-op. Assim os relays não competem (cada tipo tem 1 remetente); sem o filtro, o relay do app "errado" queimava a tentativa da linha alheia (dead-letter falso). Par disso: MensageriaService.enfileirar(String, String, String, String) falha-rápido se o tipo não tem enviador local (o remetente é quem enfileira). Não se resolve com config por-deploy (RELAY_ENABLED=false), coluna de origem, nem relay-broker único.

Schema é owned pelo app (sem Flyway na lib); o DDL canônico é publicado em db/mensagem_m2m.postgres.sql (índice (direcao, status, tipo) p/ o filtro do relay).