Build TercihAI MVP: landing page, YÖK Atlas data pipeline, rank-based results
- Add product vision/market research doc (VISION.md) - Set up shadcn/ui (radix + nova preset) with blue/orange theme, Outfit + Work Sans fonts - Landing page: hero with rank input, problem/steps sections, comparison table, FAQ - Data pipeline: CSV archive ingest (2021-2024) + live YÖK Atlas API refresh (2025) into SQLite (npm run ingest / refresh); zeros normalized to NULL - /sonuc page: hayal/dengeli/garanti buckets by COALESCE(sira2025, sira2024), score-type switcher, 2024→2025 trend indicators - Add ui-ux-pro-max and shadcn agent skills, shadcn MCP config, launch.json Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
106
src/lib/db.ts
Normal file
106
src/lib/db.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import path from "node:path";
|
||||
import Database from "better-sqlite3";
|
||||
|
||||
export type Program = {
|
||||
id: string;
|
||||
isim: string;
|
||||
universite: string;
|
||||
unitur: string | null;
|
||||
il: string | null;
|
||||
fakulte: string | null;
|
||||
tur: string;
|
||||
sure: number | null;
|
||||
sira2025: number | null;
|
||||
sira2024: number | null;
|
||||
sira2023: number | null;
|
||||
sira2022: number | null;
|
||||
sira2021: number | null;
|
||||
puan2025: number | null;
|
||||
kontenjan2025: number | null;
|
||||
yerlesen2025: number | null;
|
||||
};
|
||||
|
||||
export const PUAN_TURLERI = {
|
||||
say: "SAYISAL",
|
||||
ea: "EŞİT AĞIRLIK",
|
||||
soz: "SÖZEL",
|
||||
dil: "DİL",
|
||||
tyt: "TYT",
|
||||
} as const;
|
||||
|
||||
export type PuanTuruKey = keyof typeof PUAN_TURLERI;
|
||||
|
||||
export type RankResults = {
|
||||
hayal: Program[];
|
||||
dengeli: Program[];
|
||||
garanti: Program[];
|
||||
};
|
||||
|
||||
// Dev'de hot-reload başına yeni bağlantı açılmasın diye global cache
|
||||
const globalForDb = globalThis as unknown as { yokatlasDb?: Database.Database };
|
||||
|
||||
function getDb(): Database.Database {
|
||||
if (!globalForDb.yokatlasDb) {
|
||||
globalForDb.yokatlasDb = new Database(
|
||||
path.join(process.cwd(), "data", "yokatlas.db"),
|
||||
{ readonly: true, fileMustExist: true }
|
||||
);
|
||||
}
|
||||
return globalForDb.yokatlasDb;
|
||||
}
|
||||
|
||||
const SELECT_COLS = `id, isim, universite, unitur, il, fakulte, tur, sure,
|
||||
sira2025, sira2024, sira2023, sira2022, sira2021,
|
||||
puan2025, kontenjan2025, yerlesen2025`;
|
||||
|
||||
// 2025 sıralaması yoksa (az yerleşen/yeni program) 2024'e düşer
|
||||
const EFEKTIF_SIRA = "COALESCE(sira2025, sira2024)";
|
||||
|
||||
/**
|
||||
* Kullanıcının başarı sıralamasına göre programları üç dilime ayırır.
|
||||
* Sıralamada küçük sayı daha iyidir; program taban sıralaması kullanıcının
|
||||
* sıralamasından küçükse geçen yıl oraya yerleşmek daha iyi dereceyle mümkündü
|
||||
* demektir (hayal), büyükse daha güvenli demektir (garanti).
|
||||
*/
|
||||
export function searchByRank(
|
||||
sira: number,
|
||||
turKey: PuanTuruKey,
|
||||
limitPerBucket = 12
|
||||
): RankResults {
|
||||
const db = getDb();
|
||||
const tur = PUAN_TURLERI[turKey];
|
||||
const onlisans = turKey === "tyt" ? 1 : 0;
|
||||
|
||||
const base = `FROM programs
|
||||
WHERE tur = ? AND onlisans = ? AND ${EFEKTIF_SIRA} IS NOT NULL
|
||||
AND ${EFEKTIF_SIRA} BETWEEN ? AND ?`;
|
||||
|
||||
// hayal: kullanıcıdan daha iyi taban sıralaması (sınıra en yakın olanlar önce)
|
||||
const hayal = db
|
||||
.prepare(
|
||||
`SELECT ${SELECT_COLS} ${base} ORDER BY ${EFEKTIF_SIRA} DESC LIMIT ?`
|
||||
)
|
||||
.all(tur, onlisans, Math.round(sira * 0.5), sira - 1, limitPerBucket);
|
||||
|
||||
// dengeli: tabanı kullanıcının sıralaması civarında
|
||||
const dengeli = db
|
||||
.prepare(`SELECT ${SELECT_COLS} ${base} ORDER BY ${EFEKTIF_SIRA} ASC LIMIT ?`)
|
||||
.all(tur, onlisans, sira, Math.round(sira * 1.4), limitPerBucket);
|
||||
|
||||
// garanti: tabanı belirgin şekilde altında
|
||||
const garanti = db
|
||||
.prepare(`SELECT ${SELECT_COLS} ${base} ORDER BY ${EFEKTIF_SIRA} ASC LIMIT ?`)
|
||||
.all(
|
||||
tur,
|
||||
onlisans,
|
||||
Math.round(sira * 1.4) + 1,
|
||||
Math.round(sira * 3),
|
||||
limitPerBucket
|
||||
);
|
||||
|
||||
return {
|
||||
hayal: hayal as Program[],
|
||||
dengeli: dengeli as Program[],
|
||||
garanti: garanti as Program[],
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user