# Review — Omurga planı: chunk5 revizyonu (üç kimlik alanı) + devir listesi kapanışı — 26.07.2026

> **Review type:** plan-review (chunk5 revizyonu; chunk2/chunk3/chunk6/chunk9 senkron değişiklikleri dahil)
> **Previous review:** `docs/reviews/review-omurga-spec-2026-07-26-r2.md` (spec v1.11 APPROVED, 2 minör) · plan zinciri: `review-omurga-plan-2026-07-25-r5.md`
> **Upstream document(s) read:** `docs/specs/omurga-spec.md` v1.11 **güncel hâli dosyadan yeniden okundu** (§3 bütünü, §3.3/§3.3.1/§3.4, §5.1-5.2, I-5, §13, kriter 31-37, revizyon geçmişi) · `docs/arch/mimari-kararlar.md` AD-07/AD-09/AD-23 (önceki turda okundu; AD-09 bu turda değişmedi, revizyon kaydından teyit)
> **Other cross-referenced:** `omurga-plan_chunk5.md` tamamı · `omurga-plan_chunk6.md` tamamı · `omurga-plan_chunk2.md` §2.8 · `omurga-plan_chunk3.md` §3.6/§3.6.1 · `omurga-plan_chunk9.md` S-16/S-18 + §9.5 meta-kural · `config/tenancy.php` · `tests/Arch/TenancyTest.php` · `docs/issues.md` · kod grep (`system.access_backoffice`)
> **Stage locks in effect:** ⛔ spec v1.11 APPROVED — üç alan / yetki tavanı / kapsam tercihi modeli bu turda yeniden tartışılmaz; incelenen şey planın ona uygunluğudur. ⛔ Kapılı erişim mekanizması destek spec'ine ertelendi (Sets kararı, spec §3.3.1).

---

## Ön doğrulama — spec'teki R2 minörleri

Heyet 142'nin iki minörü spec'e işlenmiş ve doğrulandı: **R2-1** sözleşme cümlesi §3.3.1'e geri kondu, bu kez rolün adına değil *"süper admin değil ama müşteri verisine erişiyor"* durumuna bağlı (spec:129). **R2-2** §3.3'e log sınıfı tablosu (okuma → erişim logu, yazma → §7.1 audit'i, yazma her ikisini tetikler; spec:107-114) ve kriter 33 buna göre yeniden yazılmış (spec:515). Bonus: §3'ün alt bölüm sırası düzeltilmiş (3.0…3.2 → 3.3 → 3.4) — önceki turların biçim notu da kapandı. Revizyon kaydı girilmiş (heyet 142 kapanış paragrafı).

## Upstream Coverage Matrix

Spec v1.11 dosyadan okunarak sıfırdan üretildi; sunulan matris kanıt sayılmadı, satırları bağımsız doğrulandı.

| Upstream madde | Durum | Kanıt |
|---|---|---|
| §3 (spec:35): üç alan hiçbir tabloyu paylaşmaz, özellikle yetki tablolarını | ✓ | chunk5 §5.1 üç tablo ailesi + şifre sıfırlama tabloları (chunk5:18-57) · §5.1.1 üç guard/oturum (61-68) · chunk6 §6.1 üç izin ailesi (20-28) · kriter 20/21 (chunk5:226-227), chunk6 kriter 2 |
| §3 (spec:40): backoffice tenant'a ait değil | ✓ | chunk2 §2.8 (324-329) + `config/tenancy.php` exempt listesi (31 tablo) + `TenancyTest.php:89-100` pin — customer ailesi bilinçli listede değil, `consents/customers/customer_users/magic_links` muaf değil |
| §3.3 (spec:97-105): yetki tavanı yoktur; yol yokluğu ≠ kısıt | ✓ | chunk5 §5.1 (38, 40) · §5.5 backoffice giriş notu (136) · chunk6 §6.5 `SimpleScopeResolver` boş dizi + "yetki tavanı değildir" (90) — üç yerde de doğru dil |
| §3.3 log sınıfı tablosu (spec:107-114) + kriter 33 (spec:515) | ⚠ → **F-1** | Bu chunk backoffice'e tenant verisi yolu üretmiyor — bugünkü tek yol L-4 feed'i ve onun log bağı chunk3'te kurulu (kriter 34 kapsamı). **Erteleme doğru; adres eksik:** chunk5:224 kriter 33'ü "chunk6 ve chunk8'e aittir" diye işaret ediyor ama o chunk'larda karşılığı **yok** (grep doğrulandı); chunk9 §9.5 meta-kuralı gereği adressiz kural zorlamasızdır |
| §3.3.1 (spec:116-133): G-1…G-4 dar rollerin erişim biçimi | ⚠ **bilinçli kapsam dışı — doğru** | chunk5:40 ve chunk6:28 açıkça yazıyor: mekanizma destek spec'iyle gelir; burada üretilen tek şey ailenin ayrı olması. Spec §3.3.1'in kendisi bu ertelemeyi tanımlıyor — kapanış destek spec'inin matrisine aittir |
| §3.4 (spec:135-143) + kriter 37 (spec:519) | ⚠ → **F-1** | Panel kapsam taraması hiçbir chunk'ta sahipli değil. Backoffice paneline ekran **bugünden** ekleniyor (chunk8 §8.6 analitik ekranı Filament'te) — kriter bekletilemez |
| §5.1 (spec:197): yöntem matrisi üç alan bağımsız | ✓ | chunk5 §5.3 (100-108); kriter 25 (231); backoffice matrisi admin-tanımlı + MFA üstte (106) — AD-08 ile tutarlı |
| §5.2 (spec:207): backoffice **alan bazlı** MFA, ayarla kapatılamaz | ✓ | chunk5 §5.7(b) (169-174): zorlama bu chunk'ta, guard seviyesinde, yetki katmanını beklemiyor — "henüz yetki almamış kullanıcı" aralığı yok; kriter 24 (230) ayar-override denemesini de sınıyor |
| §5.2 (spec:205): yetki bazlı MFA | ✓ | chunk5 §5.7(a) → zorlama chunk6 §6.4, kriter 7 (P-4 deseni, önceden mutabık) |
| A-6 (spec:228): oturum süreleri alan bazında | ✓ | chunk5 §5.6 A-6 satırı — üç ayar tablosu adlandırılmış (157) |
| I-5 (spec:93) + kriter 36 (spec:518) | ✓ | chunk5:59 (şemada bağlayıcı kolon/eşleştirme tablosu yok) + kriter 23 (229: şema kontrolü + yetki/oturum taşımama testi) |
| §13 (spec:456-457): aynı e-posta / iki alanda kayıt | ✓ | chunk5:36, 55-57; kriterler 2, 3, 22 |
| §4.1 B-1…B-6: bağlamsız yüzey tek kapıdan | ✓ (⚠ → **F-4** sertleştirme) | chunk5 §5.1.2 (70-78): yeni bağlamsız fonksiyon **açılmıyor**, mevcut `authenticate_lookup` (S-9 envanterinde) kullanılıyor; B-3'ün "tek ve denetlenebilir kapı" hükmüne uygun. Kalanlar F-4'te |
| Kriter 31 (spec:513) | ✓ | kimlik yarısı chunk5 kriter 20, izin yarısı chunk6 kriter 2 — iki yarım açıkça etiketli, çift sayım yok |
| Kriter 32 (spec:514): Y-4/Y-5 **üç alanda da** | ⚠ → **F-2** | chunk6 §6.3 mekanizmaları alan-agnostik (doğru kurulum) ama **kanıt** iki alanda: 7b müşteri, arch testi Action'lar; backoffice alanında Y-5 (yetkisiz menü/rota) ve Y-4 (atama reddi) için test kriteri yok |
| Kriter 34 (spec:516) | ✓ | chunk3 §3.6.1: `audit.view_all_tenants` **backoffice ailesine** taşınmış (176), eski izne atıf düzeltilmiş; tek giriş noktası + S-11 taraması yerinde |
| Kriter 35 (spec:517) | ✓ | chunk5 kriter 24 |
| AD-23: provisioning izinleri | ✓ | chunk6 §6.2: `user.provision`/`user.assign_permissions` backoffice ailesinde, gerekçeli (53); ofis ailesindeki ad-eşi ayrımı kriter 2b ile sınanıyor |

**Devir listesi (heyet 142) kapanışı:** chunk5 §5.8 + kriter 19 yeni modelde ✓ · chunk6 `system.access_backoffice` kaldırıldı + üç yetki dünyası ✓ · chunk2 §2.8 backoffice izin ailesi + müşteri ailesinin bilinçli yokluğu + `sessions` düşürme notu ✓ · chunk3:176 ✓ · `docs/issues.md` tehdit varsayımı kalemi yeniden yazılmış, eski model cümlesi yok ✓ · backoffice şifre sıfırlama tablosu tanımlı ✓. **Altı kalemin altısı da kapalı.** Ayrıca chunk9 S-18 (encrypted_columns iki yönlü senkron) yazılmış ve §9.5 kesin listesine + kriter 7'ye bağlanmış — heyet 139'un açık kalemi kapalı, S-16'ya güven zinciri açıkça işaretli.

## ✅ What works

- **§5.1.1'in `sessions` kararı iki bağımsız ayakta duruyor** (soru 1'in cevabı): kriter 31 kararı zaten veriyor — spec *"kimlik, oturum, auth ayarı ve izin tabloları ayrı"* diyor, yani tek tablo + `identity_domain` kolonu spec ihlali olurdu. `user_id` çakışması "fazladan gerekçe" değil, **bağımsız ve daha güçlü** bir gerekçe: spec kuralı hiç olmasaydı bile `users.id = 1` ↔ `backoffice_users.id = 1` çakışması A-2'yi bir güvenlik hatasına çevirirdi (bir alanın kullanıcısı diğer alanın oturumunu listeler/sonlandırırdı). Spec'in soyut kuralının somut bir doğruluk hatasına karşılık geldiğini göstermek, kuralı "bürokrasi" okumasına karşı korur — ikisini de tutmak doğru.
- **§5.1.2 bağlamsız yüzeyi büyütmeden çözüyor:** ikinci bir SECURITY DEFINER fonksiyonu reddedip mevcut kapıyı kullanmak B-3'ün ruhuna uygun; "bağlamsız yüzeyi genişletmek, dönen alanı daraltmaktan pahalıdır" gerekçesi doğru sıralama. `customer_password_reset_tokens`'ın e-posta değil `customer_user_id` anahtarlı olması, çok-tenant e-posta gerçeğinin doğru sonucu.
- **§5.7'nin (a)/(b) ayrımı** spec §5.2'nin iki zorunluluğunu iki farklı katmana doğru dağıtıyor; (b)'nin guard seviyesinde ve chunk6'yı beklemeden zorlanması, "yetki tavanı olmayan alanda yetkisiz aralık bırakılmaz" gerekçesiyle sağlam.
- **§5.8 tek-kaynak host tablosu** ve `ResolveIdentityDomain` — üç ayrı host kontrolünün sessiz yanlış-alan hatası üreteceği tespiti doğru; kriter 22'nin üç yönlü oturum-host çapraz testi bu tabloyu gerçekten sınıyor.
- **chunk6 §6.1'in üç izin ailesi** gerekçesi iki yönlü ve spec §3 diliyle birebir; `teams=false` kararı Spec 3'ün çok-grup modeline karşı doğru savunma.
- **`config/tenancy.php` + `TenancyTest` pini** (31 tablo, customer ailesinin yokluğu pozitif olarak sınanıyor, `consents` dışlaması) — doküman-kod senkronu bu kez kanıtla kurulmuş.

## ⚠️ Findings & Risks (in-scope for this review type)

**F-1 (orta) — Kriter 33 ve 37 plan setinde adressiz; chunk5'in işaret ettiği adresler onları taşımıyor.** chunk5:224 *"§3.3'ün kapsam ve denetim kriterleri chunk6 ve chunk8'e aittir"* diyor; chunk6 ve chunk8'de kriter 33/37'ye karşılık gelen hiçbir kriter veya tarama yok (grep ile doğrulandı; chunk9 ve plan index'te de geçmiyorlar). Chunk9'un kendi meta-kuralı bunu bulgu yapar: *"burada olmayan kuralın zorlaması yoktur"* (chunk9:100). İkisi ayrı nitelikte: (a) **kriter 37** bugün anlamlı ve mekanik — backoffice paneline ekran chunk8 §8.6'dan beri ekleniyor, panel kayıtlarının taranması S-serisi sınıfının tam tanımı; sahipsiz bekletilemez. (b) **kriter 33** bugün ölçülecek yüzeye sahip değil (tek yol L-4 feed'i, o da kriter 34/chunk3'te kapalı) — erteleme doğru; ama "backoffice'e tenant verisi yolu ekleyen her gelecek chunk log bağını kendi kriterine alır" yükümlülüğü bir **devir kuralı** olarak hiçbir yerde yazılı değil, yani S-16 emsalindeki "kural yazıldı ama kimse zorlamıyor" sınıfına bugün değil, ilk yol açıldığında düşecek. (Soru 2 ve 3'ün cevabı budur: 2 → erteleme doğru + devir kuralı şart; 3 → chunk9'a S-19 sınıfı bir tarama, panel doğana kadar beklemek meta-kurala takılır.)

**F-2 (minör) — Kriter 32'nin backoffice kanıt bacağı yok.** chunk6 §6.3 mekanizmaları alan-agnostik kurulmuş (doğru), ama spec kriter 32 *"üç alanda da zorlanıyor"* der ve kanıt üç alanda test ister: chunk6 kriterlerinde müşteri (7b) ve ofis (arch testi) var, backoffice alanında yetkisiz menü/rota (Y-5) ve sahip olunmayan yetkiyi atama reddi (Y-4) testi yok. "Bugün tek rol var, senaryo boş" savunması geçersiz — izinsiz backoffice kullanıcısı bugün de oluşturulabilir ve test yazılabilir. (Soru 4'ün cevabı: evet, varsayım yapılıyor — mekanizma katmanında değil, kanıt katmanında.)

**F-3 (minör) — Çift kriter: chunk5 kriter 19'un dizge kontrolü ile chunk6 kriter 2a aynı kontrol.** *"`system.access_backoffice` kod tabanında hiç geçmiyor (dizge kontrolü)"* iki chunk'ta iki ayrı kriter olarak yazılmış. F-13 emsali (çift kayıt kriter tekilleştirilir — heyet 134): iki yerde yaşayan kriter iki ayrı kapanış üretir ve drift riski taşır. Tek yer seçilmeli, diğeri atıfa dönmeli.

**F-4 (minör) — §5.1.2'nin iki sertleştirme boşluğu.** (a) **Hız sınırı tanımsız:** şifre sıfırlama, kimliksiz yeni bir uç noktadır ve her istek e-posta üretir (çok-tenant e-postada kayıt başına token). A-1 yalnız *giriş* denemelerini kapsar; sıfırlama isteği için eşik/kilit (`config('security.*')` deseninde) yazılmamış — e-posta bombardımanı ve token üretim floodu açık. (b) **E-posta içeriği tanımsız:** aynı e-posta N tenant'ta kayıtlıysa "her kayıt için ayrı token, hepsi aynı kutuya" gidiyor. Ekranda kayıt sayısı gizleniyor (doğru) ama posta içeriği, kontrolü doğrulanmamış bir kutuya sistem eliyle üretilmiş bir **çapraz-tenant ilişki artifact'ı** taşır — bağlantılar tenant adı/işareti taşırsa, kutuya erişen herhangi biri (kişinin kendisi olmayabilir) "bu adresin X ve Y firmalarında hesabı var" bilgisini alır; I-1/I-2 ve kriter 15'in korumaya çalıştığı bilgi sınıfı tam budur. Postanın tenant kimliği ifşa etmeyeceği (ve tercihen kayıt başına ayrı, birbirine atıfsız posta) plan seviyesinde yazılmalı.

**F-5 (minör) — Kodda eski modeli anlatan iki yorum duruyor:** `app/Queries/Audit/BackofficeAuditFeed.php:77` ve `tests/Feature/OmurgaRls/AuditCrossTenantReadTest.php:189` — *"system.access_backoffice gets a person into the panel"*. Spec v1.11'de bu izin yok; heyet.md kural 4-5'in açıkça bulgu-konusu ilan ettiği sınıf (yanlış modeli anlatan kod yorumu). Kriter 19/2a'nın dizge kontrolü impl'de bunları zaten kıracak — ama o kontrol chunk5 impl'inde geliyor; iki yorumun bugün düzeltilmesi ucuz ve dizge kontrolünün ilk koşumunun "mevcut kod temizliği"ne takılmasını önler.

## ❓ Open Questions (to be answered before next stage)

1. **(Soru 5 — aynı ad iki ailede)** Kabul edilebilir; bulgu değil. Aile zaten namespace'tir, kriter 2b çapraz sızmayı sınıyor ve audit satırları aktör türünü taşıdığı için (chunk3 ofis/backoffice aktör ayrımı) log okuyan kişi hangi ailenin izni olduğunu her zaman ayırt edebilir. `backoffice.user.provision` gibi önekli ad `resource.action` formatını bozar ve aile bilgisini veriden ada taşır — mevcut karar daha temiz. Tek koşul: izin adının aile bağlamı olmadan tek başına gösterildiği bir arayüz/rapor yüzeyi doğarsa bu karar yeniden değerlendirilmeli; bugün öyle bir yüzey yok.
2. **F-1'in adres kararı Sets'indir:** kriter 37 için önerilen sınıf chunk9 taraması (S-19); kriter 33'ün devir kuralı için doğal adresler plan index'i veya chunk9 §9.5 girişi. Hangisi seçilirse seçilsin, "adressiz kural zorlamasızdır" meta-kuralıyla tutarlı bir kayıt gerekir.
3. F-4(b)'de posta-başına-kayıt mı, tek posta-tenant'sız-içerik mi — ürün kararı; ikisi de I-2'yi korur, plan hangisiyse onu yazsın.

## Verdict: ✅ APPROVED

Chunk5 revizyonu spec v1.11'i doğru ve yer yer spec'in kendisinden daha somut gerekçelerle (oturum `user_id` çakışması, guard-seviyesi MFA) plana indiriyor; heyet 142 devir listesinin altı kalemi de kanıtla kapalı; matriste ❌ yok. Beş bulgunun hiçbiri chunk5'in kendi implementasyonunu bloklamıyor: F-1 chunk9/index'e birkaç satırlık adres ataması (chunk6 impl'inden önce yapılmalı), F-2 chunk6 kriter listesine iki test bacağı, F-3 tekilleştirme, F-4 §5.1.2'ye iki sertleştirme cümlesi (bunlar chunk5 impl'inden **önce** işlenmeli — akışın kendisi bu chunk'ta yazılacak), F-5 iki kod yorumu. Bulgular işlendikten sonra chunk5 implementasyonuna başlanabilir. Son karar kullanıcınındır.
