# 3E Akademi — Eğitim Otomasyonu

Lojistik/denizcilik alanında mevzuata tabi zorunlu eğitimler veren 3E Group için eğitim firması otomasyonu: eğitim planlama, satış/teklif, bakanlık bildirimi, yoklama/sınav, eğitmen ve müşteri yönetimi. Multi-tenant B2B SaaS.

**Stack:** Laravel 13 · PHP 8.5 · PostgreSQL 17 (TimescaleDB + Anonymizer, PgBouncer) · Redis + Sentinel · Horizon · Reverb · Filament (backoffice) · Inertia + Vue (beş panel)

---

## Doküman haritası

Kod yazmadan önce okunacaklar — sırayla:

| Doküman | Ne için |
|---|---|
| `cati-dokumani.md` | **İş kuralları ve süreçler — tek kaynak.** Bir iş kuralı sorusunda önce buraya bak. |
| `docs/mevzuat-kurallari.md` | Mevzuattan doğrulanmış kurallar, madde referanslı. "MEVZUATTA YOK" satırları varsayımla doldurulamaz. |
| `docs/arch/mimari-kararlar.md` | AD-01…AD-28. Mimariye dokunan her işte önce bunu oku. |
| `docs/arch/kod-yerlesimi.md` | Hangi kod nereye yazılır. Satır limiti yok, adres sözleşmesi var. |
| `docs/arch/paket-surumleri.md` | Paket pinleri ve gerekçeleri. |
| `docs/infra/ortamlar.md` | Sunucular, portlar, TeamCity, YouTrack, log disiplini. |
| `design/HANDOFF.md` | Tasarım sistemi. ⛔ Tasarımcının teslimi **eksiksiz uygulanır** — sayfa kompozisyonu dahil; sapma yalnız Sets söylediğinde (`CLAUDE.md` → Tasarım Uygulama Protokolü). |
| `CLAUDE.md` | Çalışma kuralları ve kırmızı çizgiler. |

`mevzuat/` altında resmî mevzuat metinleri (envanter: `mevzuat/README.md`).

## Panel yapısı

| Ortam | Panel | Kullanıcı |
|---|---|---|
| `egitim.3egrp.com` | Landing + `/panel` + `/katilimci` | Müşteri firma yetkilileri, katılımcılar |
| `ofis.egitim.3egrp.com` | Ofis | Planlamacı, satışçı, eğitmen, yönetici |
| `backoffice.egitim.3egrp.com` | Backoffice (Filament) | Sistem yönetimi, kural motoru, tanımlar |
| `ws.infra.egitim.3egrp.com` | Reverb WebSocket | — (`infra.*` core servisler için çatı subdomain) |

Lokal karşılıkları **HTTPS** üzerinden: `egitim.dev.sets.fyi`, `ofis.egitim.dev.sets.fyi`, `backoffice.egitim.dev.sets.fyi`, `ws.infra.egitim.dev.sets.fyi`.

⚠ TLS konfor değil zorunluluk: tarayıcılar passkey'i (WebAuthn) yalnız güvenli bağlamda açar, düz http'de API tanımlı bile değildir. Adresler Cloudflare DNS ile bu makinenin LAN adresine bakar (gri bulut) ve **yalnız bu ağdan** açılır. Kurulum: `docs/infra/ortamlar.md`.

---

## Lokal kurulum

### 1. Bağımlılıklar

```bash
composer install
npm install
cp .env.example .env
php artisan key:generate
```

### 2. Altyapı (Docker)

Tüm container'lar Docker Desktop'ta **`3eegitim`** projesi altında gruplanır.

```bash
# PostgreSQL imajı (TimescaleDB + Toolkit + Anonymizer) — ~1 dk (base imaj çekiliyse)
docker pull timescale/timescaledb-ha:pg17
docker build -t 3eegitim/postgresql:17-custom deployment/postgresql

# PgBouncer kullanıcı listesi — şifre .env'deki DB_PASSWORD ile aynı olmalı
cp deployment/pgbouncer/userlist.txt.example deployment/pgbouncer/userlist.txt
chmod 600 deployment/pgbouncer/userlist.txt   # şifreyi doldur

# Ayağa kaldır
docker compose --env-file .env \
               -f deployment/docker-compose.postgresql.yml \
               -f deployment/docker-compose.pgbouncer.yml up -d
docker compose --env-file .env -f deployment/docker-compose.redis.yml up -d
```

**Portlar** — 11.08.2026'dan beri **port kayıt defterinden** gelir (blok `20200`,
`.toolkit/tools/ports`). Tek tek boş port aramak bitti: her projenin yüz portluk
bir bloğu var ve servisler blok içinde sabit bir kaymayla durur.

| Servis | Port |
|---|---|
| PostgreSQL direct (migration/psql/dump) | 20200 |
| PgBouncer (uygulamanın gerçek DB portu) | 20201 |
| Redis master / replica 1 / replica 2 | 20210 / 20211 / 20212 |
| Sentinel 1 / 2 / 3 | 20220 / 20221 / 20222 |
| Reverb | 20230 |

> Doğrulama: `./.toolkit/tools/ports/check-ports.sh` — defterle gerçeği karşılaştırır.

> ⚠ `--env-file .env` **zorunlu**: compose `.env`'i ilk compose dosyasının dizininde (`deployment/`) arar, proje kökünde değil.

> ⚠ Yeni bir servis eklerken portu **uydurma**: defterden al (`registry.sh show 3eegitim`) ve blok içinden ver. Makine paylaşımlı; eski yöntem (boş port arayıp yazmak) dört ortamın dördünde farklı port setine yol açmıştı.

**Redis Sentinel notu:** dev'de container'lar bridge ağındadır, sentinel master/replica adreslerini ağ içi IP'lerle bildirir ve macOS host'undan bu adreslere erişilemez. Bu yüzden dev'de uygulama **doğrudan master'a** bağlanır (`REDIS_PORT=20210`); sentinel'ler yine çalışır ve topoloji `redis-cli -p 20220 sentinel master 3eegitim-master` ile incelenebilir. Local prod ve production'da (Linux) `docker-compose.redis.prod.yml` override'ı `network_mode: host` kullanır ve uygulama sentinel üzerinden bağlanır.

### 3. nginx

```bash
ln -sf $(pwd)/deployment/nginx/egitim.dev.sets.fyi.conf /opt/homebrew/etc/nginx/servers/3eegitim.conf
nginx -t && nginx -s reload
```

Sertifika `acme.sh` ile Let's Encrypt'ten DNS-01 üzerinden alınır ve `/opt/homebrew/etc/nginx/ssl/egitim.dev.sets.fyi/` altında durur — komutu `docs/infra/ortamlar.md`'de. `/etc/hosts` kaydı **gerekmez**, adresleri DNS çözer. PHP-FPM 8.5 → `127.0.0.1:9000`.

### 4. Migration ve çalıştırma

```bash
php artisan migrate
php artisan reverb:start      # WebSocket
php artisan horizon           # kuyruk
npm run dev                   # Vite
```

---

## Test

Test grupları panel/alan bazlıdır (AD-26): `omurga` · `omurga-rls` · `backoffice` · `planlama` · `satis` · `egitmen` · `musteri` · `katilimci` · `entegrasyon` · `mevzuat`.

```bash
./vendor/bin/pest --group=satis        # geliştirme sırasında: yalnız ilgili grup
./vendor/bin/pest                      # merge öncesi: TAM koşum (zorunlu)
./vendor/bin/pint --dirty              # kod formatı
```

CI (TeamCity, MBP build server):

```bash
./deployment/scripts/teamcity.sh trigger Egitim_Egitim main --group=satis
./deployment/scripts/teamcity.sh trigger        # tam koşum
./deployment/scripts/teamcity.sh wait <id>
```

**Kurallar:** grupsuz test arch testiyle reddedilir · testte çıplak `now()` yasak (`Carbon::setTestNow()`) · dış HTTP çağrısı `Http::preventStrayRequests()` ile bloklu · CI'da retry yok, tutarsız test karantinaya alınır ve ticket açılır.

## Araçlar

```bash
./deployment/scripts/youtrack.sh mine            # ticket'larım
./deployment/scripts/teamcity.sh list            # son build'ler
./deployment/scripts/heyet.sh                    # heyet review (yalnız Sets başlatır)
```

Git hook kurulumu: `git config core.hooksPath .githooks` — commit mesajında AI attribution ve bozuk YouTrack formatı reddedilir.

## Süreç

İş YouTrack üzerinden yürür (`EGT` projesi). Fazlar epic, işler ticket: başlarken `In Progress`, bitince `Fixed`. Smart commit: `#EGT-12 Fixed work 30m` + ikinci satırda conventional commit açıklaması; YouTrack komutları yalnız ilk satırda.
