APIs · Serviço
AZ Chat
O serviço que carrega a conversa entre comprador e vendedor — e, junto dela, a negociação: proposta de valor, oferta de troca e a combinação das duas. Este documento descreve como a mensagem trafega, como a proposta vira pedido e como tudo isso conversa com o restante da plataforma.
Duas versões, e só uma no ar
Versão anterior
Atende os usuários hoje. Roda como processo próprio, mas debaixo do endereço do servidor principal — o servidor web encaminha o caminho de tempo real para ela. De fora, parece um sistema só.
Versão 3.0
Reconstruída com negociação, propostas e troca. Está pronta há meses e nunca foi publicada. É a versão descrita neste documento.
Como as duas usam endereços diferentes, elas podem conviver durante a virada: a 3.0 sobe no endereço próprio, é testada à vontade, e a anterior segue atendendo quem ainda não atualizou o aplicativo.
O que ele é dono
Conversas e mensagens
A conversa entre duas pessoas, quem participa dela, cada mensagem e o que já foi lido.
Negociação
Propostas de compra, de troca e mistas, com todo o ciclo: aceitar, recusar, cancelar, expirar e contrapropor.
Usuários e produtos
Nome, avatar e os dados do anúncio. O chat mantém cópias locais, alimentadas por eventos.
Checkout e notificações sociais
Aceitar uma proposta não gera pedido aqui: o chat anuncia o aceite, e o servidor principal conduz a compra.
Antes, negociação e troca viviam em módulos separados no servidor principal. Agora estão consolidadas aqui, junto da conversa em que acontecem — que é onde as pessoas de fato negociam. O módulo antigo foi aposentado.
O mapa em uma tela
Três características definem o serviço: a conexão é persistente, a entrega em tempo real acontece antes de qualquer aviso aos outros serviços, e o que precisa ser anunciado passa por uma tabela de saída — detalhada adiante.
Fluxo · Envio de mensagem
-
Aplicativo → AZ Chat Conexão e autenticação
Ao abrir o aplicativo, é estabelecida uma conexão persistente. O serviço não emite credencial nenhuma: confere a assinatura do token emitido pelo servidor principal, usando a mesma chave. Cada aparelho conectado entra na sala pessoal do seu dono e nas salas das conversas que abre.
-
AZ Chat Gravação
A mensagem é gravada no banco próprio do serviço. Na mesma transação, fica registrado o evento que precisará ser anunciado — os dois acontecem juntos ou nenhum acontece.
-
AZ Chat → aparelhos conectados Entrega em tempo real
A mensagem é emitida para a sala da conversa e para a sala pessoal de cada participante, numa única emissão. A sala pessoal existe para atualizar a lista de conversas de quem não está com aquela conversa aberta — e a emissão combinada garante que ninguém receba duas cópias.
-
AZ Chat → Firebase Notificação para quem está fora
Quem não está com o aplicativo aberto recebe notificação. Esse envio nunca derruba a operação: a mensagem já foi gravada e entregue antes de chegar aqui. Um token de aparelho expirado apenas remove aquele aparelho do cadastro.
-
AZ Chat → fila → servidor principal Anúncio
Um processo interno esvazia a tabela de saída e publica os eventos na fila. É assim que o servidor principal fica sabendo da mensagem nova e atualiza o número do ícone do aplicativo.
Por que a tabela de saída existe
Gravar no banco e publicar na fila são dois sistemas diferentes. Sem cuidado, a mensagem poderia ser gravada e o anúncio se perder — ou o contrário, com o outro serviço reagindo a algo que não aconteceu.
Registrando o evento na mesma transação da mensagem, os dois passam a ter o mesmo destino. Um processo separado publica depois, com garantia de entrega ao menos uma vez: se a publicação der certo mas a marcação falhar, o evento sai de novo. É por isso que todos os serviços descartam evento repetido pelo identificador.
Negociação
A proposta nasce dentro da conversa. São três formatos, e o mesmo ciclo de vida vale para todos.
Valor
Oferta em dinheiro pelo produto anunciado.
Troca
Oferta de um ou mais itens do próprio acervo em troca do anunciado.
Troca com diferença
Itens somados a um valor em dinheiro, para cobrir a diferença entre os dois lados.
Aguardando Aceita Recusada Cancelada Expirada Contraproposta
Ao ser aceita, a proposta é anunciada na fila e o servidor principal conduz a compra a partir dali — ele é dono do checkout, do pagamento e do envio. O chat registra a negociação; quem transforma o acordo em pedido é o outro lado.
As cópias locais
Para desenhar uma conversa, o chat precisa do nome e do avatar dos participantes, e dos dados do produto que está sendo negociado. Nada disso é dele. Em vez de consultar o servidor principal a cada abertura de tela, mantém cópias locais alimentadas por eventos.
| Evento | Efeito no AZ Chat |
|---|---|
user.created / user.updated | Cria e atualiza a cópia do usuário. |
user.deleted | Anonimiza em vez de apagar — as mensagens antigas apontam para essa linha, e sem ela o histórico ficaria com balões sem autor. Os aparelhos cadastrados saem junto, garantindo que ninguém receba notificação depois de sair. |
item.created / updated / deleted | Mantém a cópia do anúncio que aparece no card da negociação. |
notification.unread.changed | A outra metade do número do ícone: o chat soma as não lidas de conversa às notificações sociais. |
notification.card.upserted | Notificação social pronta para desenhar. Só passa por aqui — é repassada para a sala pessoal e nada é guardado. |
Quatro filas, e o motivo de não serem uma só
| Fila | Cuida de | Por que separada |
|---|---|---|
user-sync | Cópia de usuários | É o que toda tela exibe. |
item-sync | Cópia de anúncios | Falha aqui não pode afetar o nome das pessoas. |
social-unread | Contador de não lidas | Escreve no banco. |
social-notifications | Repasse de notificações | Só emite em tempo real. Na mesma fila da anterior, uma falha de banco levaria o repasse junto para a fila de mortas — e o sino pararia por um problema que não é dele. |
A fila de mensagens problemáticas é própria
O chat usa uma fila de descarte separada da do serviço de mídia. Não é preciosismo: a fila de descarte da mídia está ligada com um padrão que casa com tudo, então uma fila do chat no mesmo lugar receberia cópia de toda mensagem problemática do outro serviço — e vice-versa.
Separadas, cada serviço enxerga apenas os próprios problemas. Vale conhecer antes de mexer na configuração das filas.
O que ele anuncia
| Evento | O servidor principal usa para |
|---|---|
chat.thread.created | Registrar que uma conversa começou. |
chat.message.created | Saber da mensagem nova. |
chat.unread.changed | Atualizar o número no ícone do aplicativo. |
proposal.created | Notificar o outro lado da negociação. |
proposal.accepted | Iniciar o checkout — é o evento que transforma acordo em pedido. |
proposal.rejected · canceled · expired · countered | Acompanhar o desfecho da negociação e notificar. |
Pontos de atenção operacionais
O chat não consulta o servidor principal para validar quem está pedindo — confere a assinatura do token com a mesma chave. Se as duas divergirem, toda requisição e todo estabelecimento de conexão são recusados, e a mensagem que chega ao aplicativo é apenas “não conecta”. A esteira exige que a chave exista, mas não consegue verificar se o valor é o mesmo dos dois lados.
O encaminhamento precisa suportar a elevação da conexão para o modo persistente. Com a configuração fixa em vez do mapa apropriado, toda requisição comum passa a falhar. E o tempo limite de leitura precisa ser folgado: o padrão derruba conexão ociosa, e o aplicativo entra em ciclo de reconexão.
O aplicativo 3.0 já aponta para o endereço próprio do serviço por padrão — o mesmo endereço atende as requisições comuns e a conexão persistente, sem host separado. Esse endereço ainda não existe; criá-lo é parte da publicação, tratada no plano de virada.
Consumo de recursos
Medido em homologação: 38 MB de memória e processamento praticamente nulo entre requisições. É o mais leve dos quatro serviços da plataforma — usa 7% do limite configurado para ele.
Conexões persistentes custam pouco: cem pessoas conectadas simultaneamente somam menos de 4 MB. Os números completos, com a comparação entre os serviços, estão na análise de infraestrutura.