Prompt-to-PR: Adicionar um Sitemap e robots.txt
SOP para adicionar um sitemap XML dinâmico e robots.txt a um projeto Next.js ou Astro — corrigir lastmod, prioridade e regras de rastreamento para SEO em produção.
CursorClaude CodeCodexWindsurf Next.jsAstroTypeScript
Sitemaps e robots.txt são as primeiras primitivas de SEO que um agente toca, e frequentemente estão errados — formato lastmod errado, diretiva Sitemap: ausente no robots, ou páginas bloqueadas incluídas inadvertidamente. Este manual acerta isso.
1. Requisito
Produza um sitemap XML cobrindo todas as rotas públicas (conteúdo estático + dinâmico do banco de dados) e um robots.txt que bloqueie caminhos admin/API e referencie o sitemap. Funciona tanto para Next.js App Router quanto Astro; escolha a abordagem correta para seu framework.
2. Primeiro Prompt
Add a sitemap.xml and robots.txt to this project. Use the correct approachfor the framework detected below.
### If Next.js 14+:1. Create `src/app/sitemap.ts` using the Next.js `MetadataRoute.Sitemap` return type. Include: - All static routes: /, /pricing, /blog, /about (hardcoded is fine). - All dynamic blog posts: fetch slugs from the DB using the existing query helper, return lastModified from the post's updatedAt field. - Use `process.env.NEXT_PUBLIC_APP_URL` as the base URL. - Correct W3C datetime format for lastModified (ISO 8601).2. Create `src/app/robots.ts` using MetadataRoute.Robots. - Allow: all routes. - Disallow: /admin, /api, /dashboard. - Add `sitemap: process.env.NEXT_PUBLIC_APP_URL + "/sitemap.xml"`.
### If Astro:1. Add `@astrojs/sitemap` integration. In astro.config.ts, add `sitemap({ filter: (page) => !page.includes("/admin") })` and set `site: process.env.SITE_URL`.2. Create `public/robots.txt`: User-agent: * Disallow: /admin Disallow: /api Sitemap: <SITE_URL>/sitemap-index.xml
Do not create a custom sitemap endpoint if the integration handles it.Do not block / or any public content pages.3. Mudanças Esperadas nos Arquivos
### Next.jssrc/app/sitemap.ts (new — dynamic MetadataRoute.Sitemap)src/app/robots.ts (new — MetadataRoute.Robots)
### Astroastro.config.ts (add sitemap integration + filter)public/robots.txt (new).env.example (SITE_URL added if missing)4. Lista de Verificação
- A URL base vem de uma variável de ambiente — não hardcoded como
http://localhost:3000. lastModifiedé um objetoDatedo JavaScript (Next.js converte para ISO 8601) ou já uma string ISO válida — não"undefined"ou ausente./admin,/apie/dashboardestão na lista Disallow.- A diretiva
Sitemap:emrobots.txtusa uma URL absoluta. - Rotas dinâmicas (posts de blog) são incluídas via consulta ao banco de dados, não apenas rotas estáticas.
- O sitemap não inclui páginas 404, de redirecionamento ou noindex.
- Execute
bun run builde depoiscurl /sitemap.xmlretorna XML válido (verifique comxmllint).
5. Comandos de Teste
bun run build && bun run start# or for Astro:bun run build && bun run preview
# Validate sitemap XMLcurl -s http://localhost:3000/sitemap.xml | xmllint --format - | head -40
# Confirm robots.txtcurl http://localhost:3000/robots.txt
# Confirm admin is disallowed and sitemap directive is presentgrep -E "Disallow|Sitemap" <(curl -s http://localhost:3000/robots.txt)
# Google Rich Results / URL Inspection simulationcurl -A "Googlebot" http://localhost:3000/sitemap.xml -I6. Falhas Comuns
lastModifiedé"undefined"— campoupdatedAtdo post é nulo. Proteção:lastModified: post.updatedAt ?? post.createdAt ?? new Date().- Sitemap retorna 404 —
src/app/sitemap.tsestá faltando ou colocado fora do diretórioapp. - Todas as rotas desabilitadas — agente adiciona
Disallow: /por engano. Confirme que apenas caminhos admin/API estão bloqueados. - Diretiva
Sitemap:tem URL relativa — Google a ignora. Deve ser absoluta:https://example.com/sitemap.xml. - Apenas sitemap estático — agente hardcodea slugs de blog em vez de consultar o banco. Confirme que a função do sitemap é
asynce busca dados reais.
7. Prompt de Correção
The sitemap.xml at /sitemap.xml includes every blog post withlastModified "undefined" (rendered as the string).
Fix in src/app/sitemap.ts: const posts = await getBlogPosts(); return posts.map((post) => ({ url: `${BASE_URL}/blog/${post.slug}`, lastModified: post.updatedAt ?? post.createdAt ?? new Date(), changeFrequency: "weekly", priority: 0.8, }));
Ensure getBlogPosts() returns rows that include updatedAt and createdAt.8. Descrição do PR
## SEO: Add dynamic sitemap.xml and robots.txt
**Next.js**: `src/app/sitemap.ts` + `src/app/robots.ts` using built-in`MetadataRoute` types. Sitemap includes static routes + all published blogposts with correct `lastModified` timestamps from the DB.
**robots.txt** disallows `/admin`, `/api`, `/dashboard`; includes absolute`Sitemap:` directive pointing to the generated `/sitemap.xml`.
Base URL read from `NEXT_PUBLIC_APP_URL` — no localhost URLs in production.