Files
kolaytercih/docs/gece-vardiyasi/2026-09-22/28-cto-sartname.md
bilalgursen 2b350d0c5d content(rehber): gece vardiyasının 14 yeni yazısı + 2 düzeltme, ekip raporları ve kurallar
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>
2026-09-22 23:25:34 +03:00

38 KiB
Raw Blame History

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)

  1. CEO'nun satır numaralarının çoğu tuttu, ikisi tutmadı. rapor-actions.ts bu gece 9bd448b ile değişti: liste harcaması artık 98-99/118-124 değil 153-158, iade 212-217, revizyon harcaması 285-290, revizyon iadesi 339-344. Ayrıca giris-karti.tsx src/features/auth/ altında değil, src/features/kullanici/components/giris-karti.tsx. Aşağıdaki tüm atıflar 9bd448b üzerinde tek tek açılarak yazıldı. [D]
  2. G3'ün gizli dördüncü satırı var. spendCredits/grantCredits koşullansa bile rapor-actions.ts:243 ve :363'teki kredi: user.creditBalance - RAPOR_KREDI paketliye düşmemiş krediyi düşmüş gibi gösterir; ayrıca tercih-degisti-modali.tsx paketliye "Listemi güncelle — 3 kredi" yazmaya devam eder. Tek bir maliyet değişkeni dört yeri birden kapatıyor — kapsam bu kadar büyütülmeli, daha fazlası değil. [D]
  3. G1'in CTA'sı için ?kaynak= allowlist'i şart. /listem?uret=1&kaynak=tadimlik yazmadan önce uretim-basladi-olayi.tsx:25-41'deki IZINLI_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]
  4. İki sessiz build tuzağı var ve ikisi de G1'in metin işinde patlar: rapor-maske.ts import "server-only" (satır 6), credits.ts appdb'yi import ediyor (satır 2) — ikisi de "use client" olan tadimlik-satiri.tsx'e import EDİLEMEZ. Yeni CTA cümlesi ACIK_SATIR/DENEME_KREDISI sabitlerine uzanamaz; sayı gerekiyorsa cümle sayısız yazılır. [D]
  5. /meraklisina şeması üç pakette de değişmiyor. huni-semasi.tsx'teki SEMA yalnı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ı

  1. src/lib/analitik.ts → G2'nin. G1'in tadimlik_goruntulendi olayı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'in OlayAdi yorumuna yazma geleneği var (program_eklendi, satır 29-31). Buna rağmen G1 bu dosyaya dokunmaz: G2 aynı birliğe odeme_hata ekliyor, iki dal bitişik satırlarda çakışır. G1 seri kırılmasını (a) tadimlik-satiri.tsx:100-102'deki useGorunumOlayi çağrısının üstündeki yoruma, (b) commit mesajına yazar. Kalıcı notun analitik.ts'e taşınması backlog önerisi #B1.
  2. paket-satinal.tsx ve tercih-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.
  3. liste-uretici.tsx kimsenin değil. G3 uygulandığında o dosyadaki hasPaket dalı ("+30 kredi yükle") liste üretimi için ölü koda dönüşür (paketli artık hiç KREDI kodu 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

  1. Yalnız orkestratörün verdiği worktree + dalda lokal commit. Push yok, merge yok, main'e commit yok.
  2. git add -A / git add . yasak. Yalnız kendi dosya kümenden, yol vererek ekle. Commit öncesi git status --porcelain çıktısında kümen dışında bir şey görünüyorsa dur ve raporla.
  3. Doğrulama sırası: pnpm exec next typegen && pnpm exec tsc --noEmit && pnpm lint. Dev sunucusu yok, tarayıcı yok, pnpm build yok (disk ~5 GB; tam build'i Bilal sabah C3 komut bloğunda tek seferde alır).
  4. Taze worktree'de next typegen olmadan tsc baseline'da kırıktır — PageProps gibi global tipler .next/types'tan gelir. Kırmızı çıktıyı kendi değişikliğine yorma; önce typegen koş.
  5. Worktree'de node_modules symlink'i Turbopack'te patlar — klon kullanılır (cp -Rc ../kolaytercih/node_modules node_modules). Kurulumu orkestratör yapar; pnpm install çalıştırma.
  6. next build env'siz koşar: modül yüklenirken env zorunlu kılan kod yazma. Bu üç pakette yeni env yok.
  7. 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.
  8. AGENTS.md: rozet gerekiyorsa SectionEyebrow, CTA'da ikon metnin sonunda <ArrowRight className="size-4" aria-hidden />, Sparkles yok; modal kapatma çarpısı DialogContent varsayılanı. Sihirbaz/liste mimarisi değişirse /meraklisina şeması aynı commit'te — bu üç pakette değişmiyor (bkz. Özet #5), dokunma.
  9. Uydurma sayı yok: ekranda görünen her rakam ya tek kaynak sabitten (URUNLER, RAPOR_KREDI, ACIK_SATIR) gelir ya da hiç yazılmaz.
  10. 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).
  • /sonuc tablosunun 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

  1. sonucHref import'unu silmeyi unutmak → lint kırmızısı. (Adım 6.)
  2. 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 profil tercihProfiliDogrula gereğ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ı.
  3. Giriş dönüşünde onaysız 3 kredi. giris-linki.tsx:13-16 navbar 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).
  4. Layout kayması: boş harita null iken 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).
  5. tadimlik_goruntulendi sayı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ı

  1. fix(sonuc): boş harita ilk ekranı işgal etmez — manuel-harita.tsx
  2. fix(sonuc): tadımlık tablonun üstüne alınır — sonuc/page.tsx, tadimlik-satiri.tsx (first:mt-0)
  3. refactor(sihirbaz): listemUretHref tek kaynağa taşınır — sihirbaz-sabitler.ts, sihirbaz-cagri-karti.tsx
  4. fix(tadimlik): CTA girişten dönüşte üretimi başlatır — tadimlik-satiri.tsx, uretim-basladi-olayi.tsx
  5. content(tadimlik): teslim edilmeyen "24 satırın tamamı" iddiası kalkar — tadimlik-satiri.tsx
  6. [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ı ve server-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 üzerinde uniqueIndex("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ı requestId ile ikinci üretim DUPLICATE dönmez → BACKLOG #1'deki çifte üretim kapısı yeniden açılır.
  • amount: 0 ile spendCredits INSUFFICIENT dönmez: gte(creditBalance, 0) her zaman eşleşir ve updatedAt değiştiği için rowsAffected = 1 olur (credits.ts:65-74) [Ç — SQLite rowsAffected semantiği; QA'nın DB duman testiyle teyit edilmeli].
  • İade dalındaki grantCredits(delta: 0, reason: "refund") satırı silinmemeli: rapor-actions.ts:171-184 ve :303-316 "önceki deneme başarısız mıydı" sorusunu tam olarak bu refund satırının varlığıyla cevaplıyor. Satır yazılmazsa paketlinin başarısız denemesi SURUYOR ("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, / ve listem-govde.tsx'teki "60 danışman sorusu" metinleri: üçü de URUNLER.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:

  • :155 amount: RAPOR_KREDI → amount: maliyet
  • :165 hata metni ${RAPOR_KREDI} kredi gerekli → değişmez (bu dal yalnız maliyet > 0 iken erişilebilir).
  • :214 delta: RAPOR_KREDI → delta: maliyet
  • :243 kredi: 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.
  • :275 buton "Listemi güncelle — {raporKredi} kredi" → ücretsizse "Listemi güncelle" (ok ikonu deseni aynen). :129 krediYeter ve KrediYetersiz dalına dokunulmaz: kredi >= 0 her 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

  1. user.hasPaket 0/1 olabilir (drizzle/SQLite boolean); ? : her iki temsille de doğru çalışır — === true yazma.
  2. Revizyon dalında maliyet daima 0 — bu bir hata değil, paket vaadinin ta kendisi (MAX_REVIZYON = 2 hak sayacı sınırı korur, :274-280).
  3. Delta-0 ledger satırı ve iyzico mutabakatı: credit_ledger bir 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-uyum merge öncesi açıkça cevaplasın (aşağıda soru metni).
  4. kredi-hatirlatma.ts:36 paketliyi 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ı

  1. fix(kredi): paketliden liste ve revizyon kredisi düşmez — rapor-actions.ts
  2. fix(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 ve server-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_tamamlandi sunucu olayı, yeni sayfa görüntüleme enstrümanı, /odeme ve /odeme/sonuc yü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

  • catch dalı (:48): olay("odeme_hata", { kod: "BAGLANTI" }), sonra mevcut toast.error(BAGLANTI_HATASI).
  • "error" in sonuc dalı (:52): olay("odeme_hata", { kod: sonuc.kod, urun }), sonra mevcut toast.error(sonuc.error). olay("odeme_baslatildi", { urun }) (:43) ve disabled/gidiyor mantığı 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

  1. OdemeBaslatDurum tipi değişince tüm dönüş yolları güncellenmeli — tsc bunu yakalar; "error" in sonuc daraltması aynen çalışır.
  2. kod değ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).
  3. satin-al-form.tsx "use client"; olay() zaten import edili (:8), yeni bağımlılık yok.
  4. 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.
  5. A2 (paket adı) bu dosyaya sonra girecek — paket adına dokunma (çakışma kararı #2).

Commit planı

  1. feat(olcum): odeme_hata olayı — ödeme hunisine payda — analitik.ts, odeme-actions.ts, satin-al-form.tsx
  2. content(paket): "Paketi sonra alırsın." kalkar — paket-satinal.tsx
  3. content(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

  1. G2'nin kapsamı eksikti (düzeltildi). Sunucu bugün yalnız serbest metin error döndürüyor; istemci hatayı sınıflandıramaz, dolayısıyla "kasa neden çalışmıyor" sorusu ölçülemez. odeme-actions.ts'e kod alanı eklenmeden G2 yalnız "bir hata oldu" sayar. Düzeltilmiş kapsam yukarıda; asgari sürüm de yazıldı.
  2. G3'ün kapsamı eksikti (düzeltildi). CEO iki harcama + iki iade dalını saydı; rapor-actions.ts:243 ve :363'teki bakiye dönüşü ile tercih-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ü.
  3. CEO'nun giris-karti.tsx yolu yanlıştı (src/features/auth/… → doğrusu src/features/kullanici/components/giris-karti.tsx), rapor-actions.ts satır numaraları 84fc88e referanslıydı ve 9bd448b'de kaydı. Tüm atıflar bu şartnamede güncellendi.
  4. G1'de CEO'nun yazmadığı iki zorunlu adım var: ?kaynak= allowlist'i (yoksa ölçüm bilinmiyora düşer) ve sonucHref import'unun kaldırılması (yoksa lint kırmızı). İkisi de tek satır.
  5. İ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_goruntulendi seri kırılması notu analitik.ts'e taşınsın (G1 ile G2 aynı dosyada çakışmasın diye bu gece tadimlik-satiri.tsx'te kalıyor). XS.
  • B2 — liste-uretici.tsx:263-285'teki hasPaket "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ış. Sorgu hasPaket = false koşulu ya da metin dalı istiyor. S.
  • B4 — ACIK_SATIR rapor-maske.ts'te server-only modülde yaşıyor; istemci metinleri bu sayıyı tek kaynaktan okuyamıyor (bugün liste-uretici.tsx:274 "3 kredi"yi elle yazıyor). Sabitlerin client-safe bir modüle ayrılması. S.
  • B5 — /sonuc tadımlığının useGorunumOlayi eş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)

  1. 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.
  2. Üç 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-metin dallarını entegrasyon worktree'sinde birleştirip pnpm buildi o commit üzerinde al; ajanlar disk yüzünden build koşmadı. ~10 dk.