# Yıllık veri güncellemesi (YÖK Atlas → `data/yokatlas.db`) Her yıl yerleştirme sonuçları açıklandıktan sonra **bir kez** yapılır. Bu sayfayı yukarıdan aşağıya izleyen biri, betiklerin içini bilmeden güncellemeyi tamamlayabilir. Toplam süre: yaklaşık **30 dakika** (çoğu bekleme ve gözle kontrol). > Ürünün bütün değeri bu verinin doğruluğuna dayanır. Yanlış bir taban sıralaması, > bir öğrencinin yanlış tercih yapması demektir. Bu yüzden betikler şüphede > **durur**; "DURDU:" ile başlayan bir mesaj hata değil, emniyet kilididir. > Kilidi aşmaya çalışma — mesajı oku, aşağıdaki "Bir şey durursa" tablosuna bak. Örneklerde yeni yıl `2027` diye yazıldı; o yıl hangisiyse onu yaz. ## 0. Ne zaman? - ÖSYM yerleştirme sonuçlarını açıklar (genelde **Ağustos sonu**), YÖK Atlas verisini birkaç gün–birkaç hafta sonra günceller. Tarih her yıl değişir → **doğrulanmalı**. - Erken koşmanın zararı yok: YÖK Atlas henüz güncellenmediyse 3. adım "`… hâlâ 2026 verisi`" diyerek **hiçbir şey yazmadan** durur. Bir hafta sonra tekrar dene. - Dosya indirmen gerekmez. Veri, YÖK Atlas'ın herkese açık tercih kılavuzu servisinden (`https://yokatlas.yok.gov.tr/api/tercih-kilavuz/search`) betikle çekilir: 43 istek, aralarında yarım saniye — kaynağı yormaz. Betiği art arda defalarca koşma; ilk çekimden sonra hep kaydedilmiş ham dosyayı (`--ham`) kullan. ## 1. Hazırlık (5 dk) ```bash git switch -c veri/2027 # main'de çalışma ``` `src/lib/veri-yillari.ts` dosyasında **tek satırı** değiştir: ```ts export const SON_YIL = 2027; ``` Betikler ve site yılı yalnız buradan okur. Betiğe verdiğin `--yil` bununla aynı değilse betik durur (yanlış kolona yazmayı önler). ## 2. Kopya al — asıl dosyaya dokunma (1 dk) Dev sunucusu açıksa kapat. Sonra: ```bash mkdir -p /tmp/veri-2027 sqlite3 data/yokatlas.db ".backup '/tmp/veri-2027/once.db'" # güncelleme ÖNCESİ hâl (geri dönüş + karşılaştırma) cp /tmp/veri-2027/once.db /tmp/veri-2027/yeni.db # üzerinde çalışılacak kopya ``` Bundan sonraki her adım **`/tmp/veri-2027/yeni.db`** üzerinde koşar. `data/yokatlas.db` ancak 8. adımda, her şey yeşilken değişir. ## 3. Yeni yılı çek (3 dk) ```bash pnpm refresh --yil 2027 --db /tmp/veri-2027/yeni.db ``` Ne yapar: şemaya `sira2027/puan2027/kontenjan2027/yerlesen2027` kolonlarını ekler, **yıl kilidini** sınar, tüm kılavuzu çeker, ham hâlini `data/ham/2027-.jsonl.gz` olarak saklar (git'e girmez), sonra tek seferde DB'ye yazar. Görmen gerekenler: ``` Yıl kilidi: basariSirasi1 = sira2026 → 480/480 (%100.0); eksiz basariSirasi = sira2026 → 0/480 (%0.0) Çekilen: 21… kayıt, benzersiz kod: 21…, kodsuz: 0, API toplamı: 21… ← üç sayı aynı Güncellenen: 19…, eklenen: 1…, atlanan: 0 ``` - **Yıl kilidi** şunu kanıtlar: servisin "bir önceki yıl" diye verdiği sıralar bizim 2026 kolonumuzla birebir aynı **ve** "bu yıl" diye verdikleri ondan farklı. Yani yazacağımız veri gerçekten 2027'dir. (Servisteki `yil` alanına güvenilmez; 2026'da bu alan yüzünden 2025 verisi bozulmak üzereydi.) - "atlanan" 0 değilse satırlar altında listelenir: kaynağın puan türü vermediği yeni programlardır; uydurulmaz. Sayıyı not et. - Bu betik mevcut programların **eski yıl kolonlarına dokunmaz**; dokunursa kendi sağlaması bunu yakalar ve her şeyi geri alır. - **Kimlik kilidi.** ÖSYM bazen bir kılavuz kodunu BAŞKA programa verir (2025'te `209210292` "Diş Hekimliği"nden "İlk ve Acil Yardım" önlisansına geçti). Betik her mevcut satırın puan türü / önlisans / bölüm adını servistekiyle kıyaslar; uyuşmayan varsa listeyi basıp **hiçbir şey yazmadan durur** (`KİMLİĞİ KAYMIŞ N satır`). Listeye göz at (yılda birkaç–birkaç on satır beklenir; yüzlerce ise servis biçim değiştirmiştir, veri mühendisine göster), sonra aynı komutu `--kimlik-onar` ekleyerek, ham dosyadan tekrarla: `pnpm refresh --yil 2027 --db --ham data/ham/2027-.jsonl.gz --kimlik-onar`. Onarım: ad/tür/önlisans/fakülte/süre servisten yazılır; devirden **önceki** yılların tüm değerleri o satırda boşaltılır (başka programa aitti), eski kimlik + geçmişi `programs_arsiv`'e `~` id'siyle kopyalanır, eski yılların netleri oraya taşınır. Çıktıdaki `KİMLİĞİ ONARILAN` tablosunu commit mesajına/rapora koy. "AD DEĞİŞİMİ" yazan satırlarda yalnız ad güncellenir, geçmiş korunur. Aynı işlemi servise gitmeden tekrarlamak için (ör. 8. adımda): `pnpm refresh --yil 2027 --db --ham data/ham/2027-.jsonl.gz` ## 4. Geçmiş boşluklarını doldur (1 dk) ```bash pnpm gecmis-doldur --yil 2027 --db /tmp/veri-2027/yeni.db ``` Kılavuz kodu değişen ya da yeni koda taşınan programların eski yıllarını tamamlar. Yalnız **boş** alanı doldurur; dolu değeri asla ezmez, tahmin yapmaz. Kaynak sırası: servisin kendi geçmiş alanları → servisin bildirdiği eski kod → aynı üniversitede bire bir aynı adlı ve en az bir yılı kanıtla örtüşen tek satır. Çıktının sonundaki "**Dolu olup kaynağın FARKLI söylediği alanlar**" listesine bak. Birkaç onluk fark olağandır (kaynak eski sıraları ufak düzeltmelerle yeniden yayımlıyor; 2026'da `sira2024` farklarının %95'i on binde birin altındaydı). **Binlerce satırda büyük fark** görürsen dur ve veri mühendisine sor. ## 5. Kılavuzdan çıkan programlar: önce sadece raporla (1 dk) ```bash pnpm eski-arsivle --yil 2027 --db /tmp/veri-2027/yeni.db --kuru ``` Hiçbir şey yazmaz. Şunu söyler: bu yılın kılavuzunda **olmayan** kaç satır var ve bunlar siteden kalkarsa hangi `/bolum/...` ve `/universite/...` sayfaları tamamen kapanır (adlarıyla). Bu liste **[BİLAL] kararıdır** — sayfa kapanışı SEO'yu etkiler, gerekirse yönlendirme (redirect) eklenir. Onaydan sonra gerçek taşıma (silmez; satırlar `programs_arsiv` tablosuna geçer): ```bash pnpm eski-arsivle --yil 2027 --db /tmp/veri-2027/yeni.db ``` Neden gerekli: arşivlenmezse eski kodlu satırlar listelerde bir yıl önceki sırayla görünmeye devam eder; öğrenci o kodu tercih ekranında bulamaz, kodu değişen program iki kez listelenir. ### 5b. Kapanan sayfaları yönlendir (5–15 dk) `--kuru` raporundaki `KAPANACAK /bolum/` ve `KAPANACAK /universite/` listelerindeki her adres (ve `--kimlik-onar` sonrası kapanan sayfa olduysa onlar da) `src/lib/kapanan-sluglar.ts` içindeki `KAPANAN_SLUGLAR` listesine eklenir; site bu adresleri yaşayan en yakın sayfaya **kalıcı (308)** yönlendirir (`next.config.ts` → `redirects()`, `/sayfa/N` alt yolları dahil). Eklemezsen kapanan adres Google'da "sayfa yok" gövdesiyle kalır. - Hedef sırası: (1) program/kurum **ad değiştirdiyse yeni adı** — kanıt: aynı üniversitede geçmiş yıl sıraları yeni adlı satıra birebir taşınmış, ya da Resmî Gazete kararı; (2) aynı alanın lisans/önlisans karşılığı; (3) emin değilsen hub: `/bolumler` ya da `/universiteler`. Uydurma eşleme yapma; `gerekce` alanına kanıtı yaz. - Hedef slug `programs` tablosundan türemeli ve kendisi listede **kaynak** olmamalı (zincir). Zinciri dosyadaki `kapananYonlendirmeleri()` build'de yakalar; hedefin yaşadığını sen kontrol et: 8. adımda hedef adresi tarayıcıda aç. - Bu yıl **yeniden açılan** bir sayfa listede kaynak olarak duruyorsa kaydını sil — yönlendirme sayfadan önce çalışır, silmezsen yeni sayfa hiç görünmez. Kontrol: 8. adımda listedeki `kaynak` adlarını `/bolumler` ve `/universiteler` sayfasında ara; çıkan varsa kaydını sil. - Hedef seçimi SEO'yu etkilediği için **[BİLAL] kararıdır**; listeyi commit'ten önce göster. ## 6. İndeks + dosyayı toparla (1 dk) ```bash pnpm db:index --db /tmp/veri-2027/yeni.db --vacuum ``` Son satırda `USING INDEX idx_programs_tur_onlisans_efektif` yazmalı. Yazmıyorsa betik zaten hata verir: sitedeki sıralama aralığı sorguları yavaşlar. ## 7. Kalite kapısı (1 dk) ```bash pnpm veri-kalite --yil 2027 --db /tmp/veri-2027/yeni.db --onceki /tmp/veri-2027/once.db --arsivli --ham data/ham/2027-.jsonl.gz echo "çıkış kodu: $?" # 0 olmalı ``` (`--arsivli`'yi yalnız 5. adımda gerçek arşivlemeyi yaptıysan ekle.) - Her satır `GEÇTİ`, `KALDI`, `UYARI` ya da `bilgi` ile başlar. **Tek bir `KALDI` varsa yayına çıkılmaz**; çıkış kodu 1 olur. - En önemli üç satır: - `kimlik (tur/önlisans/baz ad = API) — … uyumsuz: 0` — her kod hâlâ aynı programı gösteriyor (uyumsuzsa satır eski adıyla başka programın sırasını gösterir). - `önceki DB: geçmiş yıllar korunmuş — … değişen/silinen satır: 0` - `sira2027/sira2026 ∈ [0,5; 2] — … (%9x)` — programların büyük çoğunluğunun sırası bir yılda yarıya inmez, iki katına çıkmaz. Oran düşükse yıllar kaymıştır. - `UYARI`'lar bilgilendirir (ör. ili boş 110 program, yetim net satırları); yeni bir uyarı türü ya da sayıda sıçrama varsa veri mühendisine göster. Elle 3 program seç (biri çok bilinen: ör. Boğaziçi Bilgisayar Mühendisliği), YÖK Atlas sitesindeki 2027 taban sırasıyla karşılaştır: ```bash sqlite3 /tmp/veri-2027/yeni.db "SELECT id, universite, isim, sira2026, sira2027, puan2027 FROM programs WHERE isim LIKE 'Bilgisayar Mühendisliği%' AND universite LIKE 'BOĞAZİÇİ%';" ``` ## 8. Yerine koy ve siteyi kontrol et (5 dk) ```bash cp /tmp/veri-2027/yeni.db data/yokatlas.db rm -f data/yokatlas.db-wal data/yokatlas.db-shm # eski dosyanın artıkları; yenisi temiz (checkpoint yapılmış) pnpm build # katalog sayfaları yeni veriden üretilir; hata vermemeli ``` Netler (yerleşen son kişinin netleri) ayrı bir servisten gelir ve genelde daha geç güncellenir; hazır olduğunda: ```bash pnpm detay --yil 2027 --db data/yokatlas.db # ~127 istek, ~2 dk; yıl sağlaması tutmazsa durur ``` `--kirilim` bayrağını **kullanma**: kontenjan kırılımını (okul birincisi, şehit-gazi…) sitede okuyan kod yok ve servis bu alanları Eylül 2026'dan beri yayımlamıyor. Bayrak verilse bile alanlar yoksa adım kendini durdurur, mevcut değerlerin üstüne boş yazmaz. Yıl değişince koddaki metinler (`"son 6 yıl"`, başlıklardaki yıl vb.) `veri-yillari.ts` sabitlerinden türediği için kendiliğinden güncellenir. Elle yıl yazılmış yer kaldıysa bul: ```bash grep -rnE "sira20[0-9]{2}|20(2[1-9])[–-]20" src scripts --include='*.ts' --include='*.tsx' | grep -v veri-yillari ``` Tadımlık havuzu ve kayıtlı raporlar eski sıralarla üretilmiştir → yayından sonra prod'da `pnpm tadimlik --force` (Bilal koşar; ayrıntı `scripts/tadimlik-uret.ts` başlığında). ## 9. Commit ve yayın ```bash git add src/lib/veri-yillari.ts data/yokatlas.db git commit -m "veri: 2027 yerleştirme verisi" ``` `data/ham/` git'e girmez (yerelde sakla; bir sonraki yıl karşılaştırma için işe yarar). Push öncesi `AGENTS.md`'deki "Push öncesi build zorunlu" kuralı geçerli. Yayın kararı Bilal'in. ## Geri alma | Ne zaman | Nasıl | Süre | |---|---|---| | 8. adımdan önce | Hiçbir şey yapma; `data/yokatlas.db` hiç değişmedi. `/tmp/veri-2027/` silinebilir. | 0 | | 8. adımdan sonra, commit'ten önce | `git checkout -- data/yokatlas.db data/yokatlas.db-wal data/yokatlas.db-shm` | 1 dk | | Commit/yayından sonra | `git revert ` + yeniden yayın. `SON_YIL` da aynı commit'te geri döner; site bir önceki yılın verisiyle tutarlı çalışır. | 10 dk | | Yalnız arşivlemeyi geri almak | `INSERT INTO programs SELECT * FROM programs_arsiv; DELETE FROM programs_arsiv;` (kopyada dene, sonra `pnpm db:index`). Netler yeni kodda kalır; zararsız. | 5 dk | `/tmp/veri-2027/once.db` dosyasını yayından bir hafta sonrasına kadar silme. ## Bir şey durursa | Mesaj | Anlamı | Ne yap | |---|---|---| | `--yil … ≠ SON_YIL` | 1. adım atlanmış | `veri-yillari.ts`'i güncelle | | `eksiz alanları hâlâ verisi` | YÖK Atlas henüz yeni yılı yayımlamamış | Bekle, bir hafta sonra tekrar dene | | `"…1" alanları DB'deki … verisiyle eşleşmiyor` | Servis bir yıl daha ilerlemiş (bir yılı atladık) **ya da** servis biçim değiştirmiş **ya da** yanlış DB | Yazma. Veri mühendisine göster | | `Benzersiz kod sayısı … ≠ API toplamı` | Çekim sırasında servis sayfaları kaydırdı | Birkaç dakika sonra 3. adımı tekrarla (DB'ye bir şey yazılmadı) | | `Aynı üniversitede birden fazla unitur` | Bir kurumun türü iki farklı yazılmış | Listelenen kurumları veri mühendisine göster; `scripts/unitur-onar.ts` | | `Güncel satır sayısı … refresh kaydıyla uyuşmuyor` (arşivle) | refresh yarım kalmış | 3. adımı tekrarla; arşivleme bilerek çalışmıyor | | `N satırın kimliği API ile uyuşmuyor` (refresh) | Kılavuz kodu başka programa devredilmiş (ya da program ad değiştirmiş) | Listeye bak; 3. adımdaki gibi `--ham … --kimlik-onar` ile tekrarla (DB'ye bir şey yazılmadı) | | `veri-kalite` içinde `KALDI` | O kontrol tutmadı | Yayına çıkma; satırdaki sayıyı ve örnek kodları veri mühendisine ilet | ## Betikler ve dokundukları | Betik | Yazar mı? | Ne yazar | |---|---|---| | `scripts/yokatlas-goc.ts` (`pnpm yokatlas:goc`) | evet | Yalnız şema: yıl kolonları, `son_kilavuz_yili`, `eski_kod`, `programs_arsiv`, `veri_meta`. refresh bunu kendisi çağırır. | | `scripts/refresh.ts` | evet | `sira/puan/kontenjan/yerlesen`, `son_kilavuz_yili`, `eski_kod`; yeni programlar; ham dosya. `--kimlik-onar` ile: kimliği kaymış satırın ad/tür/önlisans/fakülte/süresi, devir öncesi yıl kolonları (NULL), `programs_arsiv` kopyası, `netler.program_id`, `veri_meta` `kimlik_onar:` | | `scripts/gecmis-doldur.ts` | evet | Yalnız **NULL** geçmiş yıl alanları + `eski_kod`; kimliği onarılmış satırda devir öncesi yılları doldurmaz | | `scripts/eski-arsivle.ts` | `--kuru` ile hayır | Satır taşıma `programs` → `programs_arsiv`; `netler.program_id` yeni koda | | `scripts/db-index.ts` | evet | İndeks, `--vacuum`, WAL checkpoint | | `scripts/veri-kalite.ts` | **hayır** | Salt okunur; çıkış kodu 0/1 | | `scripts/detay.ts` | evet | `netler`; `--kirilim` ile (alanlar varsa) bir önceki yılın kırılım kolonları | Kolon sözlüğü: `son_kilavuz_yili` = programın görüldüğü son tercih kılavuzu (NULL = 2024 ve öncesi, bilinmiyor). `eski_kod` = kılavuz kodu değiştiyse bir önceki kod — kayıtlı listelerdeki eski kodları yeni koda çevirmek için `SELECT id FROM programs WHERE eski_kod = ?`.