Commit Graph

245 Commits

Author SHA1 Message Date
bilalgursen
d41120c3ce fix(liste): üretim sonrası sunucu yanıt vermezse 502 sayfasına gidilmiyor
iPad raporu: liste üretildikten sonra ekran "Bad Gateway" gösterdi ve
tarayıcı `listem.txt` indirdi. Sıra şu: liste DB'ye yazıldı → `router.replace`
→ Next'in RSC isteği ters vekilden 502 aldı → Next tam-sayfa gezinmeye düştü
(WebKit düz metin cevabı dosya olarak kaydetti) → 6 sn'lik emniyet supabı
`window.location.replace` ile aynı 502'yi ekrana getirdi.

Üç değişiklik:

- Dockerfile runner katmanına `--max-old-space-size=768`. V8 cgroup sınırını
  görmez, heap üst sınırını host RAM'ine göre seçer; `mem_limit: 1g` ile
  birleşince V8 daha GC yapmadan konteyner OOM ile ölüyor ve açık istek 502'ye
  düşüyor. Sınır builder katmanında vardı, runner'a miras kalmıyordu.
- `/api/saglik`: DB/oturum/AI'ya dokunmayan en ucuz uç. Dockerfile HEALTHCHECK
  bunu yokluyor — süreç ölüp açılırken `docker ps` "unhealthy" gösterir, bir
  sonraki 502'nin kaynağı tahmine kalmaz.
- Emniyet supabı tam-sayfa gezinmeden önce sunucuyu yokluyor. Sunucu yoksa
  ekranda kalınıp "listen oluşturuldu ve kaydedildi, kredin yeniden harcanmaz"
  ekranı + sunucuyu yeniden yoklayan buton gösteriliyor; `liste_uretim_hata
  {kod:"SUNUCUYA_ULASILAMIYOR"}` olayı düşüyor. Sunucu yokken `router.refresh`
  de aynı tuzağa düştüğü için o dalda atlanıyor.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 01:08:18 +03:00
bilalgursen
cc46244206 fix(ui): iPad'de progressive blur kaydırmada ortaya kaymıyor
Site geneli üst/alt blur katmanları `position: fixed` + `backdrop-filter`
taşıyordu. iOS/iPadOS WebKit (iPad'de Chrome da WebKit) bu birleşimde
bulanıklığı ayrı kompozit katmana alıp scroll sırasında bayat kaydırma
konumuyla çiziyor; katman ekranın ortasında şerit gibi görünüyordu.

Katmanların stili skiper-ui bileşeninin inline stilinden globals.css'teki
`.kt-sayfa-blur`a taşındı (inline stil `@supports` ile ezilemiyordu).
`@supports (-webkit-touch-callout: none)` yalnızca iOS/iPadOS'ta eşleşir —
masaüstü Safari dahil başka hiçbir tarayıcıda desteklenmez — ve orada
bulanıklık + maske düşer, degrade fade korunur. Geometri (112px, z-40,
print:hidden) ve diğer tarayıcılardaki görüntü değişmedi.

Katalogdaki ProgressiveBlur kullanımları `absolute` olduğu için bu hatadan
etkilenmiyor; bileşen onlar için olduğu gibi kaldı.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-22 01:08:01 +03:00
bilalgursen
507bf53a95 feat(seo): kapanan 28 bölüm + 2 üniversite sayfası benzer sayfaya kalıcı yönlendirilir
All checks were successful
Deploy / deploy (push) Successful in 6m50s
Arşivlenen slug'lar 200 + 'sayfa yok' dönüyordu (soft 404). Eşlemenin tek kaynağı
src/lib/kapanan-sluglar.ts; alt yollar (/sayfa/N) hedefin köküne gider; zincir ya da
çift kaynak build'i durdurur. Yıllık güncelleme kılavuzuna 5b adımı eklendi.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 23:34:52 +03:00
bilalgursen
992a01abf1 feat(katalog): başlığın altında kompakt sıra giriş satırı (alttaki kart yerinde)
Katalog 464 oturum → 12 sıra girişi; kart tablonun altında kalıyordu. CtaSiraForm'a
varyant="kompakt" + konum prop'u; olay adları aynı, konum: ust|alt özelliği eklendi;
alan kimlikleri useId ile (aynı sayfada iki form).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 23:34:52 +03:00
bilalgursen
ea3310ac5b fix(liste): üretim sonrası ekran listeye kesin geçer
replaceState + router.refresh() ikilisinde Next yönlendirici kuyruğu refresh'i
hiç çalıştırmıyordu (ekran 'Listen hazırlanıyor'da kalıyor, yenileyince geliyordu).
Tek router.replace; 6 sn emniyet supabı (tam yükleme); 90 sn'de 'hâlâ hazırlanıyor'.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 23:34:52 +03:00
bilalgursen
c2ec6d3102 content(anasayfa): karşılaştırma tablosu rakipler hakkında genelleme yapmaz
Bazı ücretsiz robotlar artık yapay zekâ sohbeti/dengeli liste sunuyor; ✗ yerine
"Bazılarında" / "Danışmana göre". İki ayırt edici satır eklendi (resmî kayda
dayanma, yöntemin açık olması). Sorun kartı ve SSS cevabı aynı çizgiye çekildi.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 23:34:52 +03:00
bilalgursen
95bc87e5f7 fix(paket): girişsiz ziyaretçide boş sayfa — kart gövdesi statik kabukta, yalnız CTA dinamik
Kök neden: React Flight ~3,2 KB'ı aşan dinamik parçayı ayrı satırlara bölüyor;
PPR resume bunlara verdiği segment kimliğini kabukta geç tamamlanan sınırın
(kök loading.tsx) kimliğiyle çakıştırıyor (S:3 iki kez) → HierarchyRequestError.
Lokal prod build'de yeniden üretildi, düzeltmeden sonra 5/5 temiz.
Girişsiz CTA metni: "ilk 3 tercihini ücretsiz gör" (sayılar sabitlerden).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 23:34:52 +03:00
bilalgursen
3cf8ec94a0 fix(veri): tadımlık örneği canlı tabanı gösterir; sunucudan gelen liste riskleri yeniden hesaplanır
Yayın sonrası denetim (2026-09-21):
- tadımlık havuzu snapshot'ı 2025 tabanını taşıyordu: örnek satır 'Tıp ~5.118,
  az riskli' derken aynı sayfadaki tablo 4.481 gösteriyordu. Taban ve sıra
  geçmişi artık okuma anında canlı DB'den; güncel kılavuzdan çıkmış program
  örnek gösterilmez (sıradaki kategoriye düşülür)
- sunucuylaBirlestir riskleri her zaman yeniler: sunucu kaydı taze taban +
  başka cihazın bayat riskini taşıyabiliyordu

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 20:06:35 +03:00
bilalgursen
49683fa113 fix(liste): kayıtlı manuel liste tabanları yeni veri yılına tazelenir; yıl metinleri 2021–2026
All checks were successful
Deploy / deploy (push) Successful in 7m24s
Denetim bulgusu (2026-09-21): ManuelTercih.efektifSira ekleme anının
snapshot'ıydı; 2026 verisi yüklenince /listem 2025 tabanıyla renk verirken
/sonuc tablosu 2026 gösteriyordu ve hiçbir yol yenilemiyordu.

- db.ts: efektifSiralarGetir(ids) — güncel COALESCE(sira2026, sira2025).
- liste-actions: listeTabanlariniTazele (oturumsuz, ≤24 id); sunucu kaydı
  (listeSenkronla/listeyiKaydet) tazelenmiş yazılır.
- liste-store: tabanlariGuncelle — efektif sıra + profil varsa risk yenilenir,
  arşivlenmiş program eski değerini korur, değişiklik yoksa yayın yok.
- liste-senkron: girişli/girişsiz herkes için sekme oturumu başına bir kez
  (anahtar SON_YIL taşır).
- meraklisina-icerik: "son beş yılın" → VERI_YIL_SAYISI.
- rehber (4 yazı): katalog sayfalarını anlatan "2021–2025 / son 5 yıl"
  ifadeleri 2021–2026 / son yıllar; yazıların kendi örnek tabloları
  2021–2025 olarak etiketli kaldı.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 18:59:05 +03:00
bilalgursen
3e75a6fbbd fix(rapor): yazdırma dipnotundaki yıl aralığı raporun üretildiği veri penceresinden
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 17:05:14 +03:00
bilalgursen
2356e8aa38 merge: veri/2026-pc~1 — metinler ve meraklısına şeması ([Bilal] başlık-2027 commit'i hariç) 2026-09-21 17:04:25 +03:00
bilalgursen
1879ffa326 merge: veri/2026-pb — okuyan taraf yılsız Program tipine geçti 2026-09-21 17:04:25 +03:00
bilalgursen
54be4d14db merge: veri/2026 — P-0 yıl sözleşmesi + P-A veri betikleri 2026-09-21 17:04:12 +03:00
bilalgursen
ceeb70375d feat(veri): bileşenler yılsız Program'a ve veri-yillari sözlüğüne geçti (P-B b)
- SiraSerisi = { siraGecmisi, ilkYil? }; yardımcılar dizinin kendi son iki
  elemanıyla çalışır, yıl ilkYil + indeks. raporSiraSerisi diziyi doldurmaz:
  5 elemanlı eski raporlar 2024→2025 trendini göstermeye devam eder.
- Tablo başlıkları "Son ${VERI_YIL_SAYISI} yıl"; rapor listesi başlığı kaydın
  kendi pencere uzunluğunu söyler (eski rapor: 5).
- siraYiliEtiketi SON_YIL/ONCEKI_YIL'dan; bölüm/üniversite sayfa metinleri ve
  metadata SON_YIL, TERCIH_YILI, BASLIK_YILI sözlüğünden.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 17:00:39 +03:00
bilalgursen
ce40b7c5b3 feat(veri): Program tipi yılsız — db eşleyicisi, lib ve snapshot ilkYil (P-B a)
Program artık siraGecmisi (YILLAR ile hizalı) + efektifSira + siraSon/puanSon/
kontenjanSon/yerlesenSon taşır. db.ts kolonları YILLAR'dan üretip takma adla
seçer, programSatiri eşleyicisi ham satırı Program'a çevirir; SELECT_COLS'un
üç tüketicisi de eşleyiciden geçer. EFEKTIF_SIRA veri-yillari'dan gelir.

- trend: ILK_YIL tek kaynaktan, opsiyonel ilkYil parametresi
- rapor snapshot'ına opsiyonel ilkYil yazılır (eski kayıtlar: okurken ILK_YIL)
- rapor promptu son 4 yılı göndermeye devam eder, anahtarlar dinamik
- tadımlık "son N yıl" filtresi genel: N != VERI_YIL_SAYISI ise servis edilmez
- veri-kapsami VERI_YIL_SAYISI'nı veri-yillari'dan türetir

Bileşenler bir sonraki commit'te yeni tipe geçer (ikisi birlikte derlenir).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 17:00:39 +03:00
bilalgursen
590fea749d docs(meraklisina): aday havuzu kuralı — yalnız en son tercih kılavuzundaki programlar
Bilal kararı (21 Eylül 2026): kılavuzda artık olmayan eski program kayıtları
siteden kalkar; havuza yalnız son kılavuzda yer alan programlar girer.
Şema düğümü (H), aria-label, figcaption ve 4. bölüm paragrafı birlikte
güncellendi (AGENTS.md şema senkronu).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 16:54:45 +03:00
bilalgursen
3fa5cab906 feat(veri): katalog/OG/rapor metinleri yılı veri-yillari.ts'ten okur — 2026 yüklemesi P-C
- "2025 yerleştirme" → SON_YIL, "2026 tercihleri" → TERCIH_YILI, başlık yılı → BASLIK_YILI
- yazdırılabilir rapor dipnotu: "2021–2025" → VERI_ARALIGI
- meraklısına 1. bölüm: efektif sıra açıklaması yılsız
- KATALOG_VERI_TARIHI: 2026-09-21 (2026 verisinin çekim tarihi)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 16:53:42 +03:00
bilalgursen
024a2a49c4 fix(odeme): önce kredi sonra paid damgası; çift pakette iade akışı; UNIQUE tespiti
All checks were successful
Deploy / deploy (push) Successful in 8m50s
- odemeyiSonuclandir krediyi yazıp sonra paid damgalar; araya kesinti girerse
  sipariş pending kalır ve yeniden denenir (eskiden: paid görünür, kredi yok).
  paid + deftersiz eski siparişler ilk ziyarette onarılır
- paket tek seferlik: grantCredits({ paketTekil }) zaten paketliye yazmaz
  (kontrol UPDATE'in WHERE'inde). Sipariş paid damgalanır, senkron log +
  destek@ e-postası, /odeme/sonuc 'Bu ödeme iade edilecek' kartı, /kosullar#iade
- drizzle DrizzleQueryError üst mesajında 'UNIQUE' yok → idempotent no-op yerine
  hata fırlıyordu (grant + iki spend yolu); cause zincirine bakılıyor
- callback geçici DB hatasında 500 yerine sonuç sayfasına yönlendirir
- krediKaydiVarMi (reason, ref_id) indeksini kullanır; haftalık mutabakat sorgusu

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 16:36:24 +03:00
bilalgursen
38e02e0ed9 feat(veri): yıl kapsamı tek kaynağı (veri-yillari.ts) — 2026 yüklemesi P-0
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 16:35:24 +03:00
bilalgursen
8f4669e31d fix(odeme): action redirect fırlatmaz, hedef döndürür + çift paket çekimine sunucu koruması
All checks were successful
Deploy / deploy (push) Successful in 8m46s
- baslatOdeme { error } | { yonlendir } döndürür; SatinAlForm client'ta
  router.push yapar (cacheComponents altında geri dönüşte buton tıklamaya
  sağır kalıyordu); tıklamada ok → dönen halka
- paketi olan yeniden 'paket', paketi olmayan 'topup' başlatamaz
- /odeme, paket alınmışken eski bekleyen paket siparişinin formunu göstermez

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 16:13:30 +03:00
bilalgursen
d7c29ac4a6 merge: entegrasyon/guvenli-etiket — görünen 'Garanti' dilim adı 'Güvenli'
# Conflicts:
#	src/features/sihirbaz/components/cta-sira-form.tsx
2026-09-21 16:13:04 +03:00
bilalgursen
bf6aee1fbe fix(giris): callback'te protokol-göreli adres reddi (açık yönlendirme)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 16:12:24 +03:00
bilalgursen
f05f3e0c69 fix: p7/p4 denetim bulguları — derin sayfa sıra yılı ve başlık uzunluğu, giriş sayacı, rybbit host
- derin /bolum ve /universite sayfalarında sıra aralığı hangi yıldan geldiğini
  söyler (2025 / 2024 / 2024–2025); 2024 sırası '2025 verisi' diye sunulmaz
- <title> yuvarlanmış rakamlarla ve şablon eki olmadan ≤~86 karakter
- giriş formunda tek geri sayım interval'i (çift sayaç butonu erken açıyordu)
- RYBBIT_HOST sonundaki '/' atılır

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 16:12:11 +03:00
bilalgursen
271e01e1dc merge: origin/gece/p7-katalog (gece vardiyası 2026-09-21) 2026-09-21 16:10:37 +03:00
bilalgursen
977db40099 merge: origin/gece/p4-eposta (gece vardiyası 2026-09-21) 2026-09-21 16:10:37 +03:00
bilalgursen
f7ed8f2f0b fix: denetim bulguları — çip adı sahte 'tercihlerin değişmiş', çekmece kartı, senkron riski
- tercihFarki eski 'İş garantisi' parametresini yeni ada eşleyerek kıyaslar;
  ad değişikliği 3 kredilik güncelleme çağrısı üretmesin
- çekmece kartı yalnız profil yokken sıra ister, butonu sıra kapısını açar
  (profilsiz ziyaretçi /listem giriş duvarına gönderilmiyordu → çıkmaz)
- sunucuylaBirlestir risksiz gelen kayıtların riskini doldurur
- /paket'teki fiyat kıyasına kaynak satırı

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 16:06:15 +03:00
bilalgursen
5853b7d091 feat(etiket): görünen "Garanti" dilim adı site genelinde "Güvenli"
Yalnız kullanıcıya görünen etiket değişir; iç anahtar, tip, DB değeri, API
parametresi, mermaid classDef ve analitik değeri `garanti` olarak kalır
(veri göçü yok).

- risk.ts: tek kaynak DILIM_ETIKET + dilimdenFarkliRiskEtiketi; rapor
  listesi, yazdır tablosu, /sonuc sekmeleri, seçimlerim paneli ve
  meraklısına şeridi buradan okur
- "Güvenli · Güvenli" / "Güvenli (Güvenli)": satır detayında risk etiketi
  yalnız dilimin varsayılanından farklıysa, yazdır ve seçimlerimde yalnız
  kelime farklıysa yazılır
- LLM prompt'ları: `garanti` teknik anahtar, adaya "güvenli" denir sözlüğü
  (rapor, soru, tadımlık); liste özeti modele görünen dilim adıyla gider
- meraklısına şeması (SEMA düğümü, aria-label), 2. bölüm anlatımı ve
  AGENTS.md şema kuralı görünen adla eşitlendi
- "yerleşme garantisi vermez" türü vaat reddi cümleleri aynen kaldı

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 16:03:22 +03:00
bilalgursen
0400aa5d77 chore(rehber): şema fontu lisanslı Sweet Cucumber yerine OFL Patrick Hand
Sweet Cucumber Mocktail yalnız kişisel kullanım için ücretsizdi; site ticari.
Patrick Hand (SIL OFL) next/font/google ile gelir, Türkçe glifler latin-ext'te.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 16:00:17 +03:00
bilalgursen
d79758adc0 perf: Lenis smooth scroll ve scroll skew efektini kaldır
Site geneli ScrollFlow sarmalayıcısı (Lenis lerp'li kaydırma + hıza bağlı
skewY) tüm sayfa katmanını her karede transform'luyor, kaydırma performansını
düşürüyordu. Yerel tarayıcı kaydırmasına dönüldü; bölüm çapaları mevcut
scroll-mt değerleriyle çalışmaya devam eder. lenis bağımlılığı ve
data-lenis-prevent işaretleri temizlendi.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 15:31:11 +03:00
bilalgursen
294fb2cf6a chore(metin): 'İş garantisi' çipi → 'İş bulma kolaylığı'; gizlilikte Rybbit kimlik verisi
- Sihirbaz öncelik çipi vaat diliyle çelişmesin; eski kayıtlı profillerdeki
  seçim yeni ada eşlenir (doğrulamada düşmesin).
- Gizlilik metni: giriş yapan kullanıcının e-posta ve adının kendi
  sunucumuzdaki analitik aracına kaydedildiği açıkça yazıldı (gönderim sürüyor).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 15:29:43 +03:00
bilalgursen
f17ee48a88 fix(liste): profilsiz + sonrası riskler her profil yolunda dolsun
P6'nın bilinen eksiği: riskleriYenile yalnız kapı tamamlanınca çağrılıyordu;
profil hero/CTA formu, sihirbaz ya da giriş senkronuyla yazılınca önceden
eklenenlerin riski null kalıyor, /sonuc haritasında yanlış renkle pinleniyordu.
Liste deposu artık açılışta ve her PROFIL_DEGISTI_EVENT'te riskleri yeniler.
Çekmece alt kartı da riski hesaplanmamış listede analizi 'hazır' diye duyurmaz.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 15:29:04 +03:00
bilalgursen
97952f6e06 chore(metin): danışman fiyat kıyası Armut ortalamasına göre (1.000–3.000 TL)
52520ac temel alındı; rakam Armut'un 'YKS Tercih Danışmanı Fiyatları'
sayfasındaki ortalama fiyatla (1.000–3.000 TL, 21.09.2026'da açılıp
okundu) eşitlendi, kaynak satırı tarihlendi. 'Onda bir' söylemi kalktı.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 15:27:51 +03:00
bilalgursen
899d29af04 chore(guven): hero'da YÖK logosu yerine tarihli veri satırı [Bilal onayı gerekir]
Footer "ÖSYM veya YÖK ile bağlantılı değildir" derken hero'daki kamu kurumu
logosu resmî onay iması taşıyordu. Aynı bilgi kutusu (sınıflar aynen) artık
logo + ayraç yerine metin satırı gösteriyor:
"Veri: YÖK Atlas · son güncelleme <time>9 Ağustos 2026</time>".
- veri-kaynagi.tsx: TARIH_METNI → export KATALOG_TARIH_METNI (tarih
  biçiminin tek kaynağı; katalog altı satırıyla birebir aynı biçim)
- page.tsx: next/image import'u kalktı, KATALOG_VERI_TARIHI seo import'una
  eklendi
- public/yok-logo.svg silinmedi (karar geri alınabilsin)

Yeni badge tasarlanmadı (mevcut kutu, pill değil). Bu commit diğer P3
commit'lerinden bağımsızdır (tek başına cherry-pick edilebilir).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 15:27:27 +03:00
bilalgursen
9a446df572 merge: origin/gece/p3b-tadimlik-dili~1 (gece vardiyası 2026-09-21)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 15:27:27 +03:00
bilalgursen
343fcf610a merge: origin/gece/p6-arti-aninda-ekle (gece vardiyası 2026-09-21)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 15:27:27 +03:00
bilalgursen
a834f5ff01 merge: origin/gece/p5-kapi-olcum (gece vardiyası 2026-09-21)
All checks were successful
Deploy / deploy (push) Successful in 8m3s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 15:07:25 +03:00
bilalgursen
dedf3561b3 merge: origin/gece/p2-olcum~1 (gece vardiyası 2026-09-21)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 15:07:25 +03:00
bilalgursen
1a87d89b5a feat(liste): ilk + profilsiz ziyaretçide anında eklesin [Bilal onayı gerekir]
PROTOTİP — Bilal telefonda bakıp karar verecek (CEO tur 2, karar #12).
Katalogdan +'ya basan 82 profilsiz oturumun 77'si 5 ekranlık kapıdan
dönüyordu (09-analitik-tur2, S6). Sıra tersine çevrildi: önce ver, sonra
iste.

- programEkleIste: profil yokken programı hemen ekler (sıra bilinmiyorsa
  risk null), kapıyı açmaz; dönüşe `profilsiz` eklendi.
- Buton: program_eklendi {kaynak, yol: "dogrudan", profilli: evet|hayir}.
  Profilsiz eklemede sonner toast (sabit id, 8 sn): "Seçtiklerine eklendi"
  + "Sıralamamı gir →" aksiyonu → profilToplamaAc(null, true,
  "arti_toast") (tanıtım ekranı atlanır). KapiTetik'e "arti_toast".
- Profil kapıdan girilince mevcut profilTamamlandi → riskleriYenile null
  riskleri doldurur (yeni kod yok).

Kapı bileşeni, sihirbaz adımları, SEMA ve meraklisina-icerik değişmedi
(+ kapısı şemada yok → senkron kuralı tetiklenmez). Geri almak için bu
commit'i revert etmek yeterli; K1 ölçümü (gece/p5-kapi-olcum) bağımsız.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 09:24:51 +03:00
bilalgursen
f1abedccee feat(katalog): CTA kartında vaatsiz başlık + köprü cümlesi, /bolum sayfasına CTA
CtaSiraForm'a isteğe bağlı `aciklama` prop'u (yalnız profilsiz karttaki
paragrafın yerine geçer; varsayılan paragraflar aynen kaldı). "Sıralamanla
nereye yerleşirsin?" / "…programlarına yerleşir misin?" başlıkları kalktı:
varsayılan "Sıralamana yakın programlar hangileri?", katalogda
"Sıralaman {ad} tabanlarının neresinde?".

Üniversite ve bölüm sayfaları aynı köprü cümlesini tek sabitten
(KATALOG_CTA_ACIKLAMA) alır; kart /bolum/[slug] sayfasına üniversite
sayfasıyla aynı konumda (liste + sayfalama altı, mt-10) eklendi.
cta_form_goruntulendi ölçümü ve buton deseni değişmedi.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 09:24:32 +03:00
bilalgursen
4dfb24bb13 feat(seo): derin katalog sayfalarında başlık/açıklama/H1'i sayfanın içeriğiyle ayrıştır
/bolum/*/sayfa/N: title + description + H1 o sayfanın taban sırası aralığını
taşır (dilimdeki min–max efektif sıra; veri yoksa "taban verisi olmayan
programlar"). Görünür breadcrumb üniversite sayfasındaki desenle eşitlendi
(üst bölüm linki + "Sayfa N").

/universite/*/sayfa/N: description + giriş paragrafı o sayfadaki birim adlarını
sayar (ilk 2 + "ve N birim daha"); dilim tek birimden ibaretse birim içi taban
sırası aralığı eklenir. <title> uzunluk nedeniyle değişmedi.

Dilim hesabı tek yardımcıda (sayfaDilimi); metadata ve gövde aynı hesabı
kullanır. Canonical, robots, sitemap, rota dosyaları ve 1. sayfaların
başlık/açıklaması değişmedi.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 09:22:59 +03:00
bilalgursen
79bc7fa8be fix(ai): tadımlık trendi deterministik + gerekçe dil filtresi
cae2aaa yalnız riskNotu'yu deterministik yapmıştı; aynı satırın gerekce ve
trendOzeti alanları DB'deki eski LLM metni olarak servis ediliyordu (lokal
havuzda 89 satır "Son 4 yıl…", 13+ satır "yerleşme olasılığı/ihtimali").
Oradaki "olasılık dili sızamaz" yorumu yanlıştı; düzeltildi.
- yeni src/lib/trend.ts: trendOzetiMetni() saf fonksiyonu — rapor.ts'teki
  trendOzetiUret gövdesi buraya taşındı, rapor ve tadımlık aynı kaynaktan
  okur. Yıl aralığı serideki dolu yıllardan gelir ("2021-2025 arasında…")
- trend cümlesinden tahmin yargısı çıktı: "bölüm zorlaşıyor" → "taban
  sıkılaştı", "yerleşmek görece kolaylaşıyor" → "taban gevşedi". ±%10
  eşiği, ilk–son yıl mantığı, 5/13/6 ve LLM şeması/prompt'u aynı
- tadimlikSec(): DB'deki trendOzeti servis edilmez; program.siraGecmisi'nden
  okuma anında üretilir (alan yoksa "yeterli geçmiş yıl verisi yok")
- tadimlikSec(): gerekce olasılık/ihtimal/şans/garanti/kesin/yüzde/
  "yerleşirsin"/"son 4 yıl" içeriyorsa satır yok sayılır → "genel"
  kategoriye düşer, o da takılırsa null (tadımlık gizlenir). Eşleşme
  Türkçe küçük harfle yapılır (İ/ı)
DB satırları, şema ve script'ler değişmedi.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 09:22:40 +03:00
bilalgursen
643e41cc98 fix(analitik): kullaniciTanit script'ten önce sessiz no-op olmasın
Erken olay kuyruğu yalnız olay() içindi; sert yüklemede (OAuth / e-posta
linki dönüşü) RybbitIdentify effect'i de script'ten önce koşuyor, identify
kayboluyor ve kuyruktan boşalan olaylar anonim profile yazılıyordu
(08-kod-denetimi #6).

- Tek "son değer" slotu (bekleyenKimlik): kuyruk değil, yalnız en son
  kimlik anlamlı. Yoklama zamanlayıcısı olay kuyruğuyla ortak
  (zamanlayiciyiBaslat); script 10 sn'de gelmezse slot da atılır.
- kuyruguBosalt kimliği olaylardan ÖNCE uygular.
- kullaniciTemizle slotu siler.

rybbit-identify.tsx'e dokunulmadı.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 09:22:10 +03:00
bilalgursen
67be93c394 feat(analitik): kapi_acildi + kapi_kapatildi olayları
Profil kapısının açılışı ve tamamlanmadan kapanışı doğrudan ölçülmüyordu;
"82 oturum kapıyı gördü" kod davranışından çıkarımdı (09-analitik-tur2).
İki yeni olay (adlar kalıcı sözleşme):

- kapi_acildi {tetik: arti|sonuc|sihirbaz|duzenle|diger}: depoda tek
  açılış noktası (kapiyiAc). Her açıcı kendi tetik'ini yazar:
  programEkleIste → arti, profilDuzenlemeyiAc → duzenle, profilToplamaAc →
  isteğe bağlı 3. parametre, verilmezse hedeften (sonuc/sihirbaz), o da
  yoksa diger. Depoya `tetik` alanı eklendi.
- kapi_kapatildi {adim: giris|sira|sihirbaz, tetik}: yalnız TAMAMLANMADAN
  kapanışta; kapı bileşeninde tek noktadan (vazgec) — X, dışarı tıklama,
  Esc ve "Vazgeç" butonları. Tamamlanan kapı profilTamamlandi ile depodan
  kapanır, bu noktaya uğramaz.

Ham sıra/e-posta olaylara girmez. Davranış değişmez.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 05:25:23 +03:00
bilalgursen
4b87a3e71e fix(analitik): program_eklendi yalnız gerçek eklemede atılsın
Olay, profilsiz ziyaretçide program listeye girmeyip profil kapısı
açıldığında da atılıyordu (kapiAcildi dalı else'e düşüyordu); seri
"ekleme"yi değil "+ tıklaması"nı ölçüyordu (09-analitik-tur2, S6).

- Buton: yalnız sonuc.eklendi iken {kaynak, yol: "dogrudan"}.
- profilTamamlandi: bekleyen program listeye girdiyse (ekle() true)
  {kaynak, yol: "kapi"}.
- OlayAdi yorumuna seri kırılması notu.

Davranış değişmez: profilsiz + hâlâ kapıyı açar.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 05:23:40 +03:00
bilalgursen
17046c830f feat(analitik): giris_basarili sunucu olayı
Oturum oluşturulduğunda (databaseHooks.session.create.after) Rybbit'e
sunucudan giris_basarili düşer; yontem = eposta | google | diger
(better-auth uç yolundan türetilir). Huninin "link istendi → giriş yapıldı"
adımı bugüne dek ölçülemiyordu.

- await yok: Rybbit'in 3 sn'lik timeout'u girişi geciktirmez; sunucuOlayi
  hata fırlatmaz. E-posta adresi olaya girmez, yalnızca kullanıcı ID.
- RYBBIT_HOST/SITE_ID/API_KEY yoksa no-op — prod .env.production'da bu
  üçü bugün yok (bkz. ayrı ci.yaml commit'i), eklenene dek olay düşmez.

Giriş akışının davranışını değiştirmez (yalnızca yan etki ekler).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 04:55:10 +03:00
bilalgursen
2af4a9f781 feat(giris): adres başına 60 sn soğuma
Aynı e-posta adresine 60 sn içinde ikinci giriş linki gönderilmez: istek
yine 200 döner (form "gönderildi" gösterir), mail çıkmaz. Üçüncü kişiye
mail bombardımanını ve Resend kotasının yakılmasını engeller; bugüne dek
tek sınır better-auth'un IP limitiydi (5 istek/60 sn).

- Kaynak süreç içi Map (globalThis.__girisEpostaSon), anahtar
  trim+lowercase adres. verification tablosundan türetilmez: orada
  identifier token'dır ve satır sendMagicLink'ten önce yazılır.
- Pencere kaymaz (düşen istek süreyi uzatmaz); her çağrıda eski kayıtlar
  budanır. Gönderim hata verirse kayıt silinir, kullanıcı hemen yeniden
  deneyebilir.
- Yalnızca NODE_ENV=production: dev paneli "anında giriş" art arda istek
  atıyor. Konsol modunda da işler (lokal docker testi).

Canlı giriş yolunu değiştirir; merge öncesi lokal docker testi şart.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 04:55:10 +03:00
bilalgursen
c055e8272c chore(gizlilik): rybbit identify yalnız kullanıcı ID
[Bilal onayı gerekir] Girişli kullanıcının e-postası ve ismi Rybbit'e
trait olarak gönderiliyordu. Artık yalnızca opak kullanıcı ID'si gider;
anonim → girişli oturum birleştirmesi aynen çalışır. Rybbit'te zaten
kayıtlı trait'ler bu commit'le silinmez (panelden ayrıca temizlenmeli).

Bu commit dalın en sonunda ve bağımsızdır: istenmezse
`git merge gece/p2-olcum~1` ile dışarıda bırakılır.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 04:50:04 +03:00
bilalgursen
e1bb4829fd fix(giris): 429 mesajı + 60 sn geri sayım
Hız sınırına takılan kullanıcı "Tekrar dener misin?" görüp sınırı
uzatıyordu; 429'da "Çok sık denedin, bir dakika sonra tekrar dene" denir.
"Yeniden gönder" geri sayımı 30 → 60 sn: sunucu tarafındaki adres başına
60 sn soğumayla hizalı (o değişiklik gelmese de zararsız).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 04:49:31 +03:00
bilalgursen
cf19903e19 feat(analitik): huni olayları
Huninin kör noktalarına altı olay (adlar kalıcı sözleşme):
- cta_form_goruntulendi: programatik sayfalardaki CTA kartı, yalnız
  profilsiz dalda (görünüm hook'u; sayfa ayrımı Rybbit pathname'inden)
- sira_form_hata {kaynak: hero|cta|kapi|duzenle}: facet isteği hatası;
  geçersiz sayı doğrulaması sayılmaz
- sonuc_goruntulendi {girisli, sira_kovasi}: /sonuc pathname'i maskeli,
  huni adımı bu olayla kurulur; oturum başına girişli/anonim birer kez
- paket_goruntulendi {kaynak: kilit|kredi_bitti|nav|diger}: sayfaya
  dokunmadan yeni paket/layout.tsx + client bileşenle; /paket linklerine
  ?kaynak= eklendi (listem kilit kartları, kredi-yetersiz, nav kredi pill'i)
- liste_uretim_hata {kod: HATA|ISTISNA}: AUTH/KREDI/PAKET dalları atmaz
- giris_hata {yontem: eposta|google, status}

Ham sıra ve e-posta hiçbir olaya girmez; sıra yalnız siraKovasi() ile.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-21 04:49:09 +03:00
bilalgursen
5992cf3637 fix(eposta): Reply-To + prod'da sessiz fallback yok
- Resend gönderimine replyTo eklendi (EMAIL_REPLY_TO, yoksa
  destek@kolaytercih.com) — mail.kolaytercih.com'un MX'i olmadığı için
  yanıtlar bounce oluyordu.
- epostaKonsolModu(): konsola yazma yalnızca anahtar yokken VE (dev'de ya
  da EPOSTA_KONSOL_FALLBACK=1 ile) geçerli. Production'da anahtar yoksa
  artık "gönderildi" dönmüyor, token'lı link loga yazılmıyor; gönderim
  anında net hata fırlatılıyor (better-auth 500 → formda hata toast'ı).
- Production'da EMAIL_FROM yoksa sessizce onboarding@resend.dev'e düşmek
  yerine hata. Env okumaları çağrı anında — next build etkilenmez.

Canlı giriş yolunu değiştirir; merge öncesi lokal docker testi şart.

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