Merge branch 'gece/0922-urap' into is/0923-uni-tur

This commit is contained in:
bilalgursen
2026-09-23 10:49:40 +03:00
5 changed files with 514 additions and 12 deletions

View File

@@ -0,0 +1,64 @@
# 10 · P3 — URAP tek sayı: "Tür" kartıyla takas
**Rol:** yazilimci · **Dal:** `gece/0922-urap` · **Tarih:** 23 Eylül 2026
**Commit'ler:** `68cb69e` (veri sabiti), `4932671` (okuma katmanı + kart takası + kaynak satırı + veri-kalite), `<bu rapor>`
## Özet (5 madde)
1. `src/lib/urap-siralama.ts` eklendi: 198 üniversitenin URAP Türkiye 2025-2026 sırası, `/universite/[slug]` slug'ına anahtarlı sabit + `URAP_KAYNAK_URL`, `URAP_DONEM`, `URAP_TOPLAM` + `urapSirasiBul()`. Yeni DB dosyası, göç, cron, çekme betiği **yok**.
2. Üniversite sayfası metrik ızgarasında takas yapıldı: URAP'ta olan üniversitede "Tür" kartının yerini **URAP TÜRKİYE · 18 / 198 · 2025-2026** alıyor; olmayan 31 kurumda **"Tür" yerinde duruyor**. Kart sayısı 4'te kaldı, `lg` ızgara şablonu değişmedi, yeni bileşen icat edilmedi.
3. Tablonun altına **ayrı ikinci kaynak satırı** eklendi; `VeriKaynagi` kullanılmadı ve kopyalanmadı. Satırda dönem, payda, metodoloji uyarısı ve `urapcenter.org`'a gerçek `<a href>` var (`rel="noopener"`, yeni sekme, **nofollow yok**, adres sabitten).
4. `scripts/veri-kalite.ts`'e **dosyanın en sonuna** 5 URAP kontrolü eklendi (mevcut satırlar yeniden düzenlenmedi; `main()` içine yalnız tek satırlık çağrı girdi). Beşi de geçiyor: 198/198 eşleşme, kesintisiz sıra, azalan puan, 31 kurumluk kapsama boşluğu.
5. `pnpm exec next typegen` + `tsc --noEmit` + `pnpm lint` + `pnpm build` temiz; doğrulama üretilmiş statik HTML üzerinden yapıldı (tarayıcı/dev sunucusu açılmadı).
## Değişen dosyalar
| Dosya | Ne |
|---|---|
| `src/lib/urap-siralama.ts` (**yeni**, 242 satır) | 198 satırlık `URAP_SIRA` sabiti + `URAP_DONEM`/`URAP_TOPLAM`/`URAP_KAYNAK_URL` + `urapSirasiBul()`; dosya başındaki yorumda atıf şartı yazılı |
| `src/lib/katalog.ts` (+7) | `UniDetay`'e tek alan: `urap: UrapSira \| null`; `getUniversiteBySlug` dönüşünde `urapSirasiBul(slug)` |
| `src/features/katalog/components/universite-icerik.tsx` (+89/−10) | Kart takası + `UrapKaynakSatiri` bileşeni (aynı dosyada, ızgaranın altındaki kaynak satırı) |
| `scripts/veri-kalite.ts` (+89) | Dosya sonuna `urapKontrolleri()` (5 kontrol) + `main()` sonunda tek satır çağrı + 3 satır import |
Veri kaynağı: `docs/gece-vardiyasi/2026-09-22/05-urap.md` §1-2'de tarif edilen çıkarım (`rankings.byurlandgroup`, 198 satır), veri mühendisinin scratchpad'e bıraktığı `urap-2025.txt`. **Hiçbir sıra, ad ya da puan elle uydurulmadı**; slug'lar üretimden önce DB'deki 322 ham üniversite adından `uniSayfaSlug` ile türetilen kümeyle karşılaştırıldı (198/198 tuttu, 0 karşılıksız).
## Kabul kriterleri — 6/6
| # | Kriter | Durum | Nasıl doğrulandı |
|---|---|---|---|
| 1 | URAP'ta olan sayfada 4 kart, "Tür" yerinde URAP; olmayanda 4 kart, "Tür" duruyor; hiçbir sayfada "—"/boş kutu yok | ✔ | Üretilmiş statik HTML'den metin çıkarımı: `koc-universitesi` → "Program 53 · Fakülte/Birim 7 · **URAP Türkiye 1 / 198 · 2025-2026** · En iyi sıralama 65"; `bogazici-universitesi` → "URAP Türkiye **18 / 198**"; `dogu-akdeniz-universitesi` → "Program 276 · Fakülte/Birim 17 · **Tür Kktc** · En iyi sıralama 9.061" |
| 2 | URAP sayısının göründüğü her sayfada aynı ekranda aktif atıf linki ve dönem var | ✔ | `koc-universitesi.html` içinde: `<a href="https://newtr.urapcenter.org/Rankings/2025-2026/GENEL-SIRALAMASI-2025" target="_blank" rel="noopener" …>`; HTML'de `nofollow` geçmiyor. Dönem hem kartta (`2025-2026`) hem kaynak satırında. Sayı yalnız 1. sayfada çiziliyor, kaynak satırı da yalnız 1. sayfada |
| 3 | `veri-kalite` kontrolleri geçiyor, eşleşmeyen slug sessizce düşmüyor | ✔ | `pnpm veri-kalite --yil 2026 --db data/yokatlas.db` → 5 URAP satırı: "GEÇTİ … 198 slug'ın tamamı DB'de var", "kayıt 198, URAP_TOPLAM 198", "1..198 kesintisiz", "1152.91 → 70.82", "bilgi URAP dışında 31 kurum". Sonuç: 0 ZORUNLU kaldı (3 uyarı **önceden var olan** uyarılar, URAP'la ilgisiz) |
| 4 | Renk yok, rozet yok, `/universiteler` hub'ında URAP'a göre sıralama/filtre yok | ✔ | Kart mevcut `rounded-xl border-slate-200 bg-white` kutusunun içinde, metin `text-slate-900`/`text-slate-500`; `SectionEyebrow`/`Badge` kullanılmadı, yeni renk sınıfı girmedi. `universite-listesi.tsx` ve hub sayfaları **hiç açılmadı** (`git diff --stat`: 4 dosya) |
| 5 | 24'lük listeye, `/sonuc` tablosuna ve LLM prompt'una URAP girmez | ✔ | Dokunulan dosya kümesi bunu dışlıyor; `src/lib/urap-siralama.ts`'i içe aktaran yalnız `katalog.ts`, `universite-icerik.tsx` ve `veri-kalite.ts` |
| 6 | `tsc` + `lint` + `build` temiz | ✔ | `next typegen` ✓, `tsc --noEmit` çıktısız, `pnpm lint` çıktısız, `pnpm build` "Compiled successfully" + `BUILD_ID` üretildi (229 üniversite sayfası prerender). Build günlüğündeki `BetterAuthError`/Cal Sans uyarıları **önceden var**, worktree'de `.env` olmamasından |
## Atıf şartı nerede karşılanıyor
- **Veri dosyasının başında** (`src/lib/urap-siralama.ts` yorumu): izin şartı ve "link konulamayan yüzeyde sayı gösterilmez" kuralı yazılı — sonraki geliştirici sabiti başka bir yüzeye taşırken şartı görür.
- **Ekranda** (`UrapKaynakSatiri`): tablonun altında, `VeriKaynagi`'den ayrı ikinci satır. Kanonik cümle birebir: *"URAP Türkiye Sıralaması 2025-2026 (198 üniversite arasında) — akademik yayın ve araştırma performansını ölçer; eğitim kalitesini ya da iş bulma oranını ölçmez. Kaynak: urapcenter.org."* Adres `URAP_KAYNAK_URL` sabitinden geliyor, elle yazılmadı.
- **OG görselinde URAP yok**: `opengraph-image` dosyalarına dokunulmadı, `uni.urap` oraya hiç ulaşmıyor.
- **Boş durumda** (31 kurum) sayı olmadığı için link de yok; yalnız tek cümlelik açıklama var. Şart "sayının göründüğü yüzey" için; burada sayı görünmüyor.
## Şartnameden sapmalar
1. **Kaynak satırı yalnız 1. sayfada çiziliyor.** Şartname "tablonun altına" diyor; üniversite tabloları sayfalanıyor (`/universite/<slug>/sayfa/2`…) ve metrik ızgarası yalnız 1. sayfada var. URAP sayısı 2. sayfada görünmediği için kaynak satırını da orada çizmedim — aksi hâlde sayfa 2'de bağlamsız bir URAP cümlesi kalırdı. Tersi isteniyorsa tek koşul kaldırılır (`{ilkSayfa ? <UrapKaynakSatiri … /> : null}`).
2. **Boş durum cümlesinin varyant seçimi `unitur` üzerinden.** `KKTC` / `YURTDISI KAMU` / `YURTDISI VAKIF` → "URAP yalnız Türkiye'deki üniversiteleri sıralıyor."; diğerleri → "…2025-2026 listesinde yer almıyor." **P2 ile kesişme:** P2'nin düzelteceği 3 kurum (Kıbrıs Amerikan, Uluslararası Balkan, Uluslararası Saraybosna) bugün `DEVLET` etiketli olduğu için ikinci cümleyi alıyor. İki cümle de doğru, ama P2 merge edildikten sonra bu üç sayfa kendiliğinden doğru varyanta geçer — ek kod gerekmiyor.
3. **5. veri-kalite kontrolü şartnamedekinden farklı.** Veri mühendisinin önerisi "bir önceki döneme göre listeden düşen üniversite" idi; elimizde önceki dönemin sabiti olmadığı için bunu koşturmak mümkün değil. Yerine aynı riski (sessiz düşme) yakalayan bir kontrol yazdım: URAP dışında kalan **150+ programlı bir Türkiye üniversitesi** varsa UYARI — bu neredeyse her zaman ad değişikliği demektir. Bugün 0 (en büyük eksik Türkiye kurumu Mudanya, 78 program).
4. **`veri-kalite.ts`'e 3 satır import eklendi** (dosyanın en sonuna değil, import bloğunun sonuna). Kontrol gövdesi dosyanın en sonunda, `main()` içinde yalnız tek satırlık çağrı var; mevcut satırlar yeniden düzenlenmedi. P2 ile çakışma yüzeyi bu 4 satır.
## Merge sonrası doğrulanması gerekenler
- **P2 (`gece/0922-unitur-kacagi`) merge edildikten sonra:** `dogu-akdeniz-universitesi` dışında, düzeltilen 3 kurumun sayfasında boş durum cümlesinin "URAP yalnız Türkiye'deki üniversiteleri sıralıyor." varyantına geçtiği. Kod değişikliği gerekmez, yalnız gözle bakılır.
- **`scripts/veri-kalite.ts` merge'ü:** P2 aynı dosyaya "baz ad başına tek `unitur`" kontrolü ekliyor. Çakışma beklenen yer import bloğunun sonu; iki taraf da birleştirildikten sonra `pnpm veri-kalite --yil 2026 --db data/yokatlas.db` bir kez koşturulmalı (0 ZORUNLU bekleniyor).
- **Yayın sonrası:** `/universite/bogazici-universitesi` ve `/universite/dogu-akdeniz-universitesi` canlıda açılıp kartın 4'te kaldığı ve kaynak satırındaki linkin URAP sayfasına gittiği bir kez doğrulanmalı.
## Gözlem (kapsam dışı, düzeltilmedi)
"Tür" kartı artık yalnız URAP'ta olmayan 31 kurumda görünüyor ve bunların çoğu KKTC/yurt dışı. `trBaslikDuzeni` bu değerleri **"Kktc"**, **"Yurtdisi Kamu"** diye yazıyor — eskiden de böyleydi ama şimdi bu yazım yalnız o sayfalarda kaldığı için daha görünür. Şartnamede yok, dokunmadım; backlog önerisi.
## Bilal'den istenen
1. **URAP izin e-postasını `docs/` altına koy** (kanıt) — CEO kararı §5-3'te de yazıyor. ~2 dk.
2. **İki sayfayı gözle gör:** `/universite/bogazici-universitesi` (URAP 18/198 kartı + alttaki kaynak satırı) ve `/universite/dogu-akdeniz-universitesi` ("Tür" kartı yerinde + tek cümlelik boş durum). ~3 dk.
3. **Karar:** kaynak satırı derin sayfalarda (`/universite/<slug>/sayfa/2`) da görünsün mü? Bugün görünmüyor, çünkü orada URAP sayısı da yok (sapma #1). ~1 dk.

View File

@@ -33,6 +33,10 @@ import {
tabloVar,
yilArgumani,
} from "./yokatlas-goc";
// URAP kontrolleri (dosya sonundaki urapKontrolleri) — salt okunur sabit.
import type { Db } from "./yokatlas-goc";
import { uniSayfaSlug } from "../src/lib/slug";
import { URAP_DONEM, URAP_SIRA, URAP_TOPLAM } from "../src/lib/urap-siralama";
const TURLER = ["SAYISAL", "EŞİT AĞIRLIK", "SÖZEL", "DİL", "TYT"];
@@ -291,9 +295,94 @@ async function main() {
console.log(` şimdi, tüm satırlar (yeni dahil) : ${toplamlar(simdi)}`);
}
urapKontrolleri(db, zorunlu, bilgi);
db.close();
console.log(`\nSonuç: ${basarisiz} ZORUNLU kontrol kaldı, ${uyari} uyarı.`);
if (basarisiz > 0) process.exit(1);
}
if (process.argv[1]?.endsWith("veri-kalite.ts")) calistir(main);
/**
* URAP Türkiye sıralaması sabiti (`src/lib/urap-siralama.ts`) denetimi.
* Amaç: yıllık tazelemede eşleşmeyen bir URAP satırı SESSİZCE DÜŞMESİN —
* düşerse üniversitenin adı değişmiş demektir ve o sayfada sıra kaybolur.
* DB'ye yazmaz; sabit ile DB'deki üniversite slug'larını karşılaştırır.
*/
function urapKontrolleri(
db: Db,
zorunlu: (ad: string, tamam: boolean, detay: string) => void,
bilgi: (ad: string, sorunlu: boolean, detay: string) => void
) {
const kayitlar = Object.entries(URAP_SIRA);
// (1) Sabitteki her slug DB'de karşılık bulmalı — bulamayan = ad değişikliği.
const dbToplam = new Map<string, { unitur: string | null; program: number }>();
const satirlar = db
.prepare("SELECT universite, unitur, COUNT(*) AS n FROM programs GROUP BY 1, 2")
.all() as { universite: string; unitur: string | null; n: number }[];
for (const r of satirlar) {
const slug = uniSayfaSlug(r.universite);
if (!slug) continue;
const kayit = dbToplam.get(slug) ?? { unitur: null, program: 0 };
kayit.program += r.n;
if (!kayit.unitur && r.unitur) kayit.unitur = r.unitur;
dbToplam.set(slug, kayit);
}
const karsiliksiz = kayitlar.filter(([slug]) => !dbToplam.has(slug));
zorunlu(
"URAP: her sıra bir üniversite sayfasına bağlı",
karsiliksiz.length === 0,
karsiliksiz.length === 0
? `${kayitlar.length} slug'ın tamamı DB'de var`
: `DB'de karşılığı olmayan (ad değişmiş olabilir): ${karsiliksiz.map(([slug, v]) => `${slug}(#${v.sira})`).join(", ")}`
);
// (2) Kayıt sayısı payda ile aynı olmalı — payda kartta gösteriliyor.
zorunlu(
"URAP: kayıt sayısı = URAP_TOPLAM",
kayitlar.length === URAP_TOPLAM,
`kayıt ${kayitlar.length}, URAP_TOPLAM ${URAP_TOPLAM} (dönem ${URAP_DONEM})`
);
// (3) Sıralar 1..URAP_TOPLAM; tekrarsız ve boşluksuz.
const siralar = kayitlar.map(([, v]) => v.sira).sort((a, b) => a - b);
const bozukSira = siralar.findIndex((s, i) => s !== i + 1);
zorunlu(
"URAP: sıralar 1..N tekrarsız ve boşluksuz",
bozukSira === -1 && siralar.length === URAP_TOPLAM,
bozukSira === -1
? `1..${siralar.length} kesintisiz`
: `${bozukSira + 1}. sırada beklenen ${bozukSira + 1}, gelen ${siralar[bozukSira]}`
);
// (4) Puan sıraya göre azalmalı — sıra 1 en yüksek puan.
const sirali = [...kayitlar].sort((a, b) => a[1].sira - b[1].sira);
const bozukPuan = sirali.findIndex(
(k, i) => i > 0 && sirali[i - 1][1].puan < k[1].puan
);
zorunlu(
"URAP: puanlar sıraya göre azalan",
bozukPuan === -1,
bozukPuan === -1
? `${sirali[0][1].puan} → ${sirali[sirali.length - 1][1].puan}`
: `#${sirali[bozukPuan][1].sira} (${sirali[bozukPuan][0]}) puanı bir önceki sıradan yüksek`
);
// (5) Kapsama boşluğu: URAP yalnız Türkiye'yi sıralar, KKTC/yurt dışı ve
// yalnız MYO'su olan kurumlar listede olmaz — bu normaldir. Ama büyük bir
// Türkiye üniversitesinin düşmesi neredeyse her zaman ad değişikliğidir.
const disarida = [...dbToplam.entries()].filter(([slug]) => !(slug in URAP_SIRA));
const turkiyeBuyuk = disarida.filter(
([, v]) =>
(v.unitur === "DEVLET" || v.unitur === "VAKIF") && v.program >= 150
);
bilgi(
"URAP: kapsama boşluğu",
turkiyeBuyuk.length > 0,
turkiyeBuyuk.length === 0
? `URAP dışında ${disarida.length} kurum (KKTC/yurt dışı, MYO ve yeni üniversiteler); 150+ programlı Türkiye üniversitesi yok`
: `URAP dışında kalan 150+ programlı Türkiye üniversitesi (ad değişmiş olabilir): ${turkiyeBuyuk.map(([slug, v]) => `${slug}(${v.program})`).join(", ")}`
);
}

View File

@@ -30,6 +30,11 @@ import { UniversiteKonumHaritasi } from "./universite-konum-haritasi";
import { uniUlkeKonum } from "@/lib/harita-ulkeler";
import { UniversiteProgramTablosu } from "./universite-program-tablosu";
import { VeriKaynagi } from "./veri-kaynagi";
import {
URAP_DONEM,
URAP_KAYNAK_URL,
URAP_TOPLAM,
} from "@/lib/urap-siralama";
import { UniLogo } from "@/components/uni-logo";
import { uniLogoYolu } from "@/lib/uni-logolar";
import { Skeleton } from "@/components/ui/skeleton";
@@ -38,6 +43,29 @@ import { BASLIK_YILI, SON_YIL, TERCIH_YILI } from "@/lib/veri-yillari";
const sayi = (n: number) => n.toLocaleString("tr-TR");
// Ham `unitur` değerlerinin ekranda görünen karşılığı. `trBaslikDuzeni`
// tr-TR küçültmesi yaptığı için ("I" → "ı") ham değerlere uygulanamaz:
// "YURTDISI KAMU" → "Yurtdısı Kamu" gibi Türkçede olmayan kelimeler çıkıyor.
// İki biçim tek kaynakta durur, çünkü aynı bilgi iki yerde geçiyor:
// `kart` = "Tür" kartındaki kısa etiket (yalnız URAP'ta olmayan üniversitede),
// `cumle` = özet paragrafın ilk virgülündeki öbek (her üniversitede).
// `cumle` cümle ortasında okunacak biçimde küçük harfle başlar; KKTC gibi
// kısaltmalar büyük kalır.
const UNITUR_ETIKET: Record<string, { kart: string; cumle: string }> = {
DEVLET: { kart: "Devlet", cumle: "devlet üniversitesi" },
VAKIF: { kart: "Vakıf", cumle: "vakıf üniversitesi" },
"VAKIF MYO": { kart: "Vakıf MYO", cumle: "vakıf meslek yüksekokulu" },
KKTC: { kart: "KKTC", cumle: "KKTC üniversitesi" },
"YURTDISI KAMU": {
kart: "Yurt dışı (kamu)",
cumle: "yurt dışında bir kamu üniversitesi",
},
"YURTDISI VAKIF": {
kart: "Yurt dışı (vakıf)",
cumle: "yurt dışında bir vakıf üniversitesi",
},
};
export function uniToplamSayfa(programSayisi: number): number {
return Math.max(1, Math.ceil(programSayisi / SAYFA_BOYU));
}
@@ -109,6 +137,48 @@ function fakulteOzeti({
return `${adlar[0]}, ${adlar[1]} ve ${adlar.length - 2} birim daha`;
}
/**
* Tablonun altındaki AYRI ikinci kaynak satırı. `VeriKaynagi` kullanılmaz ve
* kopyalanmaz: o satır YÖK Atlas'ın yerleştirme yılına ve son güncelleme
* tarihine bağlı, URAP'ın dönemi başka — aynı satırda birleşirlerse URAP
* verisi YÖK Atlas tarihiyle sunulmuş olur.
*
* Atıf pazarlık dışı: URAP'ın izni "urapcenter.org adresine aktif bağlantı"
* şartına bağlı, o yüzden gerçek <a href>, yeni sekme, rel="noopener" ve
* nofollow YOK. Sıra payda ("198 üniversite arasında") ve dönem olmadan
* gösterilmez. URAP listesinde olmayan üniversitede sayı yoktur; eksiklik
* gizlenmez, nedeni tek cümleyle yazılır.
*/
function UrapKaynakSatiri({ uni }: { uni: UniDetay }) {
if (!uni.urap) {
const yurtDisi =
uni.unitur === "KKTC" || uni.unitur?.startsWith("YURTDISI");
return (
<p className="mt-2 text-xs leading-5 text-slate-500">
{yurtDisi
? "Bu üniversite URAP Türkiye sıralamasında yer almıyor — URAP yalnız Türkiye'deki üniversiteleri sıralıyor."
: `Bu üniversite URAP Türkiye Sıralaması ${URAP_DONEM} listesinde yer almıyor.`}
</p>
);
}
return (
<p className="mt-2 text-xs leading-5 text-slate-500">
URAP Türkiye Sıralaması {URAP_DONEM} ({sayi(URAP_TOPLAM)} üniversite
arasında) — akademik yayın ve araştırma performansını ölçer; eğitim
kalitesini ya da iş bulma oranını ölçmez. Kaynak:{" "}
<a
href={URAP_KAYNAK_URL}
target="_blank"
rel="noopener"
className="font-medium text-primary hover:underline"
>
urapcenter.org
</a>
.
</p>
);
}
export function uniSayfaMetadata(slug: string, sayfa: number): Metadata {
const uni = getUniversiteBySlug(slug);
if (!uni) return {};
@@ -165,6 +235,14 @@ export function UniversiteIcerik({
}
const ilkSayfa = sayfa === 1;
// Devlet/vakıf bilgisi sayfada başka hiçbir yerde geçmiyor (URAP'ta olan
// üniversitede "Tür" kartının yerini URAP sırası aldı), o yüzden özet
// paragrafın ilk virgülünde duruyor. Haritada olmayan ya da NULL bir
// `unitur`'da öbek hiç yazılmaz: cümlede kopuk virgül/boşluk kalmaz ve
// ham DB değeri cümlenin içine sızmaz.
const turCumlesi = uni.unitur
? UNITUR_ETIKET[uni.unitur]?.cumle
: undefined;
const buYol = ilkSayfa
? `/universite/${slug}`
: `/universite/${slug}/sayfa/${sayfa}`;
@@ -262,8 +340,9 @@ export function UniversiteIcerik({
<>
<p className="mt-4 max-w-3xl text-sm leading-7 text-slate-600">
{uni.ad}
{uni.il ? ` (${trBaslikDuzeni(uni.il)})` : ""}, {SON_YIL} YKS
yerleştirme sonuçlarına göre{" "}
{uni.il ? ` (${trBaslikDuzeni(uni.il)})` : ""}
{turCumlesi ? `, ${turCumlesi};` : ","} {SON_YIL} YKS yerleştirme
sonuçlarına göre{" "}
<strong>{sayi(uni.programSayisi)} programda</strong> öğrenci aldı
{uni.fakulteSayisi > 1
? `; programlar ${sayi(uni.fakulteSayisi)} fakülte/yüksekokula dağılıyor`
@@ -308,17 +387,36 @@ export function UniversiteIcerik({
{sayi(uni.fakulteSayisi)}
</dd>
</div>
{/* URAP'ta olan üniversitede "Tür" kartının yeri URAP'a
bırakılır (kart sayısı 4'te kalır, ızgara şablonu değişmez);
olmayanda "Tür" yerinde durur — hiçbir sayfada boş kutu yok.
Payda kartın içindedir: "18." tek başına yanıltır. */}
<div className="rounded-xl border border-slate-200 bg-white p-4">
<dt className="text-xs font-medium uppercase tracking-wide text-slate-500">
Tür
</dt>
<dd className="mt-1 font-heading text-2xl font-bold text-slate-900">
{uni.unitur === "DEVLET"
? "Devlet"
: uni.unitur
? trBaslikDuzeni(uni.unitur)
: "—"}
</dd>
{uni.urap ? (
<>
<dt className="text-xs font-medium uppercase tracking-wide text-slate-500">
URAP Türkiye
</dt>
<dd className="mt-1 font-heading text-2xl font-bold text-slate-900">
{sayi(uni.urap.sira)} / {sayi(URAP_TOPLAM)}
<span className="mt-0.5 block font-sans text-xs font-medium text-slate-500">
{URAP_DONEM}
</span>
</dd>
</>
) : (
<>
<dt className="text-xs font-medium uppercase tracking-wide text-slate-500">
Tür
</dt>
<dd className="mt-1 font-heading text-2xl font-bold text-slate-900">
{uni.unitur
? (UNITUR_ETIKET[uni.unitur]?.kart ??
trBaslikDuzeni(uni.unitur))
: "—"}
</dd>
</>
)}
</div>
<div className="rounded-xl border border-slate-200 bg-white p-4">
<dt className="text-xs font-medium uppercase tracking-wide text-slate-500">
@@ -371,6 +469,8 @@ export function UniversiteIcerik({
veya o yıl yerleşen çıkmayan program).{" "}
</VeriKaynagi>
{ilkSayfa ? <UrapKaynakSatiri uni={uni} /> : null}
<Sayfalama
tabanYol={`/universite/${slug}`}
sayfa={sayfa}

View File

@@ -10,6 +10,7 @@ import type { Program } from "@/types/yokatlas";
import { kategoriBul, type Kategori } from "./kategoriler";
import { uniAdiNormalize } from "./harita";
import { bolumBazAdi, turkishSlugify, trBaslikDuzeni } from "./slug";
import { urapSirasiBul, type UrapSira } from "./urap-siralama";
/**
* Programatik SEO sayfalarının veri katmanı (/bolum, /universite, hub'lar).
@@ -224,6 +225,11 @@ export type UniOzet = {
};
export type UniDetay = UniOzet & {
/**
* URAP Türkiye genel sıralaması; listede olmayan üniversitede null.
* Gösterildiği her yüzeyde URAP_KAYNAK_URL'ye aktif atıf zorunludur.
*/
urap: UrapSira | null;
fakulteler: { fakulte: string; programlar: Program[] }[];
stats: {
minSira: number | null;
@@ -393,6 +399,7 @@ export function getUniversiteBySlug(slug: string): UniDetay | null {
const ozet = getAllUniversiteler().find((u) => u.slug === slug)!;
return {
...ozet,
urap: urapSirasiBul(slug),
fakulteler: [...gruplar.entries()]
.map(([fakulte, programlar]) => ({ fakulte, programlar }))
.sort((a, b) => a.fakulte.localeCompare(b.fakulte, "tr-TR")),

242
src/lib/urap-siralama.ts Normal file
View File

@@ -0,0 +1,242 @@
// URAP (University Ranking by Academic Performance) Türkiye genel sıralaması.
//
// Kaynak: URAP Araştırma Laboratuvarı, 2025-2026 genel sıralaması
// (URAP_KAYNAK_URL). Veri, URAP'ın yazılı izniyle yayımlanıyor; izin
// "urapcenter.org adresine aktif bağlantı/atıf vermek" şartına bağlı.
// Bu yüzden URAP sayısının göründüğü HER yüzeyde, aynı ekranda,
// URAP_KAYNAK_URL'ye çıkan gerçek bir <a href> bulunmak zorunda
// (rel="noopener", yeni sekme, nofollow YOK). Link konulamayan bir
// yüzeyde (ör. OG görseli) URAP sayısı hiç gösterilmez.
//
// Anahtar biçimi: /universite/[slug] sayfa slug'ı (slug.ts → uniSayfaSlug).
// URAP 198 üniversitenin 198'inde bizim yazımımızla birebir eşleşiyor;
// takma ad tablosu yok. Burada olmayan üniversite URAP listesinde yoktur —
// "kötü" demek değildir (KKTC/yurt dışı kurumlar, yalnız MYO'su olanlar ve
// araştırma çıktısı henüz oluşmamış yeni üniversiteler listeye girmiyor).
//
// Yıllık tazeleme: URAP sıralamayı her Ekim yeni bir adreste yayımlıyor;
// veri ve URAP_KAYNAK_URL aynı commit'te birlikte güncellenir. Denetimi
// `pnpm veri-kalite` içindeki URAP kontrolleri yapar.
/** Sıralamanın dönemi. Ölçtüğü veri dönemi 2020-2024'tür (URAP Yöntem sayfası). */
export const URAP_DONEM = "2025-2026";
/** Sıralamadaki toplam üniversite sayısı — payda. Sıra tek başına gösterilmez. */
export const URAP_TOPLAM = 198;
/** Atıf şartının adresi: sıralamanın o yıla ait kendi sayfası. */
export const URAP_KAYNAK_URL =
"https://newtr.urapcenter.org/Rankings/2025-2026/GENEL-SIRALAMASI-2025";
export type UrapSira = {
/** Türkiye genel sıralamasındaki sıra (1..URAP_TOPLAM) */
sira: number;
/** URAP toplam puanı — sayfada gösterilmez, veri kalitesi kontrolü kullanır */
puan: number;
};
export const URAP_SIRA: Record<string, UrapSira> = {
"koc-universitesi": { sira: 1, puan: 1152.91 },
"hacettepe-universitesi": { sira: 2, puan: 1096.48 },
"orta-dogu-teknik-universitesi": { sira: 3, puan: 1082.81 },
"istanbul-teknik-universitesi": { sira: 4, puan: 1067.01 },
"ankara-universitesi": { sira: 5, puan: 1038.45 },
"gazi-universitesi": { sira: 6, puan: 1006.92 },
"ege-universitesi": { sira: 7, puan: 1003.87 },
"istanbul-universitesi-cerrahpasa": { sira: 8, puan: 998.17 },
"istanbul-universitesi": { sira: 9, puan: 994.98 },
"sabanci-universitesi": { sira: 10, puan: 992.03 },
"yildiz-teknik-universitesi": { sira: 11, puan: 962.25 },
"gebze-teknik-universitesi": { sira: 12, puan: 933.23 },
"ataturk-universitesi": { sira: 13, puan: 932.94 },
"erciyes-universitesi": { sira: 14, puan: 931.72 },
"marmara-universitesi": { sira: 15, puan: 929.21 },
"ihsan-dogramaci-bilkent-universitesi": { sira: 16, puan: 903.76 },
"firat-universitesi": { sira: 17, puan: 885.66 },
"bogazici-universitesi": { sira: 18, puan: 881.20 },
"dokuz-eylul-universitesi": { sira: 19, puan: 869.21 },
"karadeniz-teknik-universitesi": { sira: 20, puan: 866.97 },
"akdeniz-universitesi": { sira: 21, puan: 862.50 },
"izmir-yuksek-teknoloji-enstitusu": { sira: 22, puan: 862.37 },
"acibadem-mehmet-ali-aydinlar-universitesi": { sira: 23, puan: 852.95 },
"cukurova-universitesi": { sira: 24, puan: 851.47 },
"bezm-i-alem-vakif-universitesi": { sira: 25, puan: 841.14 },
"selcuk-universitesi": { sira: 26, puan: 840.50 },
"saglik-bilimleri-universitesi": { sira: 27, puan: 837.93 },
"sakarya-universitesi": { sira: 28, puan: 836.46 },
"ondokuz-mayis-universitesi": { sira: 29, puan: 829.78 },
"bursa-uludag-universitesi": { sira: 30, puan: 828.79 },
"istinye-universitesi": { sira: 31, puan: 824.40 },
"eskisehir-osmangazi-universitesi": { sira: 32, puan: 808.86 },
"kocaeli-universitesi": { sira: 33, puan: 787.14 },
"necmettin-erbakan-universitesi": { sira: 34, puan: 775.91 },
"inonu-universitesi": { sira: 35, puan: 774.31 },
"ankara-yildirim-beyazit-universitesi": { sira: 36, puan: 769.99 },
"izmir-katip-celebi-universitesi": { sira: 37, puan: 763.47 },
"istanbul-medeniyet-universitesi": { sira: 38, puan: 761.73 },
"recep-tayyip-erdogan-universitesi": { sira: 39, puan: 755.54 },
"kadir-has-universitesi": { sira: 40, puan: 748.99 },
"istanbul-medipol-universitesi": { sira: 41, puan: 747.95 },
"suleyman-demirel-universitesi": { sira: 42, puan: 739.79 },
"mersin-universitesi": { sira: 43, puan: 736.04 },
"eskisehir-teknik-universitesi": { sira: 44, puan: 734.81 },
"harran-universitesi": { sira: 45, puan: 732.49 },
"konya-teknik-universitesi": { sira: 46, puan: 731.10 },
"van-yuzuncu-yil-universitesi": { sira: 47, puan: 728.49 },
"bahcesehir-universitesi": { sira: 48, puan: 722.03 },
"gaziantep-universitesi": { sira: 49, puan: 720.53 },
"yeditepe-universitesi": { sira: 50, puan: 720.51 },
"duzce-universitesi": { sira: 51, puan: 711.46 },
"canakkale-onsekiz-mart-universitesi": { sira: 52, puan: 711.34 },
"baskent-universitesi": { sira: 53, puan: 709.49 },
"sivas-cumhuriyet-universitesi": { sira: 54, puan: 708.36 },
"mugla-sitki-kocman-universitesi": { sira: 55, puan: 700.99 },
"abdullah-gul-universitesi": { sira: 56, puan: 698.46 },
"karabuk-universitesi": { sira: 57, puan: 695.29 },
"isparta-uygulamali-bilimler-universitesi": { sira: 58, puan: 692.14 },
"bingol-universitesi": { sira: 59, puan: 690.31 },
"bartin-universitesi": { sira: 60, puan: 690.02 },
"nigde-omer-halisdemir-universitesi": { sira: 61, puan: 686.24 },
"biruni-universitesi": { sira: 62, puan: 686.04 },
"bolu-abant-izzet-baysal-universitesi": { sira: 63, puan: 682.56 },
"manisa-celal-bayar-universitesi": { sira: 64, puan: 681.21 },
"ozyegin-universitesi": { sira: 65, puan: 674.94 },
"kastamonu-universitesi": { sira: 66, puan: 674.08 },
"erzurum-teknik-universitesi": { sira: 67, puan: 672.03 },
"aydin-adnan-menderes-universitesi": { sira: 68, puan: 671.78 },
"tarsus-universitesi": { sira: 69, puan: 669.45 },
"pamukkale-universitesi": { sira: 70, puan: 669.23 },
"tobb-ekonomi-ve-teknoloji-universitesi": { sira: 71, puan: 660.20 },
"anadolu-universitesi": { sira: 72, puan: 656.74 },
"bursa-teknik-universitesi": { sira: 73, puan: 647.49 },
"adana-alparslan-turkes-bilim-ve-teknoloji-universitesi": { sira: 74, puan: 646.96 },
"kahramanmaras-sutcu-imam-universitesi": { sira: 75, puan: 646.28 },
"cankaya-universitesi": { sira: 76, puan: 639.31 },
"siirt-universitesi": { sira: 77, puan: 631.70 },
"karamanoglu-mehmetbey-universitesi": { sira: 78, puan: 628.87 },
"zonguldak-bulent-ecevit-universitesi": { sira: 79, puan: 628.13 },
"tekirdag-namik-kemal-universitesi": { sira: 80, puan: 626.48 },
"atilim-universitesi": { sira: 81, puan: 625.01 },
"aksaray-universitesi": { sira: 82, puan: 624.78 },
"bilecik-seyh-edebali-universitesi": { sira: 83, puan: 624.59 },
"hatay-mustafa-kemal-universitesi": { sira: 84, puan: 621.04 },
"hitit-universitesi": { sira: 85, puan: 620.88 },
"cankiri-karatekin-universitesi": { sira: 86, puan: 619.86 },
"hasan-kalyoncu-universitesi": { sira: 87, puan: 618.15 },
"yozgat-bozok-universitesi": { sira: 88, puan: 611.80 },
"kirikkale-universitesi": { sira: 89, puan: 608.75 },
"erzincan-binali-yildirim-universitesi": { sira: 90, puan: 602.70 },
"trakya-universitesi": { sira: 91, puan: 601.88 },
"tokat-gaziosmanpasa-universitesi": { sira: 92, puan: 595.80 },
"iskenderun-teknik-universitesi": { sira: 93, puan: 594.68 },
"dicle-universitesi": { sira: 94, puan: 594.60 },
"burdur-mehmet-akif-ersoy-universitesi": { sira: 95, puan: 593.54 },
"izmir-ekonomi-universitesi": { sira: 96, puan: 592.96 },
"afyon-kocatepe-universitesi": { sira: 97, puan: 592.85 },
"usak-universitesi": { sira: 98, puan: 589.80 },
"ordu-universitesi": { sira: 99, puan: 582.94 },
"igdir-universitesi": { sira: 100, puan: 577.55 },
"sakarya-uygulamali-bilimler-universitesi": { sira: 101, puan: 565.68 },
"yasar-universitesi": { sira: 102, puan: 561.18 },
"osmaniye-korkut-ata-universitesi": { sira: 103, puan: 558.18 },
"altinbas-universitesi": { sira: 104, puan: 556.66 },
"balikesir-universitesi": { sira: 105, puan: 550.12 },
"adiyaman-universitesi": { sira: 106, puan: 546.48 },
"munzur-universitesi": { sira: 107, puan: 545.61 },
"istanbul-ticaret-universitesi": { sira: 108, puan: 544.68 },
"malatya-turgut-ozal-universitesi": { sira: 109, puan: 542.65 },
"kirsehir-ahi-evran-universitesi": { sira: 110, puan: 541.62 },
"batman-universitesi": { sira: 111, puan: 530.02 },
"istanbul-okan-universitesi": { sira: 112, puan: 527.88 },
"kafkas-universitesi": { sira: 113, puan: 527.04 },
"bayburt-universitesi": { sira: 114, puan: 525.89 },
"bandirma-onyedi-eylul-universitesi": { sira: 115, puan: 524.68 },
"giresun-universitesi": { sira: 116, puan: 520.78 },
"samsun-universitesi": { sira: 117, puan: 516.24 },
"alanya-alaaddin-keykubat-universitesi": { sira: 118, puan: 512.85 },
"konya-gida-ve-tarim-universitesi": { sira: 119, puan: 512.57 },
"nevsehir-haci-bektas-veli-universitesi": { sira: 120, puan: 509.45 },
"sinop-universitesi": { sira: 121, puan: 509.24 },
"gumushane-universitesi": { sira: 122, puan: 507.79 },
"izmir-bakircay-universitesi": { sira: 123, puan: 504.13 },
"antalya-bilim-universitesi": { sira: 124, puan: 503.18 },
"ibn-haldun-universitesi": { sira: 125, puan: 501.66 },
"artvin-coruh-universitesi": { sira: 126, puan: 498.79 },
"istanbul-sabahattin-zaim-universitesi": { sira: 127, puan: 497.58 },
"ted-universitesi": { sira: 128, puan: 496.02 },
"agri-ibrahim-cecen-universitesi": { sira: 129, puan: 493.56 },
"lokman-hekim-universitesi": { sira: 130, puan: 492.28 },
"istanbul-aydin-universitesi": { sira: 131, puan: 489.10 },
"amasya-universitesi": { sira: 132, puan: 486.73 },
"kutahya-saglik-bilimleri-universitesi": { sira: 133, puan: 486.66 },
"istanbul-nisantasi-universitesi": { sira: 134, puan: 479.20 },
"kayseri-universitesi": { sira: 135, puan: 478.40 },
"galatasaray-universitesi": { sira: 136, puan: 476.49 },
"istanbul-bilgi-universitesi": { sira: 137, puan: 476.16 },
"istanbul-gelisim-universitesi": { sira: 138, puan: 475.63 },
"uskudar-universitesi": { sira: 139, puan: 472.03 },
"turk-alman-universitesi": { sira: 140, puan: 471.87 },
"yalova-universitesi": { sira: 141, puan: 464.53 },
"kutahya-dumlupinar-universitesi": { sira: 142, puan: 462.86 },
"istanbul-arel-universitesi": { sira: 143, puan: 459.52 },
"piri-reis-universitesi": { sira: 144, puan: 451.88 },
"afyonkarahisar-saglik-bilimleri-universitesi": { sira: 145, puan: 448.30 },
"izmir-demokrasi-universitesi": { sira: 146, puan: 447.60 },
"kto-karatay-universitesi": { sira: 147, puan: 440.94 },
"mus-alparslan-universitesi": { sira: 148, puan: 439.94 },
"maltepe-universitesi": { sira: 149, puan: 431.24 },
"ardahan-universitesi": { sira: 150, puan: 422.37 },
"kirklareli-universitesi": { sira: 151, puan: 421.10 },
"bitlis-eren-universitesi": { sira: 152, puan: 414.54 },
"demiroglu-bilim-universitesi": { sira: 153, puan: 407.06 },
"ankara-haci-bayram-veli-universitesi": { sira: 154, puan: 404.20 },
"turk-hava-kurumu-universitesi": { sira: 155, puan: 398.48 },
"fatih-sultan-mehmet-vakif-universitesi": { sira: 156, puan: 392.99 },
"dogus-universitesi": { sira: 157, puan: 388.75 },
"sirnak-universitesi": { sira: 158, puan: 377.20 },
"trabzon-universitesi": { sira: 159, puan: 376.52 },
"halic-universitesi": { sira: 160, puan: 375.33 },
"mef-universitesi": { sira: 161, puan: 373.15 },
"gaziantep-islam-bilim-ve-teknoloji-universitesi": { sira: 162, puan: 367.89 },
"ostim-teknik-universitesi": { sira: 163, puan: 363.20 },
"sanko-universitesi": { sira: 164, puan: 361.18 },
"isik-universitesi": { sira: 165, puan: 360.25 },
"istanbul-beykent-universitesi": { sira: 166, puan: 360.02 },
"mardin-artuklu-universitesi": { sira: 167, puan: 358.73 },
"ankara-medipol-universitesi": { sira: 168, puan: 349.71 },
"hakkari-universitesi": { sira: 169, puan: 348.80 },
"ufuk-universitesi": { sira: 170, puan: 344.76 },
"kilis-7-aralik-universitesi": { sira: 171, puan: 342.59 },
"kahramanmaras-istiklal-universitesi": { sira: 172, puan: 340.49 },
"istanbul-gedik-universitesi": { sira: 173, puan: 337.25 },
"ankara-sosyal-bilimler-universitesi": { sira: 174, puan: 333.58 },
"istanbul-kultur-universitesi": { sira: 175, puan: 330.47 },
"yuksek-ihtisas-universitesi": { sira: 176, puan: 318.38 },
"cag-universitesi": { sira: 177, puan: 318.17 },
"mimar-sinan-guzel-sanatlar-universitesi": { sira: 178, puan: 315.16 },
"istanbul-yeni-yuzyil-universitesi": { sira: 179, puan: 298.64 },
"istanbul-saglik-ve-teknoloji-universitesi": { sira: 180, puan: 297.39 },
"nuh-naci-yazgan-universitesi": { sira: 181, puan: 269.70 },
"istanbul-atlas-universitesi": { sira: 182, puan: 248.03 },
"fenerbahce-universitesi": { sira: 183, puan: 243.09 },
"toros-universitesi": { sira: 184, puan: 241.33 },
"kapadokya-universitesi": { sira: 185, puan: 237.16 },
"izmir-tinaztepe-universitesi": { sira: 186, puan: 235.88 },
"istanbul-kent-universitesi": { sira: 187, puan: 231.72 },
"istanbul-rumeli-universitesi": { sira: 188, puan: 179.54 },
"avrasya-universitesi": { sira: 189, puan: 178.53 },
"alanya-universitesi": { sira: 190, puan: 176.69 },
"istanbul-topkapi-universitesi": { sira: 191, puan: 171.16 },
"istanbul-29-mayis-universitesi": { sira: 192, puan: 170.22 },
"ankara-bilim-universitesi": { sira: 193, puan: 154.45 },
"kocaeli-saglik-ve-teknoloji-universitesi": { sira: 194, puan: 116.23 },
"istanbul-galata-universitesi": { sira: 195, puan: 114.92 },
"istanbul-esenyurt-universitesi": { sira: 196, puan: 97.81 },
"beykoz-universitesi": { sira: 197, puan: 83.48 },
"antalya-belek-universitesi": { sira: 198, puan: 70.82 },
};
/** Üniversite sayfa slug'ının URAP sırası; listede yoksa null. */
export function urapSirasiBul(slug: string): UrapSira | null {
return URAP_SIRA[slug] ?? null;
}