# Review — Mevzuat dışı eğitim, marka ve belge seçenekleri planı (v1.0) — 2026-10-20

> **Review type:** plan-review
> **Previous review:** N/A (first review)
> **Upstream document(s) read:** `proje-haritasi.md` «EGT-218 kararları — mevzuat dışı eğitimler ve marka» (Sets, 20.10.2026, 5 madde; satır 254)
> **Other cross-referenced documents:** `CLAUDE.md` (17 kırmızı çizgi), `docs/arch/mimari-kararlar.md` bağlamı (AD-04/05/06/08/11/27 planla kesişen maddeler), kod: `app/Support/Trainings/TrainingStatus.php`, `app/Actions/Office/StartTraining.php`, `app/Actions/Trainings/CompleteTraining.php`, `app/Http/Requests/Office/FinishTrainingRequest.php`, `database/migrations/2026_08_02_000100_create_training_definitions.php`, `2026_10_11_000100_a_training_may_answer_to_more_than_one_regulation.php`, `2026_10_09_000100_the_house_has_its_own_certificate_too.php`, `TrainingDefinitionForm.php`, `TrainingDefinitionOptions.php`, `RegulationOptions.php`, `Office/Trainings/Plan.vue`, `Office/Requests/Create.vue`, `Portal/QuoteRequest.vue`, `CompanyProfile.php`, `SystemReadiness.php`, `ComplianceSummary.php`, `OpenMinistryNotificationTasks.php`, `CurriculaRelationManager.php`, `app/Policies/` dizini
> **Stage locks in effect:** Upstream kararlar (EGT-218, Sets 20.10.2026) locked — kararların kendisi tartışılmaz; plan onlara uyumla ölçülür.

---

## «Doğrulanmış mevcut durum» tablosunun koda karşı kontrolü

Tablodaki iddiaların tamamı dosya açılarak doğrulandı; **hepsi doğru çıktı**:

| Plan iddiası | Sonuç | Kanıt |
|---|---|---|
| `regulation_id` NOT NULL + FK `restrictOnDelete`; formda `required()` | ✓ doğru | `2026_08_02_000100_create_training_definitions.php:77` (nullable yok), FK `restrictOnDelete`; `TrainingDefinitionForm.php:83-93` `->required()` |
| Ek mevzuat pivotu bağımsız | ✓ doğru | `2026_10_11_000100_a_training_may_answer_to_more_than_one_regulation.php` mevcut |
| `notification_type`/`notification_days` nullable; boş süre atlanıyor | ✓ doğru | migration :138-139 `->nullable()`; `OpenMinistryNotificationTasks.php` `if ($days === null) continue;` |
| `Planned` → yalnız bakanlık statüleri → `InProgress`; mevzuat dışı başlatılamaz | ✓ doğru | `TrainingStatus.php:34-41` (`Planned`'ın next listesinde `InProgress` yok); `StartTraining.php:31` `allows(InProgress)` |
| Bitirmede KUMS kanıtı zorunlu | ✓ doğru | `CompleteTraining.php:61` (`kumsEvidence: $evidence !== null && trim(...)`); `FinishTrainingRequest.php:25` `required` |
| Belge: sistem üretmez, kayıt eder; düzenleyen alanı yok | ✓ doğru | migration taramasında `issuer` yalnız `institution_documents`'ta (`2026_10_09_000100:71`); `certificate_records`'ta yok |
| Plan ekranı: mevzuat kartı seçilince mevzuatsız tanım gizlenir | ✓ doğru | `TrainingDefinitionOptions.php:43` `(int) regulation_id` (null→0); `Plan.vue:319-321` `includes(regulation.value)` |
| Kart sayıları `groupBy('regulation_id')` | ✓ doğru | `RegulationOptions.php:53-64` |
| Portal firma profili başlıksız grup | ✓ doğru | `CompanyProfile.php:107-110` |
| `SystemReadiness` yenileme süresiz aktif tanımı eksik sayar | ✓ doğru | `SystemReadiness.php:186-205` (`whereNull('renewal_months')`, kategori ayrımı yok) |
| Uyum yalnız belge kayıtlarından | ✓ doğru | `ComplianceSummary.php:78-108` (`CertificateRecord` join) |
| Diğer okuyucular null-güvenli | ⚠ kısmen | `?->name` kullananlar doğru; ancak bir okuyucu listede YOK — F-5 |

## Upstream Coverage Matrix

| Upstream § / madde | Reviewed doc'ta durumu | Kanıt |
|---|---|---|
| Karar 1a — eğitim tanımı kategori taşır («seçenek değil kategori») | ✓ Uyumlu | M-1: `category` string + CHECK, mevcut satırlar `regulatory` |
| Karar 1b — mevzuat eğitiminde mevzuat ve bağlam zorunlu | ✓ Uyumlu | M-2: form zorunluluğu + DB CHECK (formu atlayan yol kapalı) |
| Karar 1c — mevzuat dışında zorunluluk yok, **evrak yine bağlanabilir** | ⚠ Kısmi | Evrak bağlanabilirliği testte var (plan satır 60); ancak M-2 mevzuat **seçimini** de mevzuat dışında serbest bırakıyor («gizli değil ama isteğe bağlı») — upstream'de bu yok ve hibrit kayıt çelişki üretir → F-1 |
| Karar 2 — marka: backoffice tanımlı liste, tanımda isteğe bağlı, katalog + teklif + belgede görünür | ✓ Uyumlu | M-6 + görev 4; faturada görünmezlik upstream'in «katalog + teklif + belge» sınırıyla uyumlu |
| Karar 3 — belge verebilme iki kategoride isteğe bağlı; **düzenleyen tanımda seçilsin** | ⚠ Kısmi | M-7 `certificate_mode` iki kategoride ✓; düzenleyen **serbest metin** — upstream «seçilsin» diyor ve karar 5 üretim dalını düzenleyenin kimliğine («3E ya da marka ise») bağlıyor → F-2 |
| Karar 4 — süreç: kısa plan + heyet, sonra kod + impl incelemesi | ✓ Uyumlu | Bu tur o sürecin plan adımı |
| Karar 5 — belge üretimi iki yollu; yazdırılabilir üretim + şablon ayrı ticket | ⚠ Kısmi | Ayrı ticket'a bırakma ✓ (plan satır 7, 79); ancak `generated` modunun bu plandaki davranışı tanımsız — «şablon yoksa kaydedilemez» deniyor, planda şablon kavramı/alanı yok → F-3 |
| Kırmızı çizgi 14 / AD-08 / AD-27 — kural koda gömülmez | ✓ Uyumlu | Kategori, mod, düzenleyen, marka: hepsi tanım verisi; M-11 bunu açıkça korur |
| AD-06 — denetim | ✓ Uyumlu | `brands` model audit (plan satır 46); tanım değişiklikleri mevcut model audit kapsamında |
| AD-11 — silinmezlik / kopya ilkesi | ✓ Uyumlu | M-8 düzenleyeni belge kaydına kopyalar; rollback «veri silinmez» |
| AD-04 / RLS | ✓ Uyumlu | Yeni tablo `brands` bağlamsız tanım tablosudur (tenant verisi değil); `certificate_records`'a yalnız kolon ekleniyor |
| Migration güvenliği / rollback | ✓ Uyumlu | Yalnız ekleme + bir gevşetme; `NOT NULL` geri dönüş tuzağı açıkça yazılmış, `down` durur ve Sets'e sorar (plan satır 75) |

## ✅ What works

- «Doğrulanmış mevcut durum» tablosu gerçekten koddan çıkarılmış — kontrol ettiğim her satır dosya ve satır düzeyinde tuttu; iki sert engel (durum makinesi, KUMS kanıtı) doğru teşhis edilmiş.
- M-2'nin zorunluluğu veritabanına da koyması (CHECK) formu atlayan yolu kapatıyor; M-4'ün kuralı kategoriden okuması kırmızı çizgi 14 ile tutarlı.
- M-8 kopya ilkesi (düzenleyen belge kaydına kopyalanır) fatura kopyası desenini doğru uyguluyor.
- Rollback bölümü `NOT NULL` geri dönülemezliğini saklamıyor; kararı Sets'e bırakıyor.
- Kapsam dışı bölümü net: belge üretimi, şablon, logo, fatura, uyum hesabı — hepsi adlı adınca.
- EGT-101 (çoklu mevzuat) ve EGT-112 (gizleme yok) kararlarıyla çelişen hiçbir madde yok; M-3 plan ekranı kartı EGT-112'nin «gizleme değil, görünür kıl» çizgisini sürdürüyor.

## ⚠️ Findings & Risks

**F-1 — Mevzuat dışı tanımda mevzuat seçimi serbest bırakılmış; upstream bunu söylemiyor ve davranış çelişkisi üretiyor.** M-2 «mevzuat dışında gizli değil ama isteğe bağlı» diyor ve CHECK (`category = 'non_regulatory' OR regulation_id IS NOT NULL`) `non_regulatory` + dolu `regulation_id` kombinasyonuna izin veriyor. Upstream karar 1 yalnız «zorunluluk yok, evrak yine bağlanabilir» diyor. Böyle bir hibrit kayıtta: kart sayımı (M-3) tanımı hem mevzuat kartında hem «mevzuat dışı» kartında mı sayar; bakanlık akışı kategoriden okunduğu için (M-4) mevzuatı OLAN ama bildirilmeyen bir eğitim doğar; mevzuat uyarıları M-11 gereği hesaplanmaz ama tanım bir mevzuata işaret eder. Plan bu kombinasyonun ne anlama geldiğini tanımlamıyor.

**F-2 — `certificate_issuer` serbest metin; upstream «tanımda seçilsin» diyor ve karar 5'in üretim dalı düzenleyenin kimliğini okumak zorunda.** Karar 5: «belgeyi düzenleyen 3E ya da marka ise, şablon yüklenirse sistem üretir». Serbest metin bir alandan «3E mi, marka mı» sorusu güvenilir okunamaz; ayrı ticket bu alanın üstüne kurulacak. Plan, upstream'deki «seçilsin» kelimesini «yazılsın»a çevirmiş durumda — bu, bu projede daha önce iş geri aldırmış türden bir yorumlama (memory: ask-dont-interpret).

**F-3 — `generated` modunun bu plandaki davranışı tanımsız.** M-7 «bu planda seçilebilir ama şablon yoksa kaydedilemez» diyor; ancak planın veri modelinde şablon diye bir alan/kavram yok (şablon yüklemesi ayrı ticket). Doğrulamanın neye bakacağı, formun bu modu nasıl sunacağı (her zaman reddedilen bir seçenek mi, gizli mi, mesajı ne) belirsiz. Test listesi de `generated` için senaryo içermiyor. Developer bu maddeyi iki farklı şekilde kodlayabilir — plan başarı kriteri («belirsizlik yok») burada sağlanmıyor.

**F-4 — M-4'ün gerekçesi mekanizmayla çelişiyor; kategori değişikliğine koruma yok.** M-4 «kural tanımın kategorisinden okunur… (eğitim planlandığı andaki tanıma bağlı)» diyor; ama tanımdan canlı okuma, planlama anındaki değeri değil **bugünkü** değeri okur. Planda tanımın kategorisinin sonradan değiştirilmesine (yürüyen eğitimi varken `regulatory` ↔ `non_regulatory`) hiçbir kısıt veya davranış tanımı yok. Senaryo: `non_regulatory` tanımla `Planned`'dan başlatılmış bir eğitim sürerken tanım `regulatory` yapılır → bitirme KUMS kanıtı istemeye başlar, ama bakanlık bildirimi hiç yapılmamıştır; tersi yönde de bildirim yükümlülüğü sessizce düşer. Mevzuat sürümünün planlamada dondurulması (`PlanTraining::currentRegulationVersion`) ve M-8'in kopya ilkesi tam da bu sınıf sorun için var; kategori için eşdeğer karar planda yok.

**F-5 — Atlanmış bir `regulation` okuyucusu: ofis planlama talebi ekranı.** `Office/Requests/Create.vue:85` tanım listesini `group: row.regulation` ile grupluyor; veriyi veren `TrainingRequestController.php:131` mevzuatsız tanımda `null` gönderir → mevzuat dışı tanım başlıksız/`null` grup altında çizilir. Bu, M-10'un portal firma profilinde düzelttiği kusurun birebir aynısıdır; «Doğrulanmış mevcut durum» tablosunun «Diğer okuyucular» satırında ve görevlerde (M-10 yalnız portalı sayıyor) bu ekran yok.

**F-6 — Yeni `brands` kaynağı için yetki yerleşimi planda yok.** Depo deseni her tanım tablosuna policy veriyor (`app/Policies/DocumentTypePolicy.php`, `InstructorRequirementPolicy.php` vb.); backoffice'in kendi yetki hiyerarşisi var (dar roller yalnız kendi alanına). Plan görev 1'de «backoffice: marka kaynağı» diyor ama policy/izin kaydından söz etmiyor — authorization yerleşimi belirsiz.

**F-7 — Test planı M-9 ve M-11'i kapsamıyor.** Test listesinde `SystemReadiness`'ın mevzuat dışı + belge vermeyen tanımı artık eksik saymadığına (M-9) ve mevzuat uyarıları/ek mevzuat zincirinin mevzuat dışında hata vermeden boş döndüğüne (M-11) dair senaryo yok; `generated` modu için de yok (F-3 ile bağlantılı).

## ❓ Open Questions

1. (F-1) `non_regulatory` bir tanımın `regulation_id` taşıması gerçekten istenen bir durum mu, yoksa mevzuat alanı mevzuat dışında tamamen boş mu kalmalı? İsteniyorsa kart sayımı ve bakanlık akışındaki anlamı nedir?
2. (F-2) Düzenleyen alanı serbest metin mi kalacak, yoksa karar 5'in üretim dalının okuyabileceği bir seçim mi olacak? Bu, ayrı ticket'ın veri sözleşmesini şimdi belirler.
3. (F-4) Kategori, yürüyen/planlanmış eğitimi olan tanımda değiştirilebilir mi? Değiştirilebilirse mevcut eğitimler hangi kuralla yürür?
4. (F-3) `generated` bu sürümde formda hiç sunulmayacak mı, yoksa sunulup her kayıtta mı reddedilecek?

## Verdict: ❌ REJECTED

Mevcut durum tablosu koda karşı sağlam ve kararların omurgası (kategori, durum makinesi, bitirme, marka, belge modu, rollback) doğru kurulmuş; ancak matrix'te üç ⚠ satır var ve toplam yedi bulgu açık: upstream'den iki sapma/belirsizlik (F-1, F-2), bir tanımsız davranış (F-3), bir yaşam döngüsü boşluğu (F-4), bir atlanmış okuyucu (F-5), yetki yerleşimi eksiği (F-6) ve test kapsamı eksiği (F-7). Scope içinde bulgu varken orta yol yok.
