Files
kolaytercih/docs/veri/yillik-guncelleme.md
bilalgursen a773ac7beb feat(veri): 2026 yükleme hattı — yıl kilitli refresh, geçmiş doldurma, arşiv, kalite kapısı (P-A)
- yokatlas-goc: idempotent şema göçü (yıl kolonları, son_kilavuz_yili, eski_kod,
  programs_arsiv, veri_meta) + betiklerin ortak yardımcıları
- refresh: --yil/--db zorunlu, YIL KİLİDİ (…1 = DB sira<yil-1> ≥%95 ve eksiz ≠),
  yıl asla r.yil'den türetilmez; ham veri data/ham/*.jsonl.gz, --ham ile API'siz
  tekrar; benzersiz kod = totalElements; tek transaction + önceki yıl sağlaması;
  yeni programda …1/2/3 → üç önceki yıl; efektif indeks EFEKTIF_SIRA_SQL ile
- gecmis-doldur: yalnız NULL alan; API …1/2/3 → eski_kod → kanıtlı 1:1 ad eşleşmesi
- eski-arsivle: güncel kılavuzda olmayanlar → programs_arsiv, netler yeni koda; --kuru
- detay: netler bağımsız + yıl sağlaması; kırılım yalnız --kirilim, alan yoksa durur,
  mevcut değerin üstüne NULL yazılmaz; `yil - 1` varsayımı kalktı
- veri-kalite: salt okunur kalite kapısı, zorunlu kontrol kalırsa çıkış kodu 1
- docs/veri/yillik-guncelleme.md: adım adım runbook + geri alma

DB commit'lenmedi (arşivleme kararı [Bilal]).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 17:03:01 +03:00

231 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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-<tarih>.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.
Aynı işlemi servise gitmeden tekrarlamak için (ör. 8. adımda):
`pnpm refresh --yil 2027 --db <db> --ham data/ham/2027-<tarih>.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.
## 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
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 iki satır:
- `ö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 <commit>` + 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â <geçen yı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 |
| `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<yıl>`, `son_kilavuz_yili`, `eski_kod`; yeni programlar; ham dosya |
| `scripts/gecmis-doldur.ts` | evet | Yalnız **NULL** geçmiş yıl alanları + `eski_kod` |
| `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 = ?`.