14 yeni rehber yazısı (hepsi editör denetiminden geçti, 46 yazıda 829 iç link tarandı, 0 kırık hedef; 180+ DB rakamı yazıların kendi filtreleriyle yeniden koşuldu): taban-siralamalari-alti-yilda-nasil-degisti · kac-net-ile-hangi-bolum · siralama-bandlari-hangi-kapilar-acilir · ayni-bolum-farkli-universite-siralama-farki · hangi-bolumlerin-kontenjani-azaldi · yeni-acilan-bolumler-nasil-degerlendirilir · bilgisayar-mi-yazilim-muhendisligi-mi · kktc-universiteleri-okunur-mu · yapay-zekaya-tercih-sordum-guvenilir-mi · ek-madde-1-puanim-yetiyor-mu · universitede-ilk-hafta-ders-kaydi-muafiyet-kayit-dondurma · yks-2027-takvimi · rehber-ogretmenler-icin-veri-kaynaklari · bolumumu-sevmedim-hangi-kapilar-var İki canlı yazı düzeltildi: - veliler-icin-tercih-rehberi: veli diliyle kapanış; altındaki "sıralamanı gir" kutusu artık veliye ölü uç değil - bos-kontenjanlar-ne-anlatiyor: "birkaç yüz kişilik fark" aslında ~9 bin (ÖSYM 265.356 ↔ bizim 256.532); payda açıklaması tersti — ek kontenjan paydaya girseydi oran düşerdi. guncelleme alanı eklendi (sitemap lastmod). Kurallar (AGENTS.md): - Yayın sonrası arama motoru bildirimi: URL denetimi yalnız canlıda 200 dönen adrese; kota sayacı; mülk/hesap notu; sitemap grep kuralı - Yıkıcı git komutları yasak: reset/checkout --/restore/clean/stash - Tarayıcı açma: tasarımcı ve UX gerekli gördüğünde açabilir (yetenek için .claude/agents/tasarimci.md'ye tarayıcı araçları eklendi) docs/gece-vardiyasi/2026-09-22/ — 34 rapor: CEO kararları ve kapanış turu, marka/ödeme analizi, sıfır ödeme teşhisi, SEO konu planı, veri kalitesi, editör denetimi, CTO şartnamesi, yazılımcı ve güvenlik raporları, SABAH-OZETI. docs/ekip/YAYIN-KUYRUGU.md — Search Console bildirim kuyruğu. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
38 KiB
28 — CTO şartnamesi: G1, G3, G2+G5
Hazırlayan: CTO ajanı · Taban commit: 9bd448b (main, push edilmiş; origin/main == main).
Kaynak kararlar: 05-ceo-kararlari.md §3, 24-ceo-kapanis.md §A/§D, 04-sifir-odeme-teshisi.md Ö1–Ö5, 00-kurucu-brief.md ("sade ve basit, over-engineering yok").
Yöntem: yalnız okuma. Kod değiştirilmedi, commit atılmadı, pnpm install/build/typegen/tsc/lint koşulmadı (disk kısıtı — orkestratör talimatı). git status bu raporun yazımı dışında değişmedi.
İşaret: [D] bu gece açıp satırını doğruladığım kod · [Ç] koddan çıkarım (çalıştırılmadı).
Özet (5 madde)
- CEO'nun satır numaralarının çoğu tuttu, ikisi tutmadı.
rapor-actions.tsbu gece9bd448bile değişti: liste harcaması artık98-99/118-124değil153-158, iade212-217, revizyon harcaması285-290, revizyon iadesi339-344. Ayrıcagiris-karti.tsxsrc/features/auth/altında değil,src/features/kullanici/components/giris-karti.tsx. Aşağıdaki tüm atıflar9bd448büzerinde tek tek açılarak yazıldı. [D] - G3'ün gizli dördüncü satırı var.
spendCredits/grantCreditskoşullansa bilerapor-actions.ts:243ve:363'tekikredi: user.creditBalance - RAPOR_KREDIpaketliye düşmemiş krediyi düşmüş gibi gösterir; ayrıcatercih-degisti-modali.tsxpaketliye "Listemi güncelle — 3 kredi" yazmaya devam eder. Tek birmaliyetdeğişkeni dört yeri birden kapatıyor — kapsam bu kadar büyütülmeli, daha fazlası değil. [D] - G1'in CTA'sı için
?kaynak=allowlist'i şart./listem?uret=1&kaynak=tadimlikyazmadan önceuretim-basladi-olayi.tsx:25-41'dekiIZINLI_KAYNAKLAR'a"tadimlik"eklenmezse değer"bilinmiyor"a düşer ve bu değişikliğin ölçümü kaybolur. Dosyanın kendi notu bunu zaten emrediyor. [D] - İki sessiz build tuzağı var ve ikisi de G1'in metin işinde patlar:
rapor-maske.tsimport "server-only"(satır 6),credits.tsappdb'yi import ediyor (satır 2) — ikisi de"use client"olantadimlik-satiri.tsx'e import EDİLEMEZ. Yeni CTA cümlesiACIK_SATIR/DENEME_KREDISIsabitlerine uzanamaz; sayı gerekiyorsa cümle sayısız yazılır. [D] /meraklisinaşeması üç pakette de değişmiyor.huni-semasi.tsx'tekiSEMAyalnızca sihirbaz adımları, aday havuzu, 24'lük iskelet, filtre gevşetme ve havuz-dışı kuralını belgeliyor (satır 11-41). G1 sayfa sırası + CTA hedefi, G3 kredi muhasebesi, G5 metin değiştiriyor — hiçbiri bu beş şeyden biri değil. Yazılımcıhuni-semasi.tsx'e dokunmayacak. [D]
Dosya sahipliği tablosu
Paketler teker teker koşacak (disk), yine de kümeler ayrık tutuldu — dal sırası bozulsa bile çakışma olmaz.
| Dosya | G1 funnel/sonuc-ilk-ekran |
G3 odeme/paket-vaadi |
G2+G5 odeme/kasa-ve-metin |
|---|---|---|---|
src/app/sonuc/page.tsx |
✅ | ||
src/features/liste/components/manuel-harita.tsx |
✅ | ||
src/features/rapor/components/tadimlik-satiri.tsx |
✅ | ||
src/features/sihirbaz/sihirbaz-sabitler.ts |
✅ | ||
src/features/sihirbaz/components/sihirbaz-cagri-karti.tsx |
✅ | ||
src/features/rapor/components/uretim-basladi-olayi.tsx |
✅ | ||
src/features/rapor/rapor-actions.ts |
✅ | ||
src/features/rapor/components/listem-icerik.tsx |
✅ | ||
src/features/rapor/components/tercih-degisti-modali.tsx |
✅ | ||
src/features/odeme/odeme-actions.ts |
✅ | ||
src/features/odeme/components/satin-al-form.tsx |
✅ | ||
src/features/odeme/components/paket-satinal.tsx |
✅ | ||
src/features/kullanici/components/giris-karti.tsx |
✅ | ||
src/lib/analitik.ts |
✅ |
Hiçbir pakette yok (yasak listesi): src/features/rapor/components/liste-uretici.tsx (Bilal'in dosyası — 9bd448b ile commit'li ama gece kuralı gereği dokunulmaz), docs/ekip/BACKLOG.md, docs/ekip/KARARLAR.md, AGENTS.md, content/rehber/**, data/**, src/features/pazarlama/components/huni-semasi.tsx, src/lib/credits.ts.
Çakışma kararları
src/lib/analitik.ts→ G2'nin. G1'intadimlik_goruntulendiolayında bir seri kırılması yaratacağı doğru (olay bugün ~2.200 px aşağıdaydı, yarın ilk ekranda olacak; 30 günlük değer 0 →01-analitik-bulgular), ve bu repoda seri kırılmasınıanalitik.ts'inOlayAdiyorumuna yazma geleneği var (program_eklendi, satır 29-31). Buna rağmen G1 bu dosyaya dokunmaz: G2 aynı birliğeodeme_hataekliyor, iki dal bitişik satırlarda çakışır. G1 seri kırılmasını (a)tadimlik-satiri.tsx:100-102'dekiuseGorunumOlayiçağrısının üstündeki yoruma, (b) commit mesajına yazar. Kalıcı notunanalitik.ts'e taşınması backlog önerisi #B1.paket-satinal.tsxvetercih-degisti-modali.tsx→ G5/G3'ün, A2'nin değil. CEO'nun A2 paketi (odeme/paket-adi, "Tercih Dönemi Paketi" → "KolayTercih Paketi") bu iki dosyaya da girmek zorunda: ad 8 dosyada geçiyor ve ikisi bu dalların içinde (paket-satinal.tsx:64,tercih-degisti-modali.tsx:329) [D]. A2 CEO'nun sırasında 10. ve kesme sırasının başında; bu yüzden A2 en sonda koşar, G1/G3/G5 dalları yazıldıktan sonra taban alır. G1/G3/G5'teki hiçbir yazılımcı paket adına dokunmaz.liste-uretici.tsxkimsenin değil. G3 uygulandığında o dosyadakihasPaketdalı ("+30 kredi yükle") liste üretimi için ölü koda dönüşür (paketli artık hiçKREDIkodu alamaz, bkz. G3 adım 1). Bu doğru ama zararsız bir tutarsızlıktır; dosya Bilal'e ait olduğu için düzeltilmez, backlog önerisi #B2 olarak kaydedilir.
Tüm yazılımcılar için ortak kurallar
- Yalnız orkestratörün verdiği worktree + dalda lokal commit. Push yok, merge yok,
main'e commit yok. git add -A/git add .yasak. Yalnız kendi dosya kümenden, yol vererek ekle. Commit öncesigit status --porcelainçıktısında kümen dışında bir şey görünüyorsa dur ve raporla.- Doğrulama sırası:
pnpm exec next typegen && pnpm exec tsc --noEmit && pnpm lint. Dev sunucusu yok, tarayıcı yok,pnpm buildyok (disk ~5 GB; tam build'i Bilal sabah C3 komut bloğunda tek seferde alır). - Taze worktree'de
next typegenolmadantscbaseline'da kırıktır —PagePropsgibi global tipler.next/types'tan gelir. Kırmızı çıktıyı kendi değişikliğine yorma; önce typegen koş. - Worktree'de
node_modulessymlink'i Turbopack'te patlar — klon kullanılır (cp -Rc ../kolaytercih/node_modules node_modules). Kurulumu orkestratör yapar;pnpm installçalıştırma. next buildenv'siz koşar: modül yüklenirken env zorunlu kılan kod yazma. Bu üç pakette yeni env yok.- Next'e özgü bir API'ye dokunmadan önce ilgili dokümanı oku (her paketin altında yolu yazılı). Eğitim verisindeki Next bu sürüm değil.
- AGENTS.md: rozet gerekiyorsa
SectionEyebrow, CTA'da ikon metnin sonunda<ArrowRight className="size-4" aria-hidden />,Sparklesyok; modal kapatma çarpısıDialogContentvarsayılanı. Sihirbaz/liste mimarisi değişirse/meraklisinaşeması aynı commit'te — bu üç pakette değişmiyor (bkz. Özet #5), dokunma. - Uydurma sayı yok: ekranda görünen her rakam ya tek kaynak sabitten (
URUNLER,RAPOR_KREDI,ACIK_SATIR) gelir ya da hiç yazılmaz. - Rapor:
docs/gece-vardiyasi/2026-09-22/altına, orkestratörün verdiği numarayla; kabul kriterlerinin her birinin çıktısını yapıştır.
G1 · funnel/sonuc-ilk-ekran
Amaç: Ödeme öncesi tek gerçek önizleme (tadımlık) /sonuc'un ilk ekranında görünsün ve kullanıcıyı giriş sonrası listenin üretildiği yere göndersin.
Dal: funnel/sonuc-ilk-ekran · Taban: 9bd448b · Öncelik: 1 (kesilmez).
Dokunulacak dosyalar (tam liste)
| Dosya | Satır | Ne |
|---|---|---|
src/features/liste/components/manuel-harita.tsx |
67-80 | Boş placeholder yerine null |
src/app/sonuc/page.tsx |
100-118 | Tadımlık tablodan önce + yorum düzeltmesi |
src/features/sihirbaz/sihirbaz-sabitler.ts |
~165 (sonucHref yanı) |
listemUretHref export edilir (yeni fonksiyon, taşınma) |
src/features/sihirbaz/components/sihirbaz-cagri-karti.tsx |
20-26, 195, 231, 260 | Yerel listemUretHref silinir, import edilir |
src/features/rapor/components/uretim-basladi-olayi.tsx |
25-41 | IZINLI_KAYNAKLAR'a "tadimlik" |
src/features/rapor/components/tadimlik-satiri.tsx |
28, 100-102, 111, 114, 186 | CTA hedefi, seri-kırılması yorumu, first:mt-0, yanlış iddia |
Kapsam dışı (yazılımcı taşmasın)
- Maskenin kaç satır açtığı (
ACIK_SATIR = 3) — değişmiyor (24-ceo-kapanis R5). /sonuctablosunun sıralaması, filtreleri,<h1>eksikliği (A3 ayrı dal), Suspense fallback'inin iskeleti (sonuc/page.tsx:45-54) — fallback bugün de haritayı temsil etmiyor (pill + başlık +h-36+ tablo satırları =ProgramTablosu'nun başlığı), boş harita kalkınca yanlışlığı artmıyor. [Ç]- Tadımlığın başka yüzeylere (
/,/paket) taşınması. - Profil çerezi olmayan ziyaretçiye özel CTA dalı yazmak — bilerek yapılmayacak, gerekçesi aşağıda (Riskler #2).
huni-semasi.tsx,analitik.ts,liste-uretici.tsx.
Adım adım
1) Boş harita ilk ekranı işgal etmesin — manuel-harita.tsx:67-80
if (liste.length === 0) return null; Yorum da düzeltilir: bugünkü not "197 KB'lık il geometrisi inmesin diye placeholder alanı rezerve eder" diyor; yeni not, boş durumda hiç yer tutulmadığını ve ilk eklemede haritanın belireceğini söylesin. TercihHaritasiLazy zaten dynamic — ölçü davranışı değişmez. [D]
2) Tadımlık tablodan önce — sonuc/page.tsx:103-118
Yeni sıra: <ManuelHarita /> → <TadimlikBolumu … /> → <SonucProgramTablosu … /> → <SonucSihirbazi … /> → dipnot. Satır 100-102'deki "Sayfa hiyerarşisi: önce Türkiye haritası, sonra liste" yorumu yeni sıraya göre yeniden yazılır (neden: tadımlık ödeme öncesi tek gerçek önizleme, ilk ekranda durur; harita yalnız manuel liste doluyken görünür). Props değişmez, bileşenlerin içine dokunulmaz.
3) Tadımlık ilk eleman olduğunda tepede boşluk bırakmasın — tadimlik-satiri.tsx:114
className="mt-16 min-w-0" → className="mt-16 min-w-0 first:mt-0". Gerekçe: ManuelHarita null döndüğünde bu <section> main'in gerçek ilk DOM çocuğu olur (JSX yorumları DOM düğümü üretmez), :first-child eşleşir ve main'in py-12'si tek başına yeterli üst boşluğu verir; harita görünürken mt-16 aynen çalışır. Tek utility, koşullu prop yok. [Ç]
4) listemUretHref tek kaynağa — sihirbaz-sabitler.ts + sihirbaz-cagri-karti.tsx
sihirbaz-cagri-karti.tsx:25-27'deki yerel fonksiyon sihirbaz-sabitler.ts'e (sonucHref'in hemen altına) taşınır ve export edilir; üstündeki "uret=1 HER ZAMAN ilk parametre kalmalı — giris-karti.tsx funnel metnini startsWith("/listem?uret=1") ile seçiyor" yorumu da birlikte taşınır. Çağrı yerleri (:195, :231, :260) import'a çevrilir, davranış birebir aynı kalır.
Neden tek satırlık kopyala-yapıştır değil: bu sözleşmenin kopyası bugün üç dosyada yorum olarak yaşıyor (listem-icerik.tsx:48-50, sihirbaz-cagri-karti.tsx:22-24, giris-karti.tsx:28-31) [D]; dördüncü bir literal kopya, funnel metnini sessizce kaybettiren bir hata sınıfı açar. Taşıma 2 satır, riski sıfır.
5) Ölçüm yüzeyi allowlist'e — uretim-basladi-olayi.tsx:25-41
IZINLI_KAYNAKLAR'a "tadimlik" eklenir + tek satır yorum ("/sonuc'taki girişsiz tadımlık CTA'sı"). Dosyanın kendi kuralı: "Yeni bir üretim yüzeyi eklerken değerini önce buraya ekle, sonra href'e koy."
6) CTA doğru yere gitsin — tadimlik-satiri.tsx:111
const girisUrl = \/giris?callback=${encodeURIComponent(listemUretHref("tadimlik"))}`;Import satırı 28 düzeltilir:sonucHref**kaldırılır** (başka kullanımı yok →no-unused-varslint hatası verir),listemUretHrefeklenir;PROFIL_DEGISTI_EVENTkalır.onClick'teki olay("giris_cta_tiklandi", { kaynak: "tadimlik" })**aynen kalır** (mevcut seri korunur). Doğrulanmış zincir:/giriscallback'i/^/(?![/\])/ kalkanından geçer (giris-karti.tsx:18-19) ✅ · startsWith("/listem?uret=1")funnel metni korunur ✅ · dönüştelistem/page.tsx:29-31→ListemIcerik uret→ListeUretici üretimi kendiliğinden başlatır (liste-uretici.tsx:243-256`) ✅. [D]
7) Seri kırılması yorumu — tadimlik-satiri.tsx:100-102
useGorunumOlayi("tadimlik_goruntulendi", …) çağrısının üstüne 2-3 satır: olayın bu değişiklikten önce sayfanın ~2.200 px altında yaşadığı, sonrasında ilk ekranda olduğu, iki dönemin karşılaştırılamayacağı. (analitik.ts'e yazılmaz — çakışma kararı #1.)
8) Teslim edilmeyen iddia kalkar — tadimlik-satiri.tsx:186
24 satırın tamamı için giriş yap — 5 deneme kredin hazır → Giriş yap ve listeni oluştur (+ mevcut <ArrowRight className="size-4" aria-hidden /> aynen kalır — AGENTS.md CTA deseni).
Gerekçe: maske paketsize 24 satırın 3'ünün analizini açıyor (rapor-maske.ts:12, 28-46); "tamamı" teslim edilmiyor. Bu commit yeni vaat eklemez, yalnız yanlış olanı kaldırır. Üstteki <p>'deki "Bu, 24 satırlık Yapay Zeka listenden yalnızca bir örnek." cümlesi doğrudur ve kalır (üretilen liste gerçekten 24 satır).
9) [Bilal] commit'i — CTA'nın yeni vaadi (ayrı, en son commit)
Önerilen: buton Kendi listemi oluştur, alt satır (:174-176) Kredi kartı gerekmez · Google ya da e-posta ile 30 saniyede · Giriş sonrası liste hemen üretilir.
Kısıt: bu dosya "use client". ACIK_SATIR (rapor-maske.ts, import "server-only" satır 6) ve DENEME_KREDISI/RAPOR_KREDI (credits.ts, satır 2'de ./appdb import ediyor) import edilemez — build'i kırar. Sayı gerekiyorsa cümle sayısız yazılır; elle "3"/"5" yazmak yasak (tek kaynak kuralı). Commit en sona konur ki Bilal git reset --hard HEAD~1 ile tek hamlede düşürebilsin.
Kabul kriterleri (tarayıcısız, komutla)
# 1) Tadımlık tablodan önce (ilk sayı küçük olmalı)
grep -n "<TadimlikBolumu\|<SonucProgramTablosu$" src/app/sonuc/page.tsx
# 2) Boş harita hiç render edilmiyor
grep -n "liste.length === 0" src/features/liste/components/manuel-harita.tsx # 1 sonuç
grep -c "haritada belirir" src/features/liste/components/manuel-harita.tsx # 0
grep -c "haritada belirir" -r src/ # 0
# 3) CTA doğru hedefe gidiyor, eski hedef kalmadı
grep -n "listemUretHref" src/features/rapor/components/tadimlik-satiri.tsx # 1
grep -c "sonucHref" src/features/rapor/components/tadimlik-satiri.tsx # 0
grep -n "export function listemUretHref" src/features/sihirbaz/sihirbaz-sabitler.ts # 1
grep -c "function listemUretHref" src/features/sihirbaz/components/sihirbaz-cagri-karti.tsx # 0
# 4) Ölçüm yüzeyi allowlist'te
grep -n '"tadimlik"' src/features/rapor/components/uretim-basladi-olayi.tsx # 1
# 5) Teslim edilmeyen iddia yok
grep -rc "24 satırın tamamı" src/ # 0
# 6) Şema ve yasak dosyalar el değmemiş
git diff --name-only HEAD~N | grep -E "huni-semasi|analitik.ts|liste-uretici|credits.ts" # boş
# 7) Tipler ve lint
pnpm exec next typegen && pnpm exec tsc --noEmit && pnpm lint
Ek el kontrolü (dosya:satır okuyarak): TadimlikBolumu girişli kullanıcıda ve havuz boşken hâlâ null dönüyor (tadimlik-bolumu.tsx:18-21 değişmedi) · ManuelHarita liste doluyken haritayı aynen render ediyor.
Riskler ve tuzaklar
sonucHrefimport'unu silmeyi unutmak → lint kırmızısı. (Adım 6.)- Profil çerezi olmayan ziyaretçi.
/listem?uret=1, seçim yoksa "profil-yok" → boş durum + sihirbaz CTA'sı gösterir (liste-uretici.tsx:243-251); kredi harcanmaz, hata ekranı çıkmaz [D]. Bu durum yalnızca eski?sira=linkiyle gelen ziyaretçide oluşabilir, çünkü geçerli bir profiltercihProfiliDogrulagereği en az 1 ilgi alanı içermek zorundadır (sihirbaz-sabitler.ts:90, 143-145) [D]. Bu yüzden CTA'ya koşullu ikinci bir dal yazılmayacak — kurucunun "over-engineering yok" kısıtı. - Giriş dönüşünde onaysız 3 kredi.
giris-linki.tsx:13-16navbar butonu için bunu bilerek yasaklıyor; burada sorun değil çünkü kullanıcı "listemi oluştur" diyen bir CTA'ya açıkça tıklıyor ve bu,hazir_cta(sihirbaz-cagri-karti.tsx:260) ile birebir aynı, onaylı desen. [D] CTA metni bu yüzden üretimi söylemeli (adım 8-9). - Layout kayması: boş harita
nulliken ilk "+" tıklamasında harita belirir ve tablo aşağı iner. Bugün de placeholder→harita geçişi var; kaybı kabul edilen bilinçli takas (CEO §3 G1-b). tadimlik_goruntulendisayısı bir gecede 0'dan yüksek bir sayıya fırlayacak — kırık ölçüm değil, kazanılan payda. Adım 7 bunu koda yazar.
Commit planı
fix(sonuc): boş harita ilk ekranı işgal etmez—manuel-harita.tsxfix(sonuc): tadımlık tablonun üstüne alınır—sonuc/page.tsx,tadimlik-satiri.tsx(first:mt-0)refactor(sihirbaz): listemUretHref tek kaynağa taşınır—sihirbaz-sabitler.ts,sihirbaz-cagri-karti.tsxfix(tadimlik): CTA girişten dönüşte üretimi başlatır—tadimlik-satiri.tsx,uretim-basladi-olayi.tsxcontent(tadimlik): teslim edilmeyen "24 satırın tamamı" iddiası kalkar—tadimlik-satiri.tsx[Bilal] content(tadimlik): CTA'nın yeni vaadi—tadimlik-satiri.tsx(en son, tek başına düşürülebilir)
Okunacak Next dokümanı (kod yazmadan önce)
node_modules/next/dist/docs/01-app/01-getting-started/05-server-and-client-components.md— client sınırı veserver-only(Adım 9'un tuzağı).node_modules/next/dist/docs/01-app/01-getting-started/04-linking-and-navigating.md—<Link href>ve sorgu parametresi.
G3 · odeme/paket-vaadi
Amaç: Paket sayfasındaki söz kodla eşitlensin — paketli kullanıcıdan liste ve revizyon için kredi düşmesin, "60 danışman sorusu" gerçekten 60 olsun.
Dal: odeme/paket-vaadi · Taban: 9bd448b · Öncelik: 2 (kesilmez). · Merge öncesi guvenlik-uyum denetimi zorunlu.
Dokunulacak dosyalar
| Dosya | Satır | Ne |
|---|---|---|
src/features/rapor/rapor-actions.ts |
152-158, 212-217, 243, 285-290, 339-344, 363 | maliyet değişkeni; 4 harcama/iade + 2 bakiye satırı |
src/features/rapor/components/listem-icerik.tsx |
167 | raporKredi prop'u paketliye 0 iner |
src/features/rapor/components/tercih-degisti-modali.tsx |
129, 188, 250, 275 | 0 bedelde "kredi" dili yerine "pakete dâhil" |
KRİTİK KISIT (CEO kararı, tartışmaya kapalı)
spendCredits ve grantCredits çağrıları KALDIRILMAZ, yalnız tutarları koşullanır. Gerekçe koddan doğrulandı:
credit_ledgerüzerindeuniqueIndex("ledger_reason_ref").on(reason, refId)var (src/lib/appdb/schema.ts:133) [D]. Üretimin tek idempotency çapası bu. Çağrı kaldırılırsa aynırequestIdile ikinci üretimDUPLICATEdönmez → BACKLOG #1'deki çifte üretim kapısı yeniden açılır.amount: 0ilespendCreditsINSUFFICIENT dönmez:gte(creditBalance, 0)her zaman eşleşir veupdatedAtdeğiştiği içinrowsAffected = 1olur (credits.ts:65-74) [Ç — SQLiterowsAffectedsemantiği; QA'nın DB duman testiyle teyit edilmeli].- İade dalındaki
grantCredits(delta: 0, reason: "refund")satırı silinmemeli:rapor-actions.ts:171-184ve:303-316"önceki deneme başarısız mıydı" sorusunu tam olarak burefundsatırının varlığıyla cevaplıyor. Satır yazılmazsa paketlinin başarısız denemesiSURUYOR("Listen zaten hazırlanıyor") gibi görünür — yanlış mesaj. [D] delta'yı koşullamazsak paketliye her başarısız üretimde bedava 3 kredi yazılır. (CEO'nun uyardığı sızıntı.)
Kapsam dışı
- Fiyat (299 TL), kredi adedi (60/30), top-up kuralları, maske (
ACIK_SATIR) — hepsi R5 ile kapalı. - Sohbet kredisi (
spendCreditForMessage, mesaj başına 1) — doğru davranış, dokunulmaz; G3'ün tüm amacı bu 60 sorunun gerçekten 60 kalması. credits.ts,liste-uretici.tsx, paket adı (A2),kredi-hatirlatma.ts./paket,/velistem-govde.tsx'teki "60 danışman sorusu" metinleri: üçü deURUNLER.paket.credits'ten türüyor (app/page.tsx:201,paket-satinal.tsx:40,listem-govde.tsx:345) [D] — G3 sonrası hiçbir metin değişikliği gerektirmeden doğru hâle gelirler. Dokunma.
Adım adım
1) listeOlustur yolu — rapor-actions.ts:152 civarı (fonksiyon: listeOlusturKilitli)
spendCredits çağrısının hemen üstüne:
// Paket vaadi (docs/urun/vizyon.md): liste ve revizyon pakete dâhil; krediler
// yalnız danışman sorusu için. Çağrı BİLEREK duruyor — ledger'daki
// UNIQUE(reason, ref_id) (appdb/schema.ts:133) üretimin tek idempotency
// çapası; paketliye delta 0 satır yazılır, aynı requestId ikinci kez
// DUPLICATE döner.
const maliyet = user.hasPaket ? 0 : RAPOR_KREDI;
Kullanım yerleri:
:155amount: RAPOR_KREDI→amount: maliyet:165hata metni${RAPOR_KREDI} kredi gerekli→ değişmez (bu dal yalnızmaliyet > 0iken erişilebilir).:214delta: RAPOR_KREDI→delta: maliyet:243kredi: user.creditBalance - RAPOR_KREDI→kredi: user.creditBalance - maliyet
2) listeRevize yolu — rapor-actions.ts:285 civarı
Aynı maliyet satırı (user.hasPaket ? 0 : RAPOR_KREDI) spendCredits'ten önce tanımlanır; :287 amount, :341 delta, :363 kredi aynı şekilde bağlanır. Not olarak yazılır: :256'daki if (!user.hasPaket) return PAKET guard'ı yüzünden burada maliyet her zaman 0'dır; ifade guard değişirse davranışın bozulmaması için koşullu bırakılıyor.
3) Sunucu davranışı dışına taşma yasak. krediBittiIsaretle, uretimKilidiAl/Birak, reports yazımı, maskeleme dalları (user.hasPaket ? sonuc : raporMaskele(sonuc)) aynen kalır.
4) Arayüz aynı şeyi söylesin — listem-icerik.tsx:167 + tercih-degisti-modali.tsx
raporKredi={RAPOR_KREDI} → raporKredi={user.hasPaket ? 0 : RAPOR_KREDI}.
Modalda tek türetilmiş bayrak: const ucretsiz = raporKredi === 0; ve üç metin yeri:
:188"…geçer ve {raporKredi} kredi düşer." → ücretsizse "…geçer; güncelleme paketine dâhil, kredi düşmez.":250"Güncelleme {raporKredi} kredi; bakiyen {kredi} kredi." → ücretsizse bu satır gösterilmez.:275buton "Listemi güncelle — {raporKredi} kredi" → ücretsizse "Listemi güncelle" (ok ikonu deseni aynen).:129 krediYeterveKrediYetersizdalına dokunulmaz:kredi >= 0her zaman doğru olduğu için o dal paketliye zaten hiç render edilmez. [Ç] Neden bu adım zorunlu: aksi hâlde kullanıcıya "3 kredi düşer" denip düşülmez — yalanın yönü değişir, kalitesi değişmez.
Kabul kriterleri
# 1) Çağrılar duruyor (idempotency çapası sağlam)
grep -c "spendCredits(" src/features/rapor/rapor-actions.ts # 2
grep -c "grantCredits(" src/features/rapor/rapor-actions.ts # 2
# 2) Tutarlar koşullu; sabit tutar hiçbir harcama/iade satırında kalmadı
grep -c "hasPaket ? 0 : RAPOR_KREDI" src/features/rapor/rapor-actions.ts # 2
grep -n "amount: maliyet\|delta: maliyet" src/features/rapor/rapor-actions.ts # 4 satır
grep -c "delta: RAPOR_KREDI\|amount: RAPOR_KREDI" src/features/rapor/rapor-actions.ts # 0
grep -c "creditBalance - RAPOR_KREDI" src/features/rapor/rapor-actions.ts # 0
# 3) requestId/refId zinciri değişmedi
grep -n "refId: requestId\|refId: input.requestId" src/features/rapor/rapor-actions.ts # 4 satır
# 4) Arayüz aynı şeyi söylüyor
grep -n "raporKredi={" src/features/rapor/components/listem-icerik.tsx # hasPaket ? 0 : RAPOR_KREDI
grep -c "ucretsiz" src/features/rapor/components/tercih-degisti-modali.tsx # >=3
# 5) Paket vaadi metinleri tek kaynaktan (hardcoded 60 yok)
grep -rn "danışman sorusu" src/ # 3 sonuç, üçü de credits/paketKredi interpolasyonu
# 6) Kapsam dışı dosyalar el değmemiş
git diff --name-only HEAD~2 # yalnız 3 dosya; credits.ts / liste-uretici.tsx YOK
pnpm exec next typegen && pnpm exec tsc --noEmit && pnpm lint
QA'ya devredilen davranış kriterleri (statik grep ile kanıtlanamaz, oturum ister): paketlide liste ve revizyon bakiyeyi düşürmez · credit_ledger'da delta = 0 satır yazılır · aynı requestId ile ikinci üretim DUPLICATE/SURUYOR döner · üretim hatasında paketliye kredi eklenmez · paketsizde davranış bit-bit aynı.
Riskler ve tuzaklar
user.hasPaket0/1 olabilir (drizzle/SQLite boolean);? :her iki temsille de doğru çalışır —=== trueyazma.- Revizyon dalında
maliyetdaima 0 — bu bir hata değil, paket vaadinin ta kendisi (MAX_REVIZYON = 2hak sayacı sınırı korur,:274-280). - Delta-0 ledger satırı ve iyzico mutabakatı:
credit_ledgerbir muhasebe defteri değil, kredi hareket kaydıdır; iyzico tarafıorders+grantCredits(reason: "purchase")üzerinden yürüyor (krediKaydiVarMi,credits.ts:202-212). Delta-0 satırının mutabakata etkisi olmaması gerekir ama bu benim çıkarımım [Ç] —guvenlik-uyummerge öncesi açıkça cevaplasın (aşağıda soru metni). kredi-hatirlatma.ts:36paketliyi de tarayabilir (sohbet kredisi 3'ün altına inerse); e-posta metni "listenin tamamını açmak istersen" diyor (eposta.ts:188) — paketliye yanlış. G3'ten önce de var olan bir hata, kapsam dışı, backlog #B3.
Commit planı
fix(kredi): paketliden liste ve revizyon kredisi düşmez—rapor-actions.tsfix(listem): fark modalı paketliye kredi bedeli göstermez—listem-icerik.tsx,tercih-degisti-modali.tsx
[Bilal] commit'i yok — paket içeriği kararı CEO'da verildi (24-ceo-kapanis §B).
Okunacak Next dokümanı
node_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md— Server Action sözleşmesi (dönüş tipi,"use server").node_modules/next/dist/docs/01-app/02-guides/data-security.md— server/client sınırında veri veserver-only.
G2 + G5 · odeme/kasa-ve-metin
Amaç: Ödeme yüzeyinde iki delik kapanır — hatanın ölçüsü yok (G2) ve satın alma niyetiyle gelen kişiye "sonra al" deniyor (G5).
Dal: odeme/kasa-ve-metin · Taban: 9bd448b · Öncelik: 3 (vakit yetmezse ilk kesilecek paket budur). · Merge öncesi guvenlik-uyum denetimi (para yüzeyi).
CEO'nun birleştirme gerekçesi: ikisi de aynı yüzeyin küçük düzeltmesi, ayrı dal maliyeti faydasından büyük (24-ceo-kapanis §D-9).
Dokunulacak dosyalar
| Dosya | Satır | Ne |
|---|---|---|
src/lib/analitik.ts |
36 civarı (OlayAdi) |
odeme_hata adı |
src/features/odeme/odeme-actions.ts |
16, 35, 45, 48, 87, 91, 102, 108 | Hata dönüşlerine kod alanı |
src/features/odeme/components/satin-al-form.tsx |
48-55 | İki hata dalında olay("odeme_hata", { kod }) |
src/features/odeme/components/paket-satinal.tsx |
140-144 | "Paketi sonra alırsın." kalkar |
src/features/kullanici/components/giris-karti.tsx |
28-31, 52-66 | /paket callback'i için üçüncü metin dalı |
Kapsam dışı
- Birincil CTA metni ve hedefi (
paket-satinal.tsx:131-139) — 21 Eylül kararı, R4 ile kalıcı kapalı. Buton metnine, rengine, hedefine dokunulmaz. - Fiyatın girişsiz dala eklenmesi (ürün Ö2a) — R4.
odeme_tamamlandisunucu olayı, yeni sayfa görüntüleme enstrümanı,/odemeve/odeme/sonucyüzeyleri, iyzico entegrasyonu,GirisBaslik'in typewriter mesajları, paket adı (A2).
Adım adım — G2 (ölçüm)
1) Olay adı — analitik.ts OlayAdi birliğine | "odeme_hata" (odeme_baslatildi'nın hemen altına) + 2 satır yorum: ne zaman atıldığı ve kod özelliğinin allowlist'li olduğu.
2) Hata kodu sunucudan gelsin — odeme-actions.ts
OdemeBaslatDurum'un hata dalı kod taşısın:
export type OdemeHataKodu = "URUN" | "ZATEN_PAKETLI" | "TOPUP_PAKETSIZ" | "SUNUCU";
export type OdemeBaslatDurum = { error: string; kod: OdemeHataKodu } | { yonlendir: string };
Eşleme: :35 → "URUN" · :45 → "ZATEN_PAKETLI" · :48 → "TOPUP_PAKETSIZ" · :87, :91(initialize başarısız), :102(imza geçersiz) → "SUNUCU". Kullanıcıya giden error metinleri ve console.error satırları aynen kalır; iyzico'nun errorCode/errorMessage değerleri Rybbit'e gönderilmez (yalnız log'da kalır — kardinalite ve sızıntı).
Kapsam düzeltmesi: CEO G2'yi yalnız satin-al-form.tsx + analitik.ts olarak tanımlamıştı; sunucu bugün yalnız serbest metin error döndürüyor (odeme-actions.ts:16) [D], dolayısıyla istemci "anahtar eksik" ile "paketin zaten aktif"i ayıramaz — G2'nin tek amacı olan teşhis oluşmaz. 6 satırlık kod alanı bunu çözer. Vakit darsa asgari sürüm: sunucuya dokunmadan yalnız iki kod ("BAGLANTI", "SUNUCU"); kabul kriteri yine sağlanır, teşhis gücü düşer.
3) İstemci olayı — satin-al-form.tsx:48-55
catchdalı (:48):olay("odeme_hata", { kod: "BAGLANTI" }), sonra mevcuttoast.error(BAGLANTI_HATASI)."error" in sonucdalı (:52):olay("odeme_hata", { kod: sonuc.kod, urun }), sonra mevcuttoast.error(sonuc.error).olay("odeme_baslatildi", { urun })(:43) vedisabled/gidiyormantığı değişmez. Toast metinleri değişmez. Kullanıcı girdisi/serbest metin olay özelliği olarak gönderilmez.
Adım adım — G5 (metin)
4) "Paketi sonra alırsın." kalkar — paket-satinal.tsx:140-144
Kalan cümle: "Girişte {DENEME_KREDISI} deneme kredisi tanımlanır; liste {RAPOR_KREDI} kredi, ilk {ACIK_SATIR} satır açık." (21 Eyl kararıyla korunan ilk iki cümle). Üç import'un üçü de kullanımda kalır → lint temiz. Birincil butona dokunulmaz.
5) /giris'te üçüncü metin dalı — giris-karti.tsx:28-31, 52-66
// Ödeme niyeti: /paket callback'i ile gelen kişiye üçüncü kez ücretsiz
// deneme anlatılmaz; girişin tek işi ödemeyi sürdürmek.
const odeme = callbackURL.startsWith("/paket");
funnel ifadesi değişmez (/sonuc ve /listem?uret=1 dalları birebir korunur — /paket zaten ikisiyle de eşleşmiyor [D]). Paragraf üç dallı olur: odeme ? (…) : funnel ? (…) : (…).
Önerilen odeme metni: "Girişten sonra ödemeye kaldığın yerden devam edersin — paketin hesabına tanımlanır." Deneme kredisi vaadi bu dalda birincil cümle olmaz; istenirse ikincil küçük satır olarak kalabilir.
<GirisBaslik funnel={funnel} /> değişmez: /paket dalında funnel === false olduğu için başlık sade "Giriş yap" olur — typewriter mesajları liste dilinde (giris-baslik.tsx:6-13), ödeme niyetine uymaz. [D]
Kabul kriterleri
grep -n "odeme_hata" src/lib/analitik.ts # 1 (OlayAdi)
grep -n "odeme_hata" src/features/odeme/components/satin-al-form.tsx # 2
grep -n "odeme_baslatildi" src/features/odeme/components/satin-al-form.tsx # 1 (davranış korunmuş)
grep -n "kod:" src/features/odeme/odeme-actions.ts # 6 hata dönüşü
grep -rn "errorMessage\|errorCode" src/features/odeme/components/ # 0 (iyzico detayı istemcide yok)
grep -rc "Paketi sonra alırsın" src/ # 0
grep -n "Giriş yap — ilk" src/features/odeme/components/paket-satinal.tsx # 1 (CTA metni değişmemiş)
grep -n 'startsWith("/paket")' src/features/kullanici/components/giris-karti.tsx # 1
grep -n 'startsWith("/sonuc")\|startsWith("/listem?uret=1")' src/features/kullanici/components/giris-karti.tsx # değişmemiş
pnpm exec next typegen && pnpm exec tsc --noEmit && pnpm lint
Riskler ve tuzaklar
OdemeBaslatDurumtipi değişince tüm dönüş yolları güncellenmeli —tscbunu yakalar;"error" in sonucdaraltması aynen çalışır.koddeğerleri allowlist'li sabit dizgiler olmalı — kullanıcı girdisinden türeyen hiçbir şey Rybbit'e gitmez (PROTOKOL 9 +uretim-basladi-olayi.tsx:18-24'teki yerleşik kural).satin-al-form.tsx"use client";olay()zaten import edili (:8), yeni bağımlılık yok.- Yayın koşulu (CEO): G2, Bilal'in gerçek test ödemesiyle aynı yayında çıkar — tek başına canlıya alınırsa ölçüm boş kalır.
- A2 (paket adı) bu dosyaya sonra girecek — paket adına dokunma (çakışma kararı #2).
Commit planı
feat(olcum): odeme_hata olayı — ödeme hunisine payda—analitik.ts,odeme-actions.ts,satin-al-form.tsxcontent(paket): "Paketi sonra alırsın." kalkar—paket-satinal.tsxcontent(giris): /paket callback'i ödemeye devam metni alır—giris-karti.tsx
Okunacak Next dokümanı
node_modules/next/dist/docs/01-app/01-getting-started/07-mutating-data.md— Server Action dönüş tipleri.node_modules/next/dist/docs/01-app/02-guides/analytics.md— istemci olay enstrümanı.
Merge sırası ve bağımlılıklar
Dosya kümeleri ayrık → teknik bağımlılık yok, sıra yalnız öncelik. Önerilen: G1 → G3 → G2+G5 → (A2, en son).
Tam pnpm buildi hiçbir dal koşmaz; entegrasyon build'i Bilal'in sabah komut sırasında (24-ceo-kapanis §C3), push edilecek commit'in kendisi üzerinde APFS klonlu worktree ile alınır.
Uzman yönlendirmesi
| Kim | Ne | Ne zaman |
|---|---|---|
guvenlik-uyum |
G3 merge öncesi zorunlu: "credit_ledger'a delta = 0 satır yazmak iyzico mutabakatını ya da iade/uyuşmazlık takibini bozar mı? refund satırının delta'sı 0 olduğunda rapor-actions.ts:171-184'teki 'önceki deneme başarısızdı' çıkarımı hâlâ geçerli mi?" |
Bu gece (24-ceo-kapanis §D-11) |
guvenlik-uyum |
G2: kod allowlist'inin kişisel veri/kart verisi taşımadığı, iyzico hata detayının istemciye inmediği |
G2 merge öncesi |
tasarimci |
G1 adım 9'un [Bilal] cümlesi + first:mt-0 sonrası ilk ekran hiyerarşisi; G5'in üçüncü /giris metni |
Dallar yazıldıktan sonra, tek raporda |
qa-muhendisi |
G3'ün davranış kriterleri (oturum + data/app.db okuması ister); G1'in giriş→üretim zinciri |
Dal başına tek rapor satırı; düşen kriterde commit alınmaz |
analitik |
tadimlik_goruntulendi seri kırılması notu; odeme_hata için pano/huni |
G1 ve G2 merge sonrası |
yapay-zeka-muhendisi |
Gerek yok — prompt, havuz kuralları ve LLM çıktısı üç pakette de değişmiyor (T12 tetiği açılmıyor) | — |
veri-muhendisi |
Gerek yok — yokatlas.db ve veri hattı dışarıda |
— |
İtirazlar
- G2'nin kapsamı eksikti (düzeltildi). Sunucu bugün yalnız serbest metin
errordöndürüyor; istemci hatayı sınıflandıramaz, dolayısıyla "kasa neden çalışmıyor" sorusu ölçülemez.odeme-actions.ts'ekodalanı eklenmeden G2 yalnız "bir hata oldu" sayar. Düzeltilmiş kapsam yukarıda; asgari sürüm de yazıldı. - G3'ün kapsamı eksikti (düzeltildi). CEO iki harcama + iki iade dalını saydı;
rapor-actions.ts:243ve:363'teki bakiye dönüşü iletercih-degisti-modali.tsx'in kredi metni dışarıda kalmıştı. Onlar kapatılmazsa paketli kullanıcı "3 kredi düştü" görür, düşmez — G3'ün amacı olan "söz = kod" sağlanmaz. Kapsam 1 dosya + 1 türetilmiş bayrak kadar büyütüldü. - CEO'nun
giris-karti.tsxyolu yanlıştı (src/features/auth/…→ doğrususrc/features/kullanici/components/giris-karti.tsx),rapor-actions.tssatır numaraları84fc88ereferanslıydı ve9bd448b'de kaydı. Tüm atıflar bu şartnamede güncellendi. - G1'de CEO'nun yazmadığı iki zorunlu adım var:
?kaynak=allowlist'i (yoksa ölçümbilinmiyora düşer) vesonucHrefimport'unun kaldırılması (yoksa lint kırmızı). İkisi de tek satır. - İtiraz etmediğim yer:
spendCredits'in kaldırılmaması kısıtı doğru ve koddan doğrulandı (uniqueIndex("ledger_reason_ref"),schema.ts:133). Daha "sade" görünen "paketliyse hiç çağırma" yolu idempotency çapasını ve başarısız-deneme işaretini birlikte kaybettirirdi.
Backlog önerileri (BACKLOG.md'ye dokunulmadı)
- B1 —
tadimlik_goruntulendiseri kırılması notuanalitik.ts'e taşınsın (G1 ile G2 aynı dosyada çakışmasın diye bu gecetadimlik-satiri.tsx'te kalıyor). XS. - B2 —
liste-uretici.tsx:263-285'tekihasPaket"kredi yetersiz" dalı G3 sonrası liste üretimi için ölü kod; Bilal'in dosyası olduğu için bu gece dokunulmadı. XS. - B3 — Kredi-bitti hatırlatma e-postası paketliyi de tarayabiliyor (
kredi-hatirlatma.ts:29-38) ve metni "listenin tamamını açmak istersen" diyor (eposta.ts:188) — paketliye yanlış. SorguhasPaket = falsekoşulu ya da metin dalı istiyor. S. - B4 —
ACIK_SATIRrapor-maske.ts'teserver-onlymodülde yaşıyor; istemci metinleri bu sayıyı tek kaynaktan okuyamıyor (bugünliste-uretici.tsx:274"3 kredi"yi elle yazıyor). Sabitlerin client-safe bir modüle ayrılması. S. - B5 —
/sonuctadımlığınınuseGorunumOlayieşiği ilk ekrana taşındıktan sonra gözden geçirilsin; "görüntülendi" artık neredeyse her ziyaretle eşit olacağı için huni değeri düşecek — anlamlı ölçüt "tadımlık CTA tıklaması / tadımlık görüntülenmesi" oranıdır. XS.
Bilal'den istenen (2 madde)
- G1'in son commit'i (
[Bilal] content(tadimlik): CTA'nın yeni vaadi) onayı — tadımlık butonunun yeni cümlesi senin diline mi uysun, yoksa kendi cümleni mi yazacaksın? Commit tek başına düşürülebilir hazırlanıyor. ~2 dk. - Üç dalın tek build'de doğrulanması — sabahki C3 komut bloğunu çalıştırırken
funnel/sonuc-ilk-ekran,odeme/paket-vaadi,odeme/kasa-ve-metindallarını entegrasyon worktree'sinde birleştirippnpm buildi o commit üzerinde al; ajanlar disk yüzünden build koşmadı. ~10 dk.