# Review — EGT-50: Ofis/Backoffice Tanımı ve Log Görünürlüğü (Upstream Revizyon) — 2026-07-26

> **Review type:** spec-re-review + plan-re-review (onaylı upstream belgelerin revizyon turu; AD-09/AD-21/AD-23 + spec v1.8 + plan chunk3)
> **Previous review:** `docs/reviews/review-omurga-spec-2026-07-25-r8.md` (spec v1.7 APPROVED) · `docs/reviews/review-omurga-plan-2026-07-25-r5.md` (plan v2.3 APPROVED) · `docs/reviews/review-omurga-chunk2-impl-2026-07-26-r3.md`
> **Upstream document(s) read:** Sets'in 7 kararı (review talebi metni — birincil upstream) · `CLAUDE.md` (17 kırmızı çizgi) · `docs/arch/mimari-kararlar.md` (AD-02/03/04/08/09/21/22/23/26/27 tam metin)
> **Other cross-referenced documents:** `docs/specs/omurga-spec.md` v1.8 (tamamı) · `docs/plans/omurga-plan.md` (index) · chunk2 (tamamı) · chunk3 (tamamı) · chunk6 §6.5/§6.9 · chunk8 §8.5-8.6 · chunk9 (tamamı) · `config/audit.php` · `tests/Feature/OmurgaRls/SchemaConformanceTest.php` · `docs/claude/heyet.md` · `docs/issues.md` · chunk1/4/5/7 (grep süpürmesi)
> **Stage locks in effect:** Spec v1.7 ve Plan v2.3 onaylıydı; bu turda onaylı belgelerin kendisi revize edildiği için **revize edilen bölümler yeniden açıktır**. Değişmeyen bölümlerdeki kararlar tartışmaya kapalıdır. Chunk 1/2 implementasyonları ayrı turlarda APPROVED — yalnız bu revizyonla çelişki aranmıştır. `backoffice_users` kararı kapsam dışı (chunk5'e ertelenmiş, `docs/issues.md:18`'de kayıtlı).

---

## Upstream Coverage Matrix

Birincil upstream: Sets'in 7 kararı. İkincil: spec v1.8'in yeni hükümlerinin plana inişi ve terim süpürmesi.

| Upstream § / madde | Reviewed doc'ta durumu | Kanıt |
|---|---|---|
| Karar 1 — backoffice = sistem çekirdeği; üretir/tüketir; tanımsız şey ofiste kullanılamaz; yazma backoffice iznine bağlı | ✓ | AD-09 `mimari-kararlar.md:59-68` — tablo + "değişmez kural" + testle denetlenen sınır ifadesi |
| Karar 2 — global parametre backoffice'te, daraltma ofiste, genişletme yok | ✓ | AD-09 `mimari-kararlar.md:70` — %20/%10/%25 örneği, "etkin değer zincirin en dar halkası"; mekanizma sahibi `docs/issues.md:27`'de açık kalem olarak kayıtlı |
| Karar 3 — backoffice mali tanım yapar, mali durumu görüntülemez; gerekçe kapsam kayması | ✓ | AD-09 `mimari-kararlar.md:72` — "iki ofis yazıp iki ofis maintain ederiz" gerekçesi aynen işlenmiş |
| Karar 4 — backoffice'in kendi yetki hiyerarşisi; kapı ≠ god tier | ✓ | AD-09 `mimari-kararlar.md:74` — destek görevlisi örneği dahil; yanlış gerekçe açıkça "bulgu konusudur" diye işaretli |
| Karar 5 — kullanıcı yönetimi iki yol; ofiste açık izin, backoffice'te provisioning; ilk kullanıcılar backoffice'ten | ⚠ | AD-23 `mimari-kararlar.md:268-272` — iki yol yazılı; ancak kalıcı backoffice yetkisi ile kural 1'in mutlak metni arasındaki ilişki çözülmemiş → **F-9** |
| Karar 6 — loglar backoffice'te toplu; ofis yalnız kendi personelinin olaylarını görür; müşteri izi ofise/müşteriye görünmez | ⚠ | AD-21 `mimari-kararlar.md:193-203` + spec §7.5 tablo — tablo doğru; ancak "son aktif" hükmü L-1 ile çelişiyor (**F-2**) ve giriş/çıkış olaylarının ofis feed'indeki durumu tanımsız (**F-3**) |
| Karar 7 — aksiyon log değildir; müşteri onayı/revize/yazışma ve katılımcı katılım/not/check-in iş verisidir | ✓ | AD-21 `mimari-kararlar.md:179-181` · spec §7.5 `omurga-spec.md:237` · chunk3 §3.1 `omurga-plan_chunk3.md:26-28` — üç katmanda tutarlı; UI-audit bağımlılığı gerekçesi de yazılı |
| Spec v1.8 — §7.3 terim değişikliğinin spec içinde eksiksizliği | ⚠ | `omurga-spec.md:412` (§13 sınır durumu) ve `omurga-spec.md:425` (§14 kriter 8) hâlâ "Aktivite logu" → **F-1** |
| Spec v1.8 — §7.5 L-1 (müşteri denetim izi ofiste görünmez) → plan | ✓ | chunk3 N-4 `omurga-plan_chunk3.md:140,144-148`, kriter 15 `:213` |
| Spec v1.8 — §7.5 L-2 (kısıt sorgu katmanında) → plan | ⚠ | chunk3 `omurga-plan_chunk3.md:146` — sorgu sınıfı deseni var; ancak gerekçe hatalı ve "atlanamaz" iddiasının zorlaması tanımsız → **F-6** |
| Spec v1.8 — §7.5 L-3 (kullanım logu satır satır gösterilmez) → plan | ✓ | chunk3 `omurga-plan_chunk3.md:89`, kriter 18 `:216` |
| Spec v1.8 — §7.5 L-4 (backoffice çapraz-tenant; tek yol, ayrı izin, kendisi audit'lenir) → plan | ⚠ | chunk3 §3.6.1 `omurga-plan_chunk3.md:150-157` — izin/audit/tek-sınıf yazılı; ancak "tüm tenant kimlikleri" listesinin kaynağı tanımsız ve chunk2 ile çelişkili (**F-4**); "tek istisna" iddiası belge setinde tek değil (**F-5**); devredilen denetimler chunk9 listesinde yok (**F-7**) |
| Terim süpürmesi — kod/config/test tarafı (`audit_activity`→`audit_usage`, `ActivityLogger`→`UsageLogger`, `LogActivity`→`LogUsage`, retention anahtarı) | ✓ | `config/audit.php:19-24,58` · `SchemaConformanceTest.php:42` · `app/`, `config/`, `database/`, `tests/` grep'inde eski ad sıfır geçiş · `docs/claude/heyet.md:21` güncel |
| Plan bütünlüğü — index'in revizyonu yansıtması | ❌ | `omurga-plan.md:3-5` — sürüm "2.3 · 25.07.2026", upstream pin "spec **v1.7**"; chunk3'ün 26.07 revizyonu ve v1.8 dayanağı index'te kayıtsız → **F-8** |
| chunk3 N-4 aktör tipolojisi ↔ spec §3 kimlik modeli | ⚠ | `omurga-plan_chunk3.md:144` `customer_user · participant` ayrımı ↔ spec §3.0 "katılımcılık ayrı hesap değil, yetenek" → **F-10** |

---

## ✅ What works

- **AD-09 tanımı, projenin en çok karışan ayrımını gerçekten sabitliyor.** Tablo + "üretir/tüketir" değişmez kuralı + mali sınırın *kapsam kayması* gerekçesi + "backoffice'e giren en geniş yetkiye sahiptir yanlıştır ve bulgu konusudur" cümlesi — yanlış tarafa kod yazacak birinin tutunabileceği gri alan bırakılmamış. Tehdit varsayımının (backoffice yöneticisi = şirket sahibi) açıkça yazılması ve yeniden değerlendirme koşulunun belirtilmesi doğru pratik.
- **"Aksiyon log değildir" ayrımı mimari olarak sağlam ve doğru yere yazılmış.** İş akışı ekranlarının audit tablosundan beslenmemesi kuralının gerekçesi (denetim katmanının izolasyon/maskeleme/saklama kuralları arayüze sızar; audit UI bağımlılığı yüzünden değiştirilemez hale gelir) üç belgede de (AD-21, spec §7.5, chunk3 §3.1) aynı ve tutarlı.
- **Terim değişikliğinin kod tarafı eksiksiz.** `config/audit.php` yalnız adı değiştirmemiş, gerekçeyi de İngilizce yorumla taşıyor (satır 14-17); `SchemaConformanceTest` istisna listesi güncel; `app/`, `config/`, `database/`, `tests/` altında eski ad sıfır geçiş. Kriter 18'in tarama kapsamını tanımlayıp `docs/reviews/`'u tarihsel kayıt olarak dışarıda bırakması doğru.
- **N-4'ün "imza parametre kabul etmez" deseni** (chunk8 §8.6 k-anonimlik deseninin aynısı) ve bunun reflection testiyle sabitlenmesi (kriter 16) — ekran filtresine güvenmeme ilkesinin somut ve ölçülebilir karşılığı.
- **NULL disiplini ile N-4'ün bileşimi** chunk2'nin kanıtlanmış deneylerine (10/11/12) dayanmaya devam ediyor; `forWrite` daraltma yolları (N4/M1 çözümleri) revizyonla bozulmamış.
- **AD-23'e eklenen bootstrap gerçeği** ("sistem ilk açıldığında yalnız backoffice kullanıcıları vardır") `docs/issues.md:23`'teki `backoffice_users` değerlendirmesine argüman olarak da işlenmiş — karar izi kopmuyor.

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

**F-1 — Spec v1.8 terim değişikliği spec'in kendi içinde eksik işlenmiş.** `omurga-spec.md:412` (§13: *"Aktivite logu yazılamıyor"*) ve `omurga-spec.md:425` (§14 kriter 8: *"Aktivite logu saklama süresi yönetim ekranından değiştirilebilir"*) hâlâ eski terimi taşıyor. Bu typo değil, v1.8'in kendi gerekçesinin ürettiği semantik çakışmadır: v1.8'e göre "aktivite" artık iş olaylarını (`audit_writes`) anlatır ve kriter 8 bu okumayla **silinmez** olan tablonun saklama süresinin ayarlanabildiğini iddia eder hale gelir. v1.8'in revizyon tablosundaki *"arayüzde 'aktivite' yazan ekranın yanlış tablodan beslenmesi"* riski, spec'in kendi kabul kriterinde gerçekleşmiş durumdadır.

**F-2 — "Son aktif" hükmü L-1 ile çelişiyor.** AD-21 `mimari-kararlar.md:214`: kişi bazında tutulan tek türetilmiş veri "son aktif" zaman damgasıdır, "hem ofis hem müşteri kullanıcısı kartında" görünür ve gerekçelerinden biri *"paneli açmayan müşteri = churn sinyali"* — doğası gereği **ofisin** (satışçının) bakacağı bir sinyal. Oysa L-1 (`omurga-spec.md:245`) ve AD-21 görünürlük tablosu (`mimari-kararlar.md:201`) müşteri kullanıcısının *"ne zaman giriş yaptığının"* ofiste **hiçbir ekranda** yer almayacağını söylüyor. "Son aktif" tam olarak giriş/kullanımdan türetilmiş bir zaman damgasıdır; müşteri kullanıcı kartı ofiste gösteriliyorsa L-1 ihlal edilir, gösterilmiyorsa churn gerekçesi karşılıksız kalır. Hangi panelin hangi kimlik alanının "son aktif"ini gösterdiği hiçbir belgede tanımlı değil. Ayrıca RT-6/AD-21 online göstergesinin gerekçesi (*"başka bir tüzel kişinin çalışanını izlemiş oluruz"*) aynı veriye uygulanmamış — anlık gösterge yasak, ondan bir tık geride olan kalıcı damga serbest ve gerekçe farkı yazılmamış.

**F-3 — Giriş/çıkış olayları, iş olayı ↔ davranış metriği ayrımının açığı.** `audit_writes` kapsamı giriş/çıkışı içeriyor (`mimari-kararlar.md:185`, spec §7.1 "kimlik doğrulama olayları") ve görünürlük tablosu ofis yöneticisine ekibinin `audit_writes` satırlarını **kişi bazında** açıyor. Sonuç: satış yöneticisi, ekip üyesinin login/logout olaylarını kişi bazlı zaman serisi olarak görür — bundan toplam çevrimiçi süre ve aktiflik çıkarımı elle yapılabilir; kırmızı çizgi 17'nin ve §8.5'in agregat/k-anonimlik rejiminin kullanım verisi için engellediği şeyin kendisi, iş olayı kapısından geri girer. "İş olayı ↔ davranış metriği" ayrımı teklif oluşturma/onay için sağlamdır; ancak giriş/çıkış bir iş aksiyonu değil oturum telemetrisidir ve `audit_writes`'ta güvenlik gereği yaşar. Hiçbir belge (AD-21 görünürlük tablosu, spec §7.5, chunk3 N-4/OfficeAuditFeed kapsamı) kimlik doğrulama olaylarının ofis feed'inde yer alıp almadığını ele almıyor. Sınır burada çizilmediği sürece ayrım, Sets'in sorduğu "kaçış yolunu" bu tek olay sınıfı üzerinden açıyor.

**F-4 — chunk3 §3.6.1'in teknik yolu, dayandığı listenin kaynağını tanımlamıyor ve chunk2'nin bugünkü araçlarıyla kurulamıyor.** "Sorgu, tenant bağlamını **tüm tenant kimlikleriyle** açar" (`omurga-plan_chunk3.md:157`) — bu listenin nereden geleceği yazılmamış. Mevcut mekanizmalarla: (a) `customers` RLS'lidir ve SELECT politikası `id = ANY(app.tenant_ids())` — tüm id'leri okumak için tüm id'lerin bağlamda olması gerekir (chunk2 §2.8'in kendisinin işaret ettiği tavuk-yumurta); (b) bilinen tek numaralandırma fonksiyonu `app.all_customer_ids()` chunk5'e taşınmış, "geçici" işaretli, `TreeScopeResolver` gelince **kaldırılacak** (`omurga-plan_chunk2.md:330-338`) ve `SECURITY DEFINER`'dır — §3.6.1'in aynı maddede kendisinin yasakladığı mekanizma; (c) `TreeScopeResolver` organizasyon **kapsamını** döndürür, "tümü"nü değil; backoffice kimliği için ne döndüreceği hiçbir yerde tanımlı değil. Kalıcı kaynak (ör. Spec 3 atama tabloları) hiçbir belgede bu yola bağlanmamış. "İzolasyonun tek meşru istisnası" olarak sunulan yol, planın kendi mekanizma envanteriyle çalıştırılamaz durumda.

**F-5 — "Tek istisna" iddiası belge setinde tek değil.** Spec §4.1 kimlik doğrulama bootstrap'ini "**Tek istisna**" ilan ediyor (`omurga-spec.md:99`); §7.5 L-4 backoffice okumasını "izolasyonun **tek istisnası**" ilan ediyor (`omurga-spec.md:248`); AD-21 aynı iddiayı taşıyor (`mimari-kararlar.md:203`); chunk3 §3.6.1 "chunk2'de kurulan izolasyonun **tek meşru istisnası**" diyor (`omurga-plan_chunk3.md:152`). Oysa T-4 sistem yöneticisine **genel** çapraz-tenant erişim verir (`omurga-spec.md:117` — yalnız denetim kaydı değil), T-6/G-1 agregat okumayı kapsam dışına çıkarır ve chunk9 S-9 `SECURITY DEFINER`'ı "RLS'i bypass eden tek meşru mekanizma" diye adlandırır. Aynı eksende birbiriyle yarışan en az üç "tek" var; L-4'ün teklik iddiası T-4 ile doğrudan çelişiyor (backoffice'in denetim-dışı verilerdeki çapraz-tenant erişimi hangi hükme tabidir — T-4 mü, L-4'ün dar yolu mu?). Sets'in "tek noktaya bağlanmış mı?" sorusunun cevabı hayırdır.

**F-6 — N-4'ün tek-katman gerekçesi hatalı; "sorgu sınıfı atlanamaz" iddiasının zorlaması yok.** Gerekçe *"RLS oturumun hangi panelden geldiğini bilemez — rol aynı roldür"* (`omurga-plan_chunk3.md:146`). Ancak RLS'in tenant'ı da "bilmesi"nin tek yolu uygulamanın `SET LOCAL` ile beyan etmesidir (chunk2 §2.4-2.5) — bilememe mutlak bir kısıt değil, beyan edilmeyen bir bilgidir; gerekçe olarak yazılmış hali, güvenlikle ilgili bir tek-katman kararını yanlış bir olgusal iddiaya dayandırıyor. Buna ek olarak: sınıf imzası parametre kabul etmese de, ofis tarafında `audit_writes`'a `OfficeAuditFeed` **dışından** sorgu yazılmasını engelleyen hiçbir arch testi veya tarama tanımlı değil — "ekran filtresi atlanabilir, sorgu sınıfı atlanamaz" iddiası, sorgu sınıfının kendisinin atlanabildiği gerçeğini karşılamıyor. (Karşılaştırma: aynı desenin k-anonimlik uygulamasında ekran tek — backoffice Filament, `analytics.view` — ve S-2 taraması var; N-4 için eşdeğeri yok.)

**F-7 — chunk3'ün chunk9'a devrettiği denetimler chunk9'un kesin listesinde yok.** chunk3 dört yerde "chunk9 kural taraması denetler" diyor: §3.1 iş akışı ekranlarının audit'ten beslenmemesi (`:28`), §3.6.1 tek giriş noktası (`:154`), kriter 17 `BYPASSRLS`/`SECURITY DEFINER` arch taraması (`:215`), kriter 18 `audit_usage` listeleme rotası taraması (`:216`). Oysa chunk9 §9.5 **S-1…S-10 ile sınırlı kesin bir listedir** ve kriter 7 "on kuralı tarıyor" der (`omurga-plan_chunk9.md:78-89,138`); chunk9 revizyon süpürmesine dahil edilmemiş. Planın kendi disiplini (kesin liste; istisna/madde eklemek plan değişikliğidir — chunk2 kriter 6 emsali) burada ihlal ediliyor: chunk3'ün güvendiği zorlama, zorlamayı tanımlayan belgede mevcut değil. Kriter 17'nin "arch taramasıyla doğrulanıyor" ifadesi de bu yüzden ölçülemez durumda — hangi taramanın, meşru `SECURITY DEFINER` envanteriyle (S-9) nasıl ayrışarak bunu doğrulayacağı tanımsız.

**F-8 — Plan index'i revizyonu yansıtmıyor.** `omurga-plan.md:3` "Sürüm 2.3 · 25.07.2026"; `:5` upstream'i "**v1.7** — heyet onaylı" olarak pinliyor. Oysa chunk3 artık v1.8'de doğan §7.5'e dayanıyor (chunk3 `:6` "Spec dayanağı: §7 (7.1–7.5)" — §7.5 v1.7'de kabul kriteriydi, log görünürlüğü değil) ve 26.07 revizyonu index'in revizyon geçmişinde kayıtsız. Chunk'lı doküman bütündür ve index tanımlayıcıdır; index'in beyan ettiği upstream ile chunk'ın gerçek dayanağı şu anda iki farklı spec sürümüdür. "Plan kanundur" rejiminde implementer'ın hangi spec'e karşı çalışacağı belirsizleşir.

**F-9 — AD-23 kural 1 ile backoffice provisioning'in ilişkisi metinde çözülmemiş.** Kural 1 "pazarlıksız" başlığı altında mutlaktır: *"**Kimse** sahip olmadığı yetkiyi devredemez"* (`mimari-kararlar.md:265`). Yeni bölüm bunu *"kural 1'in ihlali değil, ondan **önce gelen** provisioning adımıdır"* diye çerçeveliyor (`:271`) — ancak aynı cümle yetkinin *"sonrasında da backoffice'te kaldığını"* söylüyor. "Önce gelen adım" çerçevesi yalnız ilk kurulum anını tarif eder; süreklilik arz eden backoffice kullanıcı-yönetimi yetkisi bir adım değil, kural 1'e **kalıcı bir istisnadır** (backoffice yöneticisi, AD-09 gereği ayrı izin ailesinde yaşadığı için sahip olmadığı ofis yetkilerini atamaya devam eder). İki hüküm yan yana: biri istisnasız "kimse", diğeri kalıcı bir muafiyet — ve muafiyetin gerekçesi (tehdit varsayımı) başka belgede (AD-09). Bu ayrım bir ay sonra tam da "kural 1 mutlak mı değil mi" tartışması olarak geri gelir.

**F-10 — `actor_type` enum'u kimlik modelinde karşılığı olmayan bir ayrım kodluyor.** chunk3 N-4 uygulaması `customer_user` ve `participant`'ı ayrı aktör türleri olarak tanımlıyor (`omurga-plan_chunk3.md:144`). Oysa spec §3.0'a göre katılımcılık ayrı bir kimlik değil, aynı `customer_users` kaydının **yeteneğidir** — aktör her durumda aynı kayıttır. İki yeteneği olan kişi bir olay ürettiğinde (check-in, teklif onayı, evrak görüntüleme) hangi türün yazılacağı tanımsız; tür kişiye mi, oturuma mı, eyleme mi bağlı — belirsiz. Kriter 15'in testi bu tanımsız ayrıma dayanıyor. (Ayrım "magic link katılımcı oturumu" gibi bir **oturum** niteliğini kastediyorsa, yazıldığı hali kimliği tipliyor ve spec §3.0 ile çelişiyor.)

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

1. **`system` aktörlü satırlar ofis feed'inde görünür mü?** Zamanlanmış durum geçişleri, otomatik bildirimler `actor_type = system` üretir; N-4 feed'i yalnız `office_user` döndürür. Yöneticinin "bu kaydı kim değiştirdi" sorusunun cevabı sistem olduğunda ofiste ne görünür?
2. **Backoffice aktörünün `actor_type` karşılığı nedir?** `backoffice_users` kararına (chunk5, `docs/issues.md:18`) bağlı olduğu açık; karar "tek `users`" yönünde çıkarsa backoffice yöneticisinin işlemleri `office_user` satırı olarak satış yöneticisinin feed'ine girer mi?
3. **Tüm-tenant bağlamının pratik sınırı:** `app.tenant_ids` virgüllü metin değişkeni ve `ANY(array)` policy değerlendirmesi, hypertable üzerinde yüzler mertebesinde id ile sorgu başına ne maliyet üretir — §3.6.1 yolu için bir ölçüm/eşik planlanacak mı? (AD-02 ölçeğinde muhtemelen sorunsuz; ancak "tek meşru istisna" en sık backoffice'in kullanacağı sorgudur.)
4. **Spec §14 kriter 8'in öznesi** (F-1 düzeltilirken netleşmeli): saklama ayarı yalnız kullanım loguna aittir — kriterin yeni terimle yeniden ifadesinde "yönetim ekranı"nın backoffice olduğu da açıkça yazılacak mı?

## ⚠️ Upstream Findings

Yok. Bulguların tamamı bu turda revize edilen belgelerin kendi içindedir; kilitli (değişmeyen) bölümlere geri dönüş gerektiren red-line ihlali tespit edilmedi. (F-3 kırmızı çizgi 17'ye **açılan bir belirsizliktir**, gerçekleşmiş bir ihlal değil — çizgiyi çizme yeri yine bu revizyonun belgeleridir.)

## Previous Findings Status

Önceki turların (spec r8, plan r5, chunk2 impl r3) bulguları bu revizyonun konusu değildir ve yeniden açılmamıştır. Bu turda chunk2'nin onaylı mekanizmalarıyla çelişki taraması yapıldı; tek çelişki F-4'te raporlandı.

## Verdict: ❌ REJECTED

Sets'in yedi kararının AD katmanına işlenişi büyük ölçüde doğru ve güçlü (Karar 1-4 ve 7 tam karşılanmış). Ancak matrix'te bir ❌ (plan index) ve beş ⚠ satır var; on bulgu açık. Belirleyici olanlar: revizyonun kendi terim düzeltmesi spec'in kabul kriterine işlenmemiş (F-1), "son aktif" ile L-1 aynı belgede iki yöne çekiyor (F-2), kırmızı çizgi 17'ye giriş/çıkış olayları üzerinden tanımsız bir kapı kalıyor (F-3) ve "izolasyonun tek meşru istisnası" olarak sunulan backoffice okuma yolu, planın bugünkü mekanizma envanteriyle kurulamıyor (F-4). Bulguların tamamı doküman katmanında ve dar kapsamlı — chunk 3 implementasyonu başlamadan kapatılmaları, bu revizyonun tam da önlemeye çalıştığı "yanlış tarafa yazılan kod" riskini kaynağında keser.
