Kyrux
Voltar

SEO & Security.txt

Todo projeto Kyrux traz por padrão o app embutido apps/meta, instalado automaticamente (já listado em core/apps/installed.go) — sem precisar rodar startapp nem registrar nada manualmente. Ele serve três arquivos que praticamente todo site público precisa e que, sem isso, cada projeto acaba reimplementando do zero:

Rota O que é
GET /robots.txt Libera indexação total (Allow: /) e aponta pro sitemap
GET /sitemap.xml Lista de páginas indexáveis
GET /.well-known/security.txt Contato de segurança, formato RFC 9116
GET /security.txt Redireciona (301) para /.well-known/security.txt — alguns scanners antigos ainda checam a raiz primeiro

Separação: routes.go só mapeia caminho, views.go tem o conteúdo

apps/meta/
├── routes.go          ← router.Path("GET", "/robots.txt", views.RobotsView(fw), ...)
└── views/
    └── views.go        ← conteúdo, montagem do XML/texto, fallback sem APP_URL

Essa separação não é cosmética: routes.go fica legível como um índice de URLs do projeto — pra saber o que uma rota faz, você olha a view, não precisa ler lógica de string-building no meio da lista de rotas.

APP_URL — a origem canônica

# .env
APP_URL=https://meusite.com.br

APP_URL (sem barra final) é usada pra montar as URLs absolutas de Sitemap: no robots.txt, <loc> no sitemap.xml e Canonical: no security.txt. Sem ela configurada, os três arquivos continuam funcionando — só omitem os campos que dependeriam do domínio (sitemap.xml sai com <loc> relativo, robots.txt sem a linha Sitemap:, security.txt sem Canonical:). Configure antes de ir pra produção.

Customizando o conteúdo

Os três handlers ficam em apps/meta/views/views.go — edite direto ali:

// sitemapPaths lista as páginas públicas do projeto. O framework não
// descobre isso sozinho a partir das rotas registradas — nem toda rota
// GET é uma página que faz sentido indexar (endpoints JSON, rotas com
// parâmetro, etc).
var sitemapPaths = []string{
	"/",
	"/sobre/",
	"/contato/",
}

// securityContact e securityExpires — troque pelo contato real de
// segurança do projeto e revise Expires todo ano (RFC 9116: depois dessa
// data, scanners voltam a reportar o arquivo como ausente/inválido mesmo
// ele existindo).
const (
	securityContact = "mailto:[email protected]"
	securityExpires = "2027-01-01T00:00:00.000Z"
)

Se o projeto já tem uma fonte de verdade pras próprias páginas — um slice de seções, resultado de uma query, o retorno de Router.Routes() filtrado — troque o slice fixo sitemapPaths por uma função que monte a lista a partir dela, em vez de manter os dois sincronizados manualmente. É exatamente o que este site faz: seu sitemap.xml é montado a partir de content.All(), a mesma fonte que alimenta a navegação da documentação — cada seção nova em apps/docs/content/markdown/ aparece no sitemap sem editar views.go.

robots.txt bloqueando alguma área

Por padrão o RobotsView libera tudo (Allow: /). Pra restringir uma área (ex: /admin/), edite o corpo montado em RobotsView — não tem flag de configuração pra isso, é só string.