` `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-vars` lint hatası verir), `listemUretHref` eklenir; `PROFIL_DEGISTI_EVENT` kalır. `onClick`'teki `olay("giris_cta_tiklandi", { kaynak: "tadimlik" })` **aynen kalır** (mevcut seri korunur).
Doğrulanmış zincir: `/giris` callback'i `/^\/(?![/\\])/` kalkanından geçer (`giris-karti.tsx:18-19`) ✅ · `startsWith("/listem?uret=1")` funnel metni korunur ✅ · dönüşte `listem/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 `` 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 ``'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)
```sh
# 1) Tadımlık tablodan önce (ilk sayı küçük olmalı)
grep -n "` 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:
```ts
// 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
```sh
# 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:
```ts
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`
```ts
// Ö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.
`` **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
```sh
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 build`i **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 `bilinmiyor`a 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 build`i o commit üzerinde al; ajanlar disk yüzünden build koşmadı. ~10 dk.