feat: add SEO and GEO discovery metadata

This commit is contained in:
2026-08-11 11:59:14 +03:00
parent 4fd7c8d457
commit fdff6a0a26
12 changed files with 355 additions and 8 deletions
+6
View File
@@ -2,6 +2,12 @@ import Link from "next/link";
import { requireUser } from "@/lib/auth/current-user"; import { requireUser } from "@/lib/auth/current-user";
import { DashboardMobileNav } from "@/components/dashboard-mobile-nav"; import { DashboardMobileNav } from "@/components/dashboard-mobile-nav";
import { BrandLogo } from "@/components/brand-logo"; import { BrandLogo } from "@/components/brand-logo";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Dashboard",
robots: { index: false, follow: false, nocache: true }
};
const nav = [ const nav = [
["Ads", "/dashboard/ads"], ["Ads", "/dashboard/ads"],
+19 -7
View File
@@ -1,18 +1,20 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
import "./globals.css"; import "./globals.css";
import { SITE_DESCRIPTION, SITE_NAME, SITE_URL } from "@/lib/seo";
const appUrl = process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000";
export const metadata: Metadata = { export const metadata: Metadata = {
metadataBase: new URL(appUrl), metadataBase: new URL(SITE_URL),
applicationName: "AdSeeQ", applicationName: SITE_NAME,
title: { title: {
default: "AdSeeQ — Reklam ve Trend Zekâsı", default: "AdSeeQ — Reklam ve Trend Zekâsı",
template: "%s | AdSeeQ" template: "%s | AdSeeQ"
}, },
description: "Meta reklamlarını, TikTok Shop ürünlerini, yükselen trendleri ve rakip markaları yapay zekâ ile tek panelden keşfedin.", description: SITE_DESCRIPTION,
keywords: ["reklam kütüphanesi", "Meta Ads", "TikTok Shop", "trend analizi", "marka takibi", "reklam zekâsı"], keywords: ["reklam kütüphanesi", "Meta Ads", "TikTok Shop", "trend analizi", "marka takibi", "reklam zekâsı"],
alternates: { canonical: "/" }, alternates: {
canonical: "/",
languages: { "tr-TR": "/" }
},
openGraph: { openGraph: {
title: "AdSeeQ — Kazanan reklamları ve trendleri keşfedin", title: "AdSeeQ — Kazanan reklamları ve trendleri keşfedin",
description: "Meta Ads, TikTok Shop, Magic AI Trends ve Brand Tracker tek panelde.", description: "Meta Ads, TikTok Shop, Magic AI Trends ve Brand Tracker tek panelde.",
@@ -26,7 +28,17 @@ export const metadata: Metadata = {
title: "AdSeeQ — Reklam ve Trend Zekâsı", title: "AdSeeQ — Reklam ve Trend Zekâsı",
description: "Kazanan reklamları, ürünleri ve rakip marka hareketlerini keşfedin." description: "Kazanan reklamları, ürünleri ve rakip marka hareketlerini keşfedin."
}, },
robots: { index: true, follow: true } robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
"max-image-preview": "large",
"max-snippet": -1,
"max-video-preview": -1
}
}
}; };
export default function RootLayout({ children }: { children: React.ReactNode }) { export default function RootLayout({ children }: { children: React.ReactNode }) {
+37
View File
@@ -0,0 +1,37 @@
import { SITE_DESCRIPTION, SITE_URL } from "@/lib/seo";
const content = `# AdSeeQ
> ${SITE_DESCRIPTION}
AdSeeQ, reklam araştırması ve e-ticaret trend keşfi yapan ekipler için web tabanlı bir platformdur.
## Temel özellikler
- Meta Ads Library reklamlarını anahtar kelime ve ülkeye göre araştırma
- Medya içeren reklam kreatiflerini inceleme ve kaydetme
- TikTok Shop ürün keşfi
- Magic AI ile reklam ve ürün sinyallerini analiz etme
- Trends ile yükselen sinyalleri takip etme
- Brand Tracker ve Store Tracker ile marka ve mağaza takibi
## Resmî sayfalar
- Ana sayfa: ${SITE_URL}
- Fiyatlandırma: ${SITE_URL}/pricing
- Hesap oluşturma: ${SITE_URL}/register
- Giriş: ${SITE_URL}/login
## Ürün bilgisi
AdSeeQ ücretsiz ve ücretli planlar sunar. Güncel plan limitleri ve fiyatlar için resmî fiyatlandırma sayfasını kullanın. Özel dashboard ve API rotaları herkese açık içerik değildir.
`;
export function GET() {
return new Response(content, {
headers: {
"content-type": "text/plain; charset=utf-8",
"cache-control": "public, max-age=3600, s-maxage=86400"
}
});
}
+12
View File
@@ -0,0 +1,12 @@
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Giriş",
description: "AdSeeQ hesabınıza giriş yapın.",
alternates: { canonical: "/login" },
robots: { index: false, follow: false, nocache: true }
};
export default function LoginLayout({ children }: { children: React.ReactNode }) {
return children;
}
+50
View File
@@ -0,0 +1,50 @@
import { ImageResponse } from "next/og";
export const alt = "AdSeeQ — Reklam ve trend zekâsı";
export const size = { width: 1200, height: 630 };
export const contentType = "image/png";
export default function OpenGraphImage() {
return new ImageResponse(
<div
style={{
alignItems: "center",
background: "linear-gradient(135deg, #0f172a 0%, #4c1d95 58%, #7c3aed 100%)",
color: "white",
display: "flex",
height: "100%",
justifyContent: "center",
padding: "72px",
width: "100%"
}}
>
<div style={{ display: "flex", flexDirection: "column", maxWidth: "980px" }}>
<div style={{ alignItems: "center", display: "flex", fontSize: 46, fontWeight: 800 }}>
<span
style={{
alignItems: "center",
background: "white",
borderRadius: 24,
color: "#6d28d9",
display: "flex",
height: 82,
justifyContent: "center",
marginRight: 24,
width: 82
}}
>
Q
</span>
AdSeeQ
</div>
<div style={{ fontSize: 72, fontWeight: 900, letterSpacing: "-3px", lineHeight: 1.06, marginTop: 48 }}>
Kazanan reklamları ve trendleri keşfedin
</div>
<div style={{ color: "#ddd6fe", fontSize: 30, lineHeight: 1.35, marginTop: 30 }}>
Meta Ads · TikTok Shop · Magic AI · Trends · Brand Tracker
</div>
</div>
</div>,
size
);
}
+54 -1
View File
@@ -1,9 +1,14 @@
import { LinkButton } from "@/components/ui/button"; import { LinkButton } from "@/components/ui/button";
import { BrandLogo } from "@/components/brand-logo"; import { BrandLogo } from "@/components/brand-logo";
import { homeFaq, homeStructuredData, serializeJsonLd } from "@/lib/seo";
export default function LandingPage() { export default function LandingPage() {
return ( return (
<main className="min-h-screen overflow-hidden bg-[radial-gradient(circle_at_top_left,#ddd6fe,transparent_35%),#f8fafc]"> <main className="min-h-screen overflow-hidden bg-[radial-gradient(circle_at_top_left,#ddd6fe,transparent_35%),#f8fafc]">
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: serializeJsonLd(homeStructuredData) }}
/>
<nav className="mx-auto flex max-w-7xl items-center justify-between px-6 py-6"> <nav className="mx-auto flex max-w-7xl items-center justify-between px-6 py-6">
<BrandLogo /> <BrandLogo />
<div className="flex gap-3"> <div className="flex gap-3">
@@ -20,7 +25,7 @@ export default function LandingPage() {
Kazanan reklamları ve mağazaları dakikalar içinde keşfet. Kazanan reklamları ve mağazaları dakikalar içinde keşfet.
</h1> </h1>
<p className="mt-6 max-w-2xl text-lg leading-8 text-slate-600"> <p className="mt-6 max-w-2xl text-lg leading-8 text-slate-600">
Meta reklam kütüphanesi, TikTok Shop ürün keşfi, Magic AI trend analizi ve rakip marka takibi tek panelde. AdSeeQ, reklam ve e-ticaret araştırmalarını tek panelde birleştiren reklam zekâsı platformudur. Meta Ads Library reklamlarını araştırın, TikTok Shop ürünlerini keşfedin, Magic AI ile trend sinyallerini analiz edin ve rakip markaları takip edin.
</p> </p>
<div className="mt-8 flex flex-wrap gap-3"> <div className="mt-8 flex flex-wrap gap-3">
<LinkButton href="/register" className="px-6 py-3">Ücretsiz başla</LinkButton> <LinkButton href="/register" className="px-6 py-3">Ücretsiz başla</LinkButton>
@@ -45,6 +50,54 @@ export default function LandingPage() {
</div> </div>
</div> </div>
</section> </section>
<section className="mx-auto max-w-7xl px-6 py-16" aria-labelledby="features-heading">
<div className="max-w-3xl">
<p className="text-sm font-black uppercase tracking-[0.2em] text-violet-700">Tek panel, altı araştırma aracı</p>
<h2 id="features-heading" className="mt-3 text-3xl font-black tracking-tight text-slate-950 md:text-4xl">
Reklamdan trende, araştırma akışınız tek yerde
</h2>
<p className="mt-4 leading-7 text-slate-600">
Kreatifleri bulun, sinyalleri karşılaştırın ve incelemek istediğiniz reklam, mağaza ve markaları kaydedin.
</p>
</div>
<div className="mt-9 grid gap-5 md:grid-cols-2 lg:grid-cols-3">
{[
["Meta reklam araştırması", "Anahtar kelime ve ülkeye göre medya içeren reklam kreatiflerini araştırın."],
["TikTok Shop keşfi", "Ürünleri ve mağaza sinyallerini aynı araştırma akışında inceleyin."],
["Magic AI", "Kreatif açıları, hedef kitle fikirleri ve test edilebilir yaklaşımlar üretin."],
["Trends", "Yükselen reklam ve ürün sinyallerini düzenli bir görünümde takip edin."],
["Brand Tracker", "Rakip markaları kaydedin ve yeni hareketlerini tek listeden izleyin."],
["Store Tracker", "Mağazaları takip edin, benzer mağazaları ve ürün sinyallerini keşfedin."]
].map(([title, description]) => (
<article key={title} className="rounded-3xl border border-slate-200 bg-white/80 p-6 shadow-sm">
<h3 className="text-lg font-black text-slate-950">{title}</h3>
<p className="mt-2 leading-7 text-slate-600">{description}</p>
</article>
))}
</div>
</section>
<section className="border-y border-slate-200 bg-white/70" aria-labelledby="faq-heading">
<div className="mx-auto max-w-4xl px-6 py-16">
<p className="text-sm font-black uppercase tracking-[0.2em] text-violet-700">Sık sorulan sorular</p>
<h2 id="faq-heading" className="mt-3 text-3xl font-black tracking-tight text-slate-950">AdSeeQ hakkında</h2>
<div className="mt-8 space-y-4">
{homeFaq.map(({ question, answer }) => (
<details key={question} className="group rounded-2xl border border-slate-200 bg-white p-5">
<summary className="cursor-pointer list-none pr-6 font-black text-slate-950">{question}</summary>
<p className="mt-3 leading-7 text-slate-600">{answer}</p>
</details>
))}
</div>
</div>
</section>
<footer className="mx-auto flex max-w-7xl flex-col gap-4 px-6 py-10 text-sm text-slate-500 sm:flex-row sm:items-center sm:justify-between">
<BrandLogo markClassName="h-8 w-8" />
<div className="flex gap-5">
<a href="/pricing" className="hover:text-slate-950">Fiyatlandırma</a>
<a href="/register" className="hover:text-slate-950">Ücretsiz başla</a>
<a href="/login" className="hover:text-slate-950">Giriş</a>
</div>
</footer>
</main> </main>
); );
} }
+12
View File
@@ -3,6 +3,18 @@ import { LinkButton } from "@/components/ui/button";
import { Card } from "@/components/ui/card"; import { Card } from "@/components/ui/card";
import { CheckoutButton } from "@/components/checkout-button"; import { CheckoutButton } from "@/components/checkout-button";
import { BrandLogo } from "@/components/brand-logo"; import { BrandLogo } from "@/components/brand-logo";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Fiyatlandırma",
description: "AdSeeQ Free, Basic, Standard ve Premium planlarının reklam arama, mağaza takip ve kayıt limitlerini karşılaştırın.",
alternates: { canonical: "/pricing", languages: { "tr-TR": "/pricing" } },
openGraph: {
title: "AdSeeQ Fiyatlandırma",
description: "İhtiyacınıza uygun reklam ve trend araştırma planını seçin.",
url: "/pricing"
}
};
export default async function PricingPage() { export default async function PricingPage() {
const plans = await prisma.plan.findMany({ orderBy: { sortOrder: "asc" } }).catch(() => []); const plans = await prisma.plan.findMany({ orderBy: { sortOrder: "asc" } }).catch(() => []);
+12
View File
@@ -0,0 +1,12 @@
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "Ücretsiz Hesap Oluştur",
description: "AdSeeQ ücretsiz hesabınızı oluşturun ve reklam araştırmasına başlayın.",
alternates: { canonical: "/register" },
robots: { index: false, follow: false, nocache: true }
};
export default function RegisterLayout({ children }: { children: React.ReactNode }) {
return children;
}
+14
View File
@@ -0,0 +1,14 @@
import type { MetadataRoute } from "next";
import { SITE_URL } from "@/lib/seo";
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: "*",
allow: ["/", "/pricing", "/llms.txt"],
disallow: ["/api/", "/dashboard/", "/login", "/register"]
},
sitemap: `${SITE_URL}/sitemap.xml`,
host: SITE_URL
};
}
+19
View File
@@ -0,0 +1,19 @@
import type { MetadataRoute } from "next";
import { SITE_URL } from "@/lib/seo";
export default function sitemap(): MetadataRoute.Sitemap {
return [
{
url: SITE_URL,
changeFrequency: "weekly",
priority: 1,
alternates: { languages: { "tr-TR": SITE_URL } }
},
{
url: `${SITE_URL}/pricing`,
changeFrequency: "monthly",
priority: 0.8,
alternates: { languages: { "tr-TR": `${SITE_URL}/pricing` } }
}
];
}
+85
View File
@@ -0,0 +1,85 @@
export const SITE_URL = "https://adseeq.com";
export const SITE_NAME = "AdSeeQ";
export const SITE_DESCRIPTION =
"Meta reklamlarını, TikTok Shop ürünlerini, yükselen trendleri ve rakip markaları yapay zekâ destekli tek panelden araştırın.";
export const homeFaq = [
{
question: "AdSeeQ nedir?",
answer:
"AdSeeQ; Meta reklamlarını, TikTok Shop ürünlerini, yükselen trendleri ve rakip markaları tek panelde araştırmaya yardımcı olan reklam ve trend zekâsı platformudur."
},
{
question: "AdSeeQ ile hangi reklamlar araştırılabilir?",
answer:
"Meta Ads Library kaynaklı reklamlar anahtar kelime ve ülke ölçütleriyle aranabilir; medya içeren kreatifler incelenebilir ve uygun reklamlar daha sonra değerlendirmek üzere kaydedilebilir."
},
{
question: "Magic AI ne işe yarar?",
answer:
"Magic AI, reklam ve ürün sinyallerini özetleyerek kreatif açıları, hedef kitle fikirleri ve test edilebilecek pazarlama yaklaşımları üretmeye yardımcı olur."
},
{
question: "AdSeeQ ücretsiz kullanılabilir mi?",
answer:
"Evet. Ücretsiz plan günlük sınırlı reklam araması sunar; daha yüksek arama ve takip limitleri için ücretli planlar bulunur."
}
] as const;
export const homeStructuredData = {
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"@id": `${SITE_URL}/#organization`,
name: SITE_NAME,
url: SITE_URL,
logo: `${SITE_URL}/icon.svg`
},
{
"@type": "WebSite",
"@id": `${SITE_URL}/#website`,
url: SITE_URL,
name: SITE_NAME,
description: SITE_DESCRIPTION,
inLanguage: "tr-TR",
publisher: { "@id": `${SITE_URL}/#organization` }
},
{
"@type": "SoftwareApplication",
"@id": `${SITE_URL}/#software`,
name: SITE_NAME,
applicationCategory: "BusinessApplication",
applicationSubCategory: "Advertising Intelligence",
operatingSystem: "Web",
url: SITE_URL,
description: SITE_DESCRIPTION,
inLanguage: "tr-TR",
offers: {
"@type": "Offer",
price: "0",
priceCurrency: "EUR",
description: "Günlük sınırlı reklam araması içeren ücretsiz plan"
},
publisher: { "@id": `${SITE_URL}/#organization` }
},
{
"@type": "FAQPage",
"@id": `${SITE_URL}/#faq`,
mainEntity: homeFaq.map(({ question, answer }) => ({
"@type": "Question",
name: question,
acceptedAnswer: {
"@type": "Answer",
text: answer
}
}))
}
]
};
export function serializeJsonLd(value: unknown) {
return JSON.stringify(value).replace(/</g, "\\u003c");
}
+35
View File
@@ -8,6 +8,10 @@ import { stripePriceFor } from "../src/lib/stripe";
import { tikTokActorInput } from "../src/lib/apify-tiktok"; import { tikTokActorInput } from "../src/lib/apify-tiktok";
import { NextRequest } from "next/server"; import { NextRequest } from "next/server";
import { proxy } from "../src/proxy"; import { proxy } from "../src/proxy";
import sitemap from "../src/app/sitemap";
import robots from "../src/app/robots";
import { GET as llmsTxt } from "../src/app/llms.txt/route";
import { homeStructuredData, serializeJsonLd } from "../src/lib/seo";
test("Apify reklamı metin, medya ve ülke alanlarıyla normalize edilir", () => { test("Apify reklamı metin, medya ve ülke alanlarıyla normalize edilir", () => {
const ad = normalizeApifyAd({ const ad = normalizeApifyAd({
@@ -76,3 +80,34 @@ test("AdSeeQ ana alan adı yönlendirilmez", () => {
assert.equal(response.status, 200); assert.equal(response.status, 200);
assert.equal(response.headers.get("location"), null); assert.equal(response.headers.get("location"), null);
}); });
test("sitemap yalnızca indekslenebilir herkese açık sayfaları içerir", () => {
const urls = sitemap().map((entry) => entry.url);
assert.deepEqual(urls, ["https://adseeq.com", "https://adseeq.com/pricing"]);
assert.equal(new Set(urls).size, urls.length);
});
test("robots özel alanları engeller ve sitemap adresini bildirir", () => {
const value = robots();
assert.equal(value.sitemap, "https://adseeq.com/sitemap.xml");
assert.deepEqual(value.rules, {
userAgent: "*",
allow: ["/", "/pricing", "/llms.txt"],
disallow: ["/api/", "/dashboard/", "/login", "/register"]
});
});
test("llms.txt ürün kapsamını düz metin olarak açıklar", async () => {
const response = llmsTxt();
const body = await response.text();
assert.match(response.headers.get("content-type") || "", /^text\/plain/);
assert.match(body, /Meta Ads Library/);
assert.match(body, /https:\/\/adseeq\.com\/pricing/);
});
test("ana sayfa JSON-LD verisi yazılım ve SSS şemalarını içerir", () => {
const value = serializeJsonLd(homeStructuredData);
assert.match(value, /SoftwareApplication/);
assert.match(value, /FAQPage/);
assert.equal(value.includes("<"), false);
});