Files
kolaytercih/docs/gece-vardiyasi/2026-09-21/07-yazilimci-raporlari.md
bilalgursen 0ab4dbe88c
All checks were successful
Deploy / deploy (push) Successful in 7m18s
Enhance Traefik configuration for www.kolaytercih.com
Added a new router and middleware for handling www to apex domain redirection, ensuring that Let's Encrypt certificates are obtained for both domains. Updated the docker-compose.yml file to include necessary rules and middleware for proper redirection and TLS handling.

Also, updated the CEO agent description to remove redundant details and clarified the QA engineer's responsibilities regarding testing critical flows and error reporting. Adjusted the CTO agent's section for consistency in expert guidance and clarified the designer's tools to include 'Skill' for better design resource management.
2026-09-21 20:37:12 +03:00

950 lines
128 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.
# 07 — Yazılımcı / yazar raporları — 2026-09-21 gece vardiyası
## Blog: hedef-siralama-nasil-belirlenir
**Özet (5 madde)**
1. Yazı yazıldı, commit atılmadı: `.claude/worktrees/rehber-yazilari/content/rehber/hedef-siralama-nasil-belirlenir.md` (dal `gece/rehber-yazilari`). ~1.380 kelime (şema hariç), 1 `flowchart TD` şema (`%% aria` + `%% altyazi`), 3 tablo, 5 soruluk SSS, "Kaynaklar" bölümü, 16 iç link. Başka hiçbir dosyaya dokunulmadı.
2. "%10–15 tampon" yöntemi KULLANILMADI. Yerine ürünün gerçek dilim kuralı anlatıldı ve tersinden okundu: hedef bandı = `taban ÷ 1,4 … taban` (programı dengeli dilimde gören sıralamalar); `taban ÷ 1,4`'ten iyi sıralama = güvenli dilim. Yeni bir formül değil, `riskHesapla`'nın cebirsel tersi; sınırlar `Math.round(sira*1.4)` ile birebir hesaplandı.
3. Tüm rakamlar `data/yokatlas.db`'den (salt-okunur `sqlite3 -readonly "file:...?mode=ro"`); DB'ye yazılmadı/kopyalanmadı. Veri yılları: `programs` 2021–2025, `netler` 2023–2025. 2026 verisi yok; yazıda açıkça belirtildi.
4. "Yerleşme olasılığı / garanti / yerleşirsin" dili yok; iki yerde açıkça "etiket olasılık değildir" deniyor. Dilim adı CEO kuralına göre: "güvenli dilim (halk arasındaki adıyla garanti tercih; üründe dilimin adı da böyle geçer)", sonrası "güvenli". Şemada `garanti` yalnızca classDef anahtarı.
5. Görev talimatı ile CEO notu arasında 2 fark var, görev talimatına uyuldu (aşağıda "Karar bekleyen").
### Kullanılan SQL sorguları ve sonuçları
Bağlantı: `sqlite3 -readonly "file:/Users/bilalgursen/Desktop/kolaytercih/data/yokatlas.db?mode=ro"`. Tablolar: `programs` (23.610 satır), `netler` (2023: 21.341 · 2024: 20.813 · 2025: 20.821 satır).
**S1 — ana tablo (5 yıllık taban başarı sıralaması):**
```sql
SELECT id,universite,isim,tur,sira2021,sira2022,sira2023,sira2024,sira2025,
ROUND(100.0*(sira2025-sira2021)/sira2021,1) AS degisim_yuzde
FROM programs
WHERE id IN ('103410457','104410207','101110518','103410096','104110342','103110769','103510395')
ORDER BY sira2025;
```
| id | universite | isim | tur | 2021 | 2022 | 2023 | 2024 | 2025 | 2021→2025 % |
|---|---|---|---|---|---|---|---|---|---|
| 101110518 | ANKARA ÜNİVERSİTESİ | Hukuk | EŞİT AĞIRLIK | 5124 | 4387 | 3242 | 3227 | 2233 | -56,4 |
| 103410457 | EGE ÜNİVERSİTESİ | Tıp | SAYISAL | 4218 | 5159 | 5303 | 5294 | 5118 | +21,3 |
| 103410096 | EGE ÜNİVERSİTESİ | Psikoloji | EŞİT AĞIRLIK | 28306 | 18751 | 13730 | 21549 | 18557 | -34,4 |
| 104410207 | GEBZE TEKNİK ÜNİVERSİTESİ | Bilgisayar Mühendisliği | SAYISAL | 15935 | 9926 | 9764 | 13974 | 22294 | +39,9 |
| 104110342 | GAZİ ÜNİVERSİTESİ | Sınıf Öğretmenliği | EŞİT AĞIRLIK | 63986 | 66184 | 52275 | 52808 | 45590 | -28,8 |
| 103110769 | DOKUZ EYLÜL ÜNİVERSİTESİ | Hemşirelik | SAYISAL | 116356 | 121110 | 123227 | 120589 | 110484 | -5,0 |
| 103510395 | ERCİYES ÜNİVERSİTESİ | Makine Mühendisliği | SAYISAL | 230974 | 219734 | 197346 | 191513 | 154725 | -33,0 |
**S2 — kontenjan iddiaları (Ankara Hukuk 500→200; GTÜ Bilgisayar 90–95 sabit):**
```sql
SELECT id,isim,kontenjan2021,kontenjan2022,kontenjan2023,kontenjan2024,kontenjan2025
FROM programs WHERE id IN ('101110518','103410096','104410207','103410457','104110342','103110769','103510395');
```
Sonuç: 101110518 Hukuk 550/550/500/500/**200** · 104410207 GTÜ Bilg. 90/90/90/95/95 · 103410096 Ege Psikoloji 100/100/100/80/50 · 103410457 Ege Tıp 310/310/310/320/320 · 104110342 Gazi Sınıf 80/80/90/50/60 · 103110769 DEÜ Hemş. 220/220/220/220/210 · 103510395 Erciyes Makine 100/100/100/105/90. (Yazıda yalnızca ilk ikisi kullanıldı.)
**S3 — net tablosu (Ege Tıp, yerleşen son kişinin netleri):**
```sql
SELECT program_id,yil,
tytTrkNet+tytSosNet+tytMatNet+tytFenNet AS tyt_toplam,
aytMatNet+aytFizNet+aytKimNet+aytBioNet AS ayt_say_toplam,
tabanPuan, obp
FROM netler WHERE program_id IN ('103410457','104410207') ORDER BY 1,2;
```
Sonuç (103410457 Ege Tıp): 2023 → TYT 105,25 · AYT 74,25 · puan 526,53 · 2024 → 112,5 · 68,25 · 516,07 · 2025 → 101,0 · 73,75 · 516,36. (104410207 GTÜ Bilg.: 109,75/68,75 · 99,0/66,25 · 89,75/66,25 — yazıda kullanılmadı.) "120 soruda / 80 soruda" paydaları `program-netleri.tsx` `DERSLER.max` toplamından: 40+20+40+20 = 120; 40+14+13+13 = 80.
**S4 — tek varyant kontrolü (aynı üniversitede aynı adla birden çok program var mı):**
```sql
SELECT universite,isim,count(*) FROM programs WHERE (universite='ANKARA ÜNİVERSİTESİ' AND isim LIKE 'Hukuk%')
OR (universite='EGE ÜNİVERSİTESİ' AND (isim LIKE 'Psikoloji%' OR isim LIKE 'Tıp%'))
OR (universite='GAZİ ÜNİVERSİTESİ' AND isim LIKE 'Sınıf Öğr%')
OR (universite='DOKUZ EYLÜL ÜNİVERSİTESİ' AND isim LIKE 'Hemşirelik%')
OR (universite LIKE 'ERCİYES%' AND isim LIKE 'Makine Müh%')
OR (universite LIKE 'GEBZE%' AND isim LIKE 'Bilgisayar Müh%') GROUP BY 1,2;
```
Sonuç: hepsi 1; tek istisna Erciyes'te 2025'te açılan ayrı "Makine Mühendisliği (İngilizce)" (id 103590583, yalnız 2025 verisi) — tablodaki satır Türkçe program (103510395). Bu yüzden ilk adaylar elendi: Hacettepe Tıp (2 program, `isim` ikisinde de "Tıp" — İngilizce eki DB'de kayıp), ODTÜ Bilgisayar (4 kayıt, KKTC kampüsü `il=ANKARA` görünüyor), Ankara Üni. Bilgisayar (3 kayıt), Marmara İng. Öğretmenliği (2 kayıt). **Yan bulgu:** eski kayıtlarda "(İngilizce)" / kampüs eki `isim`'de yok; katalogda bu satırlar ayırt edilemiyor olabilir — ayrı bakılmalı.
**S5 — hedef bandı sınırları (DB değil, ürün kuralıyla hesap):** `node -e` ile her taban T için `T > Math.round(s*1.4)` koşulunu sağlayan en büyük `s` bulundu → 5118: güvenli ≤ 3655, dengeli 3656–5118 · 22294: ≤ 15923, 15924–22294 · 45590: ≤ 32563, 32564–45590 · 110484: ≤ 78916, 78917–110484.
### risk.ts'ten alınan kural (özet)
- `src/lib/risk.ts:27-37` `riskHesapla(efektifSira, adaySira)`: `efektifSira > Math.round(adaySira*1.4)` → `guvenli` (satır 34); `efektifSira >= adaySira` → `az-riskli` (35); aksi → `riskli` (36). Etiketler `RISK_ETIKET` (9-13): Güvenli / Az riskli / Riskli. Veri yoksa `null`.
- Efektif taban = `COALESCE(sira2025, sira2024)` (`risk.ts:23`, `src/lib/db.ts:35`). Yani etiket TEK yılın tabanına bakar; yazıda böyle anlatıldı ("filmi sen okursun").
- Dilim aralıkları `src/lib/db.ts:57-65` `dilimAraligi`: hayal `[1, sira-1]`, dengeli `[sira, round(1.4×sira)]`, garanti `[round(1.4×sira)+1, ∞)` — açık uçlu, çarpan penceresi yok. `dilimdenRisk` (`risk.ts:40-44`): garanti→güvenli, dengeli→az-riskli, hayal→riskli.
- Ürün olasılık üretmiyor; yazıda olasılık/vaat yok.
- Yazıya ALINMAYAN gerçek kural: rapordaki trend cümlesi (`src/lib/ai/rapor.ts:139-162`) eldeki ilk ve son yılı kıyaslar, ±%10 eşiği. Bu kurala göre Ege Tıp (4218→5118, +%21) "kolaylaşıyor" çıkar; oysa 2022–2025 dört yıl 5.118–5.303 bandında düz. Okuru yanıltmamak için yazıda trend nitel anlatıldı (mevcut `taban-siralamalar-nasil-degisir` ile aynı kalıplar). **Ürün notu:** ilk-son yıl kıyası tek bir aykırı başlangıç yılına duyarlı; ayrıca değerlendirilebilir.
### Yayın öncesi kontrol edilecekler (Bilal)
- [ ] `tarih`: görev talimatı gereği `2026-09-21` yazıldı; CEO notu (§2 ortak kurallar) `2026-09-22` diyor → yayın gününe göre düzelt.
- [ ] Şemayı sayfada gözle kontrol et (mermaid burada render edilemedi: node'da DOM yok, `mermaid.parse` DOMPurify hatası verdi; sözdizimi mevcut yazılardaki desenle birebir, `rehber.ts` regex'i şemayı + aria + altyazıyı buldu, `marked` 3 tablo/6 H2 üretti).
- [ ] Geniş tablo (8 kolon) mobilde taşabilir — CEO P1 kabul kriteri 5 (`overflow-x-auto`) yayına girmeden bu yazı mobilde yatay kaydırma yaratabilir.
- [ ] S1–S3 sorgularını çalıştırıp tablo rakamlarını teyit et; 2026 verisi yüklenince üç tablo + "2026 verisi yüklendiğinde güncellenecek" cümlesi güncellenmeli.
- [ ] "Kaynaklar"da katalog veri tarihi `9 Ağustos 2026` = `src/lib/seo.tsx:24` `KATALOG_VERI_TARIHI`; sabit değişirse metin de değişmeli. YÖK Atlas sitesine bu gece girilmedi (rakamlar DB'den), bu yüzden "erişim tarihi" yazılmadı.
- [ ] Bölüm linkleri slug kuralından türetildi (`src/lib/slug.ts` `bolumSayfaSlug`): `/bolum/tip`, `/hukuk`, `/psikoloji`, `/bilgisayar-muhendisligi`, `/sinif-ogretmenligi`, `/hemsirelik`, `/makine-muhendisligi`; ilk dördü ve hemşirelik mevcut yazılarda zaten kullanılıyor. `/bolumler`, `/meraklisina`, `/tercih-robotu` rotaları `src/app` altında doğrulandı (`/tercih-robotu` mevcut yazılardaki gibi 301'e güveniyor).
- [ ] `/meraklisina` metninde "1,4" sayısı açıkça geçmiyor (yalnızca `meraklisina-demo.tsx:141` hesaplıyor ve aralığı gösteriyor); yazı bu yüzden "sayfada şemasıyla görebilirsin" diyor, "orada 1,4 yazıyor" demiyor.
### Karar bekleyen / yapılmayanlar
- CEO §2.3 bu yazara 3 eski yazıda (`kac-siralama…`, `taban-siralamalar…`, `taban-puan-mi…`) yeni yazıya link + `guncelleme` satırı ekleme işi veriyor; orkestratör talimatı "yalnızca kendi dosyana dokun" dediği için YAPILMADI. Yeni yazı şu an hiçbir yazıdan link almıyor (yetim) — ayrı bir adımda eklenmeli.
- `mezuna-kalmak-mi-kayit-olmak-mi` yazısına link verilmedi (dosya yazım anında worktree'de yoktu; ölü link riski). Yayınlanırsa "Deneme sıralamanı…" bölümüne eklenebilir.
- **Mevcut yazıda tutarsızlık (dokunulmadı):** `taban-siralamalar-nasil-degisir.md` son cümlesi robotun programları "çok yıllı veriyle dilimleyerek" gösterdiğini söylüyor; kodda dilim yalnızca `COALESCE(sira2025, sira2024)`'e bakıyor (`db.ts:35`, `risk.ts:23`). P3'teki vaat dili temizliğiyle aynı sınıf; düzeltilmesi önerilir.
---
## Blog: ek-yerlestirme-sonuclari-ve-kayit
Yazar: SEO/GEO içerik ajanı · Worktree: `.claude/worktrees/rehber-yazilari` (dal `gece/rehber-yazilari`) · Commit atılmadı.
Dosyalar: `content/rehber/ek-yerlestirme-sonuclari-ve-kayit.md` (yeni, ~1.050 kelime, 1 `flowchart TD` şema, 1 tablo, 5 SSS, "Kaynaklar" bölümü) · `content/rehber/ek-yerlestirme-2026.md` (güncellendi).
### Özet (5 madde)
1. Yazıdaki her kural cümlesi bu gece açılıp okunan resmî belgeye dayanıyor (ÖSYM 2 duyuru + Ek Yerleştirme Kılavuzu PDF + Kontenjan Kılavuzu PDF + ÖSYM SSS PDF + KYGM duyurusu). Haber sitesi kullanılmadı.
2. **Sonuç tarihi, kayıt tarihi, e-kayıt tarihi ve ek yurt başvuru tarihi açıklanmamış** → yazıda dört yerde de "açıklanmadı" yazıyor; tahmin yok, geçen yılın tarihi de yok.
3. Boş kontenjan rakamı yazılmadı. 2027'ye dair tarih yazılmadı.
4. Parser simülasyonu (node + marked, `rehber.ts` regex'leriyle) geçti: frontmatter 3 alan temiz, 1 şema + `%% aria` + `%% altyazi`, 1 tablo, 6 iç link. `pnpm build` KOŞULMADI (içerik yazarı; worktree'de başka yazarlar çalışıyor).
5. `mezuna-kalmak-mi-kayit-olmak-mi` yazısına link VERİLMEDİ — dosya yazım anında worktree'de yoktu, `dynamicParams=false` yüzünden ölü link 404 olurdu. Yazı gelirse "Yerleşemediysen önünde ne var?" bölümüne eklenmeli.
### Doğrulanan bilgiler + kaynak
| Bilgi | Kaynak (21.09.2026'da açıldı) |
|---|---|
| Tercih 17 Eylül 16.00 – 21 Eylül 23.59; ais.osym.gov.tr; duyuruda sonuç/kayıt tarihi YOK | https://www.osym.gov.tr/2026-yks-ek-yerlestirme-icin-tercih-islemleri · https://www.osym.gov.tr/2026-yks-ek-yerlestirme-tercihlerin-alinmasi |
| Ücret 170,00 TL; son ödeme 22 Eylül 2026 23.59; ödemeyenin tercihi geçersiz | Ek Yerleştirme Kılavuzu §1 (PDF s.3): https://dokuman.osym.gov.tr/web/2026/9/2026-yuksekogretim-programlarina-ek-yerlestirme-kilavuzu-f2ttjv-17130413.pdf (16 Eylül tarihli `...bwch9h-16154905.pdf` sürümüyle ilk 9 sayfa diff'lendi: birebir aynı) |
| En fazla 24 tercih; merkezî yerleştirmede yerleştirilen tercih yapamaz; özel yetenekle yerleşen yapabilir; en küçük puana eşit/büyük şartı; dolmayan programı puanı hesaplanan herkes yazabilir | aynı kılavuz §1.1–1.2 |
| Sonuç `https://sonuc.osym.gov.tr`; sonuç belgesi basılmaz/gönderilmez | aynı kılavuz §3 |
| Kayıt tarihleri sonuç duyurusunda ve sonuç belgesinde; süresinde başvurmayan kayıt hakkını kaybeder | aynı kılavuz §4 |
| Kayıt hakkı kazanılan program sonradan değiştirilemez | aynı kılavuz §2-c |
| Ek yerleştirmeyle yerleşenin de sonraki yıl OBP katsayısı yarıya iner | aynı kılavuz Tablo 3/4 açıklamaları 4-c + Kontenjan Kılavuzu §1.3 ("Ek Yerleştirme ve ÖZYES dâhil") |
| OBP katsayısı 0,12; "yerleştirilen (kayıt olsun veya olmasın)" yarıya | ÖSYM 2026-YKS SSS, soru 50–52: https://dokuman.osym.gov.tr/pdfdokuman/2026/YKS/sss_yksd19022026.pdf |
| e-kayıt: tüm devlet + isteyen vakıf/KKTC; "Ek yerleştirme için de elektronik kayıt yapılabilecektir"; isteğe bağlı; turkiye.gov.tr → YÖK bölümü; MEB teyidi varsa diploma istenmez, yoksa e-kayıt yapılamaz; sağlık raporu isteyen/özel yetenek programları hariç; barkodlu çıktı; ders kaydına üniversitenin duyurduğu tarihte | Kontenjan Kılavuzu §4 YÖK açıklaması m.1–13 (PDF s.11): https://dokuman.osym.gov.tr/web/2026/8/2026-yuksekogretim-programlari-ve-kontenjanlari-kilavuzu-90wzzd-04155310.pdf (sayfa: https://www.osym.gov.tr/2026-yuksekogretim-kurumlari-sinavi-yks-yuksekogretim-programlari-ve-kontenjanlari-kilavuzu) |
| Şahsen kayıt belgeleri (diploma aslı/onaylı örnek ya da yeni tarihli mezuniyet belgesi; istenirse 12 adet 4,5×6 fotoğraf; katkı payı/ücret belgesi; üniversitenin ilan ettikleri); bizzat başvuru, posta yok, fotokopi kabul edilmez, eksik belgeyle kayıt yok; aynı anda iki örgün lisans/önlisans olmaz | Kontenjan Kılavuzu §4.1–4.2 |
| "Kesin kayıt sonunda kontenjan açığı kalan programlara ön kayıtla öğrenci alınmayacaktır" | Kontenjan Kılavuzu §3.4 |
| İlk yerleştirme: sonuç 18 Ağustos 2026; kayıt 24–28 Ağustos; e-kayıt 24–26 Ağustos | https://www.osym.gov.tr/2026-yks-yerlestirme-sonuclari-aciklandi |
| KYK: ilk yerleşenler 25–29 Ağustos e-Devlet; "Ek kontenjan öğrencileri… yurt başvuruları ilerleyen tarihlerde yükseköğrenim kayıtları tamamlanmasına müteakip alınacaktır" (tarih yok; duyuru 19.08.2026) | https://kygm.gsb.gov.tr/Duyuru/302551/2026-2027-egitim-ogretim-yili-yurt-basvurularina-iliskin-duyuru.aspx |
| "Diploma notu 80 → 48 puan yerine 24" | deterministik: 80×5×0,12 ve ×0,06 (SSS soru 49–50 formülü) |
### Çıkarılan / yazılmayan iddialar
- **Sonuç tarihi tahmini ve "kayıt süresi birkaç gündür"** (SEO planındaki GEO cümlesi): resmî dayanak yok → yazılmadı. 2025 emsali (ÖSYM: sonuç 6 Ekim 2025, kayıt 10–17 Ekim, e-kayıt 10–12 Ekim — https://www.osym.gov.tr/2025yks-ek-yerlestirme-sonuclari-aciklandi) doğrulandı ama CEO'nun "tahmin yazma" kuralına dolaylı tahmin olarak takılacağı için yazıya KONMADI. Bilal isterse "geçen yıl şöyleydi, bu yıl için tahmin değildir" notuyla eklenebilir.
- **Ek yerleşenin yatay geçiş / Ek Madde-1 hakkı** (plan tablosundaki satır): YÖK mevzuatı bu gece açılmadı → satır tablodan çıkarıldı.
- **Yerleşemeyen için "açıköğretim / ikinci üniversite / DGS dışı yollar"** (plan şemasındaki dal): doğrulanmadı → şemada genel "yolları değerlendir" + `yerlesemedim-ne-yapmaliyim` linki.
- **"KYK ek yurt başvurusu Ekim ortası"** beklentisi: yazılmadı; yalnızca KYGM'nin "kayıtlar tamamlanınca, ilerleyen tarihlerde" cümlesi var.
- **Boş kontenjan rakamı**: yazılmadı (CEO kararı).
- **"Ek yerleştirmeden sonra üçüncü şans yok"** (eski yazıdaki cümle): bu biçimiyle kılavuzda yok → eski yazıdan çıkarıldı, yerine kılavuzdaki iki kural (program değiştirilemez + OBP) kondu.
- Sonuç ekranına giriş bilgisi (T.C. no + aday şifresi) ek yerleştirme için 2026 belgesinde açıkça geçmediğinden yazılmadı.
### `ek-yerlestirme-2026.md` içinde değişenler
1. Frontmatter'a `guncelleme: 2026-09-21` eklendi (CEO §2 kararı; mevcut parser fazla anahtarı yok sayıyor — `rehber.ts:125-134`. Orkestratör "yalnızca mevcut alanlar" dediği için YENİ yazıya eklenmedi; istenmezse bu tek satır silinsin).
2. "Ek yerleştirme ne zaman?" → "ne zaman yapıldı?": gerçekleşen tarihler (17–21 Eylül, 170 TL, ücret son 22 Eylül 23.59) + evergreen işleyiş paragrafı + yeni yazıya belirgin iç link ("Tercihini yaptıysan…").
3. "Kimler başvurabilir?" listesine kılavuzdan özel yetenek maddesi eklendi.
4. Taban bölümü: "bu şart esner" muğlak ifadesi kılavuzun net kuralıyla değiştirildi ("en küçük puan"; dolmayan programı puanı hesaplanan herkes yazabilir).
5. Strateji: "hazırlığını şimdi yap" → "önceden yap" (eskiyen ifade); "dengeli-garanti" → "dengeli ve güvenli (halk arasında "garanti") tercih" (CEO dil kuralı); "üçüncü şans yok" cümlesi → doğrulanmış kural + OBP yazısına link.
6. Şemaya ve boş kontenjan bölümüne dokunulmadı.
### Yayın öncesi Bilal'in kontrol etmesi gerekenler
- [ ] **Önce osym.gov.tr duyurularına bak:** sonuç tarihi açıklandıysa ilk paragraf, "ne zaman açıklanacak?" bölümü, tablo (4 hücre) ve SSS-1 güncellenmeli. Yazı "tarih açıklanınca güncelleyeceğiz" diye söz veriyor.
- [ ] "Kaynaklar"daki 7 linki aç; özellikle Kontenjan Kılavuzu PDF s.11 (e-kayıt m.1) ve §1.3 (OBP, ek yerleştirme dâhil) cümlelerini gözle teyit et.
- [ ] `tarih`: orkestratör talimatıyla `2026-09-21` yazıldı; CEO notu `2026-09-22` diyor → yayın gününe göre düzelt (eski yazıdaki `guncelleme` dahil).
- [ ] Ücret maddesi 22 Eylül 23.59'dan sonra yayımlanacaksa geçmiş zamana çevrilebilir (şu an zamandan bağımsız: "son ödeme zamanı …").
- [ ] **Başka yazarın dosyasında tutarsızlık (dokunulmadı):** `universite-kayit-rehberi-2026.md` belgeler listesi "vesikalık genelde 4-6 adet" ve "kimlik fotokopisi" diyor; Kontenjan Kılavuzu §4.1 "talep edilirse 12 adet 4,5×6 fotoğraf" diyor ve fotokopi kabul edilmediğini yazıyor. Yeni yazı kılavuzu izliyor; eski yazı hizalanmalı.
- [ ] `ek-yerlestirme-2026.md` "Boş kontenjanlar nereden çıkar?" bölümündeki "ağırlıklı olarak vakıf… devlet üniversitelerinden şaşırtıcı fırsatlar" cümleleri bu gece doğrulanmadı (eski metin, kapsam dışı bırakıldı).
- [ ] Mezuna-kalmak yazısı yayımlanırsa yeni yazıdan ona link ekle; `yerlesemedim-ne-yapmaliyim` ve `universite-kayit-rehberi-2026` yazılarından da yeni yazıya link verilmesi önerilir (o dosyalar başka yazarın).
### Engeller
- Makinede `pdftotext/pdftoppm` yok; PDF'ler WebFetch'in kendiliğinden kaydettiği kopyalardan `pypdf` ile salt-okunur metne çevrildi (repo dışı, oturum scratchpad'i). Tarayıcıyla dosya indirilmedi.
---
## Blog: mezuna-kalmak-mi-kayit-olmak-mi
Yazar: SEO/GEO içerik yazarı (gece vardiyası) · Dosya: `.claude/worktrees/rehber-yazilari/content/rehber/mezuna-kalmak-mi-kayit-olmak-mi.md` (dal `gece/rehber-yazilari`, commit atılmadı, yalnızca bu dosya yazıldı).
### Özet (5 madde)
1. Yazı hazır: ~1.100 kelime (şema ve Kaynaklar hariç), 1 `flowchart TD` karar ağacı (`%% aria` + `%% altyazi`), 1 karşılaştırma tablosu (seçenek | kazanç | bedel | kime uygun, 4 satır), 5 soruluk SSS, Kaynaklar bölümü, 8 iç rehber linki + `/bolumler` + `/tercih-robotu`. Frontmatter ve mermaid çiti `src/lib/rehber.ts` ayrıştırıcısıyla aynı regex'lerle node'da doğrulandı; tüm `/rehber/*` link hedefleri worktree'de mevcut.
2. Yazının omurgası olan OBP kuralı **üç ayrı ÖSYM belgesinden kelimesi kelimesine teyit edildi** ("kayıt olsun veya olmasın", "Ek Yerleştirme ve ÖZYES dâhil", "2027-YKS'ye girdikleri takdirde").
3. Ek Madde-1 hem mevzuat.gov.tr'deki yönetmelik metninden hem YÖK'ün güncel (PDF üst verisi: 20.05.2026) uygulama ilkelerinden teyit edildi; 28.02.2026 tarihli yönetmelik değişikliğinin Ek Madde 1'e dokunmadığı Resmî Gazete metninden kontrol edildi.
4. **"Kontenjansız açıköğretim istisnası" 2026 kılavuzlarının hiçbirinde bulunamadı → yazıya alınmadı.** Bu cümle mevcut `obp-nedir-nasil-hesaplanir.md:34`'te duruyor; Bilal kontrol etmeli (aşağıda).
5. Askerlik/tecil, "psikolojik yük", sıra farkı eşiği, 2027 tarihi, harç/ücret rakamı yazılmadı. "Garanti/kesin/yerleşirsin/olasılık" dili yok; dilim adı ilk geçişte "güvenli (halk arasında "garanti tercih")".
### Doğrulanan bilgiler ve kaynakları (hepsi 21.09.2026 gecesi açılıp okundu)
| Yazıdaki iddia | Kaynak | Not |
|---|---|---|
| 2026-YKS ile merkezî yerleşen (ek yerleştirme ve ÖZYES dâhil) ya da özel yetenekle kayıt olan aday 2027-YKS'ye girerse OBP katsayıları yarıya düşer | 2026-YKS Yükseköğretim Programları ve Kontenjanları Kılavuzu §1.3 (s. 1) — https://dokuman.osym.gov.tr/web/2026/8/2026-yuksekogretim-programlari-ve-kontenjanlari-kilavuzu-90wzzd-04155310.pdf (sayfa: https://www.osym.gov.tr/2026-yuksekogretim-kurumlari-sinavi-yks-yuksekogretim-programlari-ve-kontenjanlari-kilavuzu) | PDF metni pypdf ile çıkarılıp okundu |
| "kayıt olsun veya olmasın" — kayıt yaptıran (soru 51) ve yaptırmayan (soru 52) için aynı cevap; OBP = diploma notu × 5; katsayı 0,12 | ÖSYM 2026-YKS SSS, soru 49–52 — https://dokuman.osym.gov.tr/pdfdokuman/2026/YKS/sss_yksd19022026.pdf | Doğrudan osym alan adından |
| Aynı kural + 0,12 katsayısı; kayıtlı olmak YKS tercih/yerleştirmesine engel değil; aynı anda iki örgün lisans/ön lisans olmaz, yeni kayıt için ilişik kesmek gerekir | 2026-YKS Kılavuzu §4.2 (s. 32–33) ve §10 (s. 45) — sayfa: https://www.osym.gov.tr/2026yuksekogretim-kurumlari-sinavi-yks-kilavuzu | **Dikkat:** ÖSYM'deki asıl PDF (`basvuru_kilavuz06022026.pdf`) 10 MB sınırını aştığı için açılamadı; metin aynı kılavuzun MEB alan adındaki kopyasından okundu: https://stuttgartegitim.meb.gov.tr/meb_iys_dosyalar/2026_02/699ed94726fa9432366760_YKS_s%C4%B1nav_k%C4%B1lavuzu.pdf (YÖK Genel Kurul 05/02/2026 ibareli). §4.2 cümlesi SSS 51–52 ile birebir aynı |
| Yerleştirilen aday ek yerleştirmede tercih yapamaz; "devam etmeyi düşünmediğiniz programı yazmayınız" uyarısı; süresinde kayıt olmayan kayıt hakkını kaybeder | 2026-YKS Ek Yerleştirme Kılavuzu §1.2 ve tercih uyarıları — https://dokuman.osym.gov.tr/web/2026/9/2026-yuksekogretim-programlarina-ek-yerlestirme-kilavuzu-f2ttjv-17130413.pdf | |
| Ana yerleştirme kayıtları 24–28 Ağustos 2026 | Kontenjan Kılavuzu §4 | |
| Ek Madde 1: kayıt olunan yıldaki puan ≥ hedef programın taban puanı; hazırlık dâhil; kontenjan fazlasında puan sırası | Yönetmelik Ek Madde 1 — https://www.mevzuat.gov.tr/anasayfa/MevzuatFihristDetayIframe?MevzuatTur=7&MevzuatNo=13948&MevzuatTertip=5 (yazıda YÖK'ün verdiği eşdeğer link: `mevzuat?MevzuatNo=13948&MevzuatTur=7&MevzuatTertip=5`) | WebFetch sertifika hatası verdi; sayfa curl ile (sertifika doğrulaması açık) alınıp okundu |
| Kayıt yaptırmış olma şartı; hedefin "girdiği yıldaki" tabanı; puan türü; bir defa; kayıt yılının güzünde başvuru yok, bahar üniversite kararına bağlı; %30 / en fazla 90 kontenjan; başarı şartı yok | YÖK "Güz ve Bahar Dönemi Ek Madde 1 Uygulama İlkeleri" A.1–2, 5–8, 11, 20 ve B girişi, B.6 — https://egitim.yok.gov.tr/tr/document/2853 (bağlayan sayfa: https://egitim.yok.gov.tr/tr/page/492) | |
| 28.02.2026 değişikliği Ek Madde 1'i değiştirmedi | Resmî Gazete 33182 — https://www.resmigazete.gov.tr/eskiler/2026/02/20260228-3.htm | Yazıda anılmıyor; yalnızca güncellik kontrolü |
| Kayıt dondurma üniversite yönetmeliğine bağlı (örnek: son başvuru günü, dondurulan yarıyılda ders yok, süre öğrenimden sayılmaz) | Karabük Üni. yönetmeliği md. 27 — https://www.mevzuat.gov.tr/anasayfa/MevzuatFihristDetayIframe?MevzuatTur=8&MevzuatNo=38896&MevzuatTertip=5 | Yazıda açıkça "örnek" diye etiketli; genelleme yapılmadı |
| 70 → 21, 85 → 25,5, 95 → 28,5 puan kayıp; aralık 15–30 | Deterministik: not × 5 × 0,06 (formül SSS 49–50) | |
**Çıkarım olan tek cümle:** "Kaydı sonradan sildirmek ya da dondurmak da bedeli silmez." Kılavuzda bu kelimelerle yazmıyor; kuralın yerleştirmeye bağlı olmasından ve "kayıt olsun veya olmasın" ifadesinden çıkarıldı. Bilal uygun görmezse o madde + 2. SSS sorusu birlikte silinebilir, yazı bozulmaz.
### Çıkarılan / yazılmayan iddialar
- **Kontenjansız açıköğretim istisnası** (plan ve CEO doğrulama listesi ii): kontenjan kılavuzunun 775 sayfasının tamamında, YKS kılavuzunda ve SSS'de "yarıya / kontenjan sınırlaması / açıköğretim + OBP" taraması yapıldı, böyle bir hüküm çıkmadı → yazılmadı.
- **"Kırık OBP kaç yıl sürer / bir yıl ara verince düzelir"**: kılavuz yalnızca bir önceki yılın yerleştirmesini sayıyor; yazıda yalnızca bu gözlem var ("sonraki yıllar için o yılın kılavuzu belirleyici"). "Bir yıl sonra tam OBP'ye döner" cümlesi kurulmadı.
- Ek Madde-1 güz başvuru tarihleri (YÖK ilkesinde 1–15 Ağustos yazıyor): CEO'nun "2027'ye dair tarih yok" kuralı gereği yazıya alınmadı; "takvimi üniversite duyurur" denildi.
- Kayıt dondurulmuşken Ek Madde-1'e başvurulup başvurulamayacağı; "YKS'ye hazırlık" gerekçesinin dondurma için kabul edilip edilmediği: kaynak yok → yazılmadı.
- Askerlik/tecil (kontenjan kılavuzunda geçiyor ama CEO yasağı), öğrencilik hakları/KYK, harç ve ücret rakamları, "psikolojik yük", "X bin sıra farkı" eşiği, plan taslağındaki "fark küçük/büyük" şema dalı: yazılmadı. Yerine eşiksiz bir soru listesi ve `/bolumler` + `hedef-siralama-nasil-belirlenir` linki kondu.
### Yayın öncesi Bilal'in kontrol etmesi gerekenler
1. **Kaynaklar bölümündeki linkleri aç, üç kural cümlesini gözle teyit et:** Kontenjan Kılavuzu §1.3; SSS soru 51–52; YÖK Ek Madde 1 ilkeleri A.5–A.8 ve B.6. Özellikle 2026-YKS Kılavuzu'nun **ÖSYM'deki asıl PDF'inde** §4.2 ve §10'u kontrol et (ben MEB kopyasından okudum).
2. **Mevcut yazıdaki teyitsiz cümle:** `obp-nedir-nasil-hesaplanir.md:34` "(kontenjansız açıköğretim programları bu kuralın dışındadır)" — 2026 kılavuzlarında karşılığını bulamadım. Kaynağı yoksa silinmeli. Ben dokunmadım.
3. **Mevcut yazıyla ince fark:** `yerlesemedim-ne-yapmaliyim.md` Yol 2 "başvuru, yerleştiğin yıl içinde değil…" diyor; YÖK ilkesi yalnızca kayıt yılının **güz** dönemini kapatıyor, **bahar** başvurusu üniversite öğrenci alıyorsa mümkün. Yeni yazı YÖK metnine göre yazıldı; çelişki değil ama eski cümle netleştirilebilir.
4. **CEO kararıyla fark (bilerek):** CEO §2.2 bu yazara `yerlesemedim-ne-yapmaliyim.md` ve `obp-nedir-nasil-hesaplanir.md`'ye yeni yazıya link + `guncelleme` satırı ekleme işini de vermişti; orkestratör görev tanımı "yalnızca kendi dosyana dokun" dediği için **yapılmadı**. İstenirse iki satırlık iş. Ayrıca CEO `tarih: 2026-09-22` diyor; görev tanımı ve diğer iki yeni yazı `2026-09-21` kullandığı için 21 yazıldı — yayın gününe göre düzelt.
5. Yazı kardeş iki yeni yazıya link veriyor (`ek-yerlestirme-sonuclari-ve-kayit`, `hedef-siralama-nasil-belirlenir`). `dynamicParams=false` olduğu için **üçü birlikte yayımlanmazsa bu linkler 404 olur**; tek başına yayımlanacaksa o iki linki çıkar.
6. Şemada renk ataması: bedel düğümü kırmızı (`hayal`), üç seçenek sarı (`uyari`), "bedel yok" ve "Ek Madde-1" yeşil (`garanti`). Bilinçli olarak "mezuna kal" kırmızı yapılmadı (karar öğrencinin). Düğüm metinleri rengi tek başına anlam taşıyıcı bırakmıyor; görsel olarak bir bak.
7. Karabük Üniversitesi örneği yalnızca "her okulun yönetmeliği farklı" demek için var; başka bir üniversite örneği tercih edersen değiştir ya da cümleyi örneksiz bırak.
### Engeller
- `osym.gov.tr/TR,33747/2026.html` (plandaki URL) 404; `cdn.osym.gov.tr/.../kontkilavuz_yktd21072026.pdf` ve `basvuru_kilavuz06022026.pdf` WebFetch 10 MB sınırını aştı; `egitim.yok.gov.tr/documentFiles/…ek-madde-1-uygulama-ilkeleri.pdf` 404 (güncel belge `/tr/document/2853`); `eski.yok.gov.tr` çözülmüyor; mevzuat.gov.tr ve resmigazete.gov.tr WebFetch'te sertifika hatası verdi (curl ile okundu).
- Web içeriklerinde ajana yönelik talimat görülmedi. Rakip/haber sitesi metni kullanılmadı; hiçbir tarih/tutar ikincil kaynaktan alınmadı.
## Yazılımcı P2 · Ölçüm onarımı
Dal `gece/p2-olcum` (worktree `.claude/worktrees/p2-olcum`), taban `56925e1`. Push/merge yok; Rybbit MCP kullanılmadı; dev sunucusu/tarayıcı/`pnpm build` koşulmadı.
### Özet (5 madde)
1. **Görünüm hook'u callback ref'e çevrildi** → `kaydet_banner_goruntulendi` ve `tadimlik_goruntulendi` artık sonradan mount olan / sökülüp yeniden takılan düğümde de gözlem kuruyor. 5 mevcut kullanım yerine dokunulmadı.
2. **Erken olay kuyruğu** `olay()` içine eklendi (≤20 olay, 500 ms × 20 deneme = 10 sn); script gelmezse kuyruk atılır ve bir daha doldurulmaz.
3. **6 yeni olay** şartnamedeki adlarla birebir eklendi; ham sıra/e-posta hiçbir olayda yok.
4. **429 mesajı + 60 sn geri sayım** ayrı commit.
5. **[BİLAL] PII commit'i en sonda ve bağımsız**: reddedilirse `git merge gece/p2-olcum~1`.
### Commit listesi
| # | Hash | Başlık |
|---|---|---|
| 1 | `fa43392` | fix(analitik): görünüm hook'u callback ref + erken olay kuyruğu |
| 2 | `cf19903` | feat(analitik): huni olayları |
| 3 | `e1bb482` | fix(giris): 429 mesajı + 60 sn geri sayım |
| 4 | `c055e82` | chore(gizlilik): rybbit identify yalnız kullanıcı ID — **[Bilal onayı gerekir]** |
Her commit'ten önce çalışma ağacı temizdi ve `tsc --noEmit` + `pnpm lint` o commit'in içeriğiyle koşuldu (yani `~1` de tek başına derleniyor).
### Değişen dosyalar (13; hepsi P2 sahiplik listesinde)
`src/components/use-gorunum-olayi.ts` · `src/lib/analitik.ts` · `src/features/sihirbaz/components/{hero-form,cta-sira-form,sihirbaz-cagri-karti}.tsx` · `src/features/liste/components/tercih-profili-kapisi.tsx` · `src/features/kullanici/components/{giris-form,user-nav}.tsx` · `src/features/rapor/components/{liste-uretici,listem-govde}.tsx` · `src/app/paket/layout.tsx` **(yeni)** · `src/features/odeme/components/paket-gorunum-olayi.tsx` **(yeni)** · `src/components/rybbit-identify.tsx`. `kaydet-banner.tsx` ve `tadimlik-satiri.tsx` değişmedi (beklendiği gibi).
### Olay tablosu
| Olay | Nerede atılıyor | Özellikler |
|---|---|---|
| `cta_form_goruntulendi` (yeni) | `cta-sira-form.tsx` — yalnız profilsiz daldaki `<section>`, viewport'a ilk girişte (hook), oturum başına 1 | yok (sayfa = Rybbit pathname) |
| `sira_form_hata` (yeni) | `hero-form.tsx`, `cta-sira-form.tsx`, `tercih-profili-kapisi.tsx` — facet isteğinin `catch` dalı; geçersiz sayı doğrulaması sayılmaz | `kaynak`: `hero` \| `cta` \| `kapi` \| `duzenle` |
| `sonuc_goruntulendi` (yeni) | `sihirbaz-cagri-karti.tsx` `SihirbazBolumu` mount effect'i, `olayBirKez` (ek: `girisli`/`anonim`) | `girisli`: `evet`\|`hayir`, `sira_kovasi` |
| `paket_goruntulendi` (yeni) | `paket-gorunum-olayi.tsx` (yeni `src/app/paket/layout.tsx` üzerinden), `olayBirKez` (ek: kaynak) | `kaynak`: `kilit` \| `kredi_bitti` \| `nav` \| `diger` |
| `liste_uretim_hata` (yeni) | `liste-uretici.tsx` — `else` dalı ve `catch`; AUTH/KREDI/PAKET atmaz | `kod`: `HATA` \| `ISTISNA` |
| `giris_hata` (yeni) | `giris-form.tsx` — magic link ve Google hata dalları | `yontem`: `eposta`\|`google`, `status` (HTTP; yoksa 0) |
| `kaydet_banner_goruntulendi` (onarıldı) | `kaydet-banner.tsx` (değişmedi; hook düzeldi) | yok |
| `tadimlik_goruntulendi` (onarıldı) | `tadimlik-satiri.tsx` (değişmedi; hook düzeldi) | `kova` |
`/paket` linklerine eklenen kaynaklar: `listem-govde.tsx` iki kilit CTA'sı → `?kaynak=kilit`; `liste-uretici.tsx` kredi-yetersiz → `?kaynak=kredi_bitti`; `user-nav.tsx` kredi pill'i → `?kaynak=nav`.
### Kabul kriterleri
| Kriter | Sonuç | Kanıt |
|---|---|---|
| typegen + tsc + lint temiz | geçti | `pnpm exec next typegen` exit 0; `pnpm exec tsc --noEmit` exit 0 (4 commit'in her birinde); `pnpm lint` çıktısız |
| `grep -rn "useGorunumOlayi" src` → mevcut 5 + `cta-sira-form` | geçti | çağrılar: `tadimlik-satiri:100`, `listem-govde:139,144`, `sihirbaz-cagri-karti:248`, `kaydet-banner:43`, `cta-sira-form:80` (+ `analitik.ts:125`'te yalnız yorum) |
| `grep -rnE "olay(BirKez)?\(" src \| grep -iE "email\|eposta:\|sira:"` → boş | geçti | grep exit 1 (eşleşme yok); sıra yalnız `siraKovasi()` ile |
| Olay adları listeyle birebir | geçti | `analitik.ts` `OlayAdi`: `cta_form_goruntulendi`, `sira_form_hata`, `sonuc_goruntulendi`, `paket_goruntulendi`, `liste_uretim_hata`, `giris_hata` |
| Hook `null→düğüm` geçişinde gözlem kuruyor, sökülünce `disconnect` | geçti (kod incelemesi) | `use-gorunum-olayi.ts`: `useCallback((el) => {…; io.observe(el); return () => io.disconnect(); }, [ad, anahtarEki])` — gözlem effect'te değil ref bağlanınca kurulur; React 19 ref temizliği sökülmede çalışır |
| [BİLAL] commit ayrı ve en sonda | geçti | `c055e82` HEAD; yalnız `rybbit-identify.tsx` + `user-nav.tsx:47`; `analitik.ts`'e dokunmuyor |
Çalıştırılarak (tarayıcıda) doğrulanan hiçbir şey yok — protokol gereği; yukarıdaki davranış iddiaları kod incelemesine dayanır.
### Şartnameden sapmalar / notlar
- **Küçük ek:** `analitik.ts`'e `export function olayAnahtari(ad, anahtarEki?)` eklendi. Şartname "anahtar mantığının aynısı" diyordu; hook'un ön kontrolü ile `olayBirKez` aynı anahtar biçimini iki yerde elle yazmasın diye tek fonksiyona alındı. Anahtar biçimi değişmedi (`kolaytercih.olay.<ad>[.<ek>]`) → mevcut oturumlardaki tekilleştirme bozulmaz.
- **Kuyruk ayrıntıları (şartnamede açık olmayan yerde en güvenli yorum):** script 10 sn'de gelmezse kuyruk atılır ve `kuyrukKapali` olur — sonraki olaylar eski sessiz no-op'a döner (reklam engelleyicide her olay yeni 10 sn'lik zamanlayıcı başlatmasın). Script daha geç gelirse sonraki olaylar doğrudan gider (ilk `window.rybbit` kontrolü). Sıra korunur: script geldikten sonra ilk `olay()` çağrısı önce bekleyenleri boşaltır.
- **`cta_form_goruntulendi` ve kayıtlı profil:** SSR/hydration'da profilsiz dal render edilir, profil `useSyncExternalStore` ile aynı görevde senkron yeniden render'la gelir; iki dal aynı `<section>` düğümünü paylaştığından ref düşer → `disconnect`. IntersectionObserver ilk bildirimi asenkron verdiği için profilli ziyaretçinin sayılmaması beklenir — **çalıştırılarak doğrulanmadı**; Rybbit'te bu olayın `sira_girildi{kaynak:cta}`'ya oranı anormal düşükse ilk bakılacak yer.
- **Kapsam dışı bırakılan gözlem:** `kullaniciTanit()` da script yokken sessiz no-op; sert yüklemede (OAuth dönüşü) identify kaçabilir. Şartname kuyruğu yalnız `olay()` için tanımladığından dokunulmadı → backlog adayı.
- `liste_uretim_hata.kod` bugün fiilen yalnız `HATA`/`ISTISNA` alır (alt neden CTO backlog #5).
- Sihirbaz/listeleme davranışı değişmedi → `huni-semasi.tsx` `SEMA` güncellenmedi. Yeni CTA/badge/modal eklenmedi.
### Bilal'in merge sonrası Rybbit'te doğrulaması gerekenler
1. **Olay adları** panelde görünüyor mu: yukarıdaki 6 yeni ad + `kaydet_banner_goruntulendi` ve `tadimlik_goruntulendi` > 0. `tadimlik_goruntulendi` hâlâ 0 ise önce prod `tadimlik_havuzu` (bellek notu: deploy sonrası `pnpm tadimlik`).
2. **Sert yükleme testi:** gizli sekmede `/paket?kaynak=nav`'ı doğrudan aç → `paket_goruntulendi{kaynak:nav}` düşmeli (kuyruk kanıtı). Aynı sekmede yenileyince ikinci kayıt **düşmemeli**.
3. **Banner:** girişsiz, listeye eşik kadar program ekle → `kaydet_banner_goruntulendi` 1 kez.
4. `sonuc_goruntulendi`: anonim gir → 1 kayıt `girisli:hayir`; giriş yapıp /sonuc'a dön → ikinci kayıt `girisli:evet`. Özelliklerde ham sıra **olmamalı**, yalnız `sira_kovasi`.
5. `giris_hata`: 5'ten fazla hızlı magic-link isteği → `status:429` + yeni toast metni; "Yeniden gönder" sayacı 60'tan başlıyor.
6. **[BİLAL] `c055e82` kararı:** alınırsa yeni oturumlarda kullanıcı profilinde `email`/`name` trait'i gelmemeli; **eski kayıtlı trait'ler Rybbit'te durur** — panelden ayrıca silinmeli. Alınmazsa `git merge gece/p2-olcum~1`.
7. Huni tanımı (Rybbit'te Bilal kurar): `cta_form_goruntulendi` / pageview → `sira_girildi` → `sihirbaz_tamamlandi` → `sonuc_goruntulendi` → `giris_denendi` → `liste_olusturuldu` → `paket_goruntulendi` → `odeme_baslatildi`.
---
## Rehber iç link ve düzeltmeler
Editör: SEO/GEO içerik editörü · Worktree `.claude/worktrees/rehber-yazilari`, dal `gece/rehber-yazilari` · Commit `0ec3907` (yalnız `content/rehber/*.md`, 8 dosya; push yok, `pnpm build` koşulmadı — `src/` değişmedi).
### Özet (5 madde)
1. Üç yeni yazı artık yetim değil: her biri 4 yazıdan link alıyor (`ek-yerlestirme-sonuclari…` ← ek-yerlestirme-2026, mezuna, kayıt rehberi, yerlesemedim · `mezuna-kalmak…` ← ek-sonuçları, hedef, obp, yerlesemedim · `hedef-siralama…` ← kac-siralama, mezuna, taban-puan, taban-siralamalar). Yazı başına en fazla 2 yeni link.
2. `universite-kayit-rehberi-2026` belge listesi Kontenjan Kılavuzu §4.1–4.2'ye göre yeniden yazıldı ("4-6 vesikalık" ve "kimlik fotokopisi" kalktı); teyit edilemeyen kalemler "üniversitenin kayıt duyurusu" diye genellendi.
3. `taban-siralamalar-nasil-degisir` son paragrafı ürünün gerçek kuralına çekildi: dilim = tek yılın tabanı (`COALESCE(sira2025, sira2024)`); geçmiş yıllar yalnızca satırda gösterim.
4. `obp-nedir…` "kontenjansız açıköğretim" istisnası 2026 belgelerinin hiçbirinde YOK → cümle çıkarıldı; yerine kılavuzda gerçekten yazan tek istisna (zamanında mezun olamadığı için kayıt yaptıramayanlar) kondu.
5. Ölü link taraması: 27 yazıda 56 farklı iç link, **0 ölü**. 30 `/bolum/<slug>` hedefi `yokatlas.db`'deki (salt-okunur) 635 bölüm slug'ına karşı doğrulandı.
### Dosya bazında değişiklikler
| Dosya | Değişiklik | `guncelleme` |
|---|---|---|
| `universite-kayit-rehberi-2026.md` | e-kayıt paragrafı YÖK açıklamasına hizalandı (tüm devlet + isteyen vakıf/KKTC; isteğe bağlı; MEB teyidi → diploma istenmez; özel yetenek/sağlık raporu programları hariç; e-kayıt yapan ders kaydına duyurulan belgelerle gider). Belge listesi §4.1'e göre: diploma aslı/onaylı örnek ya da yeni tarihli mezuniyet belgesi · istenirse 12 adet 4,5×6 fotoğraf · katkı payı/ücret belgesi · ek puan için alan belgesi · üniversitenin ilan ettiği diğerleri. §4.2 kuralları eklendi (bizzat, posta yok, fotokopi/onaysız suret kabul edilmez, eksik belgeyle kayıt yok; sağlık raporu yalnız koşullarda yazıyorsa). Yeni H2 "Ek yerleştirmeyle yerleştiysen" → `ek-yerlestirme-sonuclari-ve-kayit` linki. `ozel-kosullu-programlar` linki. "Kaynaklar" bölümü eklendi. | eklendi |
| `obp-nedir-nasil-hesaplanir.md` | Açıköğretim parantezi silindi; ek yerleştirme + özel yetenek kapsamı ve mezun olamayan istisnası yazıldı; `mezuna-kalmak…` linki; "Kaynaklar" bölümü. | eklendi |
| `taban-siralamalar-nasil-degisir.md` | Son paragraf: "çok yıllı veriyle dilimleyerek" → "son yılın tabanına göre (2025; yoksa 2024) dilimler, geçmiş yılları satırda gösterir; filmi sen okursun" + `hedef-siralama…` linki. Dilim adı CEO kuralıyla: güvenli (halk arasında "garanti"). | eklendi |
| `yerlesemedim-ne-yapmaliyim.md` | Yol 1 sonuna `ek-yerlestirme-sonuclari…`, Yol 3 girişine `mezuna-kalmak…` linki. | eklendi |
| `kac-siralama-ile-hangi-bolume-girebilirim.md` | "Bu tabloyu nasıl kullanmalısın?" listesine 4. madde: `hedef-siralama…` linki. | eklendi |
| `taban-puan-mi-siralama-mi.md` | Kapanıştan önce tek cümle: `hedef-siralama…` linki. | eklendi |
| `ek-yerlestirme-sonuclari-ve-kayit.md` | "Kayıt yaptırmazsan ne olur?" sonuna `mezuna-kalmak…` linki. | yok (yeni yazı) |
| `hedef-siralama-nasil-belirlenir.md` | Deneme bölümü 3. maddeye OBP yarıya inme hatırlatması + `mezuna-kalmak…` linki (yazarın kendi önerisi). | yok (yeni yazı) |
### Teyitler (hepsi 21.09.2026 gecesi açıldı; PDF metni WebFetch'in kaydettiği kopyadan `pypdf` ile okundu)
| İddia | Kaynak |
|---|---|
| §4.1 belge listesi (a–e), "talep edilmesi durumunda 12 adet 4,5 cm x 6 cm fotoğraf"; §4.2 a–d (bizzat/posta yok, "onaysız sureti veya fotokopisi kabul edilmez", eksik belge, sağlık raporu yalnız koşullarda); kayıt 24–28 Ağustos, e-kayıt 24–26 Ağustos; YÖK e-kayıt açıklaması m.1, 2, 5, 6, 7, 8, 10, 13 | Kontenjan Kılavuzu PDF s.11–13: https://dokuman.osym.gov.tr/web/2026/8/2026-yuksekogretim-programlari-ve-kontenjanlari-kilavuzu-90wzzd-04155310.pdf |
| Ek yerleştirmede kayıt tarihleri sonuç duyurusunda/sonuç belgesinde | Ek Yerleştirme Kılavuzu (ilk 9 sayfa): https://dokuman.osym.gov.tr/web/2026/9/2026-yuksekogretim-programlarina-ek-yerlestirme-kilavuzu-f2ttjv-17130413.pdf |
| OBP yarıya düşme: "(Ek Yerleştirme ve ÖZYES dâhil) veya özel yetenek sınavıyla… kayıt olan" | Kontenjan Kılavuzu §1.3. Kılavuzun **775 sayfasının tamamı** "yarıya / kontenjan sınırlaması / kontenjansız" için tarandı: 4 eşleşme (s.3, 17, 20, 142), hiçbirinde açıköğretim istisnası yok |
| "kayıt olsun veya olmasın"; 0,12 | ÖSYM SSS soru 50–52: https://dokuman.osym.gov.tr/pdfdokuman/2026/YKS/sss_yksd19022026.pdf (12 sayfa tarandı; açıköğretim yalnız lise bağlamında geçiyor) |
| Tek istisna: lise son sınıfken yerleşip zamanında mezun olamadığı için kayıt yaptıramayanların katsayısı düşmez | 2026-YKS Kılavuzu §4.2 (PDF s.38/147). **Dikkat:** ÖSYM'deki asıl PDF (`basvuru_kilavuz06022026.pdf`, sayfa https://www.osym.gov.tr/2026yuksekogretim-kurumlari-sinavi-yks-kilavuzu açıldı, link doğrulandı) 10 MB sınırı yüzünden okunamadı; metin ÖSYM e-imza ibareli MEB kopyasından okundu (mezuna yazarının kullandığı aynı URL). Bilal asıl PDF'te §4.2'ye bir göz atsın |
| Ürün kuralı | `src/lib/risk.ts:22-37` (`riskHesapla`, eşik `Math.round(adaySira*1.4)`), `src/lib/db.ts:35` (`EFEKTIF_SIRA = COALESCE(sira2025, sira2024)`), `db.ts:57-65` (`dilimAraligi`). Çok yıllı veri yalnız gösterim/trend: `src/components/program-liste-verileri.tsx:36-40`, `src/lib/ai/rapor.ts:139-162` |
### Teyit edilemeyen / genellenen / dokunulmayan
- Kayıt rehberinden **çıkarılan** kalemler: "ÖSYS sonuç belgesi çıktısı", "kimlik + fotokopisi", "vesikalık 4-6 adet", "ikinci öğretim/vakıf ilk taksit dekontu". Kılavuz listesinde yoklar; üniversiteler isteyebilir → "üniversitenin ilan ettiği diğer belgeler, kayıt duyurusuna bak" diye genellendi (kimlik ve sonuç belgesi yalnızca *örnek* olarak anılıyor, zorunlu denmiyor).
- e-Devlet hizmet adı *"Üniversite E-Kayıt"* eski metinden kaldı; kılavuz yalnızca "turkiye.gov.tr → Yükseköğretim Kurulu Başkanlığı bölümü" diyor. Hizmet adı bu gece doğrulanmadı.
- Aynı yazıdaki şema + başlık "belge yok, sıra yok, 5 dakika" diyor; e-kayıt anı için doğru ama ders kaydında belge istenebildiği artık gövdede yazıyor. Şemaya dokunulmadı (Bilal isterse "5 dakika" ifadesi yumuşatılabilir — kaynağı yok).
- `yerlesemedim-ne-yapmaliyim.md` Yol 2'deki "başvuru, yerleştiğin yıl içinde değil…" cümlesi (mezuna yazarının notu: YÖK ilkesi yalnız güz dönemini kapatıyor) — YÖK belgesi bu gece benim tarafımdan açılmadı, görev kapsamında değildi → **dokunulmadı**.
- `taban-siralamalar…` şeması ve gövdesi "dört yıl / son 4 yıl" diyor; DB ve yeni `hedef-siralama` yazısı 5 yıl (2021–2025). Okuma tavsiyesi olduğu için yanlış değil ama P3'teki "4→5 yıl" temizliğiyle birlikte şema + aria + gövde tek seferde hizalanmalı (şemaya bu gece dokunulmadı).
- `ek-yerlestirme-2026.md` "Boş kontenjanlar nereden çıkar?" bölümündeki doğrulanmamış cümleler (önceki yazarın notu) hâlâ duruyor.
- `guncelleme` tarihi görev talimatı gereği `2026-09-21`; CEO notu `2026-09-22` diyor → yayın gününe göre 7 dosyada topluca düzeltilebilir (`grep -l "^guncelleme:" content/rehber/*.md`).
### Ölü link taraması (yöntem)
`](/…)` kalıbındaki tüm iç linkler çıkarıldı: `/rehber/<slug>` → `content/rehber/<slug>.md` var mı; diğerleri → `src/app/<segment>` var mı. Kullanılan segmentler: `rehber`, `bolum`, `bolumler`, `meraklisina`, `tercih-robotu` (`next.config.ts:77` kalıcı redirect → `/#hero-form`). `/bolum/*` için slug, `src/lib/slug.ts` `bolumSayfaSlug` kuralı Python'da yeniden üretilip `programs.isim` değerlerinden türetilen kümeyle karşılaştırıldı: 30/30 mevcut. Web içeriklerinde ajana yönelik talimat görülmedi.
---
## Yazılımcı P1 · Rehber altyapısı
Worktree `.claude/worktrees/p1-rehber-altyapi` · dal `gece/p1-rehber-altyapi` (taban `56925e1`) · push/merge yok.
**Özet (5 madde)**
1. Şartnamedeki 6 değişikliğin tamamı 3 commit'te uygulandı; yalnız P1'e atanmış 6 dosyaya dokunuldu, `content/` ve `huni-semasi.tsx` değişmedi.
2. Şema metni artık sunucu HTML'inde: rehber makalelerinde ve `/meraklisina`'da `<details>` "Şemayı metin olarak oku" + `ariaLabel` metni build çıktısında grep ile doğrulandı (baseline 0 → 1).
3. `"Üst sıraya…"` ile başlayan iki açıklamanın baştaki tırnağı geri geldi (`content="&quot;…`).
4. `guncelleme` alanı uçtan uca akıyor (sitemap lastmod, `/rehber` dizini lastmod, JSON-LD `dateModified`, `article:modified_time`, görünür satır) — geçici bir frontmatter eklemesiyle build'de görüldü, commit'lenmeden geri alındı.
5. typegen + tsc + lint temiz; `pnpm build` 3 kez koştu (HEAD, geçici `guncelleme` testi, tekrar temiz HEAD), üçü de exit 0. Env'siz koştu — yalnız better-auth "default secret" uyarısı basıyor, build'i kırmıyor.
**Commit'ler**
| Hash | Başlık |
|---|---|
| `a9ea0bf` | fix(rehber): frontmatter tırnak + tablo sarmalayıcı |
| `d9e125c` | feat(rehber): guncelleme alanı → sitemap/JSON-LD/OG/görünür tarih |
| `1a75f42` | fix(rehber): şema metni SSR'da + mermaid hata toparlama |
**Değişen dosyalar** (`git diff --stat main..HEAD`: 6 dosya, +179 / −41)
- `src/lib/rehber.ts` — `tirnakSoy()`, `markdownHtml()` (tablo sarmalayıcı), `RehberOzet.guncelleme?`, `metaDogrula` tarih biçimi + `guncelleme >= tarih` denetimi, `oku()`/`ozetOku()` (cache kırpma dalı dahil) alanı taşıyor; "10 makale" yorumu düzeltildi.
- `src/lib/tarih.ts` **(yeni)** — `trTarih()`; `Date`/`toLocale*` yok, biçim uymazsa `throw`.
- `src/lib/seo.tsx` — yalnız `articleJsonLd`: `dateModified?`, çıktıda `dateModified ?? datePublished`.
- `src/features/rehber/components/rehber-makale.tsx` — OG `modifiedTime`, JSON-LD `dateModified`, "Yayın: … · Güncelleme: …" düz metin satırı, `[&_.rehber-tablo]:mt-4 [&_.rehber-tablo]:overflow-x-auto`.
- `src/app/sitemap.ts` — yazı `lastModified: guncelleme ?? tarih`; `/rehber` girdisi fonksiyon içine alındı, lastmod = en büyük tarih.
- `src/features/rehber/components/el-cizimi-sema.tsx` — `hata` state, `.catch` (geçici `#d<id>` div temizliği), `suppressErrorRendering: true`, hata dalında iskelet yok, `<details open={hata || undefined}>`.
**Kabul kriterleri** (hepsi temiz HEAD build'inde, `.next/server/app/…`)
| # | Kriter | Sonuç | Kanıt |
|---|---|---|---|
| 1 | `grep -c "Şemayı metin olarak oku" rehber/tercih-listesi-nasil-yapilir.html` ≥ 1 | geçti | 1 |
| 2 | aynı dosyada `"Tercih listesi dilim şeması"` ≥ 1 | geçti | 1 |
| 3 | `meraklisina.html`'de `"Sihirbaz akış şeması"` ≥ 1 | geçti | 1 |
| 4 | description `&quot;` ile başlar (2 dosya) | geçti | `content="&quot;Üst sıraya yazarsam şans` · `content="&quot;Geçen yıl 90 bin kapatmı` |
| 5 | `rehber-tablo` sarmalayıcı | geçti | tablolu 2 yazıda `<div class="rehber-tablo" role="region" aria-label="Tablo" tabindex="0"><table>` sayısı = `<table>` sayısı = `</table></div>` sayısı (`kac-siralama…`: 2/2/2, `siralama-sartlari-2026`: 1/1/1). Not: kriterde adı geçen iki yazıda tablo yok; sınıf adı orada yalnız Tailwind seçici metninde geçer, bu yüzden tablolu yazılarda ölçüldü. |
| 6 | `Yayın:` + `<time dateTime="2026-` | geçti | `Yayın: <time dateTime="2026-07-26">26 Temmuz 2026</time>` |
| 7 | sitemap `/rehber` `<lastmod>` | geçti | `<lastmod>2026-08-07</lastmod>` (= en yeni `tarih`) |
| 8 | geçici `guncelleme: 2026-09-22` testi | geçti | `"datePublished":"2026-07-26","dateModified":"2026-09-22"` · `article:modified_time content="2026-09-22"` · `· Güncelleme: <time dateTime="2026-09-22">22 Eylül 2026</time>` · sitemap'te hem yazı hem `/rehber` lastmod `2026-09-22`. Sonra `git checkout -- content/…`, `git status` temiz, tekrar build → `Güncelleme:` 0, `dateModified` 2026-07-26. |
| 9 | kod incelemesi: `.catch` var, hata dalında iskelet yok, `details` açık | geçti | `el-cizimi-sema.tsx`: `svg ? … : hata ? null : <iskelet>`; `open={hata \|\| undefined}` |
**tsc / lint / build:** `next typegen` ✓ · `tsc --noEmit` 0 hata (her commit öncesi) · `pnpm lint` temiz · `pnpm build` exit 0 ×3. Tek Turbopack uyarısı baseline'da da olan `Cal Sans` font fallback uyarısı. Build `data/` altını kirletmedi (`git status` temiz). `.next/` şu an temiz HEAD build'i.
**Şartnameden sapmalar / yorumlar**
- Kriter 4'te CTO "aynısı (`&quot;Üst sıraya`)" demiş; `taban-siralamalar…` açıklaması `"Geçen yıl…` diye başlıyor. Kastedilen baştaki tırnağın korunması — o geçti.
- `metaDogrula` assert tipine `guncelleme?: string` eklendi (yoksa tsc `oku()`'da alanı görmüyor). Boş `guncelleme:` satırı da biçim hatası sayılır (build kırar).
- `/rehber` sitemap girdisi artık `staticEntries`'ten hemen sonra geliyor (sıra değişmedi sayılır; yalnız `/paket`… satırlarının arkasına kaydı). Hiç yazı yoksa `lastModified` `undefined` kalır.
- Hata anında mermaid'in geçici div'i için `document.getElementById("d" + semaId)` kullanıldı (mermaid 11.16 `mermaid.core.mjs:1248` ile doğrulandı).
**Bilal merge öncesi elle baksın**
1. Rehber makalesi + `/meraklisina`: figcaption altındaki "Şemayı metin olarak oku" satırının görünümü/konumu (kapalı `<details>`, küçük gri metin). Ekran okuyucuda metin iki kez okunabilir (CEO kabul etti).
2. Mobilde tablolu bir yazı (`/rehber/kac-siralama-ile-hangi-bolume-girebilirim`): tablo sayfayı taşırmadan kendi içinde yatay kayıyor mu; `tabindex="0"` odak halkası kabul edilebilir mi.
3. Başlık altındaki "Yayın: 26 Temmuz 2026" satırının aralığı (`mt-3 text-xs`).
4. Hata yolu gerçek tarayıcıda denenmedi (dev/tarayıcı yasak): DevTools'ta `mermaid` chunk isteğini bloklayıp iskeletin kalktığını ve metnin açık geldiğini bir kez görmek yeter.
5. Yazar dalı merge edilirken: yeni `.md` dosyalarında `tarih`/`guncelleme` `YYYY-AA-GG` değilse build artık kırılır (istenen davranış); P1 yazar dalından **önce** merge edilirse `guncelleme` alanı sessizce yok sayılmaz.
---
## Yazılımcı P3 · Vaat dili
Worktree `.claude/worktrees/p3-vaat-dili` · dal `gece/p3-vaat-dili` · taban `56925e1` · push/merge yok, build koşulmadı (CTO itirazı #8), script/DB yazımı yok.
### Özet (5 madde)
1. **4 commit, şartnamedeki bölünmeyle:** 1 + 1b [KARAR], 2 ve 3 [BİLAL]. Yalnız P3'e atanmış 12 dosyaya dokunuldu (`seo.tsx`'e dokunulmadı; sabit yeni `src/lib/veri-kapsami.ts`'te).
2. **Olasılık dili bitti:** "yerleşme olasılığı" iki yerde "yerleşme riski ve trend analizi" oldu; risk notunun dört cümlesi tek saf fonksiyona (`riskNotuMetni`, `src/lib/risk.ts:52`) alındı, rapor ve tadımlık aynı kaynaktan okuyor. Eşikler, 5/13/6, LLM çıktı şemaları değişmedi.
3. **Tadımlık artık rozetle çelişemez:** `tadimlikSec()` DB'deki LLM cümlesini servis etmiyor; notu okuma anında adayın gerçek sırasından üretiyor. Prod'da `pnpm tadimlik` yeniden koşusu **gerekmiyor**.
4. **"4 yıl" → `VERI_YIL_SAYISI` (5):** ana sayfada 5, `/paket`'te 1 yer sabitten okuyor; prompt/mock'ta düz "5".
5. **İki [BİLAL] commit'i gerçekten bağımsız:** `main`'den geçici dalda tek tek, birlikte ve "commit 2 olmadan" senaryosunda cherry-pick edildi → çakışma yok, tsc 0 hata. **Fiyat rakamını ajanlar doğrulamadı — Bilal Armut sayfasını açmadan commit 2'yi almasın.**
### Commit listesi
| # | SHA | Mesaj | Dosyalar |
|---|---|---|---|
| 1 | `16c4508` | `fix(metin): olasılık dili + 5 yıl` | `src/lib/veri-kapsami.ts` (Y) · `src/lib/risk.ts` · `src/lib/ai/rapor.ts` · `src/app/page.tsx` · `src/features/odeme/components/paket-satinal.tsx` · `src/components/arama-funnel-karti.tsx` |
| 1b | `cae2aaa` | `fix(ai): tadımlık risk notu deterministik + prompt dili` | `src/lib/tadimlik-havuzu.ts` · `scripts/tadimlik-uret.ts` · `src/app/api/soru/route.ts` |
| 2 | `52520ac` | `chore(metin): danışman fiyat kıyası [Bilal onayı gerekir]` | `src/app/page.tsx` · `src/app/paket/page.tsx` · `src/app/layout.tsx` |
| 3 | `9d450c5` | `chore(guven): hero'da YÖK logosu yerine tarihli veri satırı [Bilal onayı gerekir]` | `src/app/page.tsx` · `src/features/katalog/components/veri-kaynagi.tsx` |
Bilal reddederse: commit 3 en üstte → `git merge gece/p3-vaat-dili~1` (3'süz) / `~2` (2 ve 3'süz). Yalnız 2 reddedilirse: `~2`'yi merge + `git cherry-pick 9d450c5` (D senaryosu, test edildi).
### Metin değişiklikleri — önce → sonra (satır numaraları dal HEAD'inde)
**Commit 1**
| Yer | Önce | Sonra |
|---|---|---|
| `src/app/page.tsx:180` | Her tercih için yerleşme olasılığı ve risk analizi (son 4 yıl) | Her tercih için yerleşme riski ve trend analizi (son 5 yıl) |
| `src/features/odeme/components/paket-satinal.tsx:32` | Her tercih için yerleşme olasılığı ve risk analizi (son 4 yıl trend) | Her tercih için yerleşme riski ve trend analizi (son 5 yıl) |
| `src/app/page.tsx:108` | Son 4 yılın YÖK Atlas verisi — … | Son 5 yılın YÖK Atlas verisi — … (gerisi aynı) |
| `src/app/page.tsx:122` (SSS + FAQ JSON-LD) | …son 4 yılın taban başarı sıralamaları… | …son 5 yılın taban başarı sıralamaları… |
| `src/app/page.tsx:148` | Son 4 yılın trend analizi | Son 5 yılın trend analizi |
| `src/app/page.tsx:355` | 4 yıl | 5 yıl |
| `src/lib/risk.ts:55` (eski `rapor.ts:166`) güvenli | Taban sıralaması senin sıranın belirgin altında; yüksek ihtimalle yerleşirsin. | Son taban sıralaması senin sıranın belirgin altında; geçmiş veriye göre güvenli aralıkta. |
| `src/lib/risk.ts:57` az-riskli | Taban sıralaması sırana yakın; orta ihtimalle yerleşilebilir. | Son taban sıralaması sırana yakın; küçük bir kayma sonucu değiştirebilir. |
| `src/lib/risk.ts:59` riskli | Taban sıralaması senin sıranın üstünde kapandı; yerleşme ihtimali düşük. | Son taban sıralaması senin sıranın üstünde kapandı; hayal tercihi olarak düşün. |
| `src/lib/risk.ts:61` veri yok | Güncel taban sıralaması verisi yok; ihtimal öngörülemez, temkinli yaklaş. | Güncel taban verisi yok; bu satırı temkinli değerlendir. |
| `src/components/arama-funnel-karti.tsx:38` | Yerleşme ihtimalini görerek seç. | Yerleşme riskini görerek seç. |
`rapor.ts:168-170` `riskNotuUret` gövdesi tek satır: `return riskNotuMetni(riskHesapla(p.sira2025 ?? p.sira2024, adaySira));` (+ import satırı). Metinlerde sayı `VERI_YIL_SAYISI`'ndan template literal ile geliyor.
**Commit 1b**
| Yer | Önce | Sonra |
|---|---|---|
| `src/lib/tadimlik-havuzu.ts:89` | `riskNotu: satir.riskNotu` (DB'deki LLM cümlesi) | `riskNotuMetni(riskHesapla(program.efektifSira, sira) ?? dilimdenRisk(satir.dilim))` — `tadimlik-satiri.tsx:107` rozetiyle aynı formül |
| `scripts/tadimlik-uret.ts:70-72` (prompt) | riskNotu: yerleşme ihtimali değerlendirmesi … "yüksek/orta/düşük ihtimal" dili kullan. | riskNotu: geçmiş taban verisine dayalı risk değerlendirmesi (TEK kısa cümle). ASLA garanti/kesin/yüzde/olasılık/ihtimal deme; "güvenli / az riskli / riskli" etiketleriyle konuş. |
| `scripts/tadimlik-uret.ts:73` (prompt) | trendOzeti: son 4 yılın… | trendOzeti: son 5 yılın… |
| `scripts/tadimlik-uret.ts:86` (mock) | (Dev mock) Taban sıralaması senin civarında; orta-yüksek ihtimalle yerleşilebilir. | (Dev mock) Son taban sıralaması sırana yakın; küçük bir kayma sonucu değiştirebilir. |
| `scripts/tadimlik-uret.ts:88` (mock) | (Dev mock) Son 4 yılda… | (Dev mock) Son 5 yılda… |
| `src/app/api/soru/route.ts:48-49` | ASLA yerleşme garantisi verme; "yüksek/orta/düşük ihtimal" dili kullan. | ASLA yerleşme garantisi verme; olasılık, yüzde ya da "ihtimal" dili kullanma — güvenli / az riskli / riskli etiketleri ve taban sıralarıyla konuş. |
Prompt'larda yalnız talimat cümlesi değişti; `TadimlikSchema` (gerekce/riskNotu/trendOzeti) ve sohbetin akışı/ayrıştırması aynı.
**Commit 2 [BİLAL]**
| Yer | Önce | Sonra |
|---|---|---|
| `src/app/page.tsx:92` | İyi bir tercih danışmanı 2.000–10.000 TL istiyor. | …1.000–5.000 TL istiyor. |
| `src/app/page.tsx:168` (kıyas tablosu) | 2.000–10.000 TL | 1.000–5.000 TL |
| `src/app/page.tsx:474` | İnsan danışmanın 2.000–10.000 TL aldığı işi… | İnsan danışmanın 1.000–5.000 TL aldığı işi… |
| `src/app/page.tsx:478-480` (yeni) | — | `<p className="text-xs text-slate-500">Danışman fiyat aralığı: Armut, 2026.</p>` (düz metin, sabit yok) |
| `src/app/page.tsx` eski 225-229 | yorum içinde ölü `<p>` ("…onda bir fiyatına yapar.") | blok silindi |
| `src/app/paket/page.tsx:49` | onda bir fiyatına | çok daha düşük fiyata |
| `src/app/paket/page.tsx:52` | …bu dönemde 2.000–10.000 TL alıyor. | …bu dönemde 1.000–5.000 TL alıyor. |
| `src/app/layout.tsx:55` (`description`) | İnsan danışmanın onda bir fiyatına, yapay zekâ destekli… | İnsan danışmandan çok daha düşük fiyata, yapay zekâ destekli… |
**Commit 3 [BİLAL]**
| Yer | Önce | Sonra |
|---|---|---|
| `src/app/page.tsx:231-241` | `<Image src="/yok-logo.svg" alt="Yükseköğretim Kurulu">` + dikey ayraç + "**YÖK Atlas'ın gerçek verileriyle** güvenilir sonuçlar" | "**Veri: YÖK Atlas** · son güncelleme `<time dateTime="2026-08-09">9 Ağustos 2026</time>`" — kutu sınıfları aynen |
| `src/app/page.tsx:15` / `:57,61` | `import Image from "next/image"` | silindi / `KATALOG_VERI_TARIHI` seo import'una + `KATALOG_TARIH_METNI` import'u eklendi |
| `src/features/katalog/components/veri-kaynagi.tsx:6` | `const TARIH_METNI` | `export const KATALOG_TARIH_METNI` (dosya içi kullanım güncellendi) |
`public/yok-logo.svg` duruyor. Yeni badge/pill yok; CTA butonlarına dokunulmadı; `huni-semasi.tsx` `SEMA` değişmedi (davranış değişmedi, CTO teyidi).
### Kabul kriterleri
| Kriter | Sonuç | Kanıt |
|---|---|---|
| typegen + tsc + lint (dal HEAD `9d450c5`) | **Geçti** | `next typegen` ✓ · `tsc --noEmit` exit 0, çıktı yok · `pnpm lint` exit 0. Ayrıca commit 1, 1b, 2, 3 sonrasında ayrı ayrı tsc+lint temiz |
| `grep -rniE "olasılı\|ihtimal" src scripts/tadimlik-uret.ts` → yalnız izinli kalıntılar | **Geçti (3 ek yorum satırıyla)** | Beklenenler: `page.tsx:78` ("binlerce ihtimal"; şartnamede :76, import eklenince kaydı), `page.tsx:132`, `program-tablosu.tsx:176`, yasaklayıcı prompt'lar `soru/route.ts:48`, `tadimlik-uret.ts:71`. **Ek:** `risk.ts:48-49` ve `tadimlik-havuzu.ts:88` — benim yazdığım, kuralı açıklayan kod yorumları (kullanıcıya görünmez, yasaklayıcı) |
| `grep -rn "4 yıl" src/app/page.tsx src/features/odeme` → boş | **Geçti** | exit 1, çıktı yok |
| `grep -rn "onda bir\|2\.000–10\.000" src` → boş | **Geçti** | exit 1, çıktı yok |
| Bağımsızlık (cherry-pick) testi | **Geçti** | Geçici dal `gece/p3-tmp-test` @ `56925e1`: **A** yalnız commit 2 → çakışmasız, tsc 0 · **B** yalnız commit 3 → çakışmasız, tsc 0 · **C** 2+3 (commit 1'siz) → tsc 0 · **D** 1+1b+3 (commit 2'siz) → çakışmasız, tsc 0. Geçici dal silindi, worktree temiz |
| Ana sayfada kamu logosu yok, tarih görünür HTML'de | **Geçti (kod incelemesi)** | `grep "yok-logo\|next/image" src/app/page.tsx` boş; `<time dateTime>` sunucu bileşeninde |
### Repo geneli tarama — kalan ifadeler ve gerekçe
- `src/features/sihirbaz/components/cta-sira-form.tsx:143,164,189,209` "Sıralamanla nereye **yerleşirsin**? Saniyede gör." — dosya P2'nin; CTO bunu Garanti→Güvenli (H2) backlog'una bağladı. **En görünür kalan vaat cümlesi bu; H2 kararıyla birlikte ele alınmalı.**
- `src/app/page.tsx:132` SSS "boşta kalma ihtimalini en aza indiririz" — şartnamede açıkça kapsam dışı (SSS). Not: yerleşme olasılığı değil ama yine bir sonuç vaadi; H2 paketinde gözden geçirilmeli.
- `src/app/page.tsx:78` "24 tercih, binlerce ihtimal" — kombinasyon anlamı, vaat değil.
- `src/features/pazarlama/components/meraklisina-icerik.tsx:64` "şansını" — `/meraklisina`, kapsam dışı (H6).
- `src/features/pazarlama/components/hero-baslik.tsx:24` "Dört yıllık geleceğini", `bolum-listesi.tsx:95` "4 Yıllık" — öğrenim süresi, veri kapsamı değil.
- `content/rehber/*.md` "son 3-4 yılın tabanına bak", "yerleşme ihtimaline göre dizme" — yazar dalının; genel tercih tavsiyesi, ürün vaadi değil. `taban-siralamalar…md:12` "dört yılın tabanı = film" ürünün "5 yıl"ıyla birebir örtüşmüyor ama ürün iddiası değil (SEO ajanına not).
- "Son 5 yıl" tablo başlıkları (`rapor-listesi.tsx:368`, `program-tablosu.tsx:242`, `bolum-program-listesi.tsx:160`, `universite-program-tablosu.tsx:51`) zaten 5; sabitten **okumuyorlar** (dosyalar P3'ün değil) → veri yılı eklenince elle güncellenecek 4 yer; backlog adayı.
- `src/app/api/soru/route.ts:46` aynı prompt'ta "Riskli = **geçen yıl** adayın sıralamasının üzerinde kapandı" — efektif sıra 2024'e düşebildiği için teknik olarak gevşek; şartname yalnız 48. satırı verdi, dokunulmadı.
- DB'deki kayıtlı raporlarda ve `tadimlik_havuzu.risk_notu` kolonunda eski cümleler duruyor: raporlar göçsüz kalır (CEO kabulü); tadımlık kolonu artık servis edilmiyor.
### Sapmalar / şartname notları
1. **`rapor.ts`'te import satırı da değişti** ("başka hiçbir şeye dokunma"ya rağmen): `riskNotuMetni` import'u olmadan gövde derlenmez. Başka değişiklik yok.
2. **`scripts/tadimlik-uret.ts` "5"i düz yazıyor**, sabitten okumuyor — şartname metni öyle ("son 5 yılın"); prompt'a import sokmamak için harfiyen uygulandı. Veri yılı eklenince güncellenecek yerler: `veri-kapsami.ts` + bu script (2 satır) + yukarıdaki 4 tablo başlığı.
3. **`layout.tsx:55`**: şartname yalnız "onda bir fiyatına → çok daha düşük fiyata" diyordu; cümle "İnsan danışman**ın** çok daha düşük fiyata" diye bozulacağı için "İnsan danışman**dan** çok daha düşük fiyata" yapıldı.
4. **Kabul grep'inde 3 fazladan satır** — kendi açıklayıcı kod yorumlarım (yukarıda). Temiz grep istenirse yorumlar yeniden yazılabilir; davranışa etkisi yok.
5. **Satır kayması:** şartnamedeki `page.tsx:76` artık `:78` (commit 1 ve 3'ün import satırları).
6. `pnpm build` koşulmadı (talimat). `KATALOG_TARIH_METNI` modül seviyesinde `new Date(<sabit string>)` kullanıyor — zaten katalog sayfalarında prerender edilen mevcut kod; ana sayfaya ilk kez giriyor, Tur 4 build'inde `cacheComponents` uyarısı çıkarsa ilk bakılacak yer (beklenmiyor: argümanlı `Date`). CTO backlog #6 (P1'in `trTarih`'ine geçiş) bunu tümden kapatır.
7. Görsel kontrol Bilal'de: hero kutusu logosuz daha dar; fiyat bölümünde kaynak satırı `gap-4` sütununun son öğesi.
## Yazılımcı P4 · Giriş e-postası
Dal `gece/p4-eposta` (worktree `.claude/worktrees/p4-eposta`), taban `56925e1`. Push/merge yok; dev sunucusu/tarayıcı/`pnpm build` koşulmadı. **Gerçek e-posta gönderilmedi**: Resend'e ulaşan hiçbir kod yolu çalıştırılmadı, canlıya istek atılmadı, `.env*` dosyaları okunmadı. Tüm doğrulama betikleri scratchpad'de, scratch SQLite DB + sahte secret + `RESEND_API_KEY` tanımsız koştu; hiçbiri commit'lenmedi.
### Özet (5 madde)
1. **Prod'da sessiz fallback bitti.** Anahtar yokken konsola yazıp "gönderildi" dönmek artık yalnız dev'de ya da `EPOSTA_KONSOL_FALLBACK=1` ile; prod + anahtarsız → gönderim anında `throw` (better-auth 500 → formda hata toast'ı), token'lı link loga düşmüyor. `EMAIL_FROM` yoksa prod'da `resend.dev`'e düşmek yerine hata. Tüm env okumaları fonksiyon gövdesinde → `next build` etkilenmez.
2. **Reply-To eklendi** (`EMAIL_REPLY_TO`, yoksa `destek@kolaytercih.com`).
3. **Adres başına 60 sn soğuma**, süreç içi `Map` (CTO itirazı #2'ye uygun; `verification` tablosuna dokunulmadı), yalnız `NODE_ENV=production`. Pencere kaymaz, gönderim hatasında kayıt geri verilir. Uçtan uca (better-auth `signInMagicLink` → `sendMagicLink`) çevrimdışı doğrulandı.
4. **`giris_basarili` sunucu olayı** `session.create.after`'da, `await`siz; `yontem: eposta|google|diger`. Stub `fetch` ile doğrulandı: verify sonrası tam 1 olay, gövdede e-posta yok.
5. **Commit 2, 3, 4, 5'in her biri tek başına `git revert` edilebiliyor** (denendi: çakışmasız + tsc temiz). Bunun için commit 3 bilinçli olarak "sarmalayıcı" biçiminde yazıldı (aşağıda sapma #2).
### Commit listesi
| # | Hash | Başlık | Canlı giriş yolunu değiştirir mi |
|---|---|---|---|
| 1 | `aac33e7` | `chore(eposta): şablondan harici font + footer iletişim` | Hayır (yalnız mail içeriği) |
| 2 | `5992cf3` | `fix(eposta): Reply-To + prod'da sessiz fallback yok` | **EVET** — prod'da anahtar/`EMAIL_FROM` eksikse giriş isteği artık 500 döner (eskiden sahte başarı). Env tamamsa tek fark `Reply-To` başlığı. |
| 3 | `2af4a9f` | `feat(giris): adres başına 60 sn soğuma` | **EVET** — aynı adrese 60 sn içinde 2. istek 200 döner ama mail çıkmaz. |
| 4 | `17046c8` | `feat(analitik): giris_basarili sunucu olayı` | Hayır (yan etki; `await` yok, hata fırlatmaz). Oturum oluşturma kancasına eklenir — Google girişinde de tetiklenir. |
| 5 | `ea3ba5f` | `chore(ci): .env.production'a RYBBIT_* ve EMAIL_REPLY_TO [Bilal onayı gerekir]` | Hayır (deploy hattı; yalnız secret ADI referansı, değer yok). Önceki dört commit'e bağımlı değil. |
### Değişen dosyalar (yalnız P4'e atananlar)
`src/lib/eposta.ts` · `src/lib/eposta-gonder.ts` · `src/lib/auth.ts` · `src/lib/analitik-sunucu.ts` · `.gitea/workflows/ci.yaml` — toplam +155/−17. Yeni dosya yok, şema/migration yok, bağımlılık yok.
### Kabul kriterleri
| Kriter | Sonuç | Kanıt |
|---|---|---|
| typegen + tsc + lint | **Geçti** | HEAD `ea3ba5f`: `next typegen` ✓, `tsc --noEmit` exit 0, `pnpm lint` exit 0. Ayrıca commit 1/2/3/4 sonrası ayrı ayrı tsc+lint temiz. |
| `grep -n "fonts.googleapis\|fonts.gstatic" src/lib/eposta.ts` → boş | **Geçti** | Çıktı boş; render edilen iki şablonda `<link` sayısı 0. |
| `grep -n "process.env" src/lib/eposta-gonder.ts` → hepsi fonksiyon gövdesinde | **Geçti** | 7 okuma: `:18` (`kacisBayragi`), `:30-31` (`epostaKonsolModu`), `:45,51,52,62` (`epostaGonder`). Modül seviyesinde okuma/`throw` yok. |
| `grep -n "await sunucuOlayi" src/lib/auth.ts` → boş | **Geçti** | Çıktı boş (`void sunucuOlayi(...)`). |
| Prod + anahtarsız + bayraksız yolda hiçbir `console.log` URL basmıyor | **Geçti** | Kod: iki dosyada 4 `console.*` var — `eposta-gonder.ts:40` ve `auth.ts:98` yalnız `epostaKonsolModu()` dalında; `auth.ts:73` soğuma bilgi satırı (adres/link içermez); `eposta-gonder.ts:73` Resend hata logu (link içermez). Çalışma kanıtı: betikte `console.log/info` yakalanarak bu yolda 0 satır + `RESEND_API_KEY tanımlı değil` hatası görüldü. |
| Footer + düz metin iletişim satırı | **Geçti** | Render: HTML'de `<a href="https://kolaytercih.com"…>kolaytercih.com</a> · <a href="mailto:destek@kolaytercih.com"…>`; iki şablonun `text`'i `—` / `kolaytercih.com · destek@kolaytercih.com` ile bitiyor. |
| Lokal docker testi (bayrakla link konsolda, 60 sn içinde 2. istek link üretmez, bayraksız → hata) | **Bilal'de** (aşağıda adımlar) | Çevrimdışı eşdeğeri geçti: `NODE_ENV=production` + scratch DB ile `auth.api.signInMagicLink` → 1. istek link, 2. istek (büyük harfli aynı adres) `{status:true}` + link yok; bayraksız → hata + link yok; hata sonrası hemen yeniden deneme link üretiyor. |
**Elle doğrulama betikleri (commit'lenmedi, scratchpad):** `p4-guard.mts` 12/12 (konsol modu matrisi: dev/prod × anahtar × bayrak; `EPOSTA_KONSOL_FALLBACK=true` açmaz, yalnız `1`; `EMAIL_FROM=""` de hata), `p4-soguma.mts` 10/10 (22 sn senaryosu, trim+lowercase, 59.999 ms düşer / 60.000 ms geçer, **pencere kaymıyor**, bırak→yeniden dene, 500 kayıt tek çağrıda budanıyor), `p4-e2e.mts` 6/6, `p4-olay.mts` 6/6 (stub fetch: `/api/track`, `pathname:/giris`, `properties:{"yontem":"eposta"}`, e-posta yok, tam 1 olay, verify 19 ms). Projede test altyapısı (vitest/jest) yok → test dosyası eklenmedi.
**better-auth doğrulamaları (kaynaktan, tahmin değil):** `databaseHooks.session.create.after: (session, context: GenericEndpointContext | null) => Promise<void>` (`@better-auth/core/dist/types/init-options.d.mts:1192`); `context` = `getCurrentAuthContext()` (`better-auth/dist/db/with-hooks.mjs:7`), `path: string` better-call `EndpointContext`'te var; uç yolları `/magic-link/verify` (`plugins/magic-link/index.mjs:84`) ve `/callback/:id` (`api/routes/callback.mjs:21`). Resend 6.18.0 `replyTo?: string | string[]` (`resend/dist/index.d.mts:559`).
### Sapmalar / şartname notları
1. **`??` yerine `||`** (`EMAIL_REPLY_TO`, `EMAIL_FROM`): şartname `process.env.EMAIL_REPLY_TO ?? "destek@…"` diyordu. Commit 5'teki CI satırı secret yokken `EMAIL_REPLY_TO=` (boş string) üretir; `??` boş string'i geçirir → Resend'e boş Reply-To gider → doğrulama hatası → **kimse giriş yapamaz**. `||` ile boş değer varsayılana düşer; CTO'nun "secret yoksa zararsız" varsayımı ancak böyle doğru.
2. **Commit 3'te fonksiyon bölündü:** soğuma, eski gövdeyi satır satır değiştirmek yerine onu `girisLinkiniIlet` adıyla olduğu gibi bırakıp üstüne yeni `sendMagicLinkEmail` sarmalayıcısı olarak eklendi (diff: 60 ekleme, 0 silme). İlk denemede gövdeyi taşımıştım; commit 2'nin tek başına revert'i çakışıyordu → "tek tek atılabilir" şartı için yeniden yazıldı. Yan etki: dev'deki `__sonMagicLink` yakalaması artık soğuma kontrolünden sonra — soğuma dev'de kapalı olduğu için davranış aynı.
3. **`girisSogumasiAl` / `girisSogumasiBirak` `auth.ts`'ten export ediliyor** (saf mantığı betikle test edebilmek için; zaman parametresi enjekte edilebilir). Uygulama içinde başka çağıranı yok.
4. **Soğumada düşen istek için bir `console.info` satırı** eklendi ("Soğuma penceresinde tekrar istek — e-posta gönderilmedi."; adres ve link **içermez**). Şartnamede yoktu; Bilal'in docker testinde "2. istek gerçekten yutuldu mu"yu görünür kılıyor. İstenmezse 3 satır silinir.
5. **Footer'da `SITE_URL` değil sabit `kolaytercih.com`** (şartnamedeki gibi): lokal/dev'de üretilen mailde bile iletişim satırı prod alan adını gösterir. İki küçük sabit (`SITE_ALANI`, `DESTEK_EPOSTA`) + `METIN_ALT_BILGI` HTML ve iki düz metin gövdede ortak.
6. `eposta.ts` üst yorumundaki "web fontları `<link>` ile yüklenir" cümlesi yeni duruma göre düzeltildi. `BASLIK_TIPI`/`MARKA_TIPI` font yığınları **bırakıldı** (cihazda kuruluysa çalışır, zararsız).
7. **Bilinen sınırlar (CTO kabulü, değişmedi):** Map yeniden başlatmada sıfırlanır, çoklu kopyada paylaşılmaz; eşzamanlı iki istekte ilki hata verirse ikincisi yutulmuş olur (nadir); soğumada düşen isteğin `verification` satırı 15 dk yetim kalır; Gmail nokta/`+etiket` eşlemesi yok (anahtar yalnız trim+lowercase). Kullanıcı 60 sn içinde sayfayı yenileyip yeniden isterse "gönderildi" görür ama mail çıkmaz — **P2'nin 60 sn geri sayımıyla birlikte merge edilmesi önerilir** (P2 commit 3).
8. `kredi-hatirlatma.ts` (P4'ün değil) aynı `epostaGonder`'ı kullanıyor: prod'da anahtar yoksa artık `throw` → mevcut `try/catch` yakalayıp logluyor, hatırlatma "yanar" (mevcut at-most-once davranışı). Eskiden sessizce konsola yazıp yine yanıyordu → fiilî fark yok.
9. `.gitea/workflows/ci.yaml` YAML'ı `ruby -ryaml` ile ayrıştırılarak doğrulandı (4 yeni satır heredoc içinde, doğru girintide). Gitea runner'da koşturulmadı.
### Bilal'in merge öncesi lokal docker testi (sırayla)
Hazırlık: `gece/p4-eposta` dalını checkout et. Lokal `.env.production`'ın **kopyasını** al ve kopyada `RESEND_API_KEY=` ile `EMAIL_FROM=` satırlarını **boşalt/sil** (gerçek mail çıkmasın); `BETTER_AUTH_URL=http://localhost:3000` yap. `docker-compose.yml` Traefik ağına bağlı olduğu için en kolayı: `docker build -t kt-p4 .` → `docker run --rm -p 3000:3000 --env-file <kopya> -e APP_DB_URL=file:/app/data/app.db [-e EPOSTA_KONSOL_FALLBACK=1] kt-p4`.
1. **Build geçiyor mu** (kritik: prod guard modül seviyesinde değil): `docker build` hatasız bitmeli.
2. **Bayraklı koşu** (`-e EPOSTA_KONSOL_FALLBACK=1`, anahtar boş): gizli pencerede `/giris` → e-posta gir → form yeşil "Bağlantı gönderildi" → `docker logs`'ta `[giris] Magic link for …` + `/giris/dogrula?token=…` linki.
3. **Soğuma:** 60 sn dolmadan aynı adresi (bir de BÜYÜK harfle) yeniden iste (P2 merge edilmediyse "Yeniden gönder" 30. sn'de açılır) → form yine başarı gösterir, logda **yeni link YOK**, yerine `[giris] Soğuma penceresinde tekrar istek — e-posta gönderilmedi.` Farklı bir adres aynı anda link alabilmeli. 60 sn sonra aynı adres yeniden link almalı.
4. **Giriş tamamlanıyor mu:** logdaki linki aç → `/giris/dogrula` onay kartı → buton → oturum açıldı, yeni kullanıcıya deneme kredisi yazıldı. Aynı link ikinci kez → "geçersiz bağlantı" mesajı. Google ile giriş de dene (session kancası orada da çalışıyor).
5. **Bayraksız + anahtarsız koşu** (konteyneri `EPOSTA_KONSOL_FALLBACK` olmadan yeniden başlat): `/giris` → e-posta gir → formda **hata toast'ı** ("Bağlantı gönderilemedi…"), logda `[eposta] RESEND_API_KEY tanımlı değil`, logda **hiçbir `token=` URL'i yok** (`docker logs … | grep -c "token="` → 0). Hemen ardından aynı adresle tekrar dene → yine hata (soğumaya takılıp sahte başarı göstermemeli).
6. **`EMAIL_FROM` guard'ı (isteğe bağlı, mail ÇIKMAZ):** kopyada `RESEND_API_KEY=re_sahte` + `EMAIL_FROM` boş + bayraksız → formda hata, logda `[eposta] EMAIL_FROM tanımlı değil` (Resend'e gitmeden atar).
7. **Gerçek gönderim (tek mail, kendi adresine):** gerçek `.env.production` ile koş → gelen mailde "Show original": `Reply-To: destek@kolaytercih.com`; HTML kaynağında `fonts.googleapis` yok; footer'da site + destek adresi; yanıtla'ya basınca alıcı `destek@…`.
8. **`giris_basarili`:** `RYBBIT_HOST/SITE_ID/API_KEY` kopyada tanımlıysa 4. adımdan sonra Rybbit'te `giris_basarili {yontem: eposta}` (ve Google ile `google`) düşmeli; olayda e-posta adresi olmamalı. Tanımlı değilse no-op (hata yok) — bu da doğrulanmış olur.
9. Merge sonrası canlıda ilk iş: gizli pencereden kendi adresinle bir giriş; 500 görürsen Gitea secret'larında `RESEND_API_KEY`/`EMAIL_FROM` boş demektir → commit 2'yi revert et (`git revert 5992cf3`, çakışmasız — denendi).
### Gereken env / secret adları
| Ad | Zorunlu mu | Not |
|---|---|---|
| `RESEND_API_KEY` | Prod'da **zorunlu** (mevcut secret) | Yoksa artık giriş isteği 500. |
| `EMAIL_FROM` | Prod'da **zorunlu** (mevcut secret) | Yoksa artık 500 (eskiden sessiz `onboarding@resend.dev`). |
| `EMAIL_REPLY_TO` | İsteğe bağlı (**yeni** Gitea secret) | Yok/boş → `destek@kolaytercih.com`. |
| `EPOSTA_KONSOL_FALLBACK` | **Yalnız lokal docker testi**, değer `1` | **Prod'a/Gitea'ya EKLEME** — eklenirse (ve anahtar da yoksa) giriş linkleri prod loguna yazılır. |
| `RYBBIT_HOST`, `RYBBIT_SITE_ID`, `RYBBIT_API_KEY` | `giris_basarili`/`odeme_tamamlandi` için gerekli (**yeni** Gitea secret'ları) | Üçünden biri boşsa no-op. Secret'lar eklenmeden commit 5 merge edilirse zararsız (boş satırlar), ama olaylar yine düşmez. |
Bilal'in kod dışı işleri (04-mail-testi'nden, bu pakette çözülemez): DMARC kaydı + apex SPF (Cloudflare), `destek@kolaytercih.com` kutusunun gerçekten açık olduğunun teyidi (Reply-To artık oraya gidiyor).
---
## Yazılımcı B · K2 tadımlık dili
Worktree `.claude/worktrees/p3b-tadimlik-dili` · dal `gece/p3b-tadimlik-dili` · taban `cae2aaa` · push/merge yok, `pnpm build` koşulmadı, script/DB yazımı yok (DB denemesi `data/app.db`'nin scratchpad'deki `.backup` kopyasına karşı, `sqlite3 -readonly` ile alındı).
### Özet (5 madde)
1. **2 commit, şartnamedeki bölünmeyle:** `79bc7fa` [KARAR] tadımlık dili · `004473a` [BİLAL] rakamsız fiyat, en tepede. Yalnız 6 sahipli dosyaya dokunuldu.
2. **Tadımlıkta servis edilen tek LLM metni artık `gerekce` ve o da filtreli.** `trendOzeti` DB'den okunmuyor; rapordakiyle aynı saf fonksiyondan (`src/lib/trend.ts` `trendOzetiMetni`) `program.siraGecmisi`'nden üretiliyor. Tüm anahtar uzayında (1.170 istek) gerçek `tadimlikSec()` çağrısıyla servis edilen metinlerde olasılık/ihtimal/şans/"son 4 yıl" **0**.
3. **Bedeli:** 514 satırın **26**'sı elendi; tadımlığın gizlendiği istek kombinasyonu 127 → **186** (1.170'te +59, +%5). CEO'nun dar kalıbı uygulansaydı 16 satır / +32 olurdu — fark bilinçli sapma (aşağıda #1), geri alması tek satır.
4. **Trend cümlesinde tahmin yargısı yok:** "bölüm zorlaşıyor" → "taban sıkılaştı", "yerleşmek görece kolaylaşıyor" → "taban gevşedi". Eşik, ilk–son yıl mantığı, 5/13/6, LLM şeması/prompt'u değişmedi. **Ege Tıp tipi yanıltma sürüyor** (4 yıl düz seri hâlâ "çıktı; taban gevşedi" diyor) — CEO backlog'unda, K2 kapsamı dışı.
5. **`9d450c5` (YÖK logosu) bu dalın hem tepesine hem `~1`'ine çakışmasız uygulanıyor** (merge-tree + gerçek cherry-pick + tsc/lint). Fiyat commit'i reddedilirse `git merge gece/p3b-tadimlik-dili~1`.
### Commit listesi
| # | SHA | Mesaj | Dosyalar |
|---|---|---|---|
| 1 [KARAR] | `79bc7fa` | `fix(ai): tadımlık trendi deterministik + gerekçe dil filtresi` | `src/lib/trend.ts` (Y) · `src/lib/tadimlik-havuzu.ts` · `src/lib/ai/rapor.ts` |
| 2 [BİLAL] | `004473a` | `chore(metin): danışman fiyat kıyası rakamsız ve atıfsız [Bilal onayı gerekir]` | `src/app/page.tsx` · `src/app/paket/page.tsx` · `src/app/layout.tsx` |
`rapor.ts` diff'i: `siraKisa` + `trendOzetiUret` gövdesi çıktı, yerine `trendOzetiMetni([p.sira2021…p.sira2025])` çağıran 9 satırlık sarmalayıcı + 1 import. İki çağrı yeri (`:200` mock, `:402` gerçek rapor) ve `AiTercihSchema`/prompt/`dilimHedefiHesapla` **dokunulmadı**. `siraGecmisi` yıl sırası doğrulandı: `scripts/tadimlik-uret.ts:94` ve `rapor.ts programBilgisi` ikisi de `[sira2021…sira2025]`; `raporSiraSerisi` de indeks 0 = 2021 okuyor → `trend.ts`'te çapa `ILK_VERI_YILI = 2021`.
### Metin değişiklikleri — önce → sonra
**Commit 1**
| Yer | Önce | Sonra |
|---|---|---|
| `src/lib/trend.ts:45` (eski `rapor.ts:160`) | …düzeyine indi; bölüm zorlaşıyor. | …düzeyine indi; taban sıkılaştı. |
| `src/lib/trend.ts:48` (eski `rapor.ts:163`) | …düzeyine çıktı; yerleşmek görece kolaylaşıyor. | …düzeyine çıktı; taban gevşedi. |
| stabil / veri yok cümleleri | aynı | aynı |
| `tadimlik-havuzu.ts` `trendOzeti` | `satir.trendOzeti` (DB, LLM: "Son 4 yılda taban sıralaması 13.000'den 6.100'e hızla yükseldi, bölüm popülerleşiyor.") | `trendOzetiMetni(program.siraGecmisi)` ("2021-2025 arasında taban 16B düzeyinden 6B düzeyine indi; taban sıkılaştı.") |
| `tadimlik-havuzu.ts` `gerekce` | koşulsuz servis | `gerekceServisEdilebilir()` geçmezse satır yok sayılır → `genel` → `null` |
| `tadimlik-havuzu.ts` yorum | "…metin ile rozet çelişemez, olasılık dili sızamaz." | riskNotu **ve** trendOzeti'nin servis edilmediğini, gerekce'nin servis edilen tek LLM metni olduğunu ve filtreden geçtiğini söylüyor |
Filtre kalıbı (Türkçe küçük harfe çevrilmiş metinde): `/olasılı|ihtimal|şans|garanti|kesin|yüzde|yerleşirsin|yerleşebil|son (4|dört) yıl/`.
**Commit 2 [BİLAL]**
| Yer | Önce | Sonra |
|---|---|---|
| `src/app/page.tsx:91` | İyi bir tercih danışmanı 2.000–10.000 TL istiyor. | İyi bir tercih danışmanının ücreti birkaç bin lirayı bulabiliyor. |
| `src/app/page.tsx:167` (kıyas tablosu) | 2.000–10.000 TL | Danışmana göre değişir |
| `src/app/page.tsx:483` | İnsan danışmanın 2.000–10.000 TL aldığı işi tek seferlik… | İnsan danışmanın birkaç bin liraya yaptığı işi tek seferlik… |
| `src/app/paket/page.tsx:49` (h1) | onda bir fiyatına | çok daha düşük fiyata |
| `src/app/paket/page.tsx:52` | Tercih danışmanları bu dönemde 2.000–10.000 TL alıyor. | Tercih danışmanlarının ücreti bu dönemde birkaç bin lirayı bulabiliyor. |
| `src/app/layout.tsx:55` (`description`) | İnsan danışmanın onda bir fiyatına, yapay zekâ destekli… | İnsan danışmandan çok daha düşük fiyata, yapay zekâ destekli… |
Kaynak satırı / şirket adı **eklenmedi**; `page.tsx:224-228` yorum içi ölü `<p>` bloğuna dokunulmadı.
### Lokal DB deneme sonuçları
Betikler (commit'lenmedi): `<scratchpad>/k2/dene.ts` (gerçek `tadimlikSec` + `trendOzetiMetni` + `gerekceServisEdilebilir`'i worktree'den import eder; `APP_DB_URL=file:<scratchpad>/k2/app-kopya.db`) ve `<scratchpad>/k2/sim.ts` (filtre varyantı kıyası). Ana `data/app.db` yalnız `sqlite3 -readonly … .backup` ile okundu.
| Ölçüm | Sonuç |
|---|---|
| `tadimlik_havuzu` satır | 514 (genel 174 · devlet 166 · vakıf 174; 13 kategori slug'ı) |
| DB `trend_ozeti`'nde "Son 4 yıl" | **89** satır (büyük-küçük harf duyarsız; 08'deki 126 sayısını üretemedim — denetçi muhtemelen daha geniş kalıp saydı). Artık hiçbiri servis edilmiyor |
| `siraGecmisi` olmayan satır | 0 (18 satırda <2 dolu yıl → "yeterli geçmiş yıl verisi yok" cümlesi) |
| **Filtreye takılan `gerekce`** | **26 / 514** (8'i `genel` kategori, 18'i kategoriye özel). Yalnız CEO kalıbıyla: 16. Ek 10 satır: `şans` 3 ("yerleşme şansınız yüksek/düşük", "kazanma şansın yüksek"), `yerleşebil` 1 ("rahatça yerleşebileceğiniz"), `son 4/dört yıl` 6 |
| Anahtar uzayı (6 kova × 5 tür × 13 kategori+kategorisiz × 3 tip = 1.170 istek), `null` dönen | filtresiz 127 → CEO kalıbı 159 → **uygulanan 186** (filtre yüzünden gizlenen: **59**) |
| Kategorisiz (yalnız `genel`) 90 istekte `null` | 10 → 15 → **18** |
| Kategoriye özel satırı elenip `genel`'e düşen istek | 17 |
| Servis edilen 984 yanıtta (`gerekce`+`riskNotu`+`trendOzeti`) `olasılı\|ihtimal\|son 4 yıl\|son dört yıl\|şans\|yerleşirsin\|garanti\|kesin\|yüzde` | **0** |
| Üretilen trend dağılımı (514 satır) | sıkılaştı 287 · gevşedi 131 · stabil 78 · veri yok 18 |
`null`'a düşen 8 `genel` anahtarı: `10-50k\|ea\|genel`, `0-10k\|say\|devlet`, `10-50k\|say\|vakif`, `10-50k\|tyt\|vakif`, `50-100k\|ea\|vakif`, `100-250k\|ea\|vakif`, `100-250k\|soz\|vakif`, `500k-plus\|say\|devlet` — bunlarda kategoriye özel satırı olmayan her istek tadımlıksız kalır; prod'da `pnpm tadimlik --force` (karar #17) geri getirir.
Üretilen `trendOzeti` örnekleri (gerçek satırlar):
- `[16356,13032,9886,7429,6106]` → "2021-2025 arasında taban 16B düzeyinden 6B düzeyine indi; taban sıkılaştı." (eski DB metni: "Son 4 yılda taban sıralaması 13.000'den 6.100'e hızla yükseldi, bölüm popülerleşiyor.")
- `[2273,1879,2364,2391,5731]` → "2021-2025 arasında taban 2B düzeyinden 6B düzeyine çıktı; taban gevşedi."
- `[16523,13251,12057,12896,15834]` → "2021-2025 arasında taban sıralaması 16B düzeyinde stabil seyretti."
- `[25412,14281,9831,15697,10244]` → "…25B düzeyinden 10B düzeyine indi; taban sıkılaştı." (eski: "son 4 yılda 14K ile 15K arasında dalgalandı" — eski metin rakamca da yanlıştı)
- `[4218,5159,5303,5294,5118]` → "…4B düzeyinden 5B düzeyine çıktı; taban gevşedi." ← **Ege Tıp tipi**: son 4 yıl düz, cümle yine "çıktı" diyor (backlog).
- Kenar: `undefined` / tek dolu yıl → "Karşılaştırma için yeterli geçmiş yıl verisi yok; trendi temkinli oku."; `[null,null,100000,null,95000]` → "2023-2025 arasında … 95B düzeyinde stabil seyretti."; `1.500.000→1.200.000` → "1,5M … 1,2M". Filtre: "İHTİMAL yüksek" ve "OLASILIK" yakalanıyor (düz `/i` İ/ı'yı kaçırırdı).
### Kabul kriterleri
| # | Kriter | Sonuç | Kanıt |
|---|---|---|---|
| 1 | `tadimlikSec()` DB `trendOzeti`'ni servis etmez; aynı saf fonksiyon; yıl sırası doğrulandı; filtre → genel → null; yorum düzeltildi | **Geçti** | `git show 79bc7fa`; `grep -n "satir.trendOzeti" src/lib/tadimlik-havuzu.ts` boş; rapor ve tadımlık ikisi de `trendOzetiMetni` import ediyor |
| 2 | Trend dili; eşik/mantık/şema/prompt aynı | **Geçti** | `trend.ts` gövdesi eski `trendOzetiUret` ile satır satır aynı, yalnız iki cümle sonu farklı; `rapor.ts` diff'inde şema/prompt satırı yok |
| 3 | DB betiği + servis edilen alanlarda 0 | **Geçti** | yukarıdaki tablo (`sizinti: 0`, 984 yanıt) |
| 4 | Commit 2: atıf ve TL aralığı yok, ölü `<p>`'ye dokunulmadı | **Geçti** | `grep -rn "2\.000–10\.000\|Armut\|1\.000–5\.000" src` boş; `grep -rn "onda bir" src` → yalnız `page.tsx:227` (yorum içi ölü blok, şartname gereği bırakıldı; `9d450c5` de silmiyor) |
| 5 | `9d450c5` çakışmasız | **Geçti** | aşağıda |
| — | typegen + tsc + lint | **Geçti** | commit 1 öncesi ve commit 2 öncesi ayrı ayrı: `next typegen` ✓ · `tsc --noEmit` exit 0 · `pnpm lint` exit 0 |
### Cherry-pick testi (`9d450c5`)
- `git merge-tree --write-tree --merge-base=9d450c5~1 HEAD 9d450c5` → exit 0, ağaç `841760c` (çakışma yok) — **tepe (`004473a`) üstüne**.
- Aynı komut `HEAD~1` (`79bc7fa`) için → exit 0, ağaç `2d991c7` — **fiyat commit'i reddedilirse** de temiz.
- Geçici dal `gece/p3b-tmp-test` @ `004473a`: `git cherry-pick 9d450c5` çakışmasız (2 dosya, +11/−13) → `tsc --noEmit` exit 0, `pnpm lint` exit 0, `grep "yok-logo\|next/image" src/app/page.tsx` boş. Dal silindi, worktree temiz, `git branch --list 'gece/p3b*'` yalnız asıl dalı gösteriyor.
### Sapmalar / şartname notları
1. **Filtre kalıbı şartnameden GENİŞ** (en güvenli yorum): CEO `/olasılı|ihtimal|garanti|kesin|yüzde/i` demişti. Eklenenler: `şans`, `yerleşirsin`, `yerleşebil` (orkestratör görevi "yerleşirsin dili"ni de sayıyordu; DB'de "yerleşme şansınız yüksek" birebir olasılık vaadi) ve `son (4|dört) yıl`. Sonuncusu **zorunluydu**: "Son 4 yıl" yalnız `trend_ozeti`'nden değil `gerekce`'den de sızıyor (6 satır; ilk koşuda 19 servis yanıtında yakalandı) — kriter 3'ün "Son 4 yıl = 0" şartı onsuz sağlanmıyordu. Bedel: 16 yerine 26 satır, +32 yerine +59 gizlenen istek. Daraltmak isteyen `YASAK_GEREKCE_DILI`'nden ilgili alternatifi siler.
2. **`/i` bayrağı yerine `toLocaleLowerCase("tr-TR")`:** JS'te düz `/i` "İhtimal"/"OLASILIK"ı eşlemez. Davranış şartnamenin niyetiyle aynı, daha sıkı.
3. **`VERI_YIL_SAYISI` `trend.ts`'te kullanılmadı:** cümle "son N yıl" demiyor, yıl aralığını serideki dolu yıllardan yazıyor ("2022-2025 arasında") — sabitten türetmek yerine gerçek veri. Yıl çapası `ILK_VERI_YILI = 2021` (dizi hep 2021'den başlıyor; yeni yıl sona eklenince değişmez).
4. **`paket/page.tsx:52`** için şartname cümle vermemişti; ana sayfadaki kalıpla eşlendi ("…ücreti bu dönemde birkaç bin lirayı bulabiliyor"). "birkaç bin lira" CEO metni; aralık değil ama yine teyitsiz bir büyüklük iddiası — Bilal tümden rakamsız isterse üç yerde "birkaç bin lira" → "yüksek ücret" tek kelimelik iş.
5. **Kapsam dışında kalan aynı dil (sahipli dosya değil, dokunulmadı):** `src/features/pazarlama/components/meraklisina-icerik.tsx:137` "çizgi yukarı tırmanıyorsa bölüm zorlaşıyor demektir" (ayrıca yön ters görünüyor: sıra **küçülünce** taban sıkılaşır; çizimin ekseni bilinmeden karar verilemez — Bilal baksın) ve `scripts/tadimlik-uret.ts:74` prompt örneği ("…bölüm zorlaşıyor"). İkincisi artık zararsız (trend servis edilmiyor) ama `--force` koşusundan önce düzeltilmeli.
6. **`gerekce`'de filtreye takılmayan kalite sorunları (bilgi):** batch metinleri temsili sırayı kullanıcıya kendi sırasıymış gibi söylüyor ("30.000 sıralamanızla", "75K bandı"), hitap karışık ("sıralamanız" / "adayın" / "sıralaman"), bazıları yumuşak vaat içeriyor ("yerleşme potansiyeli var", "rahat yerleşim sağlayan", "rahatça yetiyor"). Kalıcı çözüm yeni prompt'la yeniden üretim (karar #17); istenirse `gerekce` de deterministik şablona çekilebilir (ayrı karar).
7. P3'ün `grep -rniE "olasılı|ihtimal" src` kabul taramasına 2 yeni izinli satır eklendi: `tadimlik-havuzu.ts`'teki filtre kalıbı ve onu açıklayan yorum (yasaklayıcı, kullanıcıya görünmez).
8. `pnpm build`, dev sunucusu, tarayıcı, `pnpm tadimlik`: koşulmadı (talimat). UI bileşeni değişmedi; `SEMA` senkronu gerekmiyor (sihirbaz/havuz/iskelet davranışı aynı).
---
## Yazılımcı C · K3 katalog
Dal `gece/p7-katalog` (taban `e1bb482`), worktree `.claude/worktrees/p7-katalog`. Push yok, build koşulmadı, tarayıcı açılmadı. Şartname: `11-ceo-kararlari-tur2.md` §2-K3.
**Özet (5 madde)**
1. 667 derin sayfanın (304 bölüm + 363 üniversite) başlık/açıklaması artık sayfa numarası dışında da ayrışıyor: bölümde **taban sırası aralığı** (title + description + H1), üniversitede **o sayfadaki birim adları** (description + giriş paragrafı). Salt-okunur betikle 667 sayfanın tamamı tarandı: sayfa numarası silinince aynı kalan title+description çifti **0**.
2. Canonical (kendine), robots, sitemap, `seo.tsx`, iki `sayfa/[no]/page.tsx` ve 1. sayfaların title/description'ı **değişmedi** (`git diff e1bb482 HEAD` bu satırlarda boş).
3. "yerleşir misin? / nereye yerleşirsin?" başlıkları 5 yerden kalktı; CEO'nun uyarladığı köprü cümlesi **aynen** kullanıldı; `CtaSiraForm` `/bolum/[slug]` sayfasına üniversite sayfasıyla aynı konumda eklendi.
4. İki commit bağımsız: metin beğenilmezse `git merge gece/p7-katalog~1` yalnız sayfalamayı alır (commit 1 tek başına tsc/lint temiz doğrulandı).
5. Üç küçük sapma var (aşağıda): köprü sabitinin yeri, tek birimli üniversite sayfalarına sıra aralığı eklenmesi, uzun bölüm adlarında `<title>` uzunluğu.
### Commit listesi
| # | Hash | Mesaj | Dosyalar |
|---|---|---|---|
| 1 | `4dfb24b` | `feat(seo): derin katalog sayfalarında başlık/açıklama/H1'i sayfanın içeriğiyle ayrıştır` | `bolum-icerik.tsx`, `universite-icerik.tsx`, `sayfalama.tsx` |
| 2 | `f1abedc` | `feat(katalog): CTA kartında vaatsiz başlık + köprü cümlesi, /bolum sayfasına CTA` | `cta-sira-form.tsx`, `universite-icerik.tsx`, `bolum-icerik.tsx`, `sayfalama.tsx` |
Metadata nerede üretiliyor: rota dosyalarındaki `generateMetadata` → `bolumSayfaMetadata` / `uniSayfaMetadata` (iki `*-icerik.tsx`) → `sayfaMetadata` (`seo.tsx`, dokunulmadı). Next metadata API'sine dokunulmadı (yalnız `title`/`description` string'leri); yine de `node_modules/next/dist/docs/01-app/03-api-reference/04-functions/generate-metadata.md` title/template bölümü okundu — kök `template: "%s — KolayTercih"` derin sayfalara da uygulanıyor.
Tek yardımcı: `sayfaDilimi()` (`sayfalama.tsx`) → `bolumSayfaDilimi()` / `uniSayfaDilimi()`; hem metadata hem gövde bunları çağırıyor (gövdedeki eski elle `slice` kaldırıldı).
### Örnek üretilen metinler (gerçek veri, lokal `data/yokatlas.db`, salt-okunur betik)
Yöntem: bileşen modülü `next/link` yüzünden node'da yüklenemediği için betik `@/lib/katalog`'u gerçek DB'ye karşı çalıştırdı; metin yardımcıları dosyalardan **birebir kopyalandı** (betik scratchpad'de, commit'lenmedi).
**Bölüm — Psikoloji (381 program, 8 sayfa)**
| | 1. sayfa (değişmedi) | sayfa/2 | sayfa/3 |
|---|---|---|---|
| title | Psikoloji Taban Puanları ve Başarı Sıralamaları 2026 | Psikoloji Taban Puanları 2026 (Sıra 52.892–102.279, Sayfa 2) | Psikoloji Taban Puanları 2026 (Sıra 103.498–139.934, Sayfa 3) |
| description | Psikoloji 2025 yerleştirme verileri: 381 programın taban puanı ve sıralaması, 90 devlet / 291 vakıf. En iyi taban sıralaması 522. 2026 tercih rehberi. | Psikoloji taban puanları, sayfa 2: taban sırası 52.892–102.279 arası programlar. Toplam 381 programın 2025 yerleştirme verileri — taban puanı, başarı sıralaması ve kontenjan. | …sayfa 3: taban sırası 103.498–139.934 arası programlar. … |
| H1 | Psikoloji | Psikoloji — Sayfa 2 + (H1 içinde alt satır) Taban sırası 52.892–102.279 arası programlar | Psikoloji — Sayfa 3 + Taban sırası 103.498–139.934 arası programlar |
| breadcrumb | Ana sayfa › Bölümler › Psikoloji | Ana sayfa › Bölümler › **Psikoloji (link)** › Sayfa 2 | aynı desen |
Eski sayfa/2: title "Psikoloji Taban Puanları 2026 (Sayfa 2)", H1 "Psikoloji" (1. sayfayla aynıydı), breadcrumb'da üst bölüm linki yoktu.
**Üniversite — İstanbul Medipol (428 program, 9 sayfa)**
| | 1. sayfa (değişmedi) | sayfa/2 | sayfa/3 |
|---|---|---|---|
| title | İstanbul Medipol Üniversitesi Taban Puanları ve Başarı Sıralamaları 2026 | İstanbul Medipol Üniversitesi Taban Puanları 2026 (Sayfa 2) — **değişmedi** | … (Sayfa 3) |
| description | İstanbul Medipol Üniversitesi 2025 yerleştirme verileri: 428 programın taban puanları, başarı sıralamaları ve kontenjanları (İstanbul). 2026 tercih rehberi. | İstanbul Medipol Üniversitesi taban puanları, sayfa 2: Güzel Sanatlar Tasarım ve Mimarlık Fakültesi, Hukuk Fakültesi ve 3 birim daha. Toplam 428 programın 2025 yerleştirme verileri — taban puanı, başarı sıralaması ve kontenjan. | …sayfa 3: İşletme ve Yönetim Bilimleri Fakültesi ve Meslek Yüksekokulu. … |
| giriş paragrafı | (değişmedi) | mevcut cümle + "Bu sayfadaki birimler: Güzel Sanatlar Tasarım ve Mimarlık Fakültesi, Hukuk Fakültesi ve 3 birim daha." + ilk sayfa linki | aynı desen |
Tek birimli sayfa örneği (Beykent): sayfa/3 "…: Meslek Yüksekokulu (taban sırası 419.725–669.824 arası)." · sayfa/4 "…: Meslek Yüksekokulu (taban sırası 680.217–2.190.246 arası)."
**Uç durumlar (tüm derin sayfalar üzerinde sayıldı):** 304 bölüm derin sayfasının 21'i tümüyle taban verisiz → title "(Sayfa N)", description/H1 "taban verisi olmayan programlar"; 113'ü kısmen verisiz → "taban sırası X–Y arası programlar ile taban verisi olmayanlar"; 3'ünde min=max → "taban sırası X olan programlar". 363 üniversite derin sayfasında birim adı çıkmayan **0** (çıkmazsa eski description'a düşer; fakültesi boş satırlar "Diğer" grubunda kalır, ad listesine girmez). Dilim boşsa (geçersiz sayfa no) eski metne düşer — sayfa zaten `notFound()`.
### Önce → sonra metin tablosu (commit 2)
| Yer | Önce | Sonra |
|---|---|---|
| `cta-sira-form.tsx` profilli kart başlığı (varsayılan) | Sıralamanla nereye yerleşirsin? Saniyede gör. | Sıralamana yakın programlar hangileri? Saniyede gör. |
| `cta-sira-form.tsx` profilsiz kart başlığı (varsayılan) | Sıralamanla nereye yerleşirsin? Saniyede gör. | Sıralamana yakın programlar hangileri? Saniyede gör. |
| Çekmece `DrawerTitle` (sr-only) | Sıralamanla nereye yerleşirsin? | Sıralamana yakın programlar hangileri? |
| Çekmece H2 | Sıralamanla nereye yerleşirsin? | Sıralamana yakın programlar hangileri? |
| `universite-icerik.tsx` `baslik` | Sıralamanla {uni.ad} programlarına yerleşir misin? | Sıralaman {uni.ad} tabanlarının neresinde? |
| `bolum-icerik.tsx` `baslik` | (kart yoktu) | Sıralaman {bolum.ad} tabanlarının neresinde? |
| Katalog `aciklama` (üniversite + bölüm, yalnız profilsiz kart) | varsayılan paragraf | Bu tablodaki tabanlar geçmiş yerleştirmelerin sonucu; bu yıl değişebilir. Sıralamanı gir, tabanı sıralamana yakın programları risk seviyesine göre ayrılmış hâlde listeleyelim. Ücretsiz, üyelik gerekmez. |
| Varsayılan paragraflar (profilli + profilsiz + çekmece) | — | **Aynen** ("garanti dilimleri" dahil, dokunulmadı) |
| Buton metinleri / ikon deseni | — | Aynen (metin + sonda `ArrowRight className="size-4"`) |
### `CtaSiraForm` kullanım yerleri ve etkisi
| Yer | Prop | Etki |
|---|---|---|
| `src/app/rehber/page.tsx:45` | yok | Varsayılan başlık değişti (kart + çekmece); paragraf aynı |
| `src/features/rehber/components/rehber-makale.tsx:100` | yok | aynı |
| `src/features/katalog/components/bolum-listesi.tsx:101` (`/bolumler`) | yok | aynı |
| `src/features/katalog/components/universite-listesi.tsx:94` (`/universiteler`) | yok | aynı |
| `src/features/katalog/components/universite-icerik.tsx` | `baslik` + `aciklama` | Yeni başlık + köprü cümlesi |
| `src/features/katalog/components/bolum-icerik.tsx` (YENİ) | `baslik` + `aciklama` | Kart ilk kez geliyor; 1. ve derin sayfalarda |
Ana sayfa `CtaSiraForm` kullanmıyor (hero kendi formunu kullanıyor) → ana sayfa etkilenmedi. Çekmece başlığı `baslik` prop'undan bağımsız sabit (şartname gereği) → katalogda kart başlığı "…tabanlarının neresinde?", açılan çekmecede "Sıralamana yakın programlar hangileri?". Profilli ziyaretçide `aciklama` kullanılmaz (şartname: yalnız profilsiz kart); başlık `baslik`'tan gelir.
`cta_form_goruntulendi`: `useGorunumOlayi` çağrısı ve `ref={formRef}` bağlaması değişmedi (`cta-sira-form.tsx:91,180`). Yan etki (beklenen): olay artık `/bolum/*` pathname'lerinden de düşecek — payda büyür; Rybbit pathname'i zaten yazdığı için sayfa tipine göre ayrıştırılabilir.
### Kabul kriterleri
| Kriter | Durum | Kanıt |
|---|---|---|
| Bölüm `sayfa>1`: title+description+H1 taban sırası aralığı; null'lar hariç; tümü null yedeği | Tamam | `bolumSayfaDilimi` + `siraAraligiMetni`; yukarıdaki örnekler + uç durum sayımı |
| Üniversite: description + giriş paragrafı birim adları (ilk 2 + "ve N birim daha") | Tamam | `uniSayfaDilimi` + `fakulteOzeti`; Medipol örnekleri |
| Bölüm breadcrumb'ı üniversite deseniyle (üst link + Sayfa N) | Tamam | `bolum-icerik.tsx` nav; bölüm nav'ının kendi link class'ları kullanıldı |
| Canonical/robots/sitemap/rota dosyaları değişmez | Tamam | `git diff --stat e1bb482 HEAD` → yalnız 4 dosya; `path:` satırlarında diff yok |
| 1. sayfa regresyonu yok | Tamam | 1. sayfa dalları diff'te yok; H1/paragraf 1. sayfada aynı metni üretir |
| Metadata ve gövde tek yardımcıdan | Tamam | ikisi de `*SayfaDilimi()` çağırıyor |
| `aciklama?: string`, varsayılan paragraflar aynen | Tamam | diff: paragraf metni kelimesi kelimesine aynı, yalnız `aciklama ??` sarmalı |
| Başlıklar (varsayılan 4 yer + üniversite + bölüm) | Tamam | önce→sonra tablosu |
| Kart `/bolum`'da aynı konum (`mt-10`, liste+sayfalama altı) | Tamam | bölümde sayfalama `BolumProgramListesi` içinde; kart `</section>` sonrası `<div className="mt-10">` |
| `grep -rniE "yerleşir misin\|yerleşirsin" src` → 0 | **Kendi dosyalarımda 0**; dalda 1 isabet kalıyor | `src/lib/ai/rapor.ts:166` `riskNotuUret` ("yüksek ihtimalle yerleşirsin") — LLM prompt'u değil ama benim dosyam da değil; P3 (`cae2aaa`, `risk.ts:55`'e taşıyıp düzeltti) merge edilince 0'a iner |
| Yeni badge/pill/modal yok | Tamam | yeni eleman: yalnız H1 içinde `<span class="block …">` alt satır |
| Yeni metinlerde vaat yok | Tamam | yerleşirsin/garanti/olasılık geçmiyor |
### Doğrulama
Her iki commit'te ayrı ayrı: `pnpm exec next typegen` → 0 · `pnpm exec tsc --noEmit` → 0 · `pnpm lint` → 0. `pnpm build` koşulmadı (şartname). Çalışma ağacı temiz; `git add` yalnız adı verilen dosyalarla yapıldı.
### Sapmalar / en güvenli yorumlar
1. **Köprü sabiti `sayfalama.tsx`'te** (`KATALOG_CTA_ACIKLAMA`). Şartname bu dosyayı yalnız dilim yardımcısı için anmıştı. Gerekçe: `cta-sira-form.tsx` `"use client"` — istemci modülünden export edilen string sunucu bileşeninde değer olarak okunamaz (client reference olur); `bolum-icerik`↔`universite-icerik` çapraz import'u ise bölüm rotasının modül grafiğine üniversite sayfasının istemci bileşenlerini sokardı. `sayfalama.tsx` iki sayfanın zaten ortak import ettiği, yönergesiz küçük modül. Alternatif: cümleyi iki dosyada tekrarlamak (tek-kaynak ilkesine aykırı bulundu).
2. **Tek birimli üniversite sayfalarına taban sırası aralığı eklendi** (şartnamede yok). İlk koşuda 9 sayfanın description'ı sayfa numarası dışında komşusuyla aynı çıktı (Beykent 4-5, Nişantaşı 4 ve 7, Arel/Gelişim/Topkapı/Üsküdar 4, İzmir Kavram MYO 3 — 100+ programlı MYO'lar iki sayfayı tek başına dolduruyor). Dilim tek birimse "(taban sırası X–Y arası)" eklenince çakışma 0'a indi. Birim içinde satırlar zaten taban sırasına göre dizili olduğu için ifade doğru.
3. **Üniversite `<title>` değişmedi** (CEO: "~60 karakteri aşmasın"). 10 §B3'teki "uzunluk elverirse başlığa" seçeneği uygulanmadı: taban başlık zaten ~55–60 karakter, koşul neredeyse hiç sağlanmıyor. Üniversite derin sayfalarında farklılaşma description + gövdede.
4. **Bölüm `<title>` uzun bölüm adlarında uzuyor:** en uzun 96 karakter ("Siyaset Bilimi ve Uluslararası İlişkiler Taban Puanları 2026 (Sıra 1.193.512–1.703.790, Sayfa 3)") + " — KolayTercih". Google keser; aralık kesilen kısımda kalabilir. CEO bölümde aralığın title'da olmasını açıkça istediği için kısaltma kuralı eklenmedi — Bilal/SEO kararı (ör. uzun adlarda "Taban Puanları 2026" yerine "2026").
5. **H1 biçimi:** 10 §B3'teki öneri izlendi — "Psikoloji — Sayfa 2", aralık H1'in **içinde** blok alt satır (`text-lg sm:text-2xl`, muted). Böylece H1 aralığı taşıyor (CEO) ama 5xl punto ile üç satıra yayılmıyor.
6. Lisans + önlisans karışan dilimde aralık min–max (CEO şartı): SAY/EA sırası ile TYT sırası aynı cümlede birleşiyor; teknik olarak doğru, anlamca karışık olabilir.
7. Bölüm listesi istemci tarafında yeniden sıralanabiliyor (URL değişmeden); H1/paragraftaki aralık varsayılan (taban sırası) dizilimi anlatır. Kullanıcı "Puan"a göre sıralarsa görünen satırlar aralığın dışına çıkar — mevcut davranış, dokunulmadı.
### Bilal'in tarayıcıda bakması gerekenler
1. **Mobilde derin bölüm H1'i:** `/bolum/psikoloji/sayfa/2` — "Psikoloji — Sayfa 2" + gri alt satır; uzun adlı bir bölümde de bak (`/bolum/siyaset-bilimi-ve-uluslararasi-iliskiler/sayfa/3`).
2. **Bölüm breadcrumb'ı:** derin sayfada "Psikoloji" tıklanabilir ve 1. sayfaya gidiyor mu; mobilde satır kırılması.
3. **`/bolum/psikoloji` altındaki yeni CTA kartı:** tablo + sayfalama + veri kaynağı satırının altında; başlık "Sıralaman Psikoloji tabanlarının neresinde?"; buton → çekmece açılıyor, sıra girişi → sihirbaz → `/sonuc` akışı bozulmamış mı. Sayfada iki `#cta-siralama` yok (tek kart).
4. **Üniversite sayfası kartı:** uzun üniversite adında başlık iki satıra taşıyor mu ("Sıralaman Burdur Mehmet Akif Ersoy Üniversitesi tabanlarının neresinde?").
5. **Köprü cümlesini oku** (metin kararı senin): "…risk seviyesine göre ayrılmış hâlde listeleyelim." `/sonuc` ücretsiz tablosundaki dilim sekmeleriyle örtüşüyor mu.
6. **Profilli hâl:** sıralaman kayıtlıyken katalog kartı yeni başlığı + eski "Sıralaman kayıtlı…" paragrafını gösteriyor (köprü cümlesi bu hâlde görünmez — şartname).
7. **`/rehber`, bir rehber yazısı, `/bolumler`, `/universiteler`:** varsayılan başlık "Sıralamana yakın programlar hangileri? Saniyede gör." bağlama oturuyor mu.
8. Build sonrası kontrol (entegrasyon build'inde): `.next/server/app/bolum/psikoloji/sayfa/2.html` içinde `<link rel="canonical" …/sayfa/2>` ve `<meta name="robots" content="index, follow">` aynı; `<title>`/`<h1>` yukarıdaki gibi. Deploy sonrası Search Console'da 2–3 derin sayfa için "dizine ekleme iste".
---
## Yazılımcı A · K1 kapı ölçümü + K4 prototip
**Özet (5 madde)**
1. **K1 tamam, 3 commit, `gece/p5-kapi-olcum` (taban `e1bb482`).** `program_eklendi` artık yalnız gerçek eklemede atılıyor; `kapi_acildi` / `kapi_kapatildi` eklendi; `kullaniciTanit` script'ten önce kaybolmuyor. Davranış değişmedi: profilsiz + hâlâ kapıyı açıyor.
2. **K4 tamam, tek commit, `gece/p6-arti-aninda-ekle` (taban = P5 tepesi) — `[Bilal onayı gerekir]`.** Profilsiz + programı anında ekliyor, kapı açılmıyor; 8 sn'lik toast "Sıralamamı gir →" ile kapıyı doğrudan sıra adımında açıyor. Yalnız iki dosya.
3. **K4'ün en önemli riski (CEO varsayımı kısmen yanlış):** `riskleriYenile` yalnız **kapı** tamamlanınca çağrılıyor (`profilTamamlandi`). Profil kapı dışı yoldan yazılırsa (katalog sayfasının dibindeki `CtaSiraForm`, ana sayfa `hero-form`, `sihirbaz-cagri-karti`, giriş sonrası `liste-senkron`) önceden eklenmiş null riskler **null kalır** → `/sonuc` haritasında turuncu ("az riskli") pin. Şartname "yeni kod yazma" dediği için düzeltmedim; 3 satırlık öneri aşağıda.
4. **Profilsiz listenin tek yüzeyi çekmece.** `/listem` giriş ister ve manuel listeyi değil YZ raporunu gösterir; `secimlerim-paneli` hiçbir yere monte değil (ölü bileşen). Çekmece altındaki "Risk analizini biz yaptık / Her seçimin yerleşme riski hazır" kartı profilsiz listede **yanlış beyan** olur.
5. Her iki dalın tepesinde `next typegen` + `tsc --noEmit` + `pnpm lint` temiz. `pnpm build` koşulmadı (talimat). Tarayıcıda hiçbir şey doğrulanmadı.
### Commit listesi
| Dal | Hash | Başlık |
|---|---|---|
| `gece/p5-kapi-olcum` | `4b87a3e` | fix(analitik): program_eklendi yalnız gerçek eklemede atılsın |
| `gece/p5-kapi-olcum` | `67be93c` | feat(analitik): kapi_acildi + kapi_kapatildi olayları |
| `gece/p5-kapi-olcum` | `643e41c` | fix(analitik): kullaniciTanit script'ten önce sessiz no-op olmasın |
| `gece/p6-arti-aninda-ekle` | `1a87d89` | feat(liste): ilk + profilsiz ziyaretçide anında eklesin [Bilal onayı gerekir] |
Worktree: `.claude/worktrees/p5-kapi-olcum` (şu an `gece/p6-arti-aninda-ekle` checkout'lu; P5 dalı `643e41c`'de duruyor). Dokunulan dosyalar — K1: `src/lib/analitik.ts`, `program-ekle-butonu.tsx`, `use-tercih-profili.ts`, `tercih-profili-kapisi.tsx`. K4: `use-tercih-profili.ts`, `program-ekle-butonu.tsx`. Başka dosya yok; `rybbit-identify.tsx`, `arama-funnel-karti.tsx` vb. açıcılara dokunulmadı.
### Olay tablosu
| Olay | Nerede atılıyor | Özellikler |
|---|---|---|
| `program_eklendi` (P5) | `program-ekle-butonu.tsx` `handleClick`, yalnız `sonuc.eklendi === true` | `{kaynak, yol: "dogrudan"}` |
| `program_eklendi` (P5) | `use-tercih-profili.ts` `profilTamamlandi`, bekleyen program için `ekle()` `true` döndüyse | `{kaynak: bekleyen.kaynak, yol: "kapi"}` |
| `kapi_acildi` | `use-tercih-profili.ts` `kapiyiAc()` — depodaki **tek** açılış noktası; üç açıcı da buradan geçer | `{tetik}`: `programEkleIste`→`arti` · `profilDuzenlemeyiAc`→`duzenle` · `profilToplamaAc(hedef, dogrudanSira, tetik?)`→ verilen değer, yoksa hedeften `sonuc`/`sihirbaz`, o da yoksa `diger` |
| `kapi_kapatildi` | `tercih-profili-kapisi.tsx` `vazgec()` — bileşendeki **tek** nokta (Dialog `onOpenChange(false)` = X / dışarı tıklama / Esc, giriş adımı "Vazgeç", sıra adımı "Vazgeç") | `{adim: giris\|sira\|sihirbaz, tetik}` |
| `program_eklendi` (P6) | buton, aynı nokta | `{kaynak, yol: "dogrudan", profilli: "evet"\|"hayir"}` |
| `kapi_acildi` (P6) | toast aksiyonu → `profilToplamaAc(null, true, "arti_toast")` | `{tetik: "arti_toast"}` (P6'da `arti` artık hiç atılmaz) |
Hiçbir olayda ham sıra / e-posta / program adı yok. `tetik` türetmesi sayesinde `sonucaGitIste` (`sonuc`) ve `arama-funnel-karti` (`sihirbaz`) dosyalarına dokunmadan doğru değeri alıyor; `diger` bugün hiçbir açıcıdan çıkmıyor (ileride `profilToplamaAc()` argümansız çağrılırsa düşer).
### Kabul kriterleri — K1
| # | Kriter | Sonuç | Kanıt |
|---|---|---|---|
| 1 | `program_eklendi` yalnız gerçek eklemede; `kapiAcildi` dalında atılmaz | Geçti | Buton: `else if (sonuc.eklendi)`; `kapiAcildi` sonucu hiçbir dala girmiyor. `profilTamamlandi`: `const eklendi = ekle(...)`; `if (eklendi) olay(..., {yol: "kapi"})` |
| 2 | `kapi_acildi {tetik}` + `kapi_kapatildi {adim, tetik}`; kapatıldı yalnız tamamlanmadan | Geçti (kod incelemesi) | Tamamlanma yolu: `secimleriTamamla` → `profilTamamlandi` depoda `acik:false` yazar; `profilKapisiniKapat`/`vazgec` çağrılmaz. Radix Dialog kontrollü `open` prop'u değişince `onOpenChange` tetiklemez (yalnız kullanıcı etkileşiminde) → olay atılmaz. `adim`, üst bileşendeki `adimRef`'te; `KapıIcerik` mount'ta ve her `adimaGec`'te bildirir (key ile remount'ta başa sarar). `vazgec` `if (!acik) return` ile çift atışa karşı korumalı |
| 3 | `kullaniciTanit` tek slot, olaylardan önce; `kullaniciTemizle` slotu siler | Geçti | Scratchpad'de `tsx` betiği (commit'lenmedi): script yokken `olay(sonuc_goruntulendi)` → `kullaniciTanit(u1)` → `kullaniciTanit(u2)`; script gelince çağrı sırası `["identify:u2","event:sonuc_goruntulendi"]` (u1 ezildi, kimlik olaydan önce). Script varken `kullaniciTanit(u3)` doğrudan, `kullaniciTemizle` → `clear`. Script 10 sn'de gelmezse slot da atılır (`kuyrukKapali`). `rybbit-identify.tsx` diff'te yok |
| 4 | `OlayAdi`'na yalnız 2 ad + seri kırılması yorumu | Geçti | `git diff e1bb482..643e41c -- src/lib/analitik.ts`: birlikte yalnız `kapi_acildi`, `kapi_kapatildi`; `program_eklendi` üstünde "önce = + tıklaması, sonra = gerçek ekleme; seriler karşılaştırılamaz" notu |
| 5 | Davranış değişmez; `grep -rn "program_eklendi" src` → 2 atış + tip | Geçti | grep çıktısı: `program-ekle-butonu.tsx:59`, `use-tercih-profili.ts:289`, `analitik.ts:26`. Açıcıların durum yazımı `kapiyiAc`'a taşındı ama yazılan alanlar birebir aynı (+`tetik`) |
### Kabul kriterleri — K4
| # | Kriter | Sonuç | Kanıt |
|---|---|---|---|
| 1 | Profilsiz: hemen ekle, kapı açma, `profilsiz: true`; olayda `profilli` | Geçti | `programEkleIste`'de kapı dalı kalktı; tek ekleme yolu, `profilsiz = !tercihProfiliTamamlandiMi()`. Katalogda `adaySira` yok → `programdanManuelTercih(..., null)` → risk `null`. `kapiAcildi` alanı tipte kaldı (hep `false`) |
| 2 | Toast: sabit id, ~8 sn, başlık/açıklama/aksiyon birebir, sonda `ArrowRight` | Geçti | sonner `Action.label: React.ReactNode` (`node_modules/sonner/dist/index.d.ts:44`) → `<span className="inline-flex items-center gap-1">Sıralamamı gir <ArrowRight className="size-4" aria-hidden /></span>`. `id: "profilsiz-ekleme"`, `duration: 8000`, `toast.success`. Metin başında ikon yok, `Sparkles` yok (soldaki onay işareti sonner'ın kendi `success` ikonu, buton etiketi değil) |
| 3 | Profil girilince `riskleriYenile` null'ları doldurur (yeni kod yok) | **Kısmen** | Toast → kapı yolu: `profilTamamlandi` ilk iş `riskleriYenile(profil)` çağırır → tüm liste `riskHesapla(efektifSira, profil.sira)` ile yeniden yazılır. **Ama** `grep -rn riskleriYenile src` → tek çağrı yeri bu. Kapı dışı 4 profil yazma yolu listeyi yenilemiyor (bkz. Riskler #1) |
| 4 | Tüketici envanteri | Aşağıda | — |
| 5 | `SEMA`, `meraklisina-icerik.tsx`, kapı bileşeni, sihirbaz adımları değişmedi | Geçti | `git diff 643e41c..1a87d89 --stat` → yalnız 2 dosya. + kapısı `/meraklisina` şemasında yok (CEO §1 tablosu) → AGENTS.md şema senkron kuralı tetiklenmez |
### tsc / lint
| Dal tepesi | `next typegen` | `tsc --noEmit` | `pnpm lint` |
|---|---|---|---|
| `gece/p5-kapi-olcum` @ `643e41c` | başarılı | 0 hata | 0 hata / 0 uyarı |
| `gece/p6-arti-aninda-ekle` @ `1a87d89` | başarılı | 0 hata | 0 hata / 0 uyarı |
Ara commit'ler (`4b87a3e`, `67be93c`) de commit anında tsc + lint temizdi. `pnpm build` koşulmadı.
### K4 tüketici envanteri — profilsiz + dolu liste
| Yüzey | Ne gösteriyor | Durum |
|---|---|---|
| Navbar `listem-butonu.tsx` | İlk eklemede belirir, turuncu sayaç rozeti | Sorun yok — ekleme onayının kalıcı izi (toast kaybolunca bu kalıyor) |
| Çekmece satırı `liste-cekmecesi.tsx:398` | `tercih.risk ? nokta : null` → null riskte nokta yok, satır düzgün | Kırılmıyor. Ama başlıktaki renk lejandı (yeşil/turuncu/kırmızı) noktasız listede boşa duruyor |
| Çekmece alt kartı `liste-cekmecesi.tsx:~271` | "Risk analizini biz yaptık — Her seçimin yerleşme riski hazır" + "Listemde aç" → `/listem` | **Yanıltıcı:** profilsiz listede risk yok; link de girişsizi `/giris`'e atar, girişliye manuel listeyi değil YZ raporunu (ya da boş CTA'yı) gösterir |
| Çekmece + (kesik çizgili) | `sonucaGitIste()` → profilsizde kapı (`tetik: sonuc`) | Çalışır; sıra girişine ikinci doğal yol |
| `secimlerim-paneli.tsx` | Null riski karşılıyor (`:223`), profilsizde "Tercih profilin oluşunca uyum notları görünür" | **Hiçbir yere monte değil** (`grep -rn SecimlerimPaneli src` → yalnız kendi dosyası). Ölü kod; profilsiz listenin tam sayfa görünümü fiilen yok |
| `/listem` (`listem-icerik` → `listem-govde`) | `verifySession` → girişsiz `/giris`'e yönlenir; girişlide YZ raporu ya da `ListemBosCta`. Manuel liste burada **gösterilmiyor** | CEO'nun "profilsiz `/listem`" kontrol maddesi karşılıksız: bakılacak ekran çekmece |
| `kaydet-banner` | Girişsiz + ≥3 seçim + `/sonuc` ve kromsuz sayfalar dışında | Artık profilsiz ziyaretçi için **ulaşılabilir** (eskiden kapı yüzünden 3'e çıkılamıyordu). Metni risk iddia etmiyor. Toast üstte (`top-center`), banner altta → çakışma yok |
| `manuel-harita.tsx:33` | `t.risk ?? "az-riskli"` → null risk turuncu pin | Yalnız `/sonuc`'ta monte. Profilsiz `/sonuc` = `SiraGerekli` (harita yok) → saf profilsizde görünmez. **Görünür olduğu iki durum:** (a) eski `?sira=` linkiyle profilsiz `/sonuc`, (b) Riskler #1 — profil kapı dışından girilince null'lar kalır → katalogdan eklenenler yanlış renkle (turuncu, "az riskli") pinlenir |
| `liste-senkron` / `liste-dogrula.ts` | `risk: null` doğrulamadan geçiyor, sunucuya null yazılıyor | Kırılmıyor; girişte sunucudan profil gelirse (`tercihProfiliYaz`) riskler yine yenilenmiyor (#1) |
### K4 riskleri
1. **Null riskler kapı dışı profil girişinde kalıcı.** En olası senaryo tam da hedef kitle: üniversite sayfasında + → toast'ı kaçırır → sayfa dibindeki `CtaSiraForm`'a sırasını yazar → `/sonuc` haritasında eklediği programlar turuncu. Önerilen düzeltme (K4 commit'ine ek, sahip olunan dosyada, ~3 satır — **yazılmadı**): `use-tercih-profili.ts` `yukle()` içindeki `PROFIL_DEGISTI_EVENT` dinleyicisinde `profiliTazele()` sonrası `if (durum.profil) riskleriYenile(durum.profil);`. Alternatif/tamamlayıcı: `manuel-harita.tsx:33`'te null riski nötr (gri) pinle göstermek (Bilal/tasarım kararı).
2. **Toast mobilde görünürlük.** `Toaster position="top-center"`; %93 mobil, + genelde ekranın alt yarısında. 8 sn sonra tek kalıcı iz navbar'daki sayaç. Aksiyon butonu sonner'ın 24 px yüksekliğindeki varsayılan butonu — dokunma alanı küçük, `size-4` ok 12 px metnin yanında büyük durabilir. Gözle bakılmalı.
3. **Ölü yol:** `bekleyen` / "Kaydet ve programı ekle" etiketi / `program_eklendi {yol:"kapi"}` P6'da erişilemez (kimse `bekleyen` yazmıyor). Bilerek bırakıldı: revert tek commit kalsın, kapı bileşenine dokunulmasın. Karar "evet" olursa ayrı temizlik commit'i.
4. **Seri:** P6 canlıya çıkarsa `kapi_acildi{tetik:arti}` sıfıra iner, yerine `arti_toast` gelir; Huni C'nin yeni tanımı `program_eklendi{profilli:hayir}` → `kapi_acildi{arti_toast}` → `sira_girildi{kaynak:kapi}`.
5. Art arda +'larda sabit `id` toast'ı yeniler (yığılmaz) ama süre her seferinde baştan başlar — istenen davranış.
### Sapmalar / yorumlar
- **`kapi_acildi` depodan, `kapi_kapatildi` bileşenden.** Şartnamedeki "olay, kapı bileşeninde tek noktadan atılır" cümlesini `kapi_kapatildi` için okudum (adımı yalnız bileşen bilir). `kapi_acildi` depodaki tek açılış fonksiyonundan atılıyor: bileşende mount effect'iyle atmak, `key` profil değişince remount ettiği için çift sayıma açıktı.
- **`tetik` varsayılanı hedeften türetiliyor** (`tetik ?? hedef ?? "diger"`): şartname "her açıcı kendi değerini yazar" diyor ama `arama-funnel-karti.tsx` sahip olunan dosyalarda değil; türetme aynı sonucu dosyaya dokunmadan veriyor.
- `KapıIcerik`'e iki prop eklendi (`onAdimDegisti`, `onVazgec`) ve bir mount effect'i (`eslint-disable-next-line react-hooks/exhaustive-deps`, repoda emsali var). Görsel/metin değişikliği yok.
- K4'te `adaySira` verilmişse (yalnız `/sonuc` tablosu, eski `?sira=` linki) risk null değil o sıradan hesaplanıyor — mevcut `programdanManuelTercih` semantiği korundu; katalogda her zaman null.
- K4 toast'ı `toast.success` (mevcut iki uyarı `toast.info`); "eklendi" olumlu onay olduğu için.
### Bilal'in elle bakması gerekenler
1. **K1 deploy tarihini yaz** (karar #13) — `program_eklendi` serisi o gün kırılıyor.
2. **K4, telefonda 10 dk:** üniversite sayfasında profilsiz + → toast görünüyor mu, okunuyor mu, "Sıralamamı gir" dokunulabilir mi ve kapıyı **sıra adımında** açıyor mu; kapıyı tamamlayınca çekmecede noktalar geliyor mu.
3. **Aynı testin kötü yolu:** profilsiz 2 program ekle → toast'a dokunma → sayfa dibindeki forma sıranı gir → `/sonuc` haritasında pinlerin rengine ve çekmecede noktaların gelmediğine bak (Risk #1). K4'e "evet" diyeceksen 3 satırlık düzeltmeyi de iste.
4. Çekmece alt kartındaki "Risk analizini biz yaptık" metni profilsiz listede kalsın mı (metin/koşul kararı).
5. Rybbit canlıda: `kapi_kapatildi`'nin tamamlanan kapıda **düşmediğini** bir kez kendi oturumunla doğrula (kod incelemesiyle gösterildi, tarayıcıda denenmedi); OAuth dönüşünde `sonuc_goruntulendi`'nin tanımlı kullanıcıya yazıldığına bak (commit 3).
---
## Blog: universite-okurken-tekrar-yks
Yazar: SEO/GEO içerik yazarı (gece vardiyası, 2. tur · B1) · Worktree `.claude/worktrees/rehber-yazilari`, dal `gece/rehber-yazilari` · yalnız `content/rehber/*.md` · push yok, `pnpm build` koşulmadı (`src/` değişmedi).
### Özet (5 madde)
1. **İki commit, şartnamedeki sırayla:** `9c7ea13` `fix(rehber)` (küçük düzeltmeler) → `2602b6f` `feat(rehber): universite-okurken-tekrar-yks yazısı` (yeni yazı + 3 iç link, en tepede). Bilal yazıyı almazsa `gece/rehber-yazilari~1` = `9c7ea13`; linkler de gider, 404 kalmaz.
2. Yazı: ~1.250 kelime (şema ve Kaynaklar hariç), 1 `flowchart TD` (`%% aria` + `%% altyazi`), 1 tablo (devam / kayıt dondurma / kayıt sildirme × hak / bedel / geri dönüş), 5 soruluk SSS, Kaynaklar (6 kaynak, erişim tarihli), 7 farklı iç hedef (`mezuna-kalmak…`, `yatay-gecis…`, `obp-nedir…`, `hazirlik-sinifi…`, `hedef-siralama…`, `olu-tercih…` + `/bolumler`, `/tercih-robotu`). Frontmatter/şema çiti `src/lib/rehber.ts` regex'leriyle node'da doğrulandı; 28 yazıda 118 `/rehber/*` linki, **0 ölü**.
3. **Omurga cümleleri bu gece birincil metinden tekrar okundu** (önceki yazarın scratchpad'deki pypdf çıktıları + YÖK ilkeleri PDF'i bu oturumda yeniden indirilip okundu): kayıtlı olmak tercih/yerleştirmeye engel değil; yeni kayıt için ilişik kesme şart (YKS Kılavuzu b.10); başvuru formunda "Bir yükseköğretim programına kayıtlıyım" seçeneği (23. alan, kod 6); Ek Madde-1'in ara sınıflar/son sınıf dâhil olduğu (YÖK ilkeleri A.7).
4. **Kanibalizasyon sınırı korundu:** OBP kuralı yeniden anlatılmadı (tek paragraf özet + 2 link); Ek Madde-1'in kontenjan oranı/başvuru dönemi maddeleri tekrar edilmedi, `mezuna-kalmak…`'a bırakıldı. Bu yazıya özgü olanlar: okuyan öğrenciyi ilgilendiren ilke maddeleri (hangi yılın puanı, intibak, taban oluşmamış program, özel koşul/dil şartı, vakıf bursu kararı), not ortalamasıyla kurumlar arası geçişin yönetmelik şartları, sınava giriş→tercih→ilişik kesme sırası.
5. Vaat/kaygı dili yok; askerlik/tecil, harç/ücret rakamı, 2027 tarihi yok; dilim adı ilk geçişte "güvenli (halk arasında "garanti tercih")"; "dilimler yerleşme olasılığı değil" notu var.
### Commit 1 — `9c7ea13` ayrıntı
- `hedef-siralama-nasil-belirlenir.md:83`: "; üründe dilimin adı da böyle geçer" yan cümlesi silindi (parantez "(halk arasındaki adıyla garanti tercih)" olarak kaldı).
- `taban-siralamalar-nasil-degisir.md`: `%% aria` ("beş yılın (2021–2025) tabanı filmdir. Beş yıl üst üste…"), şema düğümü ("5 yılın tabanı = film"), kenar etiketi ("5 yıl dar bantta"), gövde :42 ("5 yılın (2021–2025) tabanı **film**dir"), :44 ("5 yıl üst üste dar bantta"), :53 ("son 5 yılın (2021–2025) tabanına bak"). **Dokunulmayan:** `%% altyazi` "en az 3-4 yıla bak" (genel okuma tavsiyesi; CEO notu).
- **DB teyidi** (`sqlite3 -readonly data/yokatlas.db`): `programs` tablosunda `sira2021…sira2025` kolonları var; dolu satır sayıları 2021: 11.450 · 2022: 18.086 · 2023: 18.373 · 2024: 20.805 · 2025: 17.994 (toplam 23.610 program). Ürün satır başlığı da "Son 5 yıl" (`bolum-program-listesi.tsx:160`, `program-tablosu.tsx:242`).
### Commit 2 — `2602b6f` iç linkler (3 dosya, şartnamedeki üst sınır)
| Dosya | Değişiklik |
|---|---|
| `mezuna-kalmak-mi-kayit-olmak-mi.md` | "Üniversitede kayıtlıyken YKS'ye girebilir misin?" paragrafının sonuna tek cümle + link |
| `yerlesemedim-ne-yapmaliyim.md` | Yol 3 girişine yarım cümle + link |
| `yatay-gecis-cap-yandal.md` | "4) Yeniden sınava girmek" 2. madde **yeniden yazıldı** + link + `guncelleme: 2026-09-21`. Eski cümle "ertesi yıl yerleştiğinde eski kaydın silinir" diyordu; kılavuzda böyle bir otomatik silme hükmü **yok** (b.10 yalnızca "ilişiğini kesmezse yeni programa kayıt yaptıramaz" diyor). Cümle kılavuz ifadesine çekildi; eski cümledeki `yks-tercih-takvimi-2026` linki düştü. **Dikkat:** Bilal commit 2'yi almazsa bu teyitsiz cümle geri gelir — o durumda elle düzeltilmeli. |
### Doğrulanan bilgiler + kaynaklar (hepsi 21.09.2026 gecesi birincil metinden okundu)
| Yazıdaki iddia | Kaynak |
|---|---|
| Kayıtlı olmak YKS (ÖZYES dâhil) tercih ve yerleştirmesinde bir programa yerleştirilmeye engel değil; aynı anda iki örgün ön lisans ya da iki örgün lisansa kayıt/devam yok; ilişiğini kesmeyen yeni yerleştirildiği programa kayıt yaptıramaz | 2026-YKS Kılavuzu b.10 (kılavuz s.45 / PDF s.50) — sayfa: https://www.osym.gov.tr/2026yuksekogretim-kurumlari-sinavi-yks-kilavuzu . **Aynı uyarı geçerli:** ÖSYM'deki asıl PDF 10 MB sınırını aşıyor; metin ÖSYM e-imza ibareli MEB kopyasından (önceki yazarın kullandığı URL) okundu |
| Başvuruda öğrenim durumu seçeneği "Bir yükseköğretim programına kayıtlıyım" (kod 6); ayrıca "yerleştirildim fakat kayıt olmadım" (5), "kaydım silindi" (9) | Aynı kılavuz, başvuru bilgileri 23. alan "Öğrenim Durumu ve Kodu" (PDF s.13) |
| OBP: bir önceki yılın YKS'siyle yerleşen, "kayıt olsun veya olmasın"; 2026-YKS ile yerleşen 2027-YKS'ye girerse katsayı yarıya | YKS Kılavuzu b.4.2 (PDF s.38) · Kontenjan Kılavuzu b.1.3 · SSS 51–52 (URL'ler önceki tabloda) |
| ÖSYM uyarısı: yerleşirsen bir sonraki yıl katsayı yarıya ineceğinden devam etmeyi düşünmediğin programı yazma | Kontenjan Kılavuzu, tercih uyarıları 2-ç (PDF s.19–20) |
| Ek Madde-1: kayıt yılındaki puan ≥ hedefin o yılki tabanı, puan türü (A.2) · bir kez (A.5) · hazırlık, ara sınıflar ve son sınıf dâhil; intibakı ilgili kurullar yapar (A.7) · fazla başvuruda puanı yüksek olandan (A.11) · hedefin özel koşulları (A.16) · kayıt yılında öğrenci almamış programa geçiş yok (A.17) · yabancı dil şartı (A.18) · yalnız yerleştiği yıldaki puan, başarı şartı yok (A.20) · vakıfta ücretli programa geçiş, burs kararı kurumun (A.21) · taban puanlar ÖSYM en küçük/en büyük puanlar yayınında (A.15) | YÖK "Güz ve Bahar Dönemi Ek Madde 1 Uygulama İlkeleri" — https://egitim.yok.gov.tr/tr/document/2853 (PDF bu oturumda WebFetch ile indirildi, 7 sayfa pypdf ile okundu; üst veri 20.05.2026) |
| Kurumlar arası yatay geçiş: aynı düzeydeki eşdeğer programlar, YÖK'ün yayımladığı kontenjanlar (m.11/1); GNO en az 100 üzerinden 60 (m.11/2) · hazırlık sınıfına, ön lisans ilk/son yarıyıla, lisans ilk iki/son iki yarıyıla geçiş yok (m.6/1) · örgünde aynı düzeydeki birden fazla programa kayıt yapılamaz (m.23/1) · Ek Madde 1 metni | Yönetmelik — https://www.mevzuat.gov.tr/mevzuat?MevzuatNo=13948&MevzuatTur=7&MevzuatTertip=5 (önceki yazarın curl ile aldığı, RG-28/2/2026 değişikliğini içeren güncel metinden okundu) |
| Kayıt dondurma örneği: akademik takvime bağlı son gün; talebi Öğrenci İşleri değerlendirir; dondurulan yarıyılda derse kaydolunamaz | Karabük Üni. yönetmeliği m.27/1–2 — https://www.mevzuat.gov.tr/anasayfa/MevzuatFihristDetayIframe?MevzuatTur=8&MevzuatNo=38896&MevzuatTertip=5 . Yazıda açıkça "bir örnek" diye etiketli |
**Çıkarım olan cümleler (kaynakta bu kelimelerle yok):** (a) "kural 'kayıt olsun veya olmasın' diye yazıldığı için kaydının durumu bunu değiştirmez" — `mezuna-kalmak…` yazısındaki aynı çıkarım; (b) "2026 kılavuzlarındaki kural aynı kalırsa her yeni yerleştirme bir sonraki yılın sınavı için OBP bedelini yeniden doğurur" — koşullu yazıldı; (c) "kaydı sildirirsen kayıtlı öğrenciye açık iki yatay geçiş kapısı kapanır" — A.7 ve m.11/2'nin "kayıtlı" şartından; (d) "yerleşemezsen kayıtla ilgili yapman gereken bir işlem doğmaz" — kılavuz yalnızca yeni kayıt anına şart koyduğu için.
### Çıkarılan / yazılmayan iddialar
- **Yerleşip yeni programa kayıt yaptırmayan öğrencinin eski kaydının durumu:** kılavuzda hüküm yok → "eski kaydın yerinde durur" ya da "silinir" **yazılmadı**; şema düğümü ve SSS yalnızca "ilişik kesme şartı doğmaz" diyor.
- **Kayıt sildirmenin geri dönüşü:** "geri dönüş yok" diye kural cümlesi kurulmadı (kaynak okunmadı); tablo "geri dönüş varmış gibi plan kurma, öğrenci işlerine yazılı sor" diyor.
- Kayıt dondurulmuşken Ek Madde-1 / yatay geçişe başvurulabilir mi; "YKS'ye hazırlık" gerekçesi kabul edilir mi; dondurulan dönemde katkı payı/ücret: kaynak yok → yazılmadı (SSS'de "genel cevabı yok" denildi).
- Eski bölümde geçilen derslerin yeni bölümde saydırılması (muafiyet/intibak): teyit yok → yalnızca "öğrenci işlerine sor" listesinde anıldı.
- Ek Madde-1 güz başvuru tarihleri (A.10: 1–15 Ağustos), %30/90 kontenjan ayrıntısı: ilki CEO'nun "tarih yok" kuralı, ikincisi tekrar olmasın diye alınmadı.
- İkinci üniversite/açıköğretim, farklı düzeylerde eşzamanlı öğrenim (kılavuzdaki Anadolu Üni. esasları), askerlik/tecil, KYK/burs-yurt etkisi, harç/ücret rakamı, 2027 takvimi: kapsam dışı/teyitsiz → yazılmadı.
- Plan taslağındaki GEO cümlesinin ikinci yarısı ("eski kaydını sildirerek yenisine kayıt olur") kılavuzun kelimesine çekildi: "ilişiğini kesmen gerekir".
### Yayın öncesi kontrol listesi (Bilal)
1. **Kaynaklar'daki linkleri aç, üç kural cümlesini gözle teyit et:** YKS Kılavuzu b.10 (ÖSYM'deki **asıl PDF'te**) ve 23. alan kod 6; YÖK ilkeleri A.7, A.17, A.20, A.21; Yönetmelik m.6/1, m.11/1–2, m.23/1.
2. Şemayı gör: 13 düğüm, bu setteki en uzun şema. `mermaid.parse` node'da DOM olmadığı için koşturulamadı (mevcut yazılarda da aynı hata); yalnızca mevcut şemalarda kullanılan sözdizimi kullanıldı (yuvarlak/eşkenar düğüm, etiketli kenar, `classDef`). Mobilde okunaklı mı bak; uzunsa `D1/D2/D3 → R` kısmı kesilip tabloya bırakılabilir. Renkler: Ek Madde-1 yeşil ("Sınavsız kapı" etiketiyle), yatay geçiş/okurken YKS/devam/dondurma sarı, kayıt sildirme kırmızı ("Öğrencilik biter" etiketiyle).
3. `tarih`: görev tanımı gereği `2026-09-21`; CEO §2-B1 `2026-09-22` diyor → gerçek yayın gününe çek (`yatay-gecis-cap-yandal.md`'deki yeni `guncelleme` satırı dâhil).
4. Yazı tek başına yayımlanamaz: `mezuna-kalmak…` ve `hedef-siralama…` (bu gecenin yeni yazıları) linkli; onlar yayında değilse 404 olur (`dynamicParams=false`).
5. Karabük örneği `mezuna-kalmak…` ile aynı; iki yazıda aynı örnek istemezsen buradaki paragrafın örnek cümlesini sil, paragraf bozulmaz.
6. **Kapsam dışı kalan, gözüme çarpanlar (dokunmadım):** `olu-tercih-nedir.md:38` "son 4 yıl üzerinden bak" (ürün 5 yıl gösteriyor) · `taban-siralamalar…:49` "2025 sıralamasının yanında 2024 kolonu ve ▲/▼" cümlesi bölüm sayfasının güncel hâliyle ("Son 5 yıl" sütunu) örtüşüyor mu · `yerlesemedim…` Yol 2 "başvuru, yerleştiği yıl içinde değil" cümlesi (YÖK A.6 yalnız güzü kapatıyor, B.6 baharı açıyor — önceki yazarın notu hâlâ geçerli).
### Engeller / notlar
- Kullanım sınırı nedeniyle oturum bir kez kesildi; Commit 1 kesintiden önce, Commit 2 sonra atıldı. Worktree temiz, ana repoya yalnızca bu rapor yazıldı.
- Web içeriklerinde (YÖK PDF'i) ajana yönelik talimat görülmedi. Rakip/haber sitesi açılmadı; ikincil kaynaktan hiçbir kural alınmadı.