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>
17 KiB
35 — Güvenlik & uyum denetimi: G3 · odeme/paket-vaadi (merge öncesi zorunlu denetim)
Rol:
guvenlik-uyum· Gece vardiyası, 22 Eylül 2026 sabah turu Denetlenen: dalodeme/paket-vaadi, commit'ler4acfd27+43b6cec, taban9bd448b(main) Kaynaklar:34-yazilimci-g3.md,31-guvenlik-satici-kimligi.md§2,28-cto-sartname.md§G3 Yöntem: yalnız okuma. Kod değiştirilmedi, dal değiştirilmedi, commit/git addyok, yıkıcı git komutu yok. Diffgit show/git diffile okundu. Proje DB'sine yalnızsqlite3 -readonlyile bakıldı. İşaret: [D] doğrulandı (komut çıktısı / dosya:satır) · [Ç] koddan çıkarım (koşturulmadı)
Özet (5 madde)
- Kritik bulgu yok; üç koşulun üçü de kodda karşılanmış. İade dalları yerinde ve tutar koşullu (
rapor-actions.ts:223-228,:358-363→delta: maliyet), dönen bakiye koşullu (:254,:382),hasPakettek yerden —getCurrentUser()'ın istek başına React-cache'lenmiş tek satır okumasından geliyor, yeni DB sorgusu eklenmemiş [D]. - Denetimin en kritik sorusu —
amount: 0idempotency çapasını kaybettirir mi — CEVAP: HAYIR, ve bu artık [Ç] değil [D]. Projenin kendi sürücüsüyle (@libsql/client@0.17.4) izole bir scratch DB'de koşturdum: bakiyesi 0 olan kullanıcıdaUPDATE … credit_balance - 0 … WHERE credit_balance >= 0→rowsAffected = 1(hiçbir kolon değeri değişmese bile 1; SQLite MySQL gibi "changed rows" saymıyor).delta = -0satırı tabloya integer 0 olarak yazılıyor ve aynı(reason, ref_id)ile ikinci insertSQLITE_CONSTRAINT: UNIQUE constraint failedile reddediliyor. Yani satır gerçekten yazılıyor, UNIQUE çapası duruyor,INSUFFICIENTyanlış alarmı yok. - Sızıntı yolu kapalı, paketsiz davranış bit-bit aynı. Paketlinin başarısız üretimi/revizyonu
delta 0refundsatırı yazıyor, bakiye artmıyor; tazerequestIdile sınırsız tekrar da kredi üretmiyor. Paketsizdemaliyet = RAPOR_KREDIolduğu için harcama, iade, hata metni vekrediBittiIsaretleyolu değişmemiş [D]. - Yeni ve gerçek olan tek risk kredi değil, maliyet: G3'ten sonra paketli kullanıcının liste üretiminde hiçbir üst sınır kalmıyor (eski tavan 60 kredi ÷ 3 ≈ 20 üretimdi). Üstelik
listeOlusturKilitlireports'urevisionCount: 0ile üzerine yazdığı için (rapor-actions.ts:247) MAX_REVIZYON=2 tavanı da "yeniden üret → 2 revizyon → yeniden üret" döngüsüyle sıfırlanabiliyor. Repoda hiçbir rate limit yok (grep -rln "rateLimit\|rate-limit\|ratelimit"src/ → 0 dosya [D]); tek fren kullanıcı başına üretim kilidinin serileştirmesi. Merge engeli değil (ücretli kullanıcı yüzeyi, CEO kararının doğal sonucu) ama kayda geçmeli — F1. - Uyum tarafında G3 bir açığı kapatıyor:
/paket"60 Yapay Zeka danışman sorusu" diyordu (paket-satinal.tsx:39-40), gerçekte liste (3) + 2 revizyon (6) düşünce elde 51 soru kalıyordu. G3 sonrası 60 gerçekten 60. Mesafeli Sözleşmeler Yön. m.5/1-a (hizmetin temel nitelikleri) bakımından "ön bilgilendirme × fiilî ifa" uyumsuzluğu kapanıyor — G3 uyumu bozmuyor, iyileştiriyor. (Hukuki değerlendirme taslaktır: avukat teyidi gerekir.)
1 · Üç koşul: doğrulama
Koşul (31-… §2) |
Hüküm | Kanıt |
|---|---|---|
| 1. İade dalları yerinde + tutar koşullu | KARŞILANDI | rapor-actions.ts:223-228 ve :358-363: grantCredits({ … delta: maliyet, reason: "refund", refId }) — çağrı kaldırılmamış, refId aynı. DUPLICATE dalındaki "önceki deneme iade edilmişti" sorgusu (:179-186, :320-327) yalnız (reason='refund', ref_id) bakıyor, delta'ya bakmıyor → delta 0 satırı bu çıkarımı aynen besliyor [D] |
| 2. Dönen bakiye koşullu | KARŞILANDI | :254 ve :382 → kredi: user.creditBalance - maliyet. grep -c "creditBalance - RAPOR_KREDI" = 0 [D] |
3. hasPaket tek yerden, yeni DB okuması yok |
KARŞILANDI | :158 ve :300 → const maliyet = user.hasPaket ? 0 : RAPOR_KREDI;. user nesnesi getCurrentUser()'dan geliyor: session.ts:27-35 tek SELECT *, react/cache ile istek başına bir kez. hasPaket ile creditBalance aynı satır anlık görüntüsünden okunuyor → harcama ile iade arasında yırtık okuma imkânsız. Diff'te yeni appDb.select/query yok [D] |
Ek doğrulamalar:
hasPaketşemadainteger("has_paket", { mode: "boolean" })(appdb/schema.ts:20) → drizzle gerçekbooleandöndürüyor; yazılımcının=== trueyazmaması doğru tercih, SQLite 0/1 temsilinde de truthiness doğru çalışır [D].- Kapsam: her iki commit toplam 3 dosya,
credits.ts/liste-uretici.tsx/huni-semasi.tsxyok; çalışma ağacındaki başkalarına aitM/??dosyalar hâlâ commit'siz duruyor [D].
2 · spendCredits(amount: 0) / grantCredits(delta: 0) — koşturulmuş hüküm
Şartname de yazılımcı raporu da bu noktayı [Ç] bırakmıştı. İzole scratch DB'de (proje DB'sine yazılmadı), projenin kendi sürücüsüyle koşturdum:
A) amount=0, balance=0 -> rowsAffected = 1 → INSUFFICIENT DÖNMEZ
B) hiçbir kolon değeri değişmiyor -> rowsAffected = 1 → SQLite matched-rows sayar
C) delta=-0 insert rowsAffected = 1
D) yazılan delta = {"delta":0,"t":"integer"} → -0 değil, temiz integer 0
E) aynı (reason, ref_id) ile ikinci insert: SQLITE_CONSTRAINT: UNIQUE constraint failed
(code SQLITE_CONSTRAINT, rawCode 2067) → idempotency ÇAPASI YERİNDE
F) refund delta=0 sonrası bakiye = 0 → kredi üretilmiyor
G) balance=-1, amount=0 -> rowsAffected = 0 → yalnız negatif bakiyede INSUFFICIENT
Hüküm:
- Soru 2 (idempotency): bozulmadı.
delta = 0satırı gerçekten yazılıyor;uniqueIndex("ledger_reason_ref").on(reason, refId)(schema.ts:133) aynırequestIdile ikinci üretimiDUPLICATE'e düşürmeye devam ediyor.uniqueIhlaliMibu hatayı yakalıyor (mesaj "UNIQUE" içeriyor,credits.ts:22-40) [D].refIdzinciri değişmedi (refId: requestId× 4, satır 165/227/306/362). - Soru 4 (
INSUFFICIENT): bakiyesi 0 olan paketli kullanıcı liste üretebiliyor. Paketin vaadi ayakta. Tek istisna satır G: bakiye negatifseINSUFFICIENTdönerdi — ama negatif bakiye ulaşılamaz: bakiyeyi yazan her yolgteile korunuyor (credits.ts:69,:110),grantCreditsyalnız ekliyor, dev paneliMath.max(0, …)uyguluyor (lib/dev/actions.ts:83, zatenNODE_ENV === "production"'da fırlatıyor) [D]. Lokal DB'de de min bakiye 5 ve 34 (sqlite3 -readonly data/app.db) [D].
3 · Bulgu tablosu
| # | Dosya:satır | Sorun | Somut senaryo | Önem | Düzeltme | Kesinlik |
|---|---|---|---|---|---|---|
| F1 | rapor-actions.ts:158 + :247 (revisionCount: 0 upsert); rate limit yok |
Paketlide liste üretiminin kredi freni kalktı, yerine hiçbir sınır konmadı | 299 TL ödemiş kullanıcı (ya da hesabı ele geçiren biri) /listem'de sihirbaz tercihini değiştirip "Listemi güncelle"ye basar; her basış tam bir rapor LLM çağrısı, bedeli 0 kredi. Üretim kilidi yalnız serileştirir, saymaz; bayat kilit eşiği 180 sn (uretim-kilidi.ts:13). Ayrıca her yeniden üretim revisionCount'u 0'a çekiyor → "2 revizyon hakkı" tavanı da döngüyle sıfırlanıyor. Eski tavan 60÷3 ≈ 20 üretimdi; şimdi tavan yok |
orta | Bu dalda değil (kapsam dışı). Ayrı iş: report_generate ledger satırları zaten sayıyor → spendCredits'ten önce "son 24 saatte reason='report_generate' satır sayısı ≥ N ise code: "SINIR"" kapısı (N'i CEO belirler; 10 tartışma başlatır, 30 kimseyi rahatsız etmez). Alternatif ucuz fren: üretim kilidini başarıdan sonra 60 sn tutmak |
DOĞRULANDI |
| F2 | credits.ts:174-176 (krediBittiAt: null) ↔ rapor-actions.ts:223-228 |
delta = 0 iade de "kredi geldi" sayılıp bekleyen kredi-bitti hatırlatmasını iptal ediyor |
Paketli kullanıcının 60 kredisi sohbette biter → /api/soru krediBittiIsaretle yazar (route.ts:180), 48 saat sonra top-up e-postası kuyruğa girer. Kullanıcı o arada bir liste üretir, üretim hata verir → grantCredits(delta: 0, reason:"refund") krediBittiAt'ı null'lar. Kredi gelmediği hâlde hatırlatma iptal olur; krediHatirlatmaGonderildiAt da hâlâ null olduğu için e-posta ancak kullanıcı bir kez daha sohbette duvara toslarsa yeniden kurulur. G3 öncesi bu doğruydu (iade gerçekten 3 kredi getiriyordu), G3 sonrası yanlış |
düşük (gelir kaybı, güvenlik değil) | credits.ts:174 → ...(opts.delta > 0 ? { krediBittiAt: null } : {}). credits.ts bu dalın kapsamı dışında (CTO yasak listesi) → backlog |
DOĞRULANDI |
| F3 | tercih-degisti-modali.tsx:254 + :336-347 (KrediYetersiz) |
Paketli için ölü dal; render edilirse "Güncelleme 0 kredi ve bakiyen yetmedi" yazar | durum = "kredi-yetersiz" yalnız code === "KREDI" | "PAKET" ile kuruluyor (:115). Paketlide KREDI artık imkânsız (bkz. §2), PAKET'i listeOlustur hiç döndürmüyor (yalnız listeRevize döndürür) → dal bugün ulaşılamaz. Ama ucretsiz bayrağı bu dala bağlanmadığı için, ileride bakiye negatife düşebilen bir yol açılırsa ekranda anlamsız cümle çıkar |
düşük | Bu dalda şart değil. İstenirse tek satır: :254'teki üçlüye !ucretsiz && eklemek ya da KrediYetersiz içinde raporKredi === 0 dalını yazmak. Aynı sınıf ölü kod liste-uretici.tsx:263-285'te de var (backlog #B2, Bilal'in dosyası) |
DOĞRULANDI |
| F4 | rapor-actions.ts:104 (getCurrentUser) → :158 |
hasPaket okuması ile harcama arasında paket satın alma yarışı |
Kullanıcı /listem'de üretimi başlatır; tam o saniyede ikinci sekmede iyzico callback'i paketi yazar. Sunucu eski anlık görüntüyü gördüğü için 3 kredi düşer — paketli olmasına rağmen. Ters yön (paketliyken ücrete düşme) imkânsız, hasPaket true→false dönmüyor |
düşük | Düzeltme önermiyorum: pencere milisaniyeler, zarar 3 kredi, G3 öncesinde de aynıydı (o zaman her paketliden düşüyordu). Kayda geçsin yeter | OLASI |
| F5 | credit_ledger (veri, kod değil) |
Ölçüm serisi kırılması | report_generate satırının delta'sı paketlide −3 → 0 oldu. Satır sayısına dayanan sorgular (ör. 04-uretim-engelleri.md §5'teki deneme/iade kırılımı) etkilenmiyor; SUM(delta) ile "kaç kredi yandı/iade edildi" soran gelecekteki bir sorgu 22 Eylül'den öncesi ve sonrası için farklı şey ölçer |
bilgi | Merge commit mesajında ya da docs/odeme/iyzico.md kenar notunda tek cümle |
DOĞRULANDI |
| F6 | süreç — çalışma ağacı | HEAD şu an odeme/paket-vaadi üzerinde; orkestratör beni "funnel/sonuc-ilk-ekran dalındasın" diye bilgilendirdi |
G1 dalına devam eden bir sonraki ajan kendini G3 dalında sanmadan commit atarsa G1 işi G3'ün üstüne biner ve merge sırası bozulur. git reflog: HEAD@{2}: checkout: moving from funnel/sonuc-ilk-ekran to odeme/paket-vaadi — yazılımcı dönmemiş. (Aynı reflog'da HEAD@{5}: reset: moving to HEAD~1 G1 dalında, G3 dalında yıkıcı komut yok — yazılımcının bu iddiası doğru) |
orta (süreç) | Bir sonraki kod ajanı işe başlamadan orkestratör dalı açıkça söylesin/doğrulasın. Ben dal değiştirmedim (kurallar gereği) | DOĞRULANDI |
Sızıntı yolları — tek tek (denetim sorusu 3)
| Yol | Sonuç |
|---|---|
| Paketli, başarısız üretim | refund satırı delta 0 → bakiye değişmez. Kredi eklenmiyor [D: kod + scratch DB] |
| Paketli, başarısız revizyon, N kez tekrar | Her denemede taze requestId → her denemede yeni (report_revision, id) + (refund, id) çifti, hepsi 0. Sınırsız tekrar sınırsız kredi üretmiyor. revisionCount yalnız başarıda artıyor (:374-380) — bu da yalnız LLM maliyeti bırakıyor (F1) |
| Paketli, bakiyesi 0, liste üretimi | Çalışır (INSUFFICIENT dönmez) — paketin vaadi ayakta |
| Paketsiz | maliyet = 3: harcama, KREDI hatası + krediBittiIsaretle, iade, dönen bakiye, modal metinleri — hiçbiri değişmedi. Diff'te paketsiz yolu etkileyen tek satır yok [D] |
| Başkasının kredisiyle LLM | G3 yeni bir yetkilendirme deliği açmıyor: listeOlustur/listeRevize oturumu doğruluyor, refId tahmini başkasının raporunu okutmuyor (DUPLICATE dalı kullanicininRaporu(user.id) ile kendi raporuna bakıyor). Maliyet riski yalnız kullanıcının kendi hesabında ve F1'de anlatıldığı gibi |
4 · Muhasebe / mutabakat (denetim sorusu 5)
Bu gece verdiğim "bozmaz" hükmü kod yazıldıktan sonra hâlâ geçerli [D]:
- Bakiyenin tek kaynağı
user.credit_balancekolonu; defteri toplayan hiçbir okuyucu yok (grep -rn "creditLedger\|credit_ledger" src scripts→ tüm okumalarfindFirst/select id,SUMyok). - iyzico mutabakat sorgusu yalnız
l.reason IN ('purchase','topup') AND l.ref_id = o.id(docs/odeme/iyzico.md:84).report_generate/report_revision/refundsatırlarınınref_id'si istemcinin ürettiğirequestId,orders.iddeğil → bu sorguya hiç girmiyor. 0 TL'lik hareket iyzico tarafında görünmüyor. krediKaydiVarMidereason'ı şart koşuyor (credits.ts:205-211) →delta 0refundsatırı bir siparişi "kredisi yazılmış" göstermiyor.- Tek kenar etkisi F2 (kredi-bitti işaretinin silinmesi) ve F5 (ölçüm serisi).
5 · Arayüz ↔ kod uyumu (denetim sorusu 6)
| Yüzey | Gösterilen | Sunucuda olan | Uyum |
|---|---|---|---|
Modal açıklaması (tercih-degisti-modali.tsx:193-197, paketli) |
"…yeni liste bunun yerine geçer; güncelleme paketine dâhil, kredi düşmez." | maliyet = 0, bakiye sabit |
✔ birebir |
Modal buton (:290-292, paketli) |
"Listemi güncelle" (bedelsiz), ok ikonu metnin sonunda | 0 kredi | ✔ (AGENTS.md CTA deseni korunmuş) |
Modal bakiye satırı (:263-267) |
!ucretsiz && !krediYeter → paketliye hiç çıkmaz |
— | ✔ |
Modal, paketsiz (:198-202, :292, :265) |
"…3 kredi düşer", "Listemi güncelle — 3 kredi", "Güncelleme 3 kredi; bakiyen N kredi" | 3 kredi düşer | ✔ değişmedi |
listem-icerik.tsx:167-172 |
raporKredi = user.hasPaket ? 0 : RAPOR_KREDI — modalın tek kredi kaynağı, raporKredi'yi başka tüketen yok (listem-govde.tsx:399 sadece geçiriyor) |
aynı ifade sunucuda :158/:300 |
✔ tek kaynak |
Başlıktaki kredi pill'i (user-nav.tsx:69) |
creditBalance |
paketlide düşmüyor | ✔ artık tutarlı (G3 öncesi düşüyordu) |
KrediYetersiz (:336-347) |
paketliye "Güncelleme 0 kredi ve bakiyen yetmedi" derdi | dal ulaşılamaz | F3 — bugün görünmez |
liste-uretici.tsx:274 "Liste üretimi 3 kredi… +30 kredi yükle" |
paketli dalı | dal ulaşılamaz | Bilinen ölü kod (backlog #B2), G3'ün değil |
paket-satinal.tsx:141-144 "liste 3 kredi" |
yalnız girişsiz ziyaretçiye gösteriliyor | paketsiz için doğru | ✔ |
Metin × kod uyumsuzluğu (yasal/pazarlama): G3'ten sonra /paket'teki "60 Yapay Zeka danışman sorusu (her mesaj 1 kredi)" ilk kez doğru. Kalan tek uyumsuzluk kod değil e-posta: kredi-hatirlatma.ts:36 paketliyi de credit_balance < 3 filtresiyle yakalıyor ve eposta.ts:175-190'daki metin "listenin tamamını açmak… için kredi yükleyebilirsin" diyor — paketlinin listesi zaten tam açık. G3 öncesinden var (backlog #B3), G3 onu büyütmüyor ama F2 ile aynı dosyada çözülmeli.
6 · HÜKÜM
Merge edilebilir. Üç koşulun üçü de kodda karşılanmış, idempotency çapası (UNIQUE(reason, ref_id)) amount/delta = 0 ile fiilen ayakta (koşturarak doğrulandı), paketliye kredi sızıntısı yok, bakiyesi 0 olan paketli liste üretebiliyor, paketsiz davranış bit-bit aynı, iyzico mutabakatı ve bakiye hesabı etkilenmiyor, arayüz sunucunun yaptığını söylüyor. Bu dalda düzeltilmesi gereken bir satır bulamadım.
Merge'e engel olmayan, ayrı iş olarak kuyruğa girmesi gereken üç şey (yazılımcıya şartname netliğinde):
- F1 — üretim tavanı (yeni dal,
credits.ts+rapor-actions.ts):rapor-actions.ts'tespendCreditsçağrısından önce,credit_ledger'dareason = 'report_generate' AND user_id = ? AND created_at > now-24hsayısı ≥ N ise{ ok:false, code:"SINIR", error:"Bugünlük liste üretim hakkın doldu; yarın devam edebilirsin." }dön. N değeri CEO'nun; kilit/bayat-kilit mantığına dokunma,revisionCountupsert'ünü (:247) değiştirme. - F2 —
credits.ts:174:krediBittiAt: nullyalnızopts.delta > 0iken yazılsın (...(opts.delta > 0 ? { krediBittiAt: null } : {})). Aynı commit'tekredi-hatirlatma.ts:36'yaeq(user.hasPaket, false)eklenirse backlog #B3 de kapanır. - F6 — süreç: sabah entegrasyonuna geçmeden
HEAD'inodeme/paket-vaadi'de durduğu bilinsin; G1'e devam eden ajan dalını açıkça doğrulasın.
Bilal'den istenen
- Yok — G3 denetimden temiz çıktı; merge kararı zaten senin kuyruğunda, bu rapor onun için ek bir soru üretmiyor. (F1'in tavan sayısı CEO'ya sorulacak bir ürün kararı, sana değil.)