
A Semana da Qualidade — 10 correções que o portfólio merecia
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.appendFileSyncfalhava no Vercel → migrado pra Capivara API - Terminal: history com cap e tracking corrigido (
external_link→terminal_command) - Analytics:
window.umamicomas any→ type augmentation limpo - ErrorBoundary: agora reporta erros via
/api/contact-notify - ContactForm: clipboard com fallback
execCommandpra HTTPS/localhost - Rate limit com contagem regressiva + botão desabilitado
- Modal CV: success state usa
var(--success)em vez detext-emerald-400fixo - Í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
String.fromCharCodenão éString(n).padStart(2, '0')— parecia óbvio depois, mas custou um Pix rejeitado pra descobrir.- Focus trap em React com múltiplos modais precisa de um único controller, não um hook por modal.
- Auditoria consolidada > correções pontuais — resolvi 10 problemas em 1 commit em vez de 10 PRs separados. Menos ruído, mais contexto.
- 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.