DEV Community

Cover image for Observabilidade no frontend: o BFF respondia 200, mas o clique falhava
Tiago Vilas Boas (Montanha)
Tiago Vilas Boas (Montanha)

Posted on Edited on

Observabilidade no frontend: o BFF respondia 200, mas o clique falhava

Imagine a cena: os gráficos de infraestrutura da sua empresa estão todos verdes. O gateway de pagamento reporta que a API está saudável, o BFF (Backend For Frontend) responde com status HTTP 200 em 99,8% das chamadas e a equipe de DevOps comemora a estabilidade dos servidores.

Mas no atendimento ao cliente, chegam centenas de mensagens revoltadas:

"Estou tentando pagar pelo meu celular e o botão simplesmente não faz nada!"

Ao auditar os 4 repositórios da nossa esteira frontend com uma busca cirúrgica (grep -rn "catch" client/ src/ | grep -v "throw" | grep -v "capture"), catalogamos um número assustador: 894 blocos try/catch engolindo exceções em silêncio absoluto ou cuspindo um console.log inútil no navegador. Desses, 312 estavam diretamente no fluxo de checkout e submissão de dados financeiros.

// O pesadelo da observabilidade:
try {
  await processarPagamento(dados);
} catch (error) {
  // O erro morreu aqui! Ninguém ficou sabendo.
  // O usuário ficou na tela congelada e o backend acha que está tudo bem.
}
Enter fullscreen mode Exit fullscreen mode

O backend respondia 200 para a consulta inicial, mas o clique do usuário morria no JavaScript do cliente sem gerar nenhum rastro.

Neste artigo, vamos ver como desenhar uma camada profissional de observabilidade de frontend em múltiplos micro frontends, sem quebrar a privacidade (LGPD) e sem estourar as cotas do Sentry com ruído.


1. O Ponto Cego: HTTP 200 Não Garante que o Usuário Teve Sucesso

Em arquiteturas modernas com APIs e BFFs, existe uma ilusão perigosa de que telemetria de backend é suficiente.

A verdade é que o dinheiro e a conversão vivem no navegador do comprador:

[ A Ilusão do Backend Verde vs o Cliente Travado ]

1. Usuário clica em "Pagar com Cartão"
              │
              ▼
2. JavaScript valida campos no navegador
              │
              ├──> 💥 TypeError: Cannot read properties of undefined (reading 'token')
              │
              ▼ (O script morre no `catch` vazio!)
    NENHUMA REQUISIÇÃO SAI DO CELULAR!
              │
              ▼
    Servidores de Backend: 100% Saudáveis (Zero erros registrados)
    Métricas de Negócio:    Vendas despencando e clientes furiosos!
Enter fullscreen mode Exit fullscreen mode

Métricas de infraestrutura medem saturação de máquina e latência de rede. Elas são completamente incapazes de enxergar um botão que parou de responder por causa de um bug de renderização no Safari.

Onde o Agente de IA é Enganado pelo HTTP 200

Quando você opera agentes autônomos de código com ferramentas de automação (como Playwright, Chrome DevTools MCP ou curl no terminal), o modelo avalia o sucesso da ação inspecionando o status de rede ou se a Promise foi resolvida.

Se a aplicação tem um try/catch vazio que consome a exceção e não propaga erro:

  1. A Promise resolve normalmente (Promise.resolve()).
  2. O BFF devolve HTTP 200 para a requisição de tela.
  3. O agente analisa o feedback e conclui no relatório: "Fluxo executado com sucesso, zero erros de rede".

O agente encerra a sessão comemorando que o bug foi corrigido, mas o comprador real continua com a tela travada no celular. No modelo de Harness Engineering, um catch vazio no frontend é um sensor quebrado que alimenta o agente de IA com feedback falso positivo.


2. A Estrutura de Domínio: Diga Adeus ao captureException Solto

O erro mais comum ao implementar ferramentas como Sentry no frontend é permitir que os desenvolvedores importem a biblioteca global em qualquer lugar e façam disparos desordenados.

Criamos um contrato padronizado de captura por domínio:

// Em vez de chamar a ferramenta diretamente, chamamos serviços de domínio:
sentry.capturePaymentError(error, { flow: 'pix', step: 'qrcode_generation' });
sentry.captureFinanceError(error, { action: 'withdraw', amount: 1500 });
Enter fullscreen mode Exit fullscreen mode

O Que Entra em Cada Evento Monitorado:

  • domain: Qual área de negócio falhou (checkout, pagamentos, autenticacao).
  • flow: O fluxo exato do cliente (pix, cartao_credito, recuperacao_senha).
  • release: O commit exato do Git que subiu para produção (checkout@git-a1b2c3).
  • Deduplicação de 5 segundos: Se o usuário clicar 10 vezes no botão de raiva em menos de 5 segundos, agrupamos tudo em um único evento para não gerar tempestade de alertas.

3. Quatro Frontends, Um Único Contrato

Nossa aplicação era composta por quatro frentes com tecnologias distintas. Padronizamos a telemetria respeitando o contexto de cada uma:

Aplicação Tecnologia Estratégia de Monitoramento
Checkout Principal Nuxt 3 / Vue Plugin ativado exclusivamente em produção; isolamento estrito de erros do fluxo de compra
Painel Administrativo Novo React 19 (MFE) Error Boundary visual na tela e interceptor HTTP que classifica falhas automaticamente
Painel Legado Vue 2 Projeto isolado no Sentry para evitar misturar eventos do legado com o sistema novo
Shell de Roteamento Go + Script Inline Envelope leve com fetch nativo (keepalive: true), sem carregar bibliotecas pesadas no carregamento

4. Segurança e Privacidade: Mascaramento Rígido de Dados (LGPD)

O monitoramento nunca pode colocar dados confidenciais dos clientes em risco. No hook beforeSend do cliente de observabilidade, aplicamos duas camadas inegociáveis de limpeza:

[ Dado Bruto no Navegador ] ──> "Cliente: João Silva, CPF: 123.456.789-00, Cartão: 4111..."
                                              │
                                              ▼
                             [ Pipeline de Mascaramento ]
                             - Substitui CPF formatado por [CPF_MASKED]
                             - Remove qualquer número de cartão de crédito
                             - Remove senhas e tokens de autenticação
                                              │
                                              ▼
[ Dado Enviado ao Sentry ]  ──> "Cliente: [NOME_MASKED], CPF: [CPF_MASKED], ID: usr_8841"
Enter fullscreen mode Exit fullscreen mode

Além disso, a gravação de tela (Session Replay) teve a flag maskAllInputs: true ativada por padrão, garantindo que nenhum dado digitado em formulários seja visível nos logs.


5. Do Caos à Resolução em Menos de 24 Horas

Antes de estruturar essa observabilidade:

  • O time dependia de chamados abertos no suporte dias depois do ocorrido;
  • Investigar um erro levava de 4 a 6 horas procurando agulha em palheiro nos logs.

Depois da padronização:

  • Bugs invisíveis foram identificados no primeiro dia: como um erro de formatação de data que afetava apenas usuários do navegador Safari no iOS;
  • Tempo médio de resposta (MTTR): caiu para menos de 30 minutos, pois o desenvolvedor já recebia o arquivo, a linha exata e as ações anteriores do usuário gravadas nos breadcrumbs.

Para validar relatórios e regras de monitoramento com eficiência de custos, você pode usar um classificador local em Go como o Downshift (harness-downshift), direcionando a análise profunda de logs para modelos via OpenRouter apenas para exceções de severidade máxima.


Referências Técnicas Canônicas

Para quem deseja construir uma observabilidade robusta no frontend e integrar telemetria a agentes:


Regra de Ouro para o Próximo PR

Na próxima vez que você estiver revisando um código frontend na sua equipe:

Se você encontrar um bloco catch {} sem tratamento de UI ou sem disparo para o serviço de telemetria, considere o Pull Request BLOQUEADO.

Um erro ignorado no frontend é uma venda perdida no presente e uma crise técnica garantida no futuro.

Top comments (0)