feat: add sitemap.xml, robots.txt, full SEO metadata

This commit is contained in:
AyrisAI
2026-07-25 00:10:11 +03:00
parent 9511682906
commit d88cf955c7
3 changed files with 145 additions and 2 deletions
+40 -2
View File
@@ -20,9 +20,47 @@ const jetbrainsMono = JetBrains_Mono({
weight: ["400", "500", "600", "700"],
});
const BASE_URL = 'https://ayrisai.xyz';
export const metadata: Metadata = {
title: "DevHub YouTube | Educational Code & Resource Portal",
description: "Official resource portal featuring tabbed code snippets, lesson notes, starter packs, and project downloads for my YouTube tutorials.",
metadataBase: new URL(BASE_URL),
title: {
default: 'ayris.tech YouTube | Code & Resource Portal',
template: '%s | ayris.tech YouTube',
},
description:
'Official resource portal for the ayris.tech YouTube channel. Browse source code, lesson notes, cheatsheets, AI prompts, and project downloads for every tutorial.',
keywords: [
'Next.js', 'React', 'TypeScript', 'Tailwind CSS', 'Python',
'YouTube tutorial', 'source code', 'ayris.tech', 'web development',
'AI agents', 'Prisma', 'Docker', 'full-stack',
],
authors: [{ name: 'ayris.tech', url: BASE_URL }],
creator: 'ayris.tech',
openGraph: {
type: 'website',
locale: 'en_US',
url: BASE_URL,
siteName: 'ayris.tech YouTube Portal',
title: 'ayris.tech YouTube | Code & Resource Portal',
description:
'Source code, lesson notes, cheatsheets, and project downloads for every ayris.tech YouTube tutorial.',
images: [{ url: `${BASE_URL}/logo.jpeg`, width: 400, height: 400, alt: 'ayris.tech Logo' }],
},
twitter: {
card: 'summary_large_image',
title: 'ayris.tech YouTube | Code & Resource Portal',
description: 'Source code, cheatsheets, AI prompts and downloads for every ayris.tech tutorial.',
images: [`${BASE_URL}/logo.jpeg`],
},
robots: {
index: true,
follow: true,
googleBot: { index: true, follow: true },
},
alternates: {
canonical: BASE_URL,
},
};
export function generateStaticParams() {
+32
View File
@@ -0,0 +1,32 @@
import type { MetadataRoute } from 'next';
const BASE_URL = 'https://ayrisai.xyz';
const PROTECTED = ['/admin/', '/api/'];
export default function robots(): MetadataRoute.Robots {
return {
rules: [
// Genel arama botları — tüm public içerik açık
{
userAgent: '*',
allow: '/',
disallow: PROTECTED,
},
// AI arama / citation botları — izin ver
{ userAgent: 'OAI-SearchBot', allow: '/', disallow: PROTECTED },
{ userAgent: 'ChatGPT-User', allow: '/', disallow: PROTECTED },
{ userAgent: 'PerplexityBot', allow: '/', disallow: PROTECTED },
{ userAgent: 'Perplexity-User', allow: '/', disallow: PROTECTED },
{ userAgent: 'Claude-SearchBot', allow: '/', disallow: PROTECTED },
{ userAgent: 'Claude-User', allow: '/', disallow: PROTECTED },
// Training crawler'ları engelle
{ userAgent: 'GPTBot', disallow: '/' },
{ userAgent: 'ClaudeBot', disallow: '/' },
{ userAgent: 'Google-Extended', disallow: '/' },
{ userAgent: 'CCBot', disallow: '/' },
{ userAgent: 'Bytespider', disallow: '/' },
{ userAgent: 'Meta-ExternalAgent', disallow: '/' },
],
sitemap: `${BASE_URL}/sitemap.xml`,
};
}
+73
View File
@@ -0,0 +1,73 @@
import type { MetadataRoute } from 'next';
import { getLessons } from '@/lib/actions/lessonActions';
import { getCheatsheets } from '@/lib/actions/cheatsheetActions';
import { getPrompts } from '@/lib/actions/promptActions';
const BASE_URL = 'https://ayrisai.xyz';
const LOCALES = ['en'];
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const now = new Date();
// Static pages
const staticRoutes = [
{ path: '', priority: 1.0, changeFrequency: 'daily' as const },
{ path: '/lessons', priority: 0.9, changeFrequency: 'daily' as const },
{ path: '/cheatsheets', priority: 0.8, changeFrequency: 'weekly' as const },
{ path: '/prompts', priority: 0.8, changeFrequency: 'weekly' as const },
{ path: '/contact', priority: 0.5, changeFrequency: 'monthly' as const },
];
const staticEntries: MetadataRoute.Sitemap = LOCALES.flatMap((locale) =>
staticRoutes.map(({ path, priority, changeFrequency }) => ({
url: `${BASE_URL}/${locale}${path}`,
lastModified: now,
changeFrequency,
priority,
}))
);
// Dynamic: Lessons
let lessonEntries: MetadataRoute.Sitemap = [];
try {
const lessons = await getLessons();
lessonEntries = LOCALES.flatMap((locale) =>
lessons.map((lesson: any) => ({
url: `${BASE_URL}/${locale}/lessons/${lesson.slug}`,
lastModified: lesson.updatedAt || now,
changeFrequency: 'weekly' as const,
priority: 0.85,
}))
);
} catch {}
// Dynamic: Cheatsheets
let cheatEntries: MetadataRoute.Sitemap = [];
try {
const sheets = await getCheatsheets();
cheatEntries = LOCALES.flatMap((locale) =>
sheets.map((sheet: any) => ({
url: `${BASE_URL}/${locale}/cheatsheets/${sheet.slug}`,
lastModified: sheet.updatedAt || now,
changeFrequency: 'monthly' as const,
priority: 0.7,
}))
);
} catch {}
// Dynamic: Prompts
let promptEntries: MetadataRoute.Sitemap = [];
try {
const prompts = await getPrompts();
promptEntries = LOCALES.flatMap((locale) =>
prompts.map((prompt: any) => ({
url: `${BASE_URL}/${locale}/prompts/${prompt.slug}`,
lastModified: prompt.updatedAt || now,
changeFrequency: 'monthly' as const,
priority: 0.7,
}))
);
} catch {}
return [...staticEntries, ...lessonEntries, ...cheatEntries, ...promptEntries];
}