O problema
Se corre, conhece a luta diária: quando devo correr e o que devo vestir? A maioria das aplicações de meteorologia só mostra números (temperatura, humidade, vento), mas não ajuda verdadeiramente na decisão. Eu via-me a fazer contas mentais todas as manhãs, equilibrando variáveis na cabeça. Às vezes errava e saía com roupa a mais, com frio, ou apanhado por chuva inesperada.
Como construí a solução
O WeatherToRun começou com uma ideia simples: e se a aplicação fizesse essa conta mental por mim? Em vez de mostrar dados brutos e deixar a interpretação para o utilizador, analisa as condições e dá uma resposta direta: é um bom momento para correr ou não?
O núcleo da aplicação é um sistema de pontuação que combina vários fatores numa nota de 1 a 100. Uma classificação por cores ("Mau", "OK" ou "Bom") acelera ainda mais a decisão.
O que eu construí:
- Algoritmo de pontuação baseado em pesquisa: Estudei como o clima afeta a performance de corrida. Os pesos não são arbitrários: temperatura tem 30% porque a faixa ideal (44-59°F) vem de estudos de maratona; vento tem 25% porque um vento contrário de 10 mph pode reduzir o ritmo em 8-15 s/milha; ponto de orvalho (20%) se mostrou melhor que umidade para prever conforto.
- Edge-first para velocidade: As rotas de API rodam no Edge Runtime da Vercel, com cold starts por volta de ~50 ms em vez de ~5000 ms de serverless tradicional.
- Cache inteligente em toda parte: Estratégia em múltiplas camadas: cache horário no edge, stale time de 1 hora no cliente com TanStack Query e arredondamento de coordenadas para 4 casas decimais para aumentar cache hit entre utilizadores próximos.
- Recomendação de roupa personalizada: Um toggle simples de "Mais camadas" / "Menos camadas" permite ajustar as sugestões ao seu perfil térmico.
- PWA com suporte offline: Funciona sem conexão e pode ser instalado no celular.
O objetivo era criar algo realmente útil, algo que eu de fato usaria antes de sair para correr.
Do esboço à interface
Antes de escrever código, peguei em papel e caneta e desenhei como a aplicação deveria funcionar. O que o corredor precisa de ver primeiro? A pontuação e o que vestir. O resto é secundário. Estes wireframes ajudaram a definir hierarquia sem me perder em detalhes de implementação.



Wireframes iniciais explorando tela principal, estrutura de componentes e fluxo de usuário.
Fazendo funcionar offline
Eu queria que o WeatherToRun se comportasse como uma aplicação nativa: instalável, rápida e funcional com ligação instável. Mas cache de PWA não é "cachear tudo".
Usei Workbox com estratégias diferentes por tipo de recurso:
- CacheFirst para estáticos (scripts, estilos, imagens), com expiração de 30 dias.
- NetworkFirst para o manifest, com timeout de 3 segundos.
- NetworkOnly para navegação e payload de React Server Components. Eu inicialmente cacheei isso, mas tive inconsistências com dados stale e estados estranhos na UI entre dispositivos.
Quando está offline, o utilizador vê uma página amigável de offline em vez de erro do navegador. A aplicação pode ser instalada no ecrã inicial e corre em ecrã inteiro.
Lidando com o mundo real
Apps de clima precisam ser rápidos e confiáveis. APIs externas caem, limites de taxa aparecem, rede falha. Eu investi bastante para tratar isso com degradação elegante.
Quando algo dá errado
- Retry com backoff: Em rate limit (429) ou falha momentânea de rede, a aplicação tenta novamente com atrasos progressivos, até 10 segundos.
- Timeouts coerentes: API de clima com 8 segundos; qualidade do ar (AQI) com 3 segundos. Se AQI falhar, a aplicação segue com dados de clima.
A matemática da pontuação
| Fator | Peso | Por que importa |
|---|---|---|
| Temperatura | 30% | 44-59°F é a faixa ideal para performance |
| Vento | 25% | Vento contrário de 10 mph custa 8-15 s/milha |
| Ponto de orvalho | 20% | Melhor que umidade para prever desconforto |
| Precipitação | 15% | Chuva, neve, tempestades |
| Índice UV | 10% | Exposição ao sol aumenta estresse térmico |
O algoritmo também lida com mais de 30 códigos climáticos, de tempestades a chuva congelante, cada um com penalidade adequada. Também combino rajadas e vento sustentado (70/30) para refletir melhor o mundo real.
Descoberta e SEO
Implementei JSON-LD em tipos de página relevantes, Open Graph dinâmico, sitemap e robots.txt configurados para melhorar descoberta orgânica.
Observabilidade
Integrei Sentry para monitorar falhas em produção com contexto de operação, coordenadas e respostas de API, sem expor dados sensíveis.
Mantendo dados de clima atualizados
No início usei ISR por tempo com revalidação de 2 horas. O problema: a revalidação só acontece quando alguém visita após o período stale. Em páginas com pouco tráfego, isso gera dados antigos no primeiro acesso.
A solução foi invalidar cache proativamente com agendamento. Criei um cron que chama /api/revalidate a cada 30 minutos.
Pontos-chave:
- Cache tags:
next: { tags: ['weather'] }nas chamadas de API e invalidação comrevalidateTag('weather'). - Stale-while-revalidate: com
revalidateTag(tag, 'max')no Next.js 16, o utilizador recebe conteúdo imediato enquanto a atualização corre em segundo plano. - GitHub Actions como cron gratuito: workflow executando a cada 30 minutos para chamar o endpoint de revalidação.
- Degradação elegante: se o cron falhar, o fallback de
revalidatepor tempo ainda cobre.
O endpoint é protegido por token secreto (REVALIDATE_SECRET). Sem ele, retorna 401.
Com isso, os dados ficam no máximo 30 minutos defasados, mesmo em páginas de baixo tráfego.
O que aprendi
Menos dados, mais síntese. O valor não estava em exibir mais informação, e sim em sintetizar melhor.
Confiabilidade é invisível até falhar. O utilizador não vê retry ou timeout, só percebe se "funciona".
Cache é mais difícil do que parece. Estratégias em múltiplas camadas evoluíram com padrão de uso real.
Edge muda tudo. Sair de ~5 s para ~50 ms em cold start muda completamente a percepção de rapidez.
Pequena personalização gera grande impacto. Um toggle de camadas já fez a recomendação parecer pessoal sem complicar a UX.
