# 3e-egitim

Lojistik/denizcilik alanında mevzuata uygun eğitimler veren köklü bir firma (3E) için **eğitim firması otomasyonu**: eğitim planlama, satış/teklif, bakanlık bildirimi, sertifika, eğitmen ve müşteri yönetimi. Multi-tenant B2B SaaS.

## Temel dokümanlar

- **🗺 Proje haritası — ÖNCE BURAYA BAK:** `proje-haritasi.md` — alan alan (backoffice, ofis/planlamacı/satışçı/operasyon/eğitmen, müşteri, katılımcı) ne karar verildi, nerede yazılı, hangi tablo, hangi ekran, hangi ticket, bugün ne durumda. Karar **taşımaz, karara götürür**; yalnız başka hiçbir dosyada yazılı olmayan kararların tam metnini tutar. Bu projenin karar dosyası budur; soru sormadan önce de buraya bakılır.
- **İş kuralları ve süreçler (tek kaynak):** `cati-dokumani.md` — tüm akışlar, roller, kararlar ve mevzuat doğrulamaları burada. Bir iş kuralı sorusunda önce buraya bak.
- **Mimari kararlar:** `docs/arch/mimari-kararlar.md` (AD-01…AD-29) — stack, tenancy, RLS, audit, auth, anonimleştirme, yetki modeli, evrak motoru, mevzuat kaydı, test stratejisi. Mimariye dokunan her işte önce bunu oku.
- **Kod yerleşimi:** `docs/arch/kod-yerlesimi.md` (AD-25'in uygulaması) — hangi kod nereye yazılır. Kod yazmadan önce oku; satır limiti yok, **adres sözleşmesi** var.
- **Mevzuattan doğrulanmış kurallar:** `docs/mevzuat-kurallari.md` — madde referanslı kural seti (sınav, katılımcı limitleri, eğitmen şartları, bildirim modelleri, yenileme periyotları). Mevzuata dayalı bir soruda önce buraya bak; **"MEVZUATTA YOK" işaretli satırlar varsayımla doldurulamaz.**
- **Müşteri tanım dokümanlarının özeti:** `yazilim-tanim-ozeti.md` (7 modüllük büyük resim; aktif kapsam şimdilik eğitim otomasyonu). Müşterinin kendi analizi: `egitim/3E_Akademi_Egitim_Uyum_Platformu_Proje_Dosyasi_v3_1.docx`.
- **Mevzuat arşivi:** `mevzuat/` (envanter: `mevzuat/README.md`). Resmî metin burada; `docs/mevzuat-kurallari.md` bunun çıkarımıdır.
- **Ortamlar/altyapı:** `docs/infra/ortamlar.md` — sunucular, TeamCity, YouTrack (EGT/GZT/TMGD), PgBouncer portları, log disiplini.

  ⛔ **Üç makine, ezberden bilinir — her seferinde aranmaz** *(Sets, 10.08.2026: "senden bir ricam var, sunucuyu bulayım dememelisin artık, yapı çok net")*:

  | | Adres | Ne |
  |---|---|---|
  | **dev** | `10.31.1.25` | **bu makine** — geliştirme, `*.dev.sets.fyi` |
  | **local prod** | `10.31.1.210` | production koşullarının denendiği yer, `*.devprod.sets.fyi`, `ssh www-data@10.31.1.210` |
  | **prod** | `167.235.48.99` | Hetzner, canlı, `ssh root@167.235.48.99` (key auth) |

  ⚠ Üçü **ayrı makinedir ve karıştırılmaz**. Local prod'un `.env`'i de `APP_ENV=production` taşır; adresleri, veritabanı ve sertifikası kendisinindir. CI ayrı: `mbproframe.local` (IP DHCP ile değişir, **ada** bağlanılır).
- **Tasarım:** brief `docs/design/tasarim-brief.md`; **handoff `design/HANDOFF.md` + `design/*.dc.html`**.

  ⛔ **Tasarımcının teslim ettiği EKSİKSİZ uygulanır** *(Sets, 30.07.2026 — kural düzeltmesi)*. Sayfa kompozisyonu, kartlar, alan sıralaması, ekran bölünmesi, menü grupları dahil. Kod yazmadan önce ilgili `design/*.dc.html` dosyası **açılır ve okunur**; "spec'te yazıyordu" tasarımı atlamanın gerekçesi değildir.

  ⚠ **"Nihai değildir" ne demek:** *"ama tasarımcı böyle yapmış"* denerek **hedeften sapılmaz**. İyileştirme ve düzenleme yapılabilir — fazladan bir kart kaldırılabilir, eksik bir form eklenebilir — **ancak ve ancak Sets söylediğinde**. Örnek: 5 adımlı planlama sihirbazından vazgeçilmesi (planlamacı bütünü kaybediyordu) böyle bir karardır; geri kalanı olduğu gibi uygulanır. Kural: **tasarım kanun değildir, ama çöp de değildir.** Sapma önerisi varsa DUR, gerekçelendir, onay al.

  Mockup dosyalarının içindeki metinler güncel değil (referans kodu, inbound adres, statü adları); çelişkide `HANDOFF.md` ve AD'ler esastır.

## ⛔ Tasarım Uygulama Protokolü — MUTLAK

*(Sets, 31.07.2026 — "tasarım konusunda seni uyarmaktan çok sıkıldım, 50 kere revize veriyorum")*

Kural zaten yazılıydı ve yine tutulmadı; çünkü yazılı olan **niyetti, prosedür değildi**. Ölçülen sebep şu: spec ve bileşen kataloğu okunuyor, **ekranın kendi kompozisyonu okunmuyordu** — alanlar doğru, yerleşim uydurma çıkıyordu. Bundan sonra bir ekran şu üç adım olmadan teslim edilmez.

### 1 · Önce ekranı aç, envanterini çıkar

Kod yazmadan önce ilgili `design/NN *.dc.html` **açılır ve baştan sona okunur** — ilgili görünen bölüm değil, dosyanın tamamı (hata durumları ve 375px bloğu dahil; ikisi de ekranın parçasıdır). Okurken şu envanter çıkarılır:

| Ne | Nereden okunur |
|---|---|
| **Izgara** | `grid-template-columns` — iki kolonluk bir bölüm tek kolon yazılmaz |
| **Alan sırası** | soldan sağa, yukarıdan aşağı — "Bakanlık ID ve Sertifika geçerlilik aynı satırda" bir karardır |
| **Etiketin tam metni** | tasarımcının kelimesi esastır; "Sertifika geçerlilik" ≠ "Belge geçerlilik" |
| **Yardım/uyarı metni** | rengiyle birlikte: gri ipucu ≠ amber sonuç uyarısı |
| **Alan içi ek** | önek/sonek, kilit işareti, takvim işareti, birim rozeti — hepsi kontrolün parçası |
| **Rozet ve durum** | kaç durum var, hangi ton, tam metin |
| **Kontrol sayısı** | üç seçenekli bir segmented iki seçenekle uygulanmaz |
| **Sabit/sticky şerit** | konumu davranıştır, süs değil |

### 2 · Atom yoksa atom yazılır

`01 Form Elemanlari` bir katalogdur: **tasarımcı bir kontrolü çizdiyse o kontrolün atomu bizde olmalıdır.** Eksikse yazılır — sayfa içine gömülmez, "yaklaşık olanı" kullanılmaz.

Ölçülmüş üç örnek *(31.07.2026)*: kapalı listelerde **aşağı ok göstergesi** (native select'in oku platforma göre değişiyor, bazılarında hiç çizilmiyordu — liste açan kontrol açmayanla aynı görünüyordu); **kompakt telefon** (ülke seçimi kapalıyken yalnız `+90`, açıkken `+90 Türkiye` — geniş select alanın üçte birini yiyordu ve tasarımın telefon+kategori tek satırı imkânsızdı); **hassas alan** (kilit işareti değerin başında durur, altındaki not değil).

### 3 · Teslimden önce kapsama matrisi

Onay Kuralı 2'nin tasarım karşılığı, **zorunlu**: implementasyondan sonra tasarım dosyası tekrar açılır ve üç sütunlu matris üretilir — **tasarım öğesi | ✓/⚠/❌ | kanıt (dosya + satır)**. Bellekten üretilen matris geçersizdir. ⚠/❌ kalan satır varsa Onay Kuralı 6 işler: taşındı mı, bilinçli kapsam dışı mı, unutuldu mu — **sorulur**.

⛔ Sapma yalnız Sets söylediğinde olur. Kendiliğinden yapılan "iyileştirme" sapmadır ve reddedilir. Bir öğe teknik olarak uygulanamıyorsa DUR, gerekçelendir, onay al — sessizce atlama.

## ⛔ Ekran değişirse yardım da değişir

*(Sets, 10.08.2026)*

Yardım Merkezi ofis panelinin **içindedir** (`/yardim`); içerik `docs/yardim/*.json`'da, ekran görüntüleri `public/images/yardim/` altında, veritabanına `HelpArticleSeeder` ile gider. Makalelerin **hepsi** anlattığı ekranın görüntüsünü taşır *(21.10.2026: 43 makale + 1 SSS — ofis 26, eğitmen 4, müşteri 13)*.

Ofis ekranında **görünür** bir değişiklik yaptıysan (ekran, buton, akış, alan adı, adım sırası): o ekranı anlatan makaleyi bul, metni güncelle, gerekiyorsa **ekran görüntüsünü Playwright ile yeniden al** (1440px), seeder'ı koş.

⚠ Sebep: makale adım adım tarif ediyor ve yanında ekranın fotoğrafı duruyor. Ekran değişince ikisi de yalan söyler — ve **yalan söyleyen yardım metni, olmayandan kötüdür**: okuyan kişi ekranda göremediği düğmeyi arar. Bunu fark edebilecek tek an, değişikliğin yapıldığı andır.

⚠ Görünmeyen değişiklik (refactor, sorgu, test, migration) yardım gerektirmez. ⛔ Landing'e yardım bağlantısı **konmaz** — yardım ofis içidir.

## Araçlar

YouTrack: `./deployment/scripts/youtrack.sh` · TeamCity: `./deployment/scripts/teamcity.sh` (default MBP build server). Git: `git@github.com:Sets/3e-egitim.git` → YouTrack EGT smart commit.

Heyet review: `./deployment/scripts/heyet.sh` (heyet-agent, proje: `3E-Egitim`). Protokol: `docs/claude/heyet.md` — design/brainstorm → spec → plan → impl lifecycle, upstream coverage matrix, FINDINGS ONLY, tek verdict. Review çıktıları `docs/reviews/` altında. **Heyet çağrısı kullanıcıya aittir** — açık talimat olmadan heyet başlatılmaz.

Git hooks: `.githooks/` (kurulum: `git config core.hooksPath .githooks`) — commit-msg hook'u AI attribution'ı ve bozuk YouTrack formatını reddeder.

## Paylaşılan araçlar

Yardımcı araçlar `.toolkit/` altında submodule olarak durur; bu projede kopyası yoktur.
Kullanmadan önce ilgili referansı oku:

- YouTrack işlemleri → `.toolkit/tools/youtrack/AGENTS.md`
- TeamCity/CI işlemleri → `.toolkit/tools/teamcity/AGENTS.md`
- Port ve proje envanteri → `.toolkit/tools/ports/AGENTS.md`

`deployment/scripts/youtrack.sh` ve `deployment/scripts/teamcity.sh` çalışmaya devam eder; artık toolkit'e yönlendirir. Komut kümesi büyüdü — YouTrack tarafında `link` `unlink` `subtasks` `tree` `command` `epics` `epic-*` `boards` `sprints` `tags` `tag` `untag` `time` `time-add` `api`, TeamCity tarafında `cancel` `queued` `running` `finished` `agents` `artifacts` `api`, hepsinde `--json`.

⚠ Port defterinde bu projenin anahtarı **`3eegitim`**, dizin adı ise `3e-egitim`. Defterdeki `aliases` ikisini birbirine bağlıyor; `./.toolkit/tools/ports/check-ports.sh` argümansız da çalışır.

**Bir aracı düzeltmen gerekirse toolkit deposunda düzelt**, burada değil — burada
yapılan düzeltme diğer beş projeye geçmez ve bu deponun varlık sebebini ortadan kaldırır.
Toolkit'i güncellemek için: `.toolkit/bin/toolkit-update`

## 🌐 Dil kuralı

Global kural geçerli (› Language and commits). Ek olarak **arayüzün tamamı Türkçe:**
kullanıcıya görünen her metin — etiket, buton, hata mesajı, bildirim, e-posta şablonu, PDF
çıktısı. Çeviri dosyaları (`lang/tr/`) üzerinden; koda gömülü kullanıcı metni olmaz.

## Global kurala istisnalar

- Overrides global › Actions with consequences: `main`'e commit + push serbesttir;
  ayrıca onay sorulmaz (branch politikası: memory `branching-policy`).
- Overrides global › Actions with consequences: ticket kapanışında TeamCity full run'ı
  agent kendisi tetikler (bkz. "Ticket kapanışında — TEAMCITY").
- Overrides global › Actions with consequences: yeşil CI'dan sonra prod'a deploy,
  ticket tesliminin parçasıdır ve ayrıca sorulmaz (bkz. "Git ve YouTrack Akışı",
  Sets 11.08.2026).

---

## ⛔ Çalışma Kuralları

### 1. Görev ortasında durmak yok

Global kural geçerli (› Scope and finishing); burada `.claude/hooks/no-promise-stop.py`
Stop hook'u söz veren kapanışı reddeder. Gerçekten duruyorsan soruyu AskUserQuestion ile
sor — düz metin soru hook'u yanıltır.

### 2. Subagent politikası

- Global kural geçerli (› Subagents): araştırma serbest, kod yazdıran subagent yok.
  Hızlı lookup'ları kendin yap (subagent stall riski).
- Heyet review tek-reviewer protokolüdür; subagent/panel kullanılmaz.

### 3. ⛔ `migrate:fresh` SORULMADAN koşulmaz *(Sets, 04.08.2026)*

Lokal veritabanı **Sets'in üzerinde çalıştığı** veritabanıdır. 04.08.2026'da tarayıcı turu için üç kez `migrate:fresh --seed` koşuldu; ilki Sets'in test hesabını (`sets@subicon.net`, iki panelde de) sildi ve kimse fark etmedi, diğer ikisi Sets tam o sırada verilen sayfaları **test ederken** altından veriyi çekti.

Kural: **veri silen hiçbir komut sorulmadan koşulmaz** — `migrate:fresh`, `migrate:rollback`, `db:wipe`, tabloyu boşaltan seeder. Tarayıcı turu için taze veri gerekiyorsa **önce sorulur**.

⚠ Hesap artık `DatabaseSeeder`'dan (yalnız `local`) seed ediliyor ve `LocalAccountSeedingTest` bunu koruyor — ama bu kaybı telafi eder, izni vermez.

### 4. Commit

Global kural geçerli (› Language and commits). İş, testler geçmeden ve Pint temiz olmadan
bitmiş sayılmaz. Büyük bir değişikliğe başlamadan önce bitmiş iş commit'lenir ki temiz bir
dönüş noktası olsun.

### 5. Sessiz çalış, milestone'da raporla

Adım adım anlatım yok ("şimdi modeli okuyacağım..."), istenmemiş ara durum raporu yok. Çalış, doğrula, sonucu tek seferde raporla.

## ⛔ Onay Kuralları — MUTLAK

Slogan değil mekanizma: artifact üretmeden onay yargısı vermek yasaktır.

1. **Doküman hiyerarşisi:** çatı design/brainstorm (ops.) → spec → plan → implementasyon; her geçişte ayrı onay.
2. **Upstream coverage matrix zorunlu:** bir doküman/implementasyon için "hazır/tamam" yargısından ÖNCE immediate upstream dokümanı Read ile aç ve üç sütunlu matrisi üret (upstream madde | ✓/⚠/❌ | kanıt: dosya+satır). Bellekten/önceki bağlamdan matrix üretmek geçersizdir.
3. **"Onaylıyorum / tamamlandı / hazır" demek yasak.** Yerine matrix + bulgu listesi; verdict gerekiyorsa APPROVED/REJECTED + gerekçe. Son karar kullanıcınındır.
4. **Kod varlığı ≠ feature varlığı ≠ wire varlığı.** (a) dosya commit'lendi mi; (b) gerçek user journey çıktı üretiyor mu — kod okumak demo değildir; (c) **bir FEATURE tamamlandı deniyorsa** yeni public symbol production entry-point'ten çağrılıyor mu — reverse-grep ile doğrula (route binding, listener kaydı, schedule, panel kaydı). "Test geçti + Pint clean" wire varlığını kanıtlamaz.

   ⛔ **Bu kural altyapı/backbone koduna UYGULANMAZ** (düzeltme, Sets 27.07.2026). Backbone'un tanımı gereği çağıranı henüz yoktur — onu kullanacak dikey modül daha yazılmamıştır. Caller'sızlığı bulgu olarak raporlamak, kendi ürettiğin işi kendi kuralınla suçlamaktır; bu hem gereksiz gürültü üretir hem heyet incelemelerinde tutarsızlığa yol açar. **Sormanın doğru zamanı, o mekanizmayı kullanacağını iddia eden bir ekran/akış teslim edildiğindedir.** Bir mekanizmanın caller'ı yoksa yapılacak tek şey plandaki kapanış adresini yazmaktır — ⚠ ya da ❌ değil.
5. **Başkasının onayı kanıt değildir.** "Developer bitti dedi / heyet onayladı" bağımsız kontrolü atlatmaz.
6. **Eksik satır implicit kabul edilemez:** matrix'te ⚠/❌ varsa açıkça sor — (a) downstream'e mi taşındı, (b) bilinçli out-of-scope mu, (c) unutuldu mu? Cevapsız matrix kapanmaz.

## ⛔ Varsayımla Kod Yazmak Yasak

Kod yazmadan önce HER ZAMAN doğrula:

1. **Route:** `php artisan route:list | grep ...` · **Component/Blade/Vue:** render'ı ve view dosyasını OKU · **DB/Model:** migration dosyasını OKU — kolon adı varsayma · **Servis:** mevcut implementasyonu kontrol et · **Permission:** policy/middleware'i kontrol et.
2. **Framework built-in:** test helper/fixture yazmadan önce `vendor/laravel/framework/src/` kaynağına bak — Laravel'in hazır fake/assert'i varken custom fixture yazma.
3. **Mevzuata dayalı kural:** `mevzuat/` içindeki resmî metinden doğrula; metinde yoksa kullanıcıya sor. Bu projede yanlış mevzuat bilgisi = müşteriyi İdare karşısında yükümlülük altına sokan sertifika/bildirim.

Harici API değerleri ve soru sorma biçimi için global kural geçerli (› Facts come from sources · › Decisions and questions).

## 🔴 Kırmızı Çizgiler — Anında Red

1. **Tenant data leak** — Müşteri A'nın verisi Müşteri B'ye görünür; tenant-scoped tabloda RLS'siz/scope'suz sorgu.
2. **Tenant context session-level `SET`** — yalnız transaction içi `SET LOCAL` (AD-04, pgbouncer tuzağı).
3. **Eksik authorization** — sensitive veriye dokunan her action/controller yetki doğrular; "auth middleware arkasında zaten" savunma değildir.
4. **Raw `DB::` ile tenant scope bypass.**
5. **Onaysız data-loss migration** — column drop/rename/type change → DUR ve SOR.
6. **Elle şema değişikliği (migration'sız DDL) — hiçbir ortamda.** Şema değişikliğinin TEK yolu commit'lenmiş migration. (Puanbenim PA-225 dersi: 1.210'a elle eklenen 4 kolon migration'da yoktu → temiz prod kurulumda sync haftalarca kırık kaldı.) Prod'da psql/tinker ile ALTER/CREATE de yasaktır.
7. **`env()` config dışında** — her zaman `config()`.
8. **Hardcoded credential** — kodda/dokümanda şifre, token, secret olmaz.
9. **Hardcoded iş kuralı** — limit, oran, süre, kapsama kuralı admin-tanımlı olmalı (AD-08).
10. **Onaysız test silme.**
11. **Commit'te AI attribution** — "Co-Authored-By: Claude", "Generated with", 🤖 vb. (commit-msg hook da engeller).
12. **Kritik kayıt hard delete** — imzalı yoklama, onaylı teklif, sınav sonucu, resmî işlem kaydı silinmez; iptal/revizyon (AD-11). Kullanıcı da silinmez, pasifleştirilir (AD-23).
13. **Audit'siz kritik işlem** — teklif, onay, masraf, kullanıcı yönetimi append-only loglanır (AD-06); **hassas kayda dokunan her OKUMA da loglanır** (AD-21 erişim logu); hassas değerler maskeli (AD-16). Audit yazımı işlemle aynı transaction'da olur — kuyruğa atılmaz.
14. **Mevzuat kuralını koda gömmek** — azami/asgari katılımcı, sınav eşiği, bildirim süresi, yenileme periyodu **eğitim tanımının admin-tanımlı alanlarıdır**; mevzuat kaydı bunları madde referanslı **uyarı** olarak hatırlatır, zorlamaz (AD-27, 27.07.2026 revizyonu). Kod içinde sabit sayı = anında red.
15. **Kod yerleşimi ihlali** — `app/Domain/` içinde framework/Eloquent import, Controller'da query builder veya `validate()`, Model'de HTTP/bildirim, Integrations dışında SDK kullanımı (AD-25, `docs/arch/kod-yerlesimi.md`). Arch testi zaten kırar; yazılmaması esastır.
16. **Test disiplini ihlali** — grup etiketi olmayan test, testte çıplak `now()`, `Http::preventStrayRequests()` bypass'ı, RLS testini owner rolüyle koşmak (AD-26).
17. **Hazır bileşen varken ham input, ve bileşene veri taşımak** — telefon `PhoneInput`, e-posta `EmailInput`. Ham `TextInput` ile telefon/e-posta alanı = anında red; her biri farklı bir şey kaybediyor (E.164 birleştirme, maske, rakam süzgeci, autocapitalise) ve **hiçbiri ekranda yanlış görünmüyor**.

    ⛔ **Bileşen verisini kendi alır.** Çağıran yalnız `v-model`, `id` ve gerekiyorsa `kind="landline"` yazar; `:countries`, `:area-codes`, `:default-country` **geçilmez** — ülke listesi ve alan kodları ortak Inertia prop'unda (`HandleInertiaRequests::share` → `contact`). Sebep ölçüldü *(Sets, 30.07.2026)*: dosya zaten tekti, ayrışan şey her sayfanın taşımayı hatırladığıydı; bir prop eksik sayfa **farklı bir kontrol** çiziyordu. İki arch testi kırar (`FrontendTest`). *Aynı ilke aramada da geçerli:* katlama yalnız `lib/search.js` üzerinden.
18. **Kişi bazlı kullanım izleme** — ürün analitiği yalnız agregat; kişi kırılımı, toplam çevrimiçi süre veya aktiflik skoru üretilmez (AD-21). Kişi eşiği **admin-tanımlı ayardır**, varsayılan 2 *(28.07.2026 revizyonu — eşik sabit kural değil)*. Personelin ne yaptığı sorusunun yeri işlem günlüğüdür, analitik ekranı değil.

## Kalite Kontrol

### Üç kademe *(Sets, 30.07.2026 — kadans revizyonu)*

**1 · Kalem üzerinde çalışırken:** yalnız **dokunulan şeyin** testi — `./vendor/bin/pest --filter="<test adı>"`, en fazla ilgili tek grup. Arch/locale/analyse gibi genel kontroller bu aşamada koşulmaz.

**2 · Commit'ten hemen önce:** `pint --dirty` → `composer analyse` → **yalnız dokunulan testler** (`--filter`, en fazla ilgili tek grup) → düzelt → commit. UI değiştiyse browser console kontrolü.

**3 · Ticket kapanışında:** TeamCity full run (aşağıdaki bölüm) — **tam koşunun tek yeri burasıdır**.

⛔ **Tam koşu yalnız ticket kapanışında** *(Sets, 10.08.2026 — kural sertleştirildi çünkü ihlal edildi)*. Grupları sırayla koşmak da tam koşudur: dokuz grup ~4 dakika CPU ve her aradan sonra yeniden. *"Her yazdığın 10 satır için full run koşarsan iş yapamayız — 2-3 dakikada halledeceğimiz işe 25 dakika harcıyoruz."* Doğrulama **yaptığın işin testiyle** yapılır: yeni yazdığın dosyanın testi + dokunduğun davranışın testi, `--filter` ile. Bir kural/istek/validasyon geniş etki yapıyorsa (ör. yeni bir doğrulama kuralı) **o kuralı çağıran yerleri grep'le bul, onların testini koş** — hepsini koşarak arama.

⛔ **Her düzenlemeden sonra ~1200 testi koşmak yasak** *(ölçüldü, Sets: "1 sayfadaki ufak düzeltme sırf test süreçleri yüzünden ~20 dakika sürdü")*. Kırılan şey neredeyse her zaman dokunulan alandır; geri kalanını yakalayacak yer CI'dır.

⚠ **`composer analyse`'ı testleri YAZMADAN önce koşup sonra unutma** — build #845 tam olarak bu yüzden kırıldı.

⛔ **CI bir checkpoint değildir** *(Sets, 12.08.2026 — kural ikinci kez hatırlatıldı)*. İş bitmeden "acaba geçiyor mu" diye tetiklemek, kırmızı gelince düzeltip yeniden tetiklemek yasak. Basit bir mail işinde art arda **dört build** koşuldu ve ticket 40 dakikayı geçti — *"bu kadar vakit kaybına, bu kadar kaynak harcamaya gerek yok"*.

⚠ **Kırılanı lokalde bul:** `./vendor/bin/pest --parallel --exclude-group=omurga-rls` CI'nın koştuğu komutun **aynısıdır** ve ~50 saniye sürer; TeamCity aynı işi 2,5 dakikada ve paylaşımlı makineyi meşgul ederek yapar. Sıra: yaz → `--filter` → iş bitince bir kez lokal CI komutu → yeşilse **bir kez** TeamCity → deploy.

⛔ **Geliştirme sırasında TeamCity tetiklenmez** *(Sets, 28.07.2026)*. Her düzenlemeden ve her sorudan sonra CI beklemek işi bitirmiyor: build paylaşımlı MBP'de koşuyor, dakikalar sürüyor ve o süre boyunca hiçbir şey ilerlemiyor. Lokal koşu geliştirme sırasında yeterli sinyaldir.

### ⛔ Doğrulama yeterliliği — MUTLAK *(Sets, 13.08.2026)*

*"Normal koşullarda diğer projelerde ben aynı sürede 10 ticket kapatıyorum; 2 saatte 2 basit ticket'ta ilerleyemedik."* Ölçüldü: **iş 20 dakika, doğrulama ve onun ürettiği gürültü 40 dakikaydı.** Kurallar aşağıdaki beş satır; hepsi ölçülmüş bir kayıptan geliyor.

1. ⛔ **Görsel doğrulama Sets isteyince yapılır.** Ekran görüntüsü almak, resmi okumak, tutmayan selector'ı kovalamak — EGT-116'da tek bir kare için sekiz tur harcandı ve davranışı zaten Pest testi kanıtlamıştı. *"Gerekirse ben söylerim görsel doğrulama yap diye."*
2. ⛔ **Dokunulan alanın testi koşulur, 2000 test değil.** *"Sadece 5 tane test için her seferinde 2000 testi koşup sonucunu beklemenin hiçbir manası yok."* Yetki, tenant, audit gibi kritik alanlarda da ölçüt aynı: **o alanın** testleri. Tam lokal koşu iş bitince **bir kez**.
3. ⛔ **Tam tarayıcı suite'i (220 test) rutin değildir.** Bu oturumda iki kez koşuldu: 11,5 dk + 3,6 dk, üstüne baseline için üçüncüsü. Dokunulan ekranların spec'i yeterlidir. ⚠ `--workers` ile hızlandırmaya çalışma: `playwright.config.js` **`workers: 1`** diyor çünkü suite lokal veritabanını paylaşıyor — dört worker 11 sahte kırık üretti ve onları soruşturmak ayrı zaman aldı.
4. ⛔ **Ticket'ın kapsamı ticket kadardır.** EGT-119 "takvim kırpılıyor"du; altı bileşen + ortak composable + yedi ilgisiz `id` düzeltmesine dönüştü. Doğru mühendislikti ama **kararı Sets'in**. Yan bulgu → yeni ticket, iş değil.
5. ⚠ **Küçük ticket'lar toplu teslim edilir:** üç küçük iş = bir commit, **bir** CI, bir deploy. Her birine ayrı döngü kurmak süreç maliyetini üçle çarpar.

⚠ Ve işe başlarken **tek satır plan**: ne yapılacak, ne kadar sürer, neyle doğrulanacak. Sets erken müdahale edebilsin diye — bu oturumda sapma ancak bir saat sonra görülebildi.

### Ticket kapanışında — TEAMCITY (zorunlu)

`./deployment/scripts/teamcity.sh trigger` → `wait <id>` → **yeşil**.

⛔ **Yeşil full run olmadan ticket `Fixed`'e çekilmez ve "tamamlandı" denmez.** Scoped ve lokal koşular cross-cutting regression kaçırır; otorite CI'dır ve otorite olduğu tek an budur.

Başarısız test → düzelt, tekrar tetikle. **Retry ile geçirme yok** (AD-26); tutarsız test karantinaya alınır + ticket açılır.

⚠ **Lokal tam koşu (`./vendor/bin/pest`) güvenilir değil** — `omurga-rls` grubu bağlantı yuvası tükenmesinden düşer (ölçüldü, değişiklikten bağımsız). Gruplar ayrı koşulur.

**Test grupları (AD-26):** `omurga` · `omurga-rls` · `backoffice` · `planlama` · `satis` · `egitmen` · `musteri` · `katilimci` · `entegrasyon` · `mevzuat`. Grupsuz test arch testiyle reddedilir.

## Git ve YouTrack Akışı

- **Süreç YouTrack üzerinden yürür.** Faz'lar epic, işler ticket. Bir işe başlarken ticket `In Progress`, biten ticket `Fixed`, sonra sıradakine geçilir. "Nerede kalmıştık?" sorusunun cevabı ticket geçmişidir.
- Smart commit: `#EGT-12 Fixed work 30m` + ikinci satırda conventional commit açıklaması. Birden fazla ticket: `(#EGT-10, #EGT-11) Fixed work 1h`. **YouTrack komutları yalnız ilk satırda** (hook zorluyor).
- ⛔ **Biten ticket `Fixed`'e değil `In Review`'a gider ve Tayfun'a atanır** *(Sets, 10.08.2026 — önceki kuralın tersi; eski satır "Sets söylediğinde" diyordu, artık varsayılan budur)*. Sıra: TeamCity yeşil → **prod'a deploy** → `In Review` + `assignee Tayfun` → **aynı turda** ticket'a iki başlıklı bir yorum yazılır:

  ⛔ **Atamadan ÖNCE deploy edilir** *(Sets, 11.08.2026)*. **Tayfun yalnız production'ı görür** — dev'e de local prod'a da bakmaz. Deploy edilmemiş bir işi ona atamak, test edemeyeceği bir şeyi test etmesini istemektir: ekranı arar, bulamaz, "yapılmamış" diye geri döner. Yani deploy, teslimin bir parçasıdır, ayrı bir iş değil. Sıra sabittir: **yeşil CI → deploy → doğrula (ekran gerçekten canlıda mı) → ata.** Deploy edilemiyorsa (ortam kapalı, engel var) ticket **atanmaz**; sebebiyle birlikte Sets'e söylenir.

  | Başlık | Ne yazar |
  |---|---|
  | **Ne yapıldı** | Kullanıcının dilinde, ekrandan görülebilen değişiklik. Sınıf/dosya adı değil; "şu menüye şu kalem geldi", "şu alan artık şu durumda kilitleniyor". Bilinçli davranışlar (boş bırakılan kutu, pasif alan) **sebebiyle** yazılır — test eden kişi onu hata sanmasın. |
  | **Test prosedürü** | Numaralı adımlar: hangi ortam, hangi hesap, hangi ekran, ne yapılacak, **ne beklenmeli**. Mutlu yol yetmez — kilitlenen/başarısız olan hâl de bir adımdır. Dar ekran adımı, ekran değiştiyse eklenir. |

  `Fixed`'e **Tayfun çeker**; doğrulamayan bir işi biz tamamlanmış ilan etmeyiz (Onay Kuralı 3 ve 5'in ticket karşılığı). Geri dönerse ticket bize atanır, döngü baştan işler.

  ⚠ **İstisna: ekranda test edilebilir yüzeyi olmayan altyapı işi** *(Sets, 11.08.2026, EGT-104)*. Kuyruk yapılandırması, kilit, deploy betiği, güvenlik güncellemesi gibi işlerde Tayfun'a verilecek bir ekran yoktur — doğrulama log ve Horizon okumakla yapılır. Bunlar deploy edildikten ve **canlıda doğrulandıktan** sonra doğrudan `Fixed`'e çekilebilir; ticket'a yine "ne yapıldı + nasıl doğrulandı" yorumu yazılır. ⛔ Ölçüt **ekran**, işin cinsi değil: bir altyapı işi görünür bir davranış değiştiriyorsa Tayfun'a gider.

  ⚠ YouTrack tarafı 10.08.2026'da kuruldu: `In Review` durumu paylaşılan state bundle'ına eklendi — **EGT, GZT, OPS ve TMGD dördünde birden görünür** — ve Tayfun EGT'nin Assignee listesine bireysel olarak eklendi. ⚠ O günkü gerekçe *"proje ekibine ekleme Cloud API'sinden yapılamıyor"* idi ve **yanlıştı** — doğru uç nokta bulunamamıştı (aşağıya bakın); bireysel kayıtlar 25.08.2026'da temizlendi.

  ⛔ **Ekip üyeliği API'DEN yapılabiliyor: `team/ownUsers`** *(25.08.2026 — bu dosyada aksi yazılıydı ve yanlıştı)*. Doğru uç nokta `POST /admin/projects/<KOD>/team/ownUsers` gövde `{"id":"<kullanıcı>"}`; `team/users` 405, `team` gövdeyle 200 döner **ama hiçbir şey yapmaz** (listeyi olduğu gibi geri yazar) — 10.08'de aranan ve bulunamayan uç bu, o yüzden Assignee bundle'ına bireysel ekleme yaması kurulmuştu.

  ⚠ **Yamanın maliyeti ölçüldü:** yama yalnız EGT ve OPS'a konmuştu, dolayısıyla Tayfun CORE/COMP/GZT/TMGD'de atanabilir görünmüyordu *(Sets, 25.08.2026: "core ticketlarinda Tayfun'u secenek olarak vermiyor")*. Bugün Tayfun **altı projenin de ekibine** üye yapıldı; Assignee listeleri zaten ekip grubunu okuyor, **bireysel kayıtların hepsi silindi** — bir kişinin atanabilirliğinin tek kaynağı artık ekip üyeliğidir. ⚠ Ekip üyeliği aynı zamanda **görme yetkisini** de getirir; bundle'a bireysel ekleme getirmiyordu.

  ⛔ **CORE kendi listesini kullanmıyor** — Assignee alanı «Compliance: Assignee» (`13-5`) bundle'ına bağlı, yani CORE ile COMP aynı listeyi paylaşıyor ve **«Core Team» ekibine eklenen kimse CORE'da atanabilir olmuyor**. Bugün Tayfun her iki ekibe de eklendiği için sorun görünmüyor, ama yapı yanlış duruyor. Kalıcı çözüm CORE'a kendi bundle'ını vermek.

- Ticket yoksa detaylı conventional commit (`fix(planlama): ...`).
- Branch: `feature/EGT-12-kisa-aciklama` / `fix/EGT-12-...`; production deploy yalnız `main`'den.
- Yeni ticket'lar Sets'e assign edilir.

## Çelişki / Belirsizlik

Kurallar çelişiyorsa veya net değilse: varsayımla İLERLEME, kullanıcıya SOR, belirsizliği `docs/issues.md`'ye yaz.
