Skip to content

PRD: Correção de Bugs de Chat e Gerenciamento Completo do Ciclo de Vida de Instâncias #243

Description

@joel299

Problem Statement

Operadores que utilizam o painel ISing para atendimento via WhatsApp enfrentam duas categorias de falhas que tornam o sistema inutilizável em produção:

Módulo de Chat: Mensagens enviadas pelo painel não aparecem na conversa, mensagens recebidas dos contatos não são refletidas em tempo real mesmo com o WebSocket ativo, e o alinhamento visual dos balões está incorreto — dificultando a distinção entre mensagens enviadas e recebidas. O resultado é que o operador não consegue realizar atendimentos de forma confiável.

Módulo de Instâncias: O fluxo de criação de instâncias apresenta falhas que confundem o usuário sobre o estado real da conexão. A exclusão de instâncias não possui confirmação, tornando a ação irreversível sem aviso prévio.


Solution

Corrigir o pipeline de mensagens (envio, recebimento em tempo real, recuperação pós-reconexão e alinhamento visual) e completar o ciclo de vida das instâncias (fluxo de QR Code robusto, exibição de foto de perfil e exclusão com confirmação).


User Stories

Chat

  1. Como operador, quero digitar uma mensagem no painel e enviá-la ao contato, para que a conversa avance sem precisar usar o WhatsApp diretamente.
  2. Como operador, quero que a mensagem que acabei de enviar apareça imediatamente na janela de chat, para que eu tenha confirmação visual do envio sem precisar recarregar a página.
  3. Como operador, quero que uma mensagem recebida do contato apareça na janela de chat em tempo real, para que eu possa responder sem atrasos.
  4. Como operador, quero ver as mensagens que enviei alinhadas à direita e as mensagens do contato alinhadas à esquerda, para que eu identifique visualmente quem escreveu cada mensagem.
  5. Como operador, quero que, ao reconectar o WebSocket após uma queda, as mensagens recebidas durante o período offline apareçam automaticamente, para que eu não perca o contexto da conversa.
  6. Como operador, quero receber uma notificação de erro visível quando o envio de uma mensagem falhar, para que eu saiba que preciso tentar novamente em vez de achar que a mensagem foi enviada.
  7. Como operador, quero que uma nova conversa iniciada por um contato apareça automaticamente na lista lateral, para que eu não precise recarregar a página para atender clientes novos.
  8. Como operador, quero que as mensagens de uma conversa apareçam apenas naquela conversa, para que não haja mistura de mensagens entre atendimentos distintos.
  9. Como operador, quero que o histórico de mensagens carregue corretamente ao selecionar uma conversa, para que eu tenha contexto do que já foi discutido com o contato.
  10. Como operador, quero que as mensagens de imagem, áudio e documento sejam exibidas corretamente na janela de chat, para que eu visualize todo o conteúdo trocado com o contato.

Instâncias — Fluxo de QR Code

  1. Como administrador, quero que ao criar uma nova instância o sistema não a marque imediatamente como conectada, para que o status reflita a realidade (aguardando QR Code).
  2. Como administrador, quero que após criar uma instância o sistema aguarde 5 segundos e então exiba o QR Code em um modal, para que eu possa escanear com o celular e realizar a conexão.
  3. Como administrador, quero ver um indicador de carregamento durante os 5 segundos de espera antes do QR Code aparecer, para que eu entenda que o sistema está processando.
  4. Como administrador, quero que o QR Code seja atualizado automaticamente a cada 30 segundos caso não seja escaneado, para que o código não expire durante o processo de conexão.
  5. Como administrador, quero que se eu fechar o modal sem escanear o QR Code, a instância apareça na lista com status "Desconectado", para que eu saiba que a conexão ainda não foi estabelecida.
  6. Como administrador, quero que no card de uma instância desconectada exista um botão "Gerar QR", para que eu possa reabrir o modal e tentar conectar novamente sem precisar excluir e recriar a instância.
  7. Como administrador, quero que após escanear o QR Code e a conexão ser estabelecida, o modal exiba uma mensagem de sucesso e o card da instância atualize para "Conectado", para que eu tenha confirmação visual imediata.
  8. Como administrador, quero que o status da instância seja consultado a cada 5 segundos durante o processo de conexão, para que o painel reflita o momento exato em que o WhatsApp conecta.

Instâncias — Foto de Perfil

  1. Como administrador, quero ver a foto de perfil do WhatsApp associada à instância diretamente no card, para que eu identifique visualmente qual número está conectado sem precisar abrir configurações.
  2. Como administrador, quero que a foto de perfil seja buscada automaticamente do campo profilePicture retornado pelo endpoint de status, para que não seja necessário nenhuma ação manual após a conexão.
  3. Como administrador, quero que caso a foto de perfil esteja indisponível (nula ou URL inválida), o card exiba um avatar padrão sem erros visuais, para que a interface permaneça consistente.
  4. Como administrador, quero que a foto de perfil seja atualizada sempre que o status da instância for consultado, para que uma troca de foto no WhatsApp seja refletida no painel.

Instâncias — Exclusão

  1. Como administrador, quero que ao clicar no botão de excluir uma instância, um modal de confirmação seja exibido antes da exclusão acontecer, para que eu não exclua uma instância acidentalmente.
  2. Como administrador, quero que o modal de confirmação de exclusão informe claramente que a ação é irreversível, para que eu tenha ciência das consequências antes de confirmar.
  3. Como administrador, quero que ao confirmar a exclusão, a instância seja removida do gateway Pastorini e da listagem do painel, para que não existam instâncias órfãs no sistema.
  4. Como administrador, quero que ao cancelar o modal de confirmação de exclusão, nenhuma ação seja tomada e eu retorne ao estado anterior, para que falsos cliques não causem exclusões indesejadas.
  5. Como administrador, quero que enquanto a exclusão está em andamento, o botão de confirmar fique desabilitado e mostre um indicador de carregamento, para que eu não submeta a ação duas vezes.

Implementation Decisions

Chat — Módulo de Mensagens

  • Store de mensagens (addMessage): A função deve filtrar mensagens pelo ID da conversa ativa antes de adicioná-las ao array de mensagens da tela. Mensagens de outras conversas devem apenas atualizar os metadados da conversa na lista (unread_count, last_message_at) sem aparecer na janela aberta. A filtragem deve usar conversation_id quando disponível no payload do WebSocket.
  • Tipo Message no frontend: Adicionar os campos conversation_id e contact_id ao tipo, pois o backend já os retorna. Isso permite filtragem precisa no store.
  • Stale closure no store: O terceiro set de reordenação da lista de conversas deve ser consolidado com o segundo set de atualização de metadados em um único set funcional para evitar sobrescrever mudanças de estado intermediárias.
  • Envio com erro silencioso (handleSend): O componente de janela de chat deve fazer await no sendMessage e capturar erros com try/catch, exibindo um toast de erro para o operador quando o envio falhar.
  • Recuperação pós-reconexão do WebSocket: A página de chat deve detectar quando o WebSocket transita de desconectado para conectado e disparar automaticamente fetchConversations e fetchMessages para cobrir o gap de mensagens recebidas durante a queda.
  • Novas conversas via webhook: Quando o evento new_message chegar via WebSocket para uma conversa que não está na lista local, o painel deve disparar fetchConversations para incluir o novo atendimento.
  • Alinhamento dos balões: Determinar lado do balão exclusivamente pelo campo direction do payload (outbound → direita, inbound → esquerda). O campo é canonicamente definido pelo backend e não deve ser inferido pelo frontend.

Instâncias — QR Code

  • Status inicial ao criar: Ao criar uma instância, o status deve permanecer connecting enquanto o gateway processa. O frontend não deve inferir connected antes de receber confirmação via polling.
  • Fluxo do modal de QR: Após o POST de criação, o frontend aguarda 5 segundos (com contador visual), chama GET /instances/{id}/qr e exibe o base64 retornado no campo qrImage (ou equivalente, conforme normalização já existente no cliente Pastorini).
  • Botão no card desconectado: Instâncias com status disconnected devem exibir um botão "Gerar QR" que abre o mesmo modal e executa GET /instances/{id}/qr sem o delay de 5 segundos (instância já existe no gateway).
  • Auto-refresh de 30 segundos: O modal deve renovar o QR automaticamente enquanto o status for qr_ready, exibindo countdown visual ao usuário.
  • Polling de status: Durante a fase de conexão, o frontend faz polling de GET /instances/{id}/status a cada 5 segundos para detectar a transição qr_ready → connected.
  • Fechamento do modal: Ao fechar o modal sem escanear, o painel não altera o status da instância — o status real vem apenas do polling ou do webhook de conexão.

Instâncias — Foto de Perfil

  • Fonte dos dados: O campo profile_picture_url deve ser extraído do retorno de GET /instances/{id}/status, que por sua vez lê do Pastorini. O cliente Pastorini já normaliza os campos profilePicture, profilePictureUrl e avatarUrl.
  • Hidratação automática: Instâncias com status connected devem ter a foto de perfil buscada automaticamente no carregamento da página de instâncias e após cada polling bem-sucedido de status.
  • Fallback visual: Caso profile_picture_url seja nulo, vazio ou resulte em erro de carregamento de imagem, exibir ícone padrão (ex: ícone de smartphone) sem quebrar o layout.

Instâncias — Exclusão com Confirmação

  • Modal de confirmação: Adicionar um componente de diálogo de confirmação genérico (ou reutilizar um existente) que exiba: título "Excluir instância", corpo "Tem certeza que deseja excluir esta instância? Esta ação não pode ser desfeita." e botões "Cancelar" / "Excluir".
  • Estado de loading no botão: Enquanto a requisição DELETE /instances/{id} estiver em andamento, o botão de confirmar deve estar desabilitado e exibir spinner.
  • Remoção da lista: Após exclusão bem-sucedida, remover o item do array de instâncias no store sem recarregar a lista completa.
  • Endpoint backend: DELETE /instances/{id} já existe no backend com lógica de auditoria e chamada ao gateway Pastorini. Não requer alteração de backend.

Contratos de API (referência)

Ação Método Endpoint (Pastorini) Campo relevante
Criar instância POST /api/instances
Obter QR Code GET /api/instances/{instance}/qr qrImage (base64)
Status / Perfil GET /api/instances/{instance}/status profilePicture, status
Excluir instância DELETE /api/instances/{instance}

Testing Decisions

Princípio geral: Testes devem verificar comportamento externo observável — o que o usuário/sistema vê — e não detalhes de implementação interna como chamadas a funções específicas ou estrutura de estado.

Módulo de Chat — Store de Mensagens

  • Testar que addMessage com uma mensagem de conversa diferente da ativa não adiciona ao array de mensagens renderizadas
  • Testar que addMessage com mensagem da conversa ativa adiciona ao array corretamente
  • Testar que deduplicação por id previne mensagens duplicadas
  • Testar que a reordenação da lista de conversas após nova mensagem está correta sem sobrescrever unread_count

Módulo de Instâncias

  • Testar que o modal de confirmação de exclusão é exibido antes de qualquer chamada de API
  • Testar que ao confirmar exclusão, a instância é removida da lista
  • Testar que ao cancelar, a lista permanece intacta
  • Testar que foto de perfil nula renderiza avatar padrão sem erro

Out of Scope

  • Implementação de funcionalidades de Typebot, Chatwoot ou AI Agent nas instâncias
  • Upload manual de foto de perfil pelo administrador
  • Operações em lote de instâncias (seleção múltipla)
  • Renomeação de instâncias após criação
  • Configuração de webhook via interface de configurações (marcada como "em migração")
  • Envio de mensagens de mídia (imagem, áudio, documento) pelo painel — apenas texto está no escopo atual
  • Implementação de autenticação pública de instâncias

Further Notes

  • O cliente Pastorini já possui normalização de campos para qrImage, profilePicture e mapeamento de status (20+ variantes mapeadas). O frontend deve confiar nessa normalização ao invés de implementar parsers próprios.
  • A variável API_DOMAIN=localhost:8010 no .env de desenvolvimento aponta para o backend local. Para que webhooks do Pastorini (servidor remoto em 187.77.55.218:3001) cheguem ao backend, é necessário expor o backend publicamente em ambiente de testes (ngrok, tunnel, etc.) — caso contrário, mensagens inbound nunca alcançarão o backend mesmo com o código correto.
  • A rota DELETE /instances/{id} já está implementada no backend e requer role ADMIN. O frontend deve garantir que o botão de exclusão apareça apenas para usuários com essa role.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions