Merge branch 'gece/p3-vaat-dili' into gece/entegrasyon-test

This commit is contained in:
bilalgursen
2026-09-21 04:58:16 +03:00
12 changed files with 79 additions and 52 deletions

View File

@@ -67,9 +67,10 @@ KURALLAR (kesin):
- METİN DİYETİ: her alan TEK kısa cümle, dolgu söz yok.
- gerekce: bu programın bu aday için neden mantıklı olduğu (TEK cümle,
en fazla ~15 kelime, Türkçe).
- riskNotu: yerleşme ihtimali değerlendirmesi (TEK kısa cümle). ASLA "garanti",
"kesin", "yüzde yüz" deme; "yüksek/orta/düşük ihtimal" dili kullan.
- trendOzeti: son 4 yılın taban sıralaması hareketi, TEK cümle (ör. "2022'den
- riskNotu: geçmiş taban verisine dayalı risk değerlendirmesi (TEK kısa cümle).
ASLA garanti/kesin/yüzde/olasılık/ihtimal deme; "güvenli / az riskli /
riskli" etiketleriyle konuş.
- trendOzeti: son 5 yılın taban sıralaması hareketi, TEK cümle (ör. "2022'den
beri taban 45B'den 38B'ye indi, bölüm zorlaşıyor").
- Adayın sıralaması yaklaşıktır; kesin sıra telaffuz etme, banda göre konuş.`;
@@ -82,9 +83,9 @@ function mockMetin(p: Program, temsiliSira: number, kategori: string | null) {
return {
gerekce: `(Dev mock) ${p.isim}, ${kategori ? `${kategori} ilgisiyle ve ` : ""}~${temsiliSira.toLocaleString("tr-TR")} bandındaki sıralamanla uyumlu bir aday.`,
riskNotu:
"(Dev mock) Taban sıralaması senin civarında; orta-yüksek ihtimalle yerleşilebilir.",
"(Dev mock) Son taban sıralaması sırana yakın; küçük bir kayma sonucu değiştirebilir.",
trendOzeti:
"(Dev mock) Son 4 yılda taban sıralaması görece stabil seyretti.",
"(Dev mock) Son 5 yılda taban sıralaması görece stabil seyretti.",
};
}

View File

@@ -45,7 +45,8 @@ KURALLAR:
sıralaması adayın belirgin altında, Az riskli (sarı) = adayın sıralaması
civarında, Riskli (kırmızı) = geçen yıl adayın sıralamasının üzerinde
kapandı. Risk sorularında bu etiketleri ve taban sıralarını kullan.
- ASLA yerleşme garantisi verme; "yüksek/orta/düşük ihtimal" dili kullan.
- ASLA yerleşme garantisi verme; olasılık, yüzde ya da "ihtimal" dili kullanma —
güvenli / az riskli / riskli etiketleri ve taban sıralarıyla konuş.
- Bilmediğin güncel veriyi uydurma; emin değilsen YÖK Atlas'a bakmasını söyle.
- Taban sıralamalarının her yıl değiştiğini gerektiğinde hatırlat.
- Cevapları kısa ve öz tut (genelde 3-6 cümle); istenirse detaylandır.

View File

@@ -52,7 +52,7 @@ export const metadata: Metadata = {
template: "%s — KolayTercih",
},
description:
"YKS sıralamana göre gerçek YÖK Atlas verisiyle dengeli 24 tercihlik liste. İnsan danışmanın onda bir fiyatına, yapay zekâ destekli tercih danışmanlığı.",
"YKS sıralamana göre gerçek YÖK Atlas verisiyle dengeli 24 tercihlik liste. İnsan danışmandan çok daha düşük fiyata, yapay zekâ destekli tercih danışmanlığı.",
applicationName: "KolayTercih",
openGraph: {
type: "website",

View File

@@ -12,7 +12,6 @@ import {
TrendingUp,
Wallet,
} from "lucide-react";
import Image from "next/image";
import Link from "next/link";
import { Suspense } from "react";
import { ComparisonCell } from "@/features/pazarlama/components/landing-parcalari";
@@ -30,6 +29,7 @@ import {
SectionEyebrow,
} from "@/components/pixel-decor";
import { MAX_REVIZYON, URUNLER } from "@/lib/credits";
import { VERI_YIL_SAYISI } from "@/lib/veri-kapsami";
import {
Accordion,
AccordionContent,
@@ -54,9 +54,11 @@ import {
import type { Metadata } from "next";
import {
JsonLd,
KATALOG_VERI_TARIHI,
faqPageJsonLd,
softwareApplicationJsonLd,
} from "@/lib/seo";
import { KATALOG_TARIH_METNI } from "@/features/katalog/components/veri-kaynagi";
import { SiteFooter } from "@/components/site-footer";
export const metadata: Metadata = {
@@ -87,7 +89,7 @@ const problems = [
icon: Wallet,
title: "Danışman lüks haline geldi",
description:
"İyi bir tercih danışmanı 2.000–10.000 TL istiyor. Ücretsiz robotlar ise sadece liste filtreliyor, akıl vermiyor.",
"İyi bir tercih danışmanı 1.000–5.000 TL istiyor. Ücretsiz robotlar ise sadece liste filtreliyor, akıl vermiyor.",
},
];
@@ -103,8 +105,7 @@ const steps = [
icon: BarChart3,
step: "2",
title: "Yapay zekâ veriyi tarasın",
description:
"Son 4 yılın YÖK Atlas verisi — taban sıralaması trendleri, kontenjan değişimleri, doluluk oranları — senin için analiz edilsin.",
description: `Son ${VERI_YIL_SAYISI} yılın YÖK Atlas verisi — taban sıralaması trendleri, kontenjan değişimleri, doluluk oranları — senin için analiz edilsin.`,
},
{
icon: ShieldCheck,
@@ -118,8 +119,7 @@ const steps = [
const faqs = [
{
question: "KolayTercih'in önerileri neye dayanıyor?",
answer:
"Tüm öneriler YÖK Atlas'ın resmî verisine dayanır: son 4 yılın taban başarı sıralamaları, kontenjanlar, yerleşme istatistikleri ve doluluk oranları. Yapay zekâ bu veriyi yorumlar; veri olmadan tahmin yürütmez.",
answer: `Tüm öneriler YÖK Atlas'ın resmî verisine dayanır: son ${VERI_YIL_SAYISI} yılın taban başarı sıralamaları, kontenjanlar, yerleşme istatistikleri ve doluluk oranları. Yapay zekâ bu veriyi yorumlar; veri olmadan tahmin yürütmez.`,
},
{
question: "Ücretsiz tercih robotlarından farkı ne?",
@@ -145,7 +145,7 @@ const comparison = [
tercihai: true,
},
{
feature: "Son 4 yılın trend analizi",
feature: `Son ${VERI_YIL_SAYISI} yılın trend analizi`,
robot: false,
danisman: true,
tercihai: true,
@@ -165,7 +165,7 @@ const comparison = [
{
feature: "Fiyat",
robot: "Ücretsiz",
danisman: "2.000–10.000 TL",
danisman: "1.000–5.000 TL",
tercihai: `${PAKET_FIYATI} TL · tek seferlik`,
},
];
@@ -177,7 +177,7 @@ const paketOzellikleri = [
},
{
icon: ShieldCheck,
text: "Her tercih için yerleşme olasılığı ve risk analizi (son 4 yıl)",
text: `Her tercih için yerleşme riski ve trend analizi (son ${VERI_YIL_SAYISI} yıl)`,
},
{ icon: FileText, text: "Veliyle paylaşılabilir PDF rapor" },
{ icon: RefreshCcw, text: `${MAX_REVIZYON} liste revizyon hakkı` },
@@ -222,11 +222,6 @@ export default function Home() {
className="mx-auto flex min-h-[calc(100svh-5.5rem)] max-w-6xl flex-col items-center justify-center px-4 pb-4 pt-12 text-center sm:pb-36 sm:pt-4"
>
<HeroBaslik />
{/* <p className="mt-6 max-w-2xl text-lg leading-relaxed text-slate-600">
KolayTercih, gerçek YÖK Atlas verisiyle çalışan yapay zekâ tercih
danışmanın. İnsan danışmanın binlerce lira aldığı işi — dengeli
liste, risk analizi, soru-cevap — onda bir fiyatına yapar.
</p> */}
<div
id="hero-form"
className="mt-6 flex w-full scroll-mt-28 justify-center"
@@ -234,19 +229,14 @@ export default function Home() {
<HeroForm />
</div>
<div className="mt-3 inline-flex items-center gap-2.5 rounded-lg border border-slate-200 bg-white px-3 py-2 text-left text-xs text-slate-700 shadow-xs">
<Image
src="/yok-logo.svg"
alt="Yükseköğretim Kurulu"
width={68}
height={33}
className="h-7 w-auto shrink-0"
/>
<span className="h-5 w-px shrink-0 bg-slate-200" aria-hidden />
<span>
<strong className="font-semibold text-slate-900">
YÖK Atlas&apos;ın gerçek verileriyle
Veri: YÖK Atlas
</strong>{" "}
güvenilir sonuçlar
· son güncelleme{" "}
<time dateTime={KATALOG_VERI_TARIHI}>
{KATALOG_TARIH_METNI}
</time>
</span>
</div>
</Parallax>
@@ -362,7 +352,7 @@ export default function Home() {
{[
{ value: "23.000+", label: "Taranan lisans programı" },
{
value: "4 yıl",
value: `${VERI_YIL_SAYISI} yıl`,
label: "Taban sıralaması trend verisi",
},
{ value: "%100", label: "Resmî YÖK Atlas kaynağı" },
@@ -481,10 +471,13 @@ export default function Home() {
Ne kadar? Ne dahil?
</h2>
<p className="max-w-xl text-lg leading-relaxed text-slate-600">
İnsan danışmanın 2.000–10.000 TL aldığı işi tek seferlik{" "}
İnsan danışmanın 1.000–5.000 TL aldığı işi tek seferlik{" "}
{PAKET_FIYATI} TL&apos;ye alırsın. Abonelik yok, gizli ücret
yok.
</p>
<p className="text-xs text-slate-500">
Danışman fiyat aralığı: Armut, 2026.
</p>
</Reveal>
</Parallax>

View File

@@ -46,10 +46,10 @@ export default function PaketPage({
<SectionEyebrow>Tek seferlik ödeme · Abonelik yok</SectionEyebrow>
<h1 className="mt-4 font-heading text-3xl font-bold sm:text-4xl">
İnsan danışmanın işini,{" "}
<span className="text-primary">onda bir fiyatına</span>
<span className="text-primary">çok daha düşük fiyata</span>
</h1>
<p className="mx-auto mt-3 max-w-xl text-slate-600">
Tercih danışmanları bu dönemde 2.000–10.000 TL alıyor. KolayTercih
Tercih danışmanları bu dönemde 1.000–5.000 TL alıyor. KolayTercih
aynı işi gerçek YÖK Atlas verisiyle, dakikalar içinde yapar.
</p>
</Parallax>

View File

@@ -35,7 +35,7 @@ const FUNNEL_METINLERI = [
"Sıralaman ne söylüyor? Birlikte bakalım.",
"Her satırı senin için hesaplıyoruz.",
"Akıllı tercih, içi rahat bir bekleyiş.",
"Yerleşme ihtimalini görerek seç.",
"Yerleşme riskini görerek seç.",
"Sana özel liste birkaç dakikada hazır.",
"İlgi alanların ve şehrin, tek listede.",
"Boş kalan tercih, kaçan fırsattır.",

View File

@@ -1,7 +1,9 @@
import { KATALOG_VERI_TARIHI } from "@/lib/seo";
import { cn } from "@/lib/utils";
const TARIH_METNI = new Date(
// Veri tarihinin görünür biçimi ("9 Ağustos 2026") — tek biçim kaynağı; ana
// sayfa hero'sundaki veri satırı da bunu kullanır.
export const KATALOG_TARIH_METNI = new Date(
`${KATALOG_VERI_TARIHI}T00:00:00Z`,
).toLocaleDateString("tr-TR", {
day: "numeric",
@@ -23,7 +25,7 @@ export function VeriKaynagi({
<p className={cn("mt-3 text-xs leading-5 text-slate-500", className)}>
{children}
Kaynak: YÖK Atlas 2025 yerleştirme sonuçları. Son güncelleme:{" "}
<time dateTime={KATALOG_VERI_TARIHI}>{TARIH_METNI}</time>.
<time dateTime={KATALOG_VERI_TARIHI}>{KATALOG_TARIH_METNI}</time>.
</p>
);
}

View File

@@ -12,6 +12,7 @@ import {
} from "lucide-react";
import { getCurrentUser } from "@/lib/session";
import { URUNLER, DENEME_KREDISI } from "@/lib/credits";
import { VERI_YIL_SAYISI } from "@/lib/veri-kapsami";
import { Button } from "@/components/ui/button";
import { Parallax } from "@/components/parallax";
import { Skeleton } from "@/components/ui/skeleton";
@@ -28,7 +29,7 @@ const OZELLIKLER = [
},
{
icon: ShieldCheck,
text: "Her tercih için yerleşme olasılığı ve risk analizi (son 4 yıl trend)",
text: `Her tercih için yerleşme riski ve trend analizi (son ${VERI_YIL_SAYISI} yıl)`,
},
{ icon: FileText, text: "Veliyle paylaşılabilir PDF rapor" },
{ icon: RefreshCcw, text: "2 liste revizyon hakkı" },

View File

@@ -18,7 +18,12 @@ import {
type AdayProgram,
} from "../rapor-havuzu";
import { secimOzeti } from "@/features/sihirbaz/sihirbaz-sabitler";
import { RISK_ETIKET, dilimdenRisk, riskHesapla } from "../risk";
import {
RISK_ETIKET,
dilimdenRisk,
riskHesapla,
riskNotuMetni,
} from "../risk";
// Yapay zekâdan istenen küçük şema (kullanıcı kararı, 6 Ağu 2026): riskNotu
// ve trendOzeti gerçek sıra geçmişinden deterministik üretilir; dilim iskeleti
@@ -161,16 +166,7 @@ function trendOzetiUret(p: AdayProgram): string {
}
function riskNotuUret(p: AdayProgram, adaySira: number): string {
switch (riskHesapla(p.sira2025 ?? p.sira2024, adaySira)) {
case "guvenli":
return "Taban sıralaması senin sıranın belirgin altında; yüksek ihtimalle yerleşirsin.";
case "az-riskli":
return "Taban sıralaması sırana yakın; orta ihtimalle yerleşilebilir.";
case "riskli":
return "Taban sıralaması senin sıranın üstünde kapandı; yerleşme ihtimali düşük.";
default:
return "Güncel taban sıralaması verisi yok; ihtimal öngörülemez, temkinli yaklaş.";
}
return riskNotuMetni(riskHesapla(p.sira2025 ?? p.sira2024, adaySira));
}
/** Havuz programını render için gereken bilgiye indirger. */

View File

@@ -42,3 +42,22 @@ export function dilimdenRisk(dilim: Dilim | string): RiskSeviyesi {
if (dilim === "dengeli") return "az-riskli";
return "riskli";
}
/**
* Risk seviyesinin tek cümlelik açıklaması (rapor satırları + tadımlık).
* Ürün yerleşme olasılığı HESAPLAMAZ; yalnızca son taban sıralamasını adayın
* sırasıyla kıyaslar. Bu yüzden metin olasılık/ihtimal/"yerleşirsin" demez.
* "Geçen yıl" da denmez: efektif sıra 2025 yoksa 2024'e düşüyor.
*/
export function riskNotuMetni(risk: RiskSeviyesi | null): string {
switch (risk) {
case "guvenli":
return "Son taban sıralaması senin sıranın belirgin altında; geçmiş veriye göre güvenli aralıkta.";
case "az-riskli":
return "Son taban sıralaması sırana yakın; küçük bir kayma sonucu değiştirebilir.";
case "riskli":
return "Son taban sıralaması senin sıranın üstünde kapandı; hayal tercihi olarak düşün.";
default:
return "Güncel taban verisi yok; bu satırı temkinli değerlendir.";
}
}

View File

@@ -8,6 +8,7 @@ import { turkishSlugify } from "./slug";
import type { PuanTuruKey } from "@/types/yokatlas";
import type { Dilim } from "./rapor-havuzu";
import type { RaporSonuc } from "@/features/rapor/types/rapor";
import { dilimdenRisk, riskHesapla, riskNotuMetni } from "./risk";
/** Sihirbaz kategorisi seçilmemiş kullanıcı için kova×tür başına fallback satır. */
export const GENEL_KATEGORI = "genel";
@@ -76,13 +77,20 @@ export async function tadimlikSec(
),
});
if (satir) {
const program = satir.program as RaporSonuc["programlar"][string];
return {
programId: satir.programId,
dilim: satir.dilim,
gerekce: satir.gerekce,
riskNotu: satir.riskNotu,
// DB'deki riskNotu batch'te LLM'in temsili sıraya göre yazdığı
// cümledir; servis EDİLMEZ. Not, rozetle (tadimlik-satiri.tsx) aynı
// formülden adayın gerçek sırasına göre okuma anında üretilir — metin
// ile rozet çelişemez, olasılık dili sızamaz.
riskNotu: riskNotuMetni(
riskHesapla(program.efektifSira, sira) ?? dilimdenRisk(satir.dilim),
),
trendOzeti: satir.trendOzeti,
program: satir.program as RaporSonuc["programlar"][string],
program,
};
}
}

6
src/lib/veri-kapsami.ts Normal file
View File

@@ -0,0 +1,6 @@
/**
* Taban sıralaması geçmişinin kapsadığı yıl sayısı. Veritabanında
* sira2021–sira2025 kolonları var (5 yıl); "son N yıl" diyen tüm metinler bu
* sabitten okur. Yeni veri yılı eklenince (ör. sira2026) burayı güncelle.
*/
export const VERI_YIL_SAYISI = 5;