feat: update app.db and BACKLOG.md with new decisions and adjustments
All checks were successful
Deploy / deploy (push) Successful in 7m45s

- Updated the app.db file to reflect recent changes in the application state.
- Modified BACKLOG.md to include new entries regarding the removal of certain wizard steps, adjustments to priority chips, and the introduction of special quota conditions for candidates.
- Added details on the decision to link priority chips to data sources and clarified the implications for user experience and data handling.
This commit is contained in:
bilalgursen
2026-10-06 17:17:49 +03:00
parent c0696e2cbc
commit a3cb058a3b
74 changed files with 10334 additions and 445 deletions

View File

@@ -2,13 +2,13 @@ import type { Metadata } from "next";
import Link from "next/link";
import { notFound } from "next/navigation";
import {
Armchair,
Briefcase,
Building2,
Calculator,
ChartLine,
ChevronRight,
GraduationCap,
Landmark,
LayoutList,
Target,
} from "lucide-react";
import {
@@ -34,7 +34,13 @@ import { BolumProgramListesi } from "./bolum-program-listesi";
import { VeriKaynagi } from "./veri-kaynagi";
import { NavBaslik } from "./nav-baslik";
import { AkademikAyrinti } from "./akademik-ayrinti";
import { OzetKart } from "@/components/ozet-kart";
import { OzetKart, kartSayisi } from "@/components/ozet-kart";
import {
KartBaglantisi,
kisaUniAdi,
ortaTabanAciklamasi,
} from "./taban-karti";
import { trBaslikDuzeni } from "@/lib/slug";
import {
BOLUM_ISTIHDAM_KAYNAK_URL,
BOLUM_ISTIHDAM_YIL,
@@ -56,24 +62,6 @@ import {
const sayi = (n: number) => n.toLocaleString("tr-TR");
/**
* Özet kartında iri sayı telefonda ~94 px'e sığmalı (DESIGN.md §4.8):
* 36 px Cal Sans'ta "1.618.988" 123 px ölçüldü, ikonun altına giriyor. 6 ve
* 7 haneli sıralar birimle kısalır: 245.300 → "245" + "bin",
* 1.618.988 → "1,62" + "milyon".
*/
function kartSayisi(n: number): { deger: string; birim?: string } {
// 999.500+ "1.000 bin" olmasın diye milyona geçer
if (n >= 999_500) {
return {
deger: (n / 1e6).toLocaleString("tr-TR", { maximumFractionDigits: 2 }),
birim: "milyon",
};
}
if (n >= 100_000) return { deger: sayi(Math.round(n / 1000)), birim: "bin" };
return { deger: sayi(n) };
}
const ondalik = (n: number) =>
n.toLocaleString("tr-TR", { maximumFractionDigits: 1 });
@@ -420,19 +408,22 @@ export function BolumIcerik({ slug, sayfa }: { slug: string; sayfa: number }) {
...(bolum.lisansProgramlari.length > 0 ? ["Lisans"] : []),
...(bolum.onlisansProgramlari.length > 0 ? ["Önlisans"] : []),
];
// Özet kartları: devlet ve vakıf ayrı sayılır; KKTC ve yurt dışı
// programları toplamda var ama iki karta da girmez (vakıf sayılmaz).
const devletUni = new Set<string>();
const vakifUni = new Set<string>();
let vakifProgram = 0;
for (const p of tumProgramlar) {
if (p.unitur === "DEVLET") devletUni.add(p.universite);
else if (p.unitur === "VAKIF" || p.unitur === "VAKIF MYO") {
vakifProgram += 1;
vakifUni.add(p.universite);
}
}
const { stats } = bolum;
// Özet kartları (Bilal, 6 Eki 2026: "kaç program var" sayıları ilgi
// çekmiyor): öğrencinin sorusuna cevap veren dört sayı — en seçici
// program, devlette en geniş kapı, orta tabanın yıllar içindeki seyri ve
// boş kalan koltuk. Hesap lib/taban-ozeti.ts; program/devlet/vakıf sayıları
// özet paragrafta kalır. Üniversite sayfasıyla aynı düzen (DESIGN.md §4.8).
const { taban } = bolum;
const uniBaglantisi = (universite: string) => (
<KartBaglantisi
href={(() => {
const s = uniSlugFromAd(universite);
return s ? `/universite/${s}` : null;
})()}
>
{kisaUniAdi(trBaslikDuzeni(universite))}
</KartBaglantisi>
);
// TÜİK mezun istihdamı: lisansı olan bölümde lisans tablosu, yalnız ön
// lisansı olanda ön lisans tablosu. Tabloda yoksa satır hiç çizilmez.
const istihdamDuzeyi: IstihdamDuzeyi =
@@ -568,38 +559,62 @@ export function BolumIcerik({ slug, sayfa }: { slug: string; sayfa: number }) {
{ilkSayfa ? (
<dl className="mt-8 grid grid-cols-2 gap-4 lg:grid-cols-4">
<OzetKart
ikon={LayoutList}
etiket="Program"
deger={sayi(stats.toplam)}
alt={`${sayi(stats.ilSayisi)} ilde`}
ikon={Target}
etiket="En seçici"
{...(taban.enSecici
? kartSayisi(taban.enSecici.sira)
: { deger: "—" })}
alt={
taban.enSecici ? (
<>
{uniBaglantisi(taban.enSecici.universite)} · {SON_YIL} taban
sırası
</>
) : (
"henüz taban oluşmadı"
)
}
/>
{/* Etiket kısa kalır ("Devlette en geniş" 131 px'te iki satıra
kırılıyor, 6 Eki 2026 ölçümü); küme açıklamanın başında. */}
<OzetKart
ikon={Landmark}
etiket="Devlet"
deger={sayi(stats.devlet)}
alt={
devletUni.size > 0
? `${sayi(devletUni.size)} üniversitede`
: "bu bölümde yok"
}
/>
<OzetKart
ikon={Building2}
etiket="Vakıf"
deger={sayi(vakifProgram)}
alt={
vakifUni.size > 0
? `${sayi(vakifUni.size)} üniversitede`
: "bu bölümde yok"
}
/>
<OzetKart
ikon={Target}
etiket="En iyi sıralama"
{...(stats.minSira != null
? kartSayisi(stats.minSira)
etiket="En geniş kapı"
{...(taban.enGenis
? kartSayisi(taban.enGenis.sira)
: { deger: "—" })}
alt={`${SON_YIL} taban sırası`}
alt={
taban.enGenis ? (
<>
{taban.kume === "devlet" ? "Devlet · " : ""}
{uniBaglantisi(taban.enGenis.universite)} · {SON_YIL} taban
sırası
</>
) : (
"henüz taban oluşmadı"
)
}
/>
<OzetKart
ikon={ChartLine}
etiket="Orta taban"
{...(() => {
const son = [...taban.ortaTaban].reverse().find((v) => v != null);
return son != null ? kartSayisi(son) : { deger: "—" };
})()}
alt={ortaTabanAciklamasi(taban)}
/>
<OzetKart
ikon={Armchair}
etiket="Boş koltuk"
deger={taban.doluluk ? sayi(taban.doluluk.bosKoltuk) : "—"}
alt={
taban.doluluk
? taban.doluluk.bosKoltuk > 0
? `${sayi(taban.doluluk.programSayisi)} programın ${sayi(taban.doluluk.dolmayanProgram)} tanesi dolmadı · ${SON_YIL}`
: `Her program doldu · ${SON_YIL}`
: "kontenjan verisi yok"
}
/>
</dl>
) : null}