O Navistron é deployado na Vercel — a plataforma criada pela mesma equipe do Next.js. Isso significa suporte nativo a Server Components, ISR, API Routes como Serverless Functions e CDN global. Mas o deploy não é mágico: requer configuração cuidadosa de variáveis de ambiente, connection patterns para MongoDB e decisões sobre o que pré-renderizar. Neste artigo, vamos explorar cada aspecto do pipeline de deploy.
Build Automático via Git Push
O fluxo de deploy é simples: cada git push para a branch main aciona um build automático na Vercel. O processo executa next build, que:
- Compila Server Components — home, ranking, blog, stats, sponsors, perfis de jogador são renderizados para HTML estático ou ISR
- Gera páginas SSG — 23 artigos de blog via
generateStaticParams()e até 500 perfis de jogador - Empacota Client Components — apenas 3 páginas (
play,dashboard,admin) geram bundles JavaScript para o navegador - Cria Serverless Functions — cada Route Handler (
route.js) se torna uma função Lambda independente - Gera sitemap dinâmico — consulta o MongoDB para listar até 1.000 jogadores
- Gera robots.txt — via função que referencia o sitemap e bloqueia
/api/e/admin/
Não há pré-build script, dockerfile ou CI/CD customizado. O build usa o adaptador nativo da Vercel para Next.js — sem output: 'standalone' ou output: 'export'.
3 Variáveis de Ambiente: Tudo Que o Deploy Precisa
O Navistron inteiro funciona com apenas 3 variáveis de ambiente customizadas, configuradas no painel da Vercel:
- MONGODB_URI (server-only) — Connection string do MongoDB Atlas. Usada por
getClientPromise()emmongodb.jse peloseed.mjs. Sem prefixoNEXT_PUBLIC_, nunca exposta ao client - NAVISTRON_PASSWORD (server-only) — Senha do painel admin. Usada por
validateAdmin()em 3 rotas admin. Também sem prefixo público - NEXT_PUBLIC_SITE_URL (build-time, pública) — URL base do site. Com prefixo
NEXT_PUBLIC_, o valor é embutido no bundle no build time. Fallback:https://navistron.io. Usada em 13+ arquivos para canonical URLs, OpenGraph, sitemap e metadataBase
Uma consequência do prefixo NEXT_PUBLIC_: em preview deployments (ex: navistron-abc123.vercel.app), os canonicals e OG URLs ainda apontam para a URL de produção, a menos que a variável seja sobrescrita por branch.
8 API Routes como Serverless Functions
Cada arquivo route.js dentro de src/app/api/ é deployado como uma Serverless Function independente na Vercel — 8 funções no total, com 13 handlers HTTP:
- /api/scores — GET (top 100) + POST (registrar score). Collection:
scores - /api/anonymous-sessions — GET (7 aggregations) + POST (registrar sessão). Collection:
anonymous_sessions - /api/sponsors — GET (listar por valor). Collection:
sponsors - /api/sponsors/click — POST (registrar clique,
$inc+ insert). Collections:sponsors,sponsor_clicks - /api/stats — GET (10 aggregations paralelas via
Promise.all). Collection:scores - /api/admin/scores — GET + DELETE + PUT (protegido). Collection:
scores - /api/admin/sponsors — GET + POST + PUT + DELETE (protegido). Collection:
sponsors - /api/admin/sponsors/stats — GET (7 aggregations com
$lookup). Collections:sponsors,sponsor_clicks
Cada função é stateless: inicia, executa a query MongoDB, retorna a resposta JSON e pode ser destruída. O auto-scaling da Vercel cria réplicas conforme a demanda — zero configuração de infraestrutura.
MongoDB Singleton em Ambiente Serverless
A conexão com o MongoDB usa um padrão singleton em mongodb.js. A variável clientPromise armazena a Promise de conexão no escopo do módulo. Em ambiente serverless, isso funciona assim:
- Cold start — Primeira invocação de uma função: cria
new MongoClient(uri), chama.connect(), armazena a Promise emclientPromise. Latência de ~200-500ms adicional - Warm container — Invocações subsequentes no mesmo container reutilizam o mesmo
clientPromise— a conexão já está estabelecida. Latência de conexão: ~0ms - Container reciclado — Após inatividade, a Vercel destrói o container. Próxima invocação = novo cold start
Em desenvolvimento (NODE_ENV === 'development'), o singleton é armazenado em global._mongoClientPromise para sobreviver ao Hot Module Replacement (HMR) do Next.js. Em produção, usa o escopo do módulo — suficiente para containers serverless.
Todas as 8 API routes + as funções SSR usam o mesmo padrão: const client = await getClientPromise(); const db = client.db('navistron').
ISR na Vercel: Edge Cache com Stale-While-Revalidate
O Navistron tem 10 páginas ISR com intervalos diferentes. Na Vercel, o ISR funciona como stale-while-revalidate:
- A página é renderizada e cacheada no edge da Vercel (ponto de presença mais próximo do usuário)
- Dentro do intervalo de
revalidate, todas as requisições recebem a versão cacheada (instantâneo) - Após o intervalo expirar, a próxima requisição recebe o cache stale enquanto a Vercel re-renderiza a página em background
- A versão nova substitui o cache — próximos visitantes veem dados atualizados
Os intervalos são calibrados por volatilidade dos dados:
- 120s — Stats diário (dados mudam a cada partida)
- 300s — Ranking (geral, semanal, mensal) e Stats (geral, mensal)
- 600s — Stats anual e Sponsors (dados estáveis)
- 3.600s — Home e perfis de jogador
SSG: 23 Artigos + 500 Perfis Pré-Renderizados
Duas rotas dinâmicas usam generateStaticParams() para pré-renderizar páginas no build:
- Blog
[slug]— ChamagetAllSlugs()que retorna os 23 slugs do array JavaScript emblogArticles.js. Sem consulta ao banco — são dados estáticos. Cada slug gera uma página HTML completa no build. Sem revalidate — só atualiza com novo deploy - Player
[nickname]— ChamagetAllPlayerNames()que consulta o MongoDB via aggregation$group. Os primeiros 500 nomes (.slice(0, 500)) são pré-renderizados. ComdynamicParams = true, jogadores além dos 500 são renderizados on-demand e cacheados com ISR de 1 hora
Na Vercel, páginas SSG são servidas como arquivos estáticos da CDN — latência mínima, sem execução de código no servidor. Os artigos de blog, em particular, são entregues como HTML puro sem JavaScript de página (Server Components).
Sitemap Dinâmico com Dados do MongoDB
O sitemap.js é executado no build e gera o sitemap.xml com 3 fontes de URLs:
- 12 páginas estáticas — Com prioridades explícitas: home (1.0), play (0.9), ranking (0.8), blog (0.8), stats (0.7), sponsors (0.6), dashboard (0.5), e sub-rotas
- 23 slugs de blog — Via
getAllSlugs(), prioridade 0.7,changeFrequency: 'monthly' - Até 1.000 jogadores — Consulta
db.collection('scores').distinct('playerName')diretamente no MongoDB. Cada nome gera/player/{nome}com prioridade 0.5 echangeFrequency: 'daily'
Isso garante que o Google descubra perfis de jogadores automaticamente — sem necessidade de links internos para cada um.
Security Headers no Edge
O next.config.mjs define 3 headers de segurança aplicados a todas as rotas via source: '/(.*)':
X-Content-Type-Options: nosniff— Impede MIME sniffing de conteúdoX-Frame-Options: SAMEORIGIN— Bloqueia embedding em iframes de terceiros (anti-clickjacking)Referrer-Policy: strict-origin-when-cross-origin— Controla dados no header Referer
Na Vercel, esses headers são injetados na camada edge — aplicados antes de qualquer resposta chegar ao navegador. Adicionalmente, poweredByHeader: false remove o header X-Powered-By: Next.js, reduzindo surface area de ataque. O robots.js complementa bloqueando crawlers de /api/ e /admin/.
Image Optimization na Vercel
O componente next/image serve imagens otimizadas via /_next/image — na Vercel, isso é processado por uma função serverless de otimização. As 11 imagens WebP do projeto passam por:
- Redimensionamento automático — Baseado no atributo
sizes(ex:(max-width: 768px) 100vw, 800px), gera múltiplas versões para o srcset - Negociação de formato — Se o navegador suporta AVIF (via header
Accept), a Vercel pode converter de WebP para AVIF automaticamente - Cache na CDN — Imagens otimizadas são cacheadas no edge após a primeira requisição
- Preload de hero images — Imagens com
prioritygeram<link rel="preload">no<head>, iniciando download antes do parser chegar ao<img>
As imagens OG (1200×630) são servidas como arquivos estáticos de /public — não passam pelo Image Optimization, pois são referenciadas diretamente nos metadados OpenGraph.
FAQ — Perguntas Frequentes sobre o Deploy
O deploy é automático?
Sim. Cada push para a branch main aciona build + deploy automático na Vercel. Preview deployments são criados para branches e pull requests, cada um com URL única. O rollback é instantâneo — basta selecionar um deploy anterior no dashboard da Vercel.
O seed.mjs roda durante o deploy?
Não. O script npm run seed (node scripts/seed.mjs) é executado manualmente, uma única vez, para criar os 2 patrocinadores iniciais e os índices do MongoDB ({ score: -1 }, { playedAt: -1 }, { name: 1 } em scores e { value: -1 } em sponsors). O script é idempotente — não insere dados se a collection já tem documentos.
O que acontece no cold start de uma Serverless Function?
O container é inicializado, o módulo é carregado, e getClientPromise() cria uma nova conexão MongoDB (~200-500ms). Requisições subsequentes no mesmo container warm reutilizam a conexão. A Vercel mantém containers warm por alguns minutos após a última invocação, reduzindo cold starts em APIs com tráfego regular.
O banco de dados fica exposto publicamente?
Não. O MONGODB_URI é server-only (sem prefixo NEXT_PUBLIC_), nunca incluído em bundles do client. Rotas admin são protegidas por validateAdmin() com comparação direta contra NAVISTRON_PASSWORD. O robots.js bloqueia /api/ de crawlers, e os endpoints públicos (scores GET, sponsors GET) retornam apenas dados já públicos no ranking.
Como configurar o deploy na Vercel do zero?
3 passos: (1) conectar o repositório Git no dashboard da Vercel; (2) configurar as 3 variáveis de ambiente — MONGODB_URI, NAVISTRON_PASSWORD e NEXT_PUBLIC_SITE_URL; (3) executar npm run seed manualmente para criar índices e dados iniciais. A Vercel detecta o Next.js automaticamente, sem configuração adicional.
