feat(etiket): görünen "Garanti" dilim adı site genelinde "Güvenli"

Yalnız kullanıcıya görünen etiket değişir; iç anahtar, tip, DB değeri, API
parametresi, mermaid classDef ve analitik değeri `garanti` olarak kalır
(veri göçü yok).

- risk.ts: tek kaynak DILIM_ETIKET + dilimdenFarkliRiskEtiketi; rapor
  listesi, yazdır tablosu, /sonuc sekmeleri, seçimlerim paneli ve
  meraklısına şeridi buradan okur
- "Güvenli · Güvenli" / "Güvenli (Güvenli)": satır detayında risk etiketi
  yalnız dilimin varsayılanından farklıysa, yazdır ve seçimlerimde yalnız
  kelime farklıysa yazılır
- LLM prompt'ları: `garanti` teknik anahtar, adaya "güvenli" denir sözlüğü
  (rapor, soru, tadımlık); liste özeti modele görünen dilim adıyla gider
- meraklısına şeması (SEMA düğümü, aria-label), 2. bölüm anlatımı ve
  AGENTS.md şema kuralı görünen adla eşitlendi
- "yerleşme garantisi vermez" türü vaat reddi cümleleri aynen kaldı

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
bilalgursen
2026-09-21 16:03:22 +03:00
parent d79758adc0
commit 5853b7d091
17 changed files with 103 additions and 51 deletions

View File

@@ -41,6 +41,9 @@ iş imkânları, tercih sırası) net ve dürüst yanıtlamak.
KURALLAR:
- Cevaplarını adayın 24'lük listesi ve seçimleri bağlamında ver; listedeki
programlara referans verebilirsin.
- Dilimlerin adı Hayal, Dengeli ve Güvenli'dir. Üçüncü dilime her zaman
"Güvenli" de; "garanti dilimi", "garanti tercih" gibi ifadeler KULLANMA
(aday ya da eski mesajlar böyle dese bile sen "güvenli" diye düzelt).
- Listedeki her satırda dilim ve risk etiketi var: Güvenli (yeşil) = taban
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

View File

@@ -112,7 +112,7 @@ const steps = [
step: "3",
title: "Dengeli 24'lük listeni al",
description:
"Hayal, dengeli ve garanti dilimlerine dağıtılmış, her satırı gerekçeli tercih listeni indir; aklına takılanı listen üzerinden yapay zekâya sor.",
"Hayal, dengeli ve güvenli dilimlerine dağıtılmış, her satırı gerekçeli tercih listeni indir; aklına takılanı listen üzerinden yapay zekâya sor.",
},
];
@@ -129,7 +129,7 @@ const faqs = [
{
question: "Yerleşme garantisi veriyor musunuz?",
answer:
"Hayır — ve verdiğini iddia eden herkesten uzak dur. Taban sıralamaları her yıl adayların davranışına göre değişir; kimse garanti veremez. Biz riski şeffaf gösterir, listeyi hayal/dengeli/garanti dilimleriyle kurarak boşta kalma ihtimalini en aza indiririz. Tercih listenin son hali ve ÖSYM başvurusu her zaman senin sorumluluğundadır.",
"Hayır — ve verdiğini iddia eden herkesten uzak dur. Taban sıralamaları her yıl adayların davranışına göre değişir; kimse garanti veremez. Biz riski şeffaf gösterir, listeyi hayal/dengeli/güvenli dilimleriyle kurarak boşta kalma ihtimalini en aza indiririz. Tercih listenin son hali ve ÖSYM başvurusu her zaman senin sorumluluğundadır.",
},
{
question: "Fiyatlandırma nasıl çalışıyor?",

View File

@@ -20,7 +20,7 @@ import type {
PuanTuruKey,
RankResultsListe,
} from "@/types/yokatlas";
import { riskHesapla, type RiskSeviyesi } from "@/lib/risk";
import { DILIM_ETIKET, riskHesapla, type RiskSeviyesi } from "@/lib/risk";
import { bolumSayfaSlug, uniSayfaSlug } from "@/lib/slug";
import {
ProgramSiraGecmisi,
@@ -51,21 +51,21 @@ const DILIMLER: {
}[] = [
{
key: "hayal",
etiket: "Hayal",
etiket: DILIM_ETIKET.hayal,
icon: Rocket,
renk: "text-red-500",
renkAktif: "text-red-400",
},
{
key: "dengeli",
etiket: "Dengeli",
etiket: DILIM_ETIKET.dengeli,
icon: Scale,
renk: "text-amber-500",
renkAktif: "text-amber-400",
},
{
key: "garanti",
etiket: "Garanti",
etiket: DILIM_ETIKET.garanti,
icon: ShieldCheck,
renk: "text-emerald-600",
renkAktif: "text-emerald-400",

View File

@@ -13,7 +13,7 @@ import {
X,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { RISK_ETIKET, type RiskSeviyesi } from "@/lib/risk";
import { DILIM_ETIKET, RISK_ETIKET, type RiskSeviyesi } from "@/lib/risk";
import { sonucHref } from "@/features/sihirbaz/sihirbaz-sabitler";
import {
tercihDegerlendir,
@@ -156,9 +156,12 @@ export function SecimlerimPaneli() {
{ozet ? (
<dl className="mt-4 grid grid-cols-2 gap-3 sm:grid-cols-4">
<Istatistik etiket="Hayal" deger={ozet.hayal} />
<Istatistik etiket="Dengeli" deger={ozet.dengeli} />
<Istatistik etiket="Daha güvenli" deger={ozet.dahaGuvenli} />
<Istatistik etiket={DILIM_ETIKET.hayal} deger={ozet.hayal} />
<Istatistik etiket={DILIM_ETIKET.dengeli} deger={ozet.dengeli} />
<Istatistik
etiket={DILIM_ETIKET.garanti}
deger={ozet.dahaGuvenli}
/>
<Istatistik etiket="Dikkat" deger={ozet.dikkat} />
</dl>
) : null}
@@ -272,7 +275,9 @@ const SecimSatiri = memo(function SecimSatiri({
/>
) : null}
{degerlendirme.riskEtiketi}
{risk ? (
{/* Dilim adı ile risk etiketi aynı kelimeyse ("Güvenli")
parantez yazılmaz — "Güvenli (Güvenli)" olmasın. */}
{risk && RISK_ETIKET[risk] !== degerlendirme.riskEtiketi ? (
<span className="font-normal text-slate-500">
({RISK_ETIKET[risk]})
</span>

View File

@@ -6,6 +6,8 @@ import { ElCizimiSema } from "@/features/rehber/components/el-cizimi-sema";
// Renkler ürünün risk dilinden (kırmızı/sarı/yeşil) ve slate paletinden;
// renk tek başına anlam taşımaz, her düğüm metinle etiketlidir.
// Üçüncü dilimin görünen adı "güvenli"dir; `classDef garanti` yalnızca iç
// renk sınıfıdır (render edilmez), iç anahtarla aynı kalır.
const SEMA = `---
config:
look: handDrawn
@@ -25,7 +27,7 @@ flowchart TD
R --> L("En fazla 24 tercihlik liste")
L --> L1("üstte hayal — hedef 5, havuz elverdiğince")
L --> L2("ortada dengeli — hedef 13, havuz elverdiğince")
L --> L3("sonda garanti — hedef 6, havuz elverdiğince")
L --> L3("sonda güvenli — hedef 6, havuz elverdiğince")
classDef havuz fill:#eff6ff,stroke:#3b82f6,color:#1e3a8a
classDef uyari fill:#fffbeb,stroke:#f59e0b,color:#92400e
@@ -42,7 +44,7 @@ export function HuniSemasi() {
return (
<ElCizimiSema
tanim={SEMA}
ariaLabel="Sihirbaz akış şeması: sıralamanla açılan programlar alan, il ve devlet/vakıf adımlarıyla aday havuzuna daraltılır; alanlar bölümün adına ve bağlı olduğu fakülteye göre belirlenir, il adımında programı olan tüm iller listelenir; havuz 24'ün altına düşerse filtreler gevşetilir, yine de dar kalırsa liste eldeki programlarla kurulur ve dağılım havuza uyarlanır; yapay zekâ havuzdan üstte hayal, ortada dengeli, sonda garanti olacak şekilde en fazla 24 tercih seçip her satıra gerekçe yazar; risk notu ve trend özeti gerçek sıralama geçmişinden hesaplanır."
ariaLabel="Sihirbaz akış şeması: sıralamanla açılan programlar alan, il ve devlet/vakıf adımlarıyla aday havuzuna daraltılır; alanlar bölümün adına ve bağlı olduğu fakülteye göre belirlenir, il adımında programı olan tüm iller listelenir; havuz 24'ün altına düşerse filtreler gevşetilir, yine de dar kalırsa liste eldeki programlarla kurulur ve dağılım havuza uyarlanır; yapay zekâ havuzdan üstte hayal, ortada dengeli, sonda güvenli olacak şekilde en fazla 24 tercih seçip her satıra gerekçe yazar; risk notu ve trend özeti gerçek sıralama geçmişinden hesaplanır."
figcaption={
<>
Her adım havuzu biraz daha daraltır; yapay zekâ listeyi bu havuzun{" "}

View File

@@ -20,6 +20,7 @@ import { useTercihProfili } from "@/features/liste/hooks/use-tercih-profili";
import { PUAN_TURU_ETIKET, sonucHref } from "@/features/sihirbaz/sihirbaz-sabitler";
import type { DilimKey, SihirbazFacetleri } from "@/types/yokatlas";
import { onbellekliJsonGetir } from "@/lib/istek-cache";
import { DILIM_ETIKET } from "@/lib/risk";
export type DemoVeri = {
facetler: SihirbazFacetleri;
@@ -146,7 +147,7 @@ export function DilimSeridiCanli() {
<svg
viewBox="0 0 640 168"
role="img"
aria-label={`Sıralama ekseni: ${fmt(sira)}. sıradaki aday için Hayal diliminde ${fmt(t.hayal)}, Dengeli diliminde ${fmt(t.dengeli)}, Garanti diliminde ${fmt(t.garanti)} program var.`}
aria-label={`Sıralama ekseni: ${fmt(sira)}. sıradaki aday için ${DILIM_ETIKET.hayal} diliminde ${fmt(t.hayal)}, ${DILIM_ETIKET.dengeli} diliminde ${fmt(t.dengeli)}, ${DILIM_ETIKET.garanti} diliminde ${fmt(t.garanti)} program var.`}
className="w-full"
>
{/* eksen */}
@@ -174,7 +175,7 @@ export function DilimSeridiCanli() {
{/* hayal */}
<rect x="20" y="70" width="150" height="32" rx="4" className="fill-red-100" />
<text x="95" y="40" textAnchor="middle" className="fill-red-600 text-[12px] font-semibold">
Hayal
{DILIM_ETIKET.hayal}
</text>
<text x="95" y="56" textAnchor="middle" className="fill-slate-600 text-[11px] font-medium tabular-nums">
{fmt(t.hayal)} program
@@ -192,7 +193,7 @@ export function DilimSeridiCanli() {
{/* dengeli */}
<rect x="174" y="70" width="120" height="32" rx="4" className="fill-amber-100" />
<text x="234" y="40" textAnchor="middle" className="fill-amber-600 text-[12px] font-semibold">
Dengeli
{DILIM_ETIKET.dengeli}
</text>
<text x="234" y="56" textAnchor="middle" className="fill-slate-600 text-[11px] font-medium tabular-nums">
{fmt(t.dengeli)} program
@@ -204,7 +205,7 @@ export function DilimSeridiCanli() {
{/* garanti */}
<rect x="296" y="70" width="324" height="32" rx="4" className="fill-emerald-100" />
<text x="458" y="40" textAnchor="middle" className="fill-emerald-700 text-[12px] font-semibold">
Garanti
{DILIM_ETIKET.garanti}
</text>
<text x="458" y="56" textAnchor="middle" className="fill-slate-600 text-[11px] font-medium tabular-nums">
{fmt(t.garanti)} program

View File

@@ -68,12 +68,12 @@ export function MeraklisinaIcerik() {
(listenin bel kemiği — sıralamanın yaklaşık yüzde kırk fazlasına
kadar pay bırakılır), tabanı{" "}
<strong>belirgin şekilde altında</strong> kalan her şey ise{" "}
<span className="font-semibold text-emerald-600">Garanti</span>{" "}
<span className="font-semibold text-emerald-600">Güvenli</span>{" "}
dilimidir.
</p>
<DilimSeridiCanli />
<p className="mt-4">
Garanti diliminin bir sonu yok: 87. sıradaki bir adayın da 500
Güvenli diliminin bir sonu yok: 87. sıradaki bir adayın da 500
bininci sıradaki bir adayın da ulaşabildiği <em>bütün</em>{" "}
programlar listededir. Liste sana en yakın tabandan başlar; aşağı
indikçe ve &ldquo;Daha fazla göster&rdquo;e bastıkça senden
@@ -131,7 +131,7 @@ export function MeraklisinaIcerik() {
<p className="mt-2">
Tüm bu hesaplar <strong>geçen yılların</strong>{" "}
yerleştirme sonuçlarına dayanır. Kontenjanlar, tercih davranışları
ve puanlar her yıl değişir; geçen yıl &ldquo;garanti&rdquo;
ve puanlar her yıl değişir; geçen yıl &ldquo;güvenli&rdquo;
görünen bir bölüm bu yıl dolabilir. Bu yüzden satırlarda son beş
yılın taban seyrini de gösteririz — çizgi yukarı tırmanıyorsa
bölüm zorlaşıyor demektir. KolayTercih karar <em>destek</em>{" "}

View File

@@ -29,17 +29,14 @@ import {
import { bolumSayfaSlug, uniSayfaSlug } from "@/lib/slug";
import type { RaporSonuc } from "@/features/rapor/types/rapor";
import {
DILIM_ETIKET,
RISK_ETIKET,
dilimdenFarkliRiskEtiketi,
dilimdenRisk,
riskHesapla,
type RiskSeviyesi,
} from "@/lib/risk";
export const DILIM_ETIKET: Record<string, string> = {
hayal: "Hayal",
dengeli: "Dengeli",
garanti: "Garanti",
};
import type { Dilim } from "@/lib/rapor-havuzu";
// Risk renk dili: yeşil = güvenli, sarı = az riskli, kırmızı = riskli.
// Nokta hiçbir yerde tek başına durmaz; yanındaki etiket dar ekranda sr-only
@@ -75,12 +72,16 @@ export function RaporSatirDetayi({
trendOzeti: string;
}) {
const stil = RISK_STIL[risk];
// Risk etiketi yalnızca dilimin varsayılanından farklıysa yazılır; yoksa
// üçüncü dilimde başlık "Güvenli · Güvenli" olurdu (bkz. risk.ts).
const farkliRisk = dilimdenFarkliRiskEtiketi(dilim, risk);
return (
<>
<div className="mb-2 flex flex-wrap items-center gap-2 text-xs text-slate-500">
<stil.icon className="size-3.5" aria-hidden />
<span className="font-medium">
{DILIM_ETIKET[dilim]} · {RISK_ETIKET[risk]}
{DILIM_ETIKET[dilim as Dilim] ?? dilim}
{farkliRisk ? ` · ${farkliRisk}` : null}
</span>
{unitur ? <span>· {unitur}</span> : null}
</div>
@@ -345,7 +346,7 @@ export function RaporListesi({
<p className="mt-3 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-900">
Tercihlerine göre {rapor.kapsam.toplam} uygun program bulundu; listen{" "}
{rapor.kapsam.dagilim.hayal} hayal · {rapor.kapsam.dagilim.dengeli}{" "}
dengeli · {rapor.kapsam.dagilim.garanti} garanti olarak kuruldu. Daha
dengeli · {rapor.kapsam.dagilim.garanti} güvenli olarak kuruldu. Daha
fazla seçenek için alan veya il filtreni genişletebilirsin.
</p>
) : null}

View File

@@ -2,16 +2,19 @@ import Image from "next/image";
import { redirect } from "next/navigation";
import { verifySession, getCurrentUser } from "@/lib/session";
import { kullanicininRaporu } from "../rapor-queries";
import { PUAN_TURLERI } from "@/types/yokatlas";
import { PUAN_TURLERI, type DilimKey } from "@/types/yokatlas";
import { DILIM_ETIKET, RISK_ETIKET, dilimdenRisk } from "@/lib/risk";
import type { RaporParams, RaporSonuc } from "../types/rapor";
import { Skeleton } from "@/components/ui/skeleton";
import { YazdirButonu } from "./yazdir-butonu";
const DILIM_LABEL: Record<string, string> = {
hayal: "Hayal (Riskli)",
dengeli: "Dengeli (Az riskli)",
garanti: "Garanti (Güvenli)",
};
// Dilim sütunu: dilim adı + varsayılan riski. Üçüncü dilimde ikisi aynı
// kelime ("Güvenli") olduğu için parantez düşer — "Güvenli (Güvenli)" yazmaz.
function dilimLabel(dilim: DilimKey): string {
const ad = DILIM_ETIKET[dilim] ?? dilim;
const risk = RISK_ETIKET[dilimdenRisk(dilim)];
return ad === risk ? ad : `${ad} (${risk})`;
}
export async function RaporYazdir() {
const session = await verifySession("/rapor/yazdir");
@@ -50,7 +53,7 @@ export async function RaporYazdir() {
Not: Tercihlerine göre {rapor.kapsam.toplam} uygun program bulundu;
liste {rapor.kapsam.dagilim.hayal} hayal ·{" "}
{rapor.kapsam.dagilim.dengeli} dengeli ·{" "}
{rapor.kapsam.dagilim.garanti} garanti olarak kuruldu.
{rapor.kapsam.dagilim.garanti} güvenli olarak kuruldu.
</p>
) : null}
</header>
@@ -91,7 +94,7 @@ export async function RaporYazdir() {
{p?.universite} · {p?.il ?? "—"}
</span>
</td>
<td className="py-2 pr-2">{DILIM_LABEL[t.dilim]}</td>
<td className="py-2 pr-2">{dilimLabel(t.dilim)}</td>
<td className="py-2 pr-2">{t.gerekce}</td>
<td className="py-2 pr-2">{t.riskNotu}</td>
<td className="py-2">{t.trendOzeti}</td>

View File

@@ -76,7 +76,7 @@ export function RevizyonKutusu({ kalanHak }: { kalanHak: number }) {
onChange={(e) => setFeedback(e.target.value)}
rows={2}
maxLength={1000}
placeholder="ör. İlk 5 tercihte daha fazla İstanbul olsun, garanti dilimini genişlet…"
placeholder="ör. İlk 5 tercihte daha fazla İstanbul olsun, güvenli dilimi genişlet…"
disabled={pending}
className="w-full rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50"
/>

View File

@@ -150,7 +150,7 @@ export function CtaSiraForm({ baslik }: { baslik?: string }) {
</h2>
<p className="mt-2 text-sm leading-6 text-slate-600">
Sıralaman kayıtlı ({profil.sira.toLocaleString("tr-TR")}. sıra) —
gerçek YÖK Atlas verisiyle hayal, dengeli ve garanti dilimlerindeki
gerçek YÖK Atlas verisiyle hayal, dengeli ve güvenli dilimlerindeki
programların hazır.
</p>
<Link
@@ -174,7 +174,7 @@ export function CtaSiraForm({ baslik }: { baslik?: string }) {
</h2>
<p className="mt-2 text-sm leading-6 text-slate-600">
YKS başarı sıralamanı gir; gerçek YÖK Atlas verisiyle sıralamana uygun
hayal, dengeli ve garanti dilimlerindeki programları anında listele.
hayal, dengeli ve güvenli dilimlerindeki programları anında listele.
Ücretsiz, üyelik gerekmez.
</p>
<Button
@@ -217,7 +217,7 @@ export function CtaSiraForm({ baslik }: { baslik?: string }) {
</h2>
<p className="mt-2 max-w-xl text-sm leading-6 text-slate-600">
Puan türünü seç, başarı sıralamanı yaz; hayal, dengeli ve
garanti dilimlerindeki programları bu sayfadan ayrılmadan
güvenli dilimlerindeki programları bu sayfadan ayrılmadan
gör. Ücretsiz, üyelik gerekmez.
</p>
</div>

View File

@@ -322,7 +322,7 @@ export function SihirbazBolumu({
<p className="relative mx-auto mt-3 max-w-xl text-white/90">
Tablodan elle eklemek her zaman serbest. Ama üç adımda ilgi
alanlarını ve şehirlerini söylersen, yapay zekâ hayal, dengeli
ve garanti dilimlerine dağıtılmış 24 tercihi — her satırı
ve güvenli dilimlerine dağıtılmış 24 tercihi — her satırı
yerleşme riski ve gerekçesiyle — senin yerine dizer.
</p>
<Button

View File

@@ -19,6 +19,7 @@ import {
} from "../rapor-havuzu";
import { secimOzeti } from "@/features/sihirbaz/sihirbaz-sabitler";
import {
DILIM_ETIKET,
RISK_ETIKET,
dilimdenRisk,
riskHesapla,
@@ -77,6 +78,11 @@ KURALLAR (kesin):
- METİN DİYETİ: aday ${toplam} satır okuyacak; gerekce TEK kısa cümle (en fazla ~15
kelime, Türkçe): bu programın bu aday için neden mantıklı olduğu. Dolgu söz
yok; ASLA "garanti", "kesin", "yüzde yüz" deme.
- SÖZLÜK: "garanti" yalnızca üçüncü listenin teknik JSON alan adı ve havuzdaki
"dilim" değeridir. Adaya dönük HİÇBİR metinde (gerekce, genelDegerlendirme,
uyarilar) "garanti" kelimesini kullanma; bu dilimi adaya "güvenli dilim" /
"güvenli tercihler" diye an. Aday ya da önceki liste özeti "güvenli dilim"
derse kastedilen "garanti" listesidir.
- Adayın notlarındaki şehir/bölüm tercihlerine saygı göster ama dengeyi bozma.
- genelDegerlendirme: listenin genel stratejisi, EN FAZLA 2 cümle. Uyarıları
buraya yazma.
@@ -209,12 +215,12 @@ function mockRapor(
tercihler,
genelDegerlendirme: `(Dev mock — Yapay Zeka anahtarı tanımlı değil, bu rapor gerçek Yapay Zeka çıktısı değildir.) ${params.sira.toLocaleString(
"tr-TR",
)}. sıra için hayal/dengeli/garanti dağılımlı ${toplamHedef} tercihlik örnek liste kuruldu.${
)}. sıra için hayal/dengeli/güvenli dağılımlı ${toplamHedef} tercihlik örnek liste kuruldu.${
revizyonNotu ? ` Revizyon isteğin not alındı: "${revizyonNotu}".` : ""
}`,
uyarilar: [
"(Dev mock) Tercih dönemi kapanmadan listeyi ÖSYM sistemine kendin gir.",
"(Dev mock) Garanti dilimindeki son tercihleri asla silme.",
"(Dev mock) Güvenli dilimindeki son tercihleri asla silme.",
],
programlar,
kapsam: kapsamUret(hedef),
@@ -406,7 +412,7 @@ export async function raporUret(
tercihler,
genelDegerlendirme:
genel.trim() ||
`Listen ${toplamHedef} tercihten oluşuyor; hayal, dengeli ve garanti dilimleri sıralamana göre dengelendi.`,
`Listen ${toplamHedef} tercihten oluşuyor; hayal, dengeli ve güvenli dilimleri sıralamana göre dengelendi.`,
uyarilar: uyarilar.length > 0 ? uyarilar : undefined,
programlar,
kapsam: kapsamUret(hedef),
@@ -424,7 +430,10 @@ export function listeOzetiCikar(rapor: RaporSonuc, adaySira?: number): string {
p?.efektifSira != null
? ` (taban sırası ~${p.efektifSira.toLocaleString("tr-TR")})`
: "";
return `${t.sira}. [${t.dilim} | ${RISK_ETIKET[risk]}] ${p?.isim ?? "?"} — ${p?.universite ?? "?"}${taban}`;
// Modele ham `garanti` anahtarı değil görünen dilim adı gider; yoksa
// sohbet cevaplarına "garanti dilimi" sızıyor. Dilim ve risk aynı kelime
// olabildiği için ("Güvenli") alanlar adlandırılır.
return `${t.sira}. [dilim: ${DILIM_ETIKET[t.dilim] ?? t.dilim} | risk: ${RISK_ETIKET[risk]}] ${p?.isim ?? "?"} — ${p?.universite ?? "?"}${taban}`;
})
.join("\n");
}

View File

@@ -12,6 +12,18 @@ export const RISK_ETIKET: Record<RiskSeviyesi, string> = {
riskli: "Riskli",
};
/**
* Dilimin kullanıcıya GÖRÜNEN adı — tek kaynak. Üçüncü dilimin iç anahtarı
* (tip, DB değeri, API parametresi, mermaid classDef, analitik) `garanti`
* olarak kalır; ekranda "Güvenli" yazar. Ham anahtarı kullanıcıya basma,
* buradan oku.
*/
export const DILIM_ETIKET: Record<Dilim, string> = {
hayal: "Hayal",
dengeli: "Dengeli",
garanti: "Güvenli",
};
/** Harita pinlerinin SVG dolgu renkleri — risk renk dilinin oklch karşılığı. */
export const RISK_PIN_RENK: Record<RiskSeviyesi, string> = {
guvenli: "oklch(0.696 0.17 162.5)", // emerald-500
@@ -43,6 +55,19 @@ export function dilimdenRisk(dilim: Dilim | string): RiskSeviyesi {
return "riskli";
}
/**
* Dilim başlığının yanına yazılacak risk etiketi. Yalnızca satırın riski
* dilimin varsayılanından FARKLIYSA döner; aynıysa null. Üçüncü dilimin adı
* risk etiketiyle aynı kelime olduğu için aksi hâlde "Güvenli · Güvenli"
* görünürdü.
*/
export function dilimdenFarkliRiskEtiketi(
dilim: Dilim | string,
risk: RiskSeviyesi,
): string | null {
return dilimdenRisk(dilim) === risk ? null : RISK_ETIKET[risk];
}
/**
* 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

View File

@@ -1,5 +1,5 @@
import { kategoriEslesir } from "./kategoriler";
import { riskHesapla, type RiskSeviyesi } from "./risk";
import { DILIM_ETIKET, riskHesapla, type RiskSeviyesi } from "./risk";
import type { TercihProfili } from "@/features/sihirbaz/sihirbaz-sabitler";
export type DegerlendirilecekProgram = {
@@ -11,7 +11,8 @@ export type DegerlendirilecekProgram = {
export type TercihDegerlendirmesi = {
risk: RiskSeviyesi | null;
riskEtiketi: "Hayal" | "Dengeli" | "Daha güvenli" | "Veri yetersiz";
/** Görünen dilim adı (DILIM_ETIKET) ya da "Veri yetersiz". */
riskEtiketi: string;
riskMetni: string;
olumlu: string[];
celiskiler: string[];
@@ -65,11 +66,11 @@ export function tercihDegerlendir(
const riskEtiketi =
risk === "riskli"
? "Hayal"
? DILIM_ETIKET.hayal
: risk === "az-riskli"
? "Dengeli"
? DILIM_ETIKET.dengeli
: risk === "guvenli"
? "Daha güvenli"
? DILIM_ETIKET.garanti
: "Veri yetersiz";
const riskMetni =
risk === "riskli"