# Kod Yerleşimi Sözleşmesi

*AD-25'in uygulama dokümanı. Sürüm 1.0 — 25.07.2026.*

Bu doküman **satır limiti koymaz.** Limitler kodu doğru yere değil, limitin altına sığacak yere iter. Buradaki kural şudur: **her sorumluluğun tek bir doğru adresi vardır.** "Bu parça nereye ait?" sorusu her seferinde yeniden cevaplanmaz — cevabı burada yazar.

Büyüyen dosya bir sonuçtur, sebep değildir. Sebep, gidecek başka adresi olmayan koddur. Adres varsa dosya büyümez.

---

## 1. Katman sözleşmesi

| Ne | Nereye | Kural |
|---|---|---|
| İş kuralı kararı (kapsama, muafiyet, indirim/fiyat hesabı, süre ve geçerlilik hesabı, kontenjan kuralları) | `app/Domain/<Alan>/` | **Framework'süz saf sınıflar.** `Illuminate\*`, Eloquent modeli, Request, Facade **import edilemez**. Girdi olarak primitive veya DTO alır, karar döner. |
| Tek bir kullanıcı eylemi | `app/Actions/<Alan>/<FiilNesne>.php` | Tek public `__invoke`. Controller iş yapmaz, Action çağırır. Bir Action bir transaction sınırıdır. |
| Sorgu | `app/Queries/<Alan>/` | Controller, Blade, Vue veya Filament içinde query builder **yasak**. Liste/rapor sorguları buraya. |
| Yetki | `app/Policies/` | Action veya Controller içinde inline yetki kontrolü **yasak**. Tenant/grup kapsamı global scope + policy ile. |
| Dış servis | `app/Integrations/<Saglayici>/` | Uygulama kodu SDK'yı doğrudan görmez; adaptör arkasında durur (Postmark, İletiMerkezi, KamuSM, YouTube, Zoom, e-fatura). Sağlayıcı değişimi tek dizinde kalır. |
| Girdi doğrulama | `app/Http/Requests/` | Controller içinde `validate()` **yasak**. |
| Veri taşıyıcı | `app/Data/` | Katmanlar arası aktarımda dizi değil tiplenmiş nesne. |
| Durum makinesi | `app/Domain/<Alan>/State/` | Geçiş kuralları tek yerde; "hangi statüden hangisine geçilir" koşulları dağıtılmaz. |
| Kuyruk işi | `app/Jobs/` | İçinde iş kuralı barındırmaz; Action veya Domain çağırır. |
| Olay dinleyici | `app/Listeners/` | Aynı kural: orkestrasyon yapar, karar vermez. |
| Eloquent modeli | `app/Models/` | İlişkiler, cast'ler, scope'lar. **İş kuralı, HTTP çağrısı, bildirim gönderimi yasak.** |
| Framework'e bağlı yardımcı (cast, ifade üreticisi, bağlam çözücü, maskeleyici) | `app/Support/<Konu>/` | **Karar vermez.** Framework'e bağlı olduğu için `app/Domain/`'e giremeyen, ama iş kuralı taşımayan kod. Bir yardımcı "hangi durumda ne olur"a karar vermeye başladıysa yeri burası değil, `app/Domain/`'dir. |
| Filament kaynağı | `app/Filament/Resources/` | Form ve tablo şeması ayrı sınıflara çıkar (`…/Schemas/`), Resource dosyası şişmez. |

**Ana kural:** bir dosyaya ekleme yapmadan önce sorulacak tek soru — *"bu sorumluluk bu katmana mı ait?"* Değilse yeri yukarıdaki tabloda yazar.

---

## 2. Arch testleriyle zorlama

Kural, testi olmayan yerde kural değildir. Pest arch testleriyle denetlenenler:

- `app/Domain/**` içinde `Illuminate\*`, `App\Models\*`, Facade kullanımı yok.
- `app/Http/Controllers/**` içinde `DB::`, query builder, `validate()` yok.
- `app/Models/**` içinde HTTP çağrısı, Notification, Mail yok.
- `app/Actions/**` sınıfları tek public method (`__invoke`) expose eder.
- `app/Integrations/**` dışında sağlayıcı SDK sınıfı import edilmez.
- Tenant-scoped her model audit'e bağlıdır (AD-21).
- Her test dosyası tam olarak bir panel grubuna aittir (AD-26).
- Testlerde çıplak `now()` / `Carbon::now()` yok — `setTestNow` zorunlu (AD-26).

---

## 3. Frontend — atomic design (Inertia + Vue)

Beş panel (planlamacı, satışçı, müşteri, eğitmen, katılımcı) tek tasarım sisteminden beslenir. Yapı:

```
resources/js/
├── atoms/          Buton, input, rozet, ikon, chip — tek görev, state'siz
├── molecules/      Form alanı (label+input+hata), tablo satırı, KPI kartı
├── organisms/      Tablo, filtre barı, sihirbaz adımı, bildirim merkezi
├── templates/      Panel iskeletleri (sidebar+topbar+içerik), boş/hata düzenleri
└── pages/          Inertia sayfaları — yalnız kompozisyon ve veri bağlama
```

Kurallar:
- **Sayfa iş mantığı barındırmaz.** Hesap, dönüşüm ve karar composable'a veya sunucuya taşınır.
- Bir bileşen üç seviyeden fazla aşağı prop geçiriyorsa yapı yanlıştır — composable veya store'a taşınır.
- **Token dışı renk/spacing kullanılmaz** (tasarım handoff kuralı).
- Bir organizma birden çok sayfada kullanılamıyorsa muhtemelen sayfaya ait bir molekül yığınıdır — yeniden konumlandırılır.

**Derleme girişi panel başına ayrılır** *(ofis spec'i karar 5, 28.07.2026)*: `office` · `portal` (müşteri) · `participant` · `landing`. Her kök şablon kendi girişini çağırır; hangi şablonun kullanılacağını **route grubu** söyler — kimlik alanı değil, çünkü public host tek başına üç yüz taşır (`/` landing, `/panel` portal, `/katilimci` nav'sız tek akış) ve son ikisi aynı kimlik alanındadır.

Gerekçe: katılımcı neredeyse tamamen mobil ve hayatında bir-iki kez girer; tek pakette ofisin tablo ve matris kodu o telefona da inerdi. Ortak atom ve moleküller Vite'ın paylaşılan chunk'ına düşer, kod tekrarı doğmaz.

⚠ Bir giriş dosyası **yalnız kendi sayfa dizinini** çözer (`import.meta.glob('./pages/Office/**/*.vue')`). Glob'u genişletmek paylaşımı değil **sızmayı** üretir.

## 4. Frontend — Filament (backoffice)

Filament'e atomic hiyerarşi **dayatılmaz**; kendi bileşen sistemi vardır ve zorlamak ters teper.

- **Custom Blade view yazma.** Filament primitive'leri kullanılır; gerçekten gerekiyorsa gerekçesiyle birlikte istisna açılır.
- Form/tablo şemaları Resource'tan ayrı sınıflara çıkar.
- Design token'ları **tek CSS değişken kaynağından** Filament dışındaki tüm ön yüzlere beslenir. **Filament kendi paletini taşır** *(ofis spec'i karar 8, 28.07.2026)*: tasarımcı Filament'i kapsam dışı bıraktı ve backoffice kendi bileşen sistemiyle boyandı. Sınır Filament'tir — sayım değil dışlama, çünkü sayım yarın doğacak yüzeyi dışarıda bırakır.

---

## 5. Ne zaman yeni katman açılır?

Yeni bir sorumluluk türü çıktığında (ör. "rapor üreticileri", "içe aktarım dönüştürücüleri") bu dokümana **önce satır eklenir**, sonra kod yazılır. Adresi burada yazmayan kod, yazılmadan önce tartışılır.
