A Semana da Qualidade — 10 correções que o portfólio merecia
🚀 Portfólio·

A Semana da Qualidade — 10 correções que o portfólio merecia

📖 6 min de leitura← Voltar para timeline

A calmaria depois do rebuild

O portfólio v3 tava no ar. Vue 3.5 + Vite 8, build em 12 segundos, 122 testes passando, tudo lindo. Mas duas semanas depois, comecei a notar: coisas pequenas não funcionavam.

O Pix não gerava código válido. O modal de currículo não deixava digitar. O scroll suave pulava seção. Nada crítico isoladamente, mas juntos pareciam que o site tava desleixado.

Eu podia corrigir cada um separado. Mas decidi fazer diferente: uma auditoria profunda, de uma vez.

O que estava quebrado

Pix BR Code — String.fromCharCode é a vilã

O Pix BR Code é um payload de texto com campos TLV (Tag-Length-Value). O length de cada campo não é um caractere Unicode — é um número decimal com padding zero.

// Antes (quebrado):
const keyField = `01${String.fromCharCode(key.length)}${key}`;
// String.fromCharCode(10) = '\n' (line feed), não '10'

// Depois (correto):
const keyLen = String(key.length).padStart(2, "0");
const keyField = `01${keyLen}${key}`;

String.fromCharCode converte o número em codepoint Unicode. key.length sendo 10 vira \n (line feed) em vez de "10". O payload chegava no banco com campos de tamanho inválido — Pix rejeitado silenciosamente.

O mesmo bug aparecia em 4 campos (chave Pix, Merchant Name, Merchant City, e o CRC que usava slice(0, -4) em vez de concatenar o CRC no final). O commit 977eaf6 corrigiu todos.

Focus trap roubando o teclado

O modal de CV tem um formulário. Quando tentava digitar, o focus trap do modal de projeto entrava em conflito — o onMouseDown de um modal interceptava o onMouseDown do outro, e o foco voltava pro background.

// Raiz: dois handlers Escape competindo
// ProjectModal e TimelineModal tinham listeners duplicados
git show 83efb93  # fix: focus trap roubando foco ao digitar
git show 0d7c218  # fix: remove duplicate Escape handlers

Smooth scroll com race condition

Clicar num link de navegação disparava animação antes do hash atualizar. Se clicasse rápido em dois links, o primeiro scroll nunca terminava e o segundo começava de um ponto intermediário.

// Fix: pausar observer durante animação
git show 3b31bc4  # navigationRef pausa observer durante smooth-scroll
git show 8782a3d  # handleNavClick seta activeSection no click

+6 problemas no mesmo dia

O commit refactor: auditoria profunda — 10 correções de qualidade (713a556) consolidou:

  • CV download: fs.appendFileSync falhava no Vercel → migrado pra Capivara API
  • Terminal: history com cap e tracking corrigido (external_linkterminal_command)
  • Analytics: window.umami com as any → type augmentation limpo
  • ErrorBoundary: agora reporta erros via /api/contact-notify
  • ContactForm: clipboard com fallback execCommand pra HTTPS/localhost
  • Rate limit com contagem regressiva + botão desabilitado
  • Modal CV: success state usa var(--success) em vez de text-emerald-400 fixo
  • Ícone Download adicionado no header do modal CV

O commit que documenta tudo

A mensagem do commit 713a556 é longa de propósito — cada correção tem o o quê e o por quê. Debugging futuro agradece.

refactor: auditoria profunda — 10 correções de qualidade

1. CV download: substitui fs.appendFileSync pela Capivara API
2. Terminal: history + commandHistoryRef com cap (100/50)
3. Terminal: tracking tipo corrigido
4. AnalyticsTracker: type augmentation, remove as any
5. ErrorBoundary: reporta erros via /api/contact-notify
6. ErrorBoundary: reset recarrega a página
7. ContactForm: clipboard com fallback execCommand
8. ContactForm: rate limit com contagem regressiva
9. Modal CV: success state usa var(--success)
10. Ícone Download no header do modal CV

Métricas

Métrica Antes Depois
Pix BR Code válido ❌ Não ✅ Sim
Focus trap modais Conflito Isolado
E2E links-audit Esperava 200 em 404 ✅ 404 correto
Lint + type errors 7 warnings 0
CI health check Manual Automático

O que aprendi

  1. String.fromCharCode não é String(n).padStart(2, '0') — parecia óbvio depois, mas custou um Pix rejeitado pra descobrir.
  2. Focus trap em React com múltiplos modais precisa de um único controller, não um hook por modal.
  3. Auditoria consolidada > correções pontuais — resolvi 10 problemas em 1 commit em vez de 10 PRs separados. Menos ruído, mais contexto.
  4. Teste E2E de link não testa código Pix — nenhum teste pegou o bug porque o payload era válido em formato, inválido em conteúdo. Preciso de um validador de schema.
~/lifelog — bash
$cat about.txt
╔══════════════════════════════════════╗
║  Samuel Medeiros                    ║
║  Senior Software Engineer           ║
║  Stack: Python · TypeScript · Rust  ║
║  Projetos: Arachne, Dogwalk,        ║
║            Capivara, TatuEngine      ║
╚══════════════════════════════════════╝
      
$