Tratamento de erros e normalização de mensagens

Como a PayCal padroniza relatórios de erro em todos os módulos frontend para que usuários recebam feedback útil, seguro e consistente sem expor detalhes sensíveis.

Visão geral e objetivo

Quando usuários encontram erros, eles merecem feedback claro explicando o que aconteceu e como corrigir. Mensagens brutas do backend precisam ser normalizadas para:

  • Remover ruído: retirar prefixos "Error:" redundantes e limpar espaços
  • Evitar vazamentos: garantir que detalhes sensíveis de implementação nunca cheguem ao usuário
  • Fornecer fallbacks: mostrar mensagens seguras quando erros estão vazios ou malformados
  • Garantir consistência: aplicar a mesma lógica em todos os 11+ módulos frontend
  • Melhorar debugging: registrar detalhes completos no Phantom Wing enquanto usuários veem resumos seguros

O problema: erros genéricos versus mensagens úteis

Antes da padronização, os módulos da PayCal usavam tratamento de erro ad hoc:

// ❌ BAD: Exposes raw error, duplicates logic
PC.showToast(error?.message || 'Import failed.');
PW.error(`Import failed: ${error.message}`);

Problemas dessa abordagem:

  • Usuários veem mensagens brutas confusas como "ECONNREFUSED: Connection refused"
  • Cada módulo implementa sua própria lógica de fallback independentemente
  • Não há limpeza consistente de espaços nem remoção de prefixos
  • Mensagens vazias podem aparecer como "undefined" na UI

A solução: resolvedor de erro padronizado

Todos os módulos frontend da PayCal agora usam uma função resolvedora unificada que normaliza mensagens de erro:

// ✅ GOOD: Normalized, consistent, safe
const resolveThrownMessage = (error, fallbackMessage) => {
  const raw = typeof error?.message === 'string' 
    ? error.message 
    : String(error || '');
  const normalized = raw.replace(/^Error:\s*/i, '').trim();
  return normalized !== '' ? normalized : fallbackMessage;
};

Uso:

// In catch blocks across modules
try {
  await updateProfile(data);
} catch (error) {
  const message = resolveThrownMessage(error, 'Unable to update profile.');
  PC.showToast(message, 'error');  // User sees meaningful feedback
  PW.error(message);                // Logged for debugging
}

Escopo de implementação

Em abril de 2026, esse padrão foi aplicado a 11 módulos frontend com aproximadamente 40+ blocos catch normalizados:

Autenticação e configurações (7 módulos)

  • html/js/auth-recovery/index.php (4 catches)
  • html/js/signin/index.php (2 catches)
  • html/js/signin/verification-reminder.js (2 catches)
  • html/js/signin/verification-status-banner.js (1 catch)
  • html/js/settings/index.php (8+ catches)

Módulos core e de dados (4 módulos)

  • html/js/core/network.js (3 catches)
  • html/js/core/index.php (5 catches)
  • html/js/core/billing.js (5 catches)
  • html/js/earnings/index.php (4 catches)

Módulos de alto valor (10+ pontos catch):

  • html/js/organizations/index.php - Org management, access requests, audit trails (19+ catches)
  • html/js/sites/index.php - Site CRUD, earnings, orphan work recovery (10+ catches)
  • html/js/calendar/calendar.js - Day-entry operations, copy/paste/delete (2 catches)

Categorias de erro e padrões de tratamento

O resolvedor é aplicado de forma consistente em várias categorias de erro:

1. Falhas de requisições de rede

// Network module: HTTP errors, timeouts, connection issues
async function deleteResource(ep, id) {
  try {
    // ...fetch logic...
  } catch (error) {
    const resolved = resolveThrownMessage(error, 'Network error');
    const msg = `[deleteResource] ${resolved}`;
    PW.error(msg);
    throw new Error(msg);
  }
}

2. Tratamento de respostas API

// Billing/Settings: Server returned error message in payload
try {
  const response = await fetch('/api/v1/billing/subscription');
  const payload = await response.json();
  if (!response.ok) {
    throw new Error(payload?.message || 'Unable to load billing status.');
  }
} catch (error) {
  const resolved = resolveThrownMessage(error, 'Unable to load billing status.');
  setScreenReaderStatus(resolved);
}

3. Falhas de operações de UI

// Calendar/Organizations: User-initiated actions (paste, delete, update)
button.addEventListener('click', async () => {
  try {
    await performAction();
    PC.showToast('Success!', 'save');
  } catch (error) {
    const message = resolveThrownMessage(error, 'Action failed. Try again.');
    PC.showToast(message, 'error');
  }
});

4. Inicialização assíncrona

// Core modules: Startup or dependent initialization failures
try {
  NavigationToggle.init();
} catch (err) {
  const resolved = resolveThrownMessage(err, 'Navigation init failed');
  PW.warn(resolved);  // Logged but doesn't block page
}

Considerações de segurança

A normalização de mensagens protege a privacidade do usuário e a integridade do sistema:

  • Sem detalhes de banco: erros backend como "UNIQUE constraint failed on email" são interceptados na fronteira da API
  • Sem caminhos de arquivo: erros de sistema que expõem caminhos ou processos são removidos
  • Sem vazamento de autenticação: falhas de login nunca revelam se uma conta existe
  • Sem detalhes CORS/rede: erros de transporte viram mensagens genéricas de conexão
  • Fallbacks seguros: todos os catchers têm mensagens explícitas; nunca exibem "undefined" ou "null"

Benefícios para a experiência do usuário

Essa padronização dá aos usuários feedback mais claro, seguro e consistente, enquanto facilita suporte e debugging.

  • Mensagens são compreensíveis sem expor detalhes de implementação
  • O texto fallback permanece seguro quando o erro do backend falta ou é malformado
  • Logs continuam úteis para debugging sem vazar valores sensíveis para a UI

Fluxo de debugging e suporte

A equipe de suporte pode confiar em um caminho de resolvedor consistente e consultar logs do Phantom Wing quando precisar do detalhe técnico completo.

  • Usuário vê mensagem normalizada
  • Phantom Wing registra o contexto completo do erro de forma privada
  • Suporte correlaciona a classe do problema sem expor a resposta bruta do backend

Testes e garantia de qualidade

A lógica de normalização é coberta por testes focados de módulo e checks de integração nos principais fluxos frontend.

Manutenção e extensões futuras

Conforme a PayCal adiciona módulos, o mesmo padrão de resolvedor deve ser reutilizado em vez de duplicar formatação personalizada.

  • Novos módulos devem chamar diretamente o resolvedor compartilhado
  • Mensagens fallback específicas devem permanecer curtas e voltadas ao usuário
  • Mudanças no resolvedor devem ter regressão em fluxos representativos

Isso mantém o comportamento previsível à medida que a base cresce e evita uma nova geração de tratamento de erro por módulo.

Resumo: o padrão PayCal de tratamento de erros

A PayCal padronizou o tratamento de erros frontend para que usuários recebam mensagens seguras e consistentes enquanto desenvolvedores preservam informações necessárias para debugging.

  • Normalizar mensagens antes da exibição
  • Ocultar detalhes de implementação dos usuários
  • Usar fallback explícito para erros vazios ou malformados
  • Registrar detalhes técnicos privadamente para suporte e debugging