PushMesh
Entrar Solicitar acesso
Abrir navegação das seções

Índice

Versionamento e estabilidade

O que está congelado por teste de contrato na API PushMesh, o que pode mudar sem aviso, e como saber qual versão está no ar — sem confundir a versão do serviço com a do SDK.

Versionamento e estabilidade

A pergunta que importa quando você confia a sua base de usuários a uma API não é “qual a versão?”, é “o que aqui pode mudar debaixo de mim?”. Esta página responde exatamente isso, e separa o que é promessa do que é detalhe de implementação.

A versão está no caminho

Todo o contrato público vive sob /api/v1. Dentro da v1, as mudanças são aditivas: campos novos podem aparecer nas respostas, campos existentes não somem nem mudam de tipo. Uma quebra de contrato exigiria um caminho novo.

Para saber o que está no ar:

curl https://api.pushmesh.io/
{ "servico": "pushmesh", "versao": "0.1.0", "git": "unknown" }

Três leituras honestas desse retorno:

  • versao é a versão do SERVIÇO. Ela vem do pacote do serviço e sobe a cada publicação. No momento em que esta página foi escrita, a instância pública respondia 0.1.0.
  • A versão do SDK é outra coisa, com numeração própria. O pacote React Native @pushmesh/sdk está hoje em 0.7.2. Os dois números não andam juntos e nunca vão coincidir por acaso — não deduza um a partir do outro.
  • git pode vir "unknown". Ele carrega o commit do build quando a instância foi compilada com essa informação injetada; quando não foi, o campo existe e vale "unknown". É diagnóstico, não contrato: não escreva lógica em cima dele.

O que é contrato aqui: o caminho /api/v1 e o fato de a raiz responder um JSON com esses três campos.


O que está congelado por teste de contrato

O projeto guarda respostas-modelo de chamadas reais, e a suíte de testes as compara byte a byte. Mudar qualquer um desses formatos quebra o teste antes de chegar em produção — é isso que transforma “compatibilidade” de intenção em garantia mecânica.

Estão congelados assim:

O que está congelado
Resposta de sucesso do envio
Resposta de repetição idempotente
Envio parcial (errors como objeto)
Ninguém alcançável (200 com id vazio)
422 de chave de idempotência reusada
Consulta de um disparo
Consulta no plano gratuito (com o bloco recebidos_gate)
Lista de disparos
Corpo enviado ao provedor Android
Corpo enviado ao provedor iOS
Resposta do registro de aparelho

Além dos formatos de resposta, estão travados por teste:

Os tetos publicados. Os números de requisições por segundo têm um teste próprio, com a justificativa escrita junto: se alguém mudar isso sem querer, o cliente que integrou pelo número publicado começa a tomar 429 sem explicação.

A assinatura dos webhooks. Vetor fixo: prefixo sha256=, 64 caracteres hexadecimais, determinística, e segredo diferente produz assinatura diferente. Se ela mudasse, todo endpoint de cliente passaria a rejeitar as entregas como falsas.

A curva de reenvio dos webhooks. 1 s → 10 s → 60 s → 5 min → 15 min, com teto.

A serialização canônica do corpo de envio. É ela que gera o request_hash da idempotência: chaves de objeto ordenadas recursivamente, arrays na ordem, números como vieram, send_after nunca reinterpretado. Mudar essa função faria todo cliente tomar 422 no retry de uma chave já usada.

As strings assinadas das provas. A prova de recibo de push e a de exibição In-App têm o texto exato da assinatura congelado no contrato — o SDK só ecoa, nunca calcula:

pm_rcpt = hex(HMAC-SHA256(receipt_key, "<notification_id>:<device_uuid>"))[..32]
pm_iam  = hex(HMAC-SHA256(receipt_key, "iam:<campanha_id>:<device_uuid>:<pacote_id>"))[..32]

O prefixo iam: é o que separa os dois universos: um recibo de push nunca vale como prova de In-App, e vice-versa, mesmo com a mesma chave.

O tamanho medido do payload. O orçamento de 3.891 bytes e os 96 bytes que o servidor injeta são conferidos por teste contra o render real — a porta não pode “esquecer” bytes que ela mesma vai acrescentar depois.

O formato dos parâmetros públicos do Firebase. android vem null quando não configurado e ios é campo reservado, sempre null nesta fase — o contrato nasce estável para o SDK não mudar quando o iOS chegar.


O que pode mudar sem aviso

Seja explícito com o seu código sobre estas três coisas, porque elas não são contrato:

  1. O texto de explain.causa e explain.como_corrigir. Eles existem para um ser humano ler e para o seu log guardar. Nunca ramifique a sua lógica pelo texto de um erro — use o código HTTP e, quando existir, os campos estruturados do explain (campo, bytes, limite, hash_original, mau…).
  2. Campos novos nas respostas. Podem aparecer a qualquer momento, sempre aditivos e, nas rotas de compatibilidade, sempre no namespace pm_*. Seu desserializador precisa ignorar campos desconhecidos.
  3. As rotas fora de /api/v1. O que o painel usa para falar com o serviço é contrato interno e muda junto com o painel. Não automatize nada por ele: tudo que uma integração precisa está em /api/v1.

Também não são contrato: os detalhes de infraestrutura (quantas instâncias atendem, o valor de X-Pm-Instance, o campo git da raiz), a ordem de campos dentro de um objeto JSON, e o desempenho de uma chamada específica.


Como o serviço evolui sem quebrar você

Três regras internas sustentam as promessas acima, e elas valem a pena porque explicam por que você pode confiar:

  • Migrações de banco só somam. Nenhuma migração já publicada é editada.
  • Extensões nascem em pm_*. O formato de compatibilidade é congelado; tudo que é nosso entra em namespace próprio, para nunca colidir com um campo que a sua integração já lê.
  • Nada é aceito em silêncio. Um campo que mudaria quem recebe, quando recebe ou o que a pessoa vê e que ainda não implementamos devolve 400 nomeado, em vez de ser ignorado. A lista está em Migrando de outro provedor.

Depreciação

Quando algum comportamento precisar sair, o caminho é o mesmo da rotação de chaves: janela de convivência primeiro, corte depois. A rotação de chave de API é o exemplo já implementado — a chave anterior segue válida por 24 horas, e a rotação nunca produz 401.


Saúde do serviço

curl https://api.pushmesh.io/health

Devolve status, versao, git, papel, lider, uptime_s, instancia, estado do banco e do cache, modo_degradado, lideranca, pg_down_ha_s e fila_mais_antiga_s.

Responde 200 enquanto o serviço serve — inclusive com o cache fora (o banco é a verdade; o cache é acelerador) e durante uma falha curta de banco. Só cai para 503 quando o banco está fora há mais de 60 segundos ou a instância está em drenagem.


Veja também

AssuntoPágina
a tabela de códigos e a política de retryAutenticação e erros
todos os tetos publicadosLimites
a assinatura e a reentrega dos webhooksWebhooks
o que é aceito tal e qual vindo de outro provedorMigrando de outro provedor