// src/app/sitemap.ts // ───────────────────────────────────────────────────────────────────────────── // Dynamic sitemap generated from Prisma data — emits one entry per locale per // active page (home, applications, news articles, heritage, news hub). // // Auto-discoverable at /sitemap.xml, no Nginx config needed. // Search engines re-crawl this on each visit; Next.js caches it for `revalidate`. // ───────────────────────────────────────────────────────────────────────────── import type { MetadataRoute } from "next"; import { prisma } from "@/lib/prisma"; const LOCALES = ["en", "it", "vec", "es", "de"] as const; function baseUrl() { return (process.env.NEXT_PUBLIC_APP_URL || "https://rf-flux.com").replace(/\/$/, ""); } export const revalidate = 3600; // Re-generate sitemap once per hour export default async function sitemap(): Promise { const base = baseUrl(); const now = new Date(); const entries: MetadataRoute.Sitemap = []; // ── Static routes ───────────────────────────────────────────── const staticPaths = [ { path: "", priority: 1.0, changeFrequency: "weekly" as const }, { path: "/news", priority: 0.7, changeFrequency: "daily" as const }, { path: "/heritage", priority: 0.6, changeFrequency: "monthly" as const }, { path: "/team", priority: 0.6, changeFrequency: "monthly" as const }, { path: "/privacy", priority: 0.3, changeFrequency: "yearly" as const }, ]; for (const locale of LOCALES) { for (const { path, priority, changeFrequency } of staticPaths) { entries.push({ url: `${base}/${locale}${path}`, lastModified: now, changeFrequency, priority, alternates: { languages: Object.fromEntries( LOCALES.map((alt) => [alt, `${base}/${alt}${path}`]) ), }, }); } } // ── Application pages ───────────────────────────────────────── try { const applications = await prisma.application.findMany({ where: { isActive: true }, select: { slug: true, updatedAt: true }, }); for (const app of applications) { for (const locale of LOCALES) { entries.push({ url: `${base}/${locale}/applications/${app.slug}`, lastModified: app.updatedAt, changeFrequency: "weekly", priority: 0.9, alternates: { languages: Object.fromEntries( LOCALES.map((alt) => [alt, `${base}/${alt}/applications/${app.slug}`]) ), }, }); } } } catch (error) { console.error("[sitemap] Failed to load applications:", error); } // ── News articles ───────────────────────────────────────────── try { const articles = await prisma.newsArticle.findMany({ where: { isActive: true }, select: { slug: true, updatedAt: true, publishedAt: true }, orderBy: { publishedAt: "desc" }, }); for (const article of articles) { for (const locale of LOCALES) { entries.push({ url: `${base}/${locale}/news/${article.slug}`, lastModified: article.updatedAt, changeFrequency: "monthly", priority: 0.7, alternates: { languages: Object.fromEntries( LOCALES.map((alt) => [alt, `${base}/${alt}/news/${article.slug}`]) ), }, }); } } } catch (error) { console.error("[sitemap] Failed to load news articles:", error); } return entries; }