﻿# fikoyt-sunucu (Go/Fiber + MongoDB) - Mimari & Guvenlik Denetimi + Uzaktan Lisans Entegrasyon Analizi

**Tarih:** 28.09.2026
**Proje:** `D:\__sistem__\Masaustu\FikoYT.Yeni.Cag\docker\fikoyt-sunucu`
**Kapsam:** `merkez.go-server.com` (Go 1.23, Fiber v3, MongoDB driver, Socket.IO v2, Redis adapter), `docker-compose.yml`, `Dockerfile`
**Yontem:** Statik kod okumasi - degisiklik yapilmamistir.

---

## 1. MIMARI HARITA

### 1.1 Kabuk (Docker)

`docker-compose.yml` - 3 servis:

| Servis | Image | Port | Rol |
|--------|-------|------|-----|
| `fikoyt-sunucu` | build `./merkez.go-server.com` | 9000 | Go/Fiber ana API + Socket.IO + lisans paneli |
| `redis` | redis:7-alpine | 6379 | Socket.IO adapter (prefork olmadigi icin **kullanilmiyor**) |
| `yuz-tanima-servisi` | build `../yuz-tanima-servisi` | 8100 | Yuz tanima (GPU, **kodda devre disi**) |

Ag: `fikoyt_ag` (external). MongoDB **bu compose'da YOK** - `mongo_uri` ile `mongodb:27017` adresine baglaniyor, yani ayri bir stack'te calisiyor.

`Dockerfile`: `golang:1.23-alpine` -> `go mod tidy && go build -o ./tmp/main .` -> `CMD ["./tmp/main"]`
- **Cift katmanli derleme**: Go toolchain build icinde, runtime'da binary statik calisiyor (iyi).
- **`COPY . .`** - `.dockerignore` kontrolu yoksa `.env`, `fikoyt.env.json`, `cert/`, `tmp/` hepsi build context'e giriyor.
- Healthcheck `curl -fks https://localhost:9000/rag/gomme/durum` - RAG modulune bagli (koparsa container "unhealthy" olur).

### 1.2 Go Modul Grafiği (`main.go`)

```
main()
 ├─ jsonenv.Load("fikoyt.env.json")        // env.json -> os.Setenv
 ├─ fiber.New(BodyLimit: 2GB, StreamRequestBody, Immutable)
 ├─ recoverer.New()                         // PANIC YAKALAYICI
 ├─ COOP/COEP header middleware
 ├─ FikoYTCtx.Ayarla(app)                  // JSON + Dosya + Session + FikoYTCtx
 ├─ fiko_socket_io.Ayarla(app)             // ANA Socket.IO (/socket.io)
 ├─ uyar_app_main.Ayarla(app)              // Dokum/Tetikleyici
 ├─ fikoyt_api.Ayarla(app)                 // Ajan sistemi
 ├─ rag.Ayarla(app)                        // RAG + MCP
 ├─ guncelleme.Ayarla(app)                 // Native updater
 ├─ lisans_kontrol.Ayarla(app)             // LISANS KONTROL PANELI (/isans)
 ├─ TetikleyiciMotorOrnek.Baslat()
 ├─ mail_dinleyici.Baslat(...)             // IMAP
 ├─ kok.KokRouting(app)                    // /fapiv1 - sistem API'leri
 ├─ kokDB.KokDBRouting(app)                // /fapiv1 - DB CRUD + mail
 └─ runSslWithPrefork(app)                 // TLS + Listen
```

**Iki ayri Socket.IO sunucusu var** - bu onemli:

| Sunucu | Yol | Namespace | Kullanim |
|--------|-----|-----------|----------|
| `FikoSocketIo` | `/socket.io/` | varsayilan + `/fikoyt` | Mobil/Flutter istemciler, ajan, RAG |
| `FikoLisansSocketIo` | `/isans.socket.io/` | `/isans` | **FikoCAD lisans istemcisi** |

Izole olmalari dogru bir karar - FikoCAD'nin lisans trafigi genel socket havuzunu kirletmiyor.

### 1.3 Veri Katmani (MongoDB)

`sistem/fikoyt_mongo/fiko_mongo.go`:
- `Init()` -> 10 denemeli MongoDB baglantisi (replicaSet rs0)
- Session store: `go_sessions` koleksiyonu, `CookieSecure: true, CookieHTTPOnly: true, SameSite: lax, Expiration: 24h`
- `FikoYTCollection(isim)` -> `Database("fikoyt").Collection(isim)` - **veritabani adi sabit kodlanmis**

**Kullanilan koleksiyonlar:**
| Koleksiyon | Kullanim |
|------------|----------|
| `goUyeler` | Kullanicilar + `yetkiler` alani |
| `go_sessions` | Fiber session |
| `goCihazlar` | Cihaz kayitlari (cihaz_tipi, bilgiler) |
| `goSoketler` | Socket <-> cihaz <-> kullanici eslesmesi |
| `hareketler` | Genel kayit (hareket) tablosu - **"korunan"** |
| `go_files` | GridFS dosyalar |
| `go_hareketler` (implied) | Bildirimler |

`apps/rag/`, `apps/fikoyt_api/ajanlar/`, `apps/collab/` kendi koleksiyonlarini kullanir.

### 1.4 Kimlik & Yetki Sistemi

Katmanli: **Session tabanli** (JWT degil).

```
HTTP istek
 ├─ session middleware  -> c.Locals("session")
 ├─ araIsleyici()      -> alAktifKullanici(c)
 │    └─ session.Get("aktifKullaniciID")
 │         └─ FikoYTKullanici.Yeni(c, objectIDStr)
 │              └─ goUyeler.FindOne(projection: parola/epostaOnayKodu/anlasma/aktifDurum HARIC)
 │                   └─ yetkiler: []string
 └─ FikoYT.YetkiVarmi("Super Yonetici")
```

`yoneticiMi()` (guvenlik.go:43) = `Super Yonetici` VEYA `Yonetici`.

**Tutarsizlik bulundu:** `yetki.go:124` `("Super Yonetici" || "Süper Yönetici")` diye iki sekli kontrol ediyor, `admin_uye.go:22` de ayni sekilde ikisini kontrol ediyor. Ama `guvenlik.go:45` ve cogu yerde **sadece `"Super Yonetici"`** kontrol ediliyor. Turkce karakter varyanti olan bir yetki, bazi yerlerde yonetici sayilir bazi yerlerinde sayilmaz.

### 1.5 `kokDB` - Generic DB CRUD (Aggregate dahil)

`POST /fapiv1/fikoyt.com.FikoYT.sistem.DB.:db.<islem>`

| Endpoint | Islem | Guvenlik |
|----------|-------|----------|
| `.aggregate` | `Aggregate(pipeline)` | **YOK** |
| `.ekle` | `EkleYadaGuncelle` (upsert) | `korunanKoleksiyonMu(db)` kontrolu |
| `.sil` | `DeleteMany` | `korunanKoleksiyonMu(db)` kontrolu |
| `.guncelle` | `UpdateMany` | `korunanKoleksiyonMu(db)` kontrolu |

`korunanKoleksiyonlar = { "hareketler": true }` - **sadece 1 koleksiyon korumali**.

`convertStagesToPipeline(aggrSlice)` istemciden gelen JSON'u dogrudan MongoDB pipeline'ina ceviriyor. `$lookup`, `$out`, `$merge` dahil her stage calistirilabilir.

---

## 2. KRITIK GUVENLIK ACIKLARI

### ACIK 1 (KRITIK) - `/lisans-kontrol` Token Yoksa TAMAMEN ACIK

`apps/lisans_kontrol/lisans_kontrol.go:364-375`

```go
func tokenTamam(c fiber.Ctx) bool {
	if adminToken == "" {
		return true          // <-- TOKEN YOKSA HERKES GIRER
	}
	if c.Query("token") == adminToken {
		return true
	}
	if c.Get("X-Token") == adminToken {
		return true
	}
	return false
}
```

`adminToken = os.Getenv("LISANS_ADMIN_TOKEN")`.

**`docker-compose.yml`'de `LISANS_ADMIN_TOKEN` TANIMLI DEGIL.** Yani varsayilan dagitimda `adminToken == ""` -> `tokenTamam()` her zaman `true` doner.

Sonuc:
- `GET /lisans-kontrol/api/istemciler` -> **herkes** bagli tum musteri makinelerini, seri numaralarini, makine parmak izlerini, IP'leri gorur
- `POST /lisans-kontrol/api/karar` -> **herkes** imzali bir engelleme karari uretebilir
- `/lisans-kontrol` panel sayfasi da korumasiz

Bu, Node.js surumundeki `server.js`'in `ADMIN_TOKEN` kontrolunden **cok daha zayif** - Node surumunde token bos olursa uçlar "TÜM istekleri reddeder" diye reddediyor, Go surumunde tam tersi: hepsini kabul ediyor.

**Agirlik:** Bu panel lisans imzalama yetkisine **erisim** demek. Saldirgan ozel anahtara erisemez (PEM dosyada, imzalama sunucu ici) ama:
- Müsteri listesini okur (veri sizintisi)
- Rastgele bir musteriye imzali "engelli" karar gonderir -> **DoS (musteri calisamaz)**
- Olmayan seri numarasiyla karar yazar -> istemci tarafinda `Belirsiz` durumuna dustugu icin etkisiz, ama kural seti kirlenir

**Duzeltme:**
```go
func tokenTamam(c fiber.Ctx) bool {
	if adminToken == "" {
		log.Printf("[LISANS-KONTROL] KRITIK: LISANS_ADMIN_TOKEN tanimsiz - panel KAPALI")
		return false   // fail-closed
	}
	return subtle.ConstantTimeCompare([]byte(c.Query("token")), []byte(adminToken)) == 1 ||
	       subtle.ConstantTimeCompare([]byte(c.Get("X-Token")), []byte(adminToken)) == 1
}
```

### ACIK 2 (KRITIK) - Generic DB API: Yetkisiz Kullanici Tum Veritabanini Okuyup Yazabilir

`kokDB/kok.go:20-23` + `kokDB/routes.go`

```go
fapiv1.Post("/fikoyt.com.FikoYT.sistem.DB.:db.aggregate", fikoyt_sistem_db_agregate)
fapiv1.Post("/fikoyt.com.FikoYT.sistem.DB.:db.ekle",      fikoyt_sistem_db_ekle)
fapiv1.Post("/fikoyt.com.FikoYT.sistem.DB.:db.sil",       fikoyt_sistem_db_sil)
fapiv1.Post("/fikoyt.com.FikoYT.sistem.DB.:db.guncelle",  fikoyt_sistem_db_guncelle)
```

`aggregate` handler'inda **hicbir yetki kontrolu yok**:

```go
func fikoyt_sistem_db_agregate(c fiber.Ctx) error {
	FikoYT := c.Locals("FikoYTCtx").(*FikoYTCtx.FikoYTCtx)
	db := c.Params("db")                    // <-- istemci koleksiyon adi seciyor
	koleksiyon := FikoYT.Koleksiyon(db)      // <-- Koleksiyon() oturum kontrolu YAPMIYOR
	...
	pipeline, _ := convertStagesToPipeline(aggrSlice)   // <-- istemci pipeline'i calistiriliyor
	cursor, _ := koleksiyon.Aggregate(ctx, pipeline, ...)
	return c.JSON(results)
}
```

`FikoYT.Koleksiyon(db)` sadece `Database("fikoyt").Collection(db)` - **session/yetki denetimi icermiyor**.

`ekle`/`sil`/`guncelle` icin `korunanKoleksiyonMu(db)` kontrolu var ama sadece `"hareketler"` icin. `goUyeler`, `go_sessions`, `goCihazlar`, `goSoketler` **korumasiz**.

**Saldiri senaryolari (oturum ACIK, yetki gerekmiyor):**

1. **Tum kullanicilar + parolalar:**
```bash
POST /fapiv1/fikoyt.com.FikoYT.sistem.DB.goUyeler.aggregate
{"aggregate":[{"$match":{}}]}
```
`aggregate` icinde `projection` yok - `parola` alani dahil **TUM belgeler** doner.

2. **Yetki yukseltme (kendini Super Yonetici yap):**
```bash
POST /fapiv1/fikoyt.com.FikoYT.sistem.DB.goUyeler.guncelle
{"filter":{"kullaniciAdi":"saldirgan"},"veri":{"yetkiler":["Super Yonetici"]}}
```
`goUyeler` korunmadigi icin `hareketFiltreKisitla` cagrilmaz -> sadece oturum yeterli.

3. **Session calma:** `go_sessions` koleksiyonu aggregate ile okunabilir -> `aktifKullaniciID` + session ID calinir.

4. **Tum veri toplama:** `$lookup`/`$out`/`$merge` ile **herhangi bir koleksiyona yazabilir** (`$out` yazma yetkisi icin ayrica yetki kontrolu yok).

**Agirlik: KRITIK.** Sifirlama: `aggregate` + `ekle` + `guncelle` + `sil` uclarina `FikoYT.AktifKullanici != nil` ve yonetici yetkisi zorunlulugu.

**Oneri (guvenlik.go'ya):**
```go
func dbErisimKontrol(FikoYT *FikoYTCtx.FikoYTCtx, db string, okuma bool) (bool, int, string) {
	if FikoYT == nil || FikoYT.AktifKullanici == nil {
		return false, 401, "Oturum gerekli"
	}
	if !yoneticiMi(FikoYT) {
		return false, 403, "Bu koleksiyona erişim yetkiniz yok"
	}
	return true, 0, ""
}
```
Ve **beyaz liste**: yalniz `goUyeler`, `hareketler`, `goCihazlar` gibi bilinen koleksiyonlara erisim.

### ACIK 3 (YUKSEK) - CORS `Origin: "*"` + Credentials

`fiko_socket_io.go:64-67` ve `lisans_kontrol.go:392-395`:
```go
socketioSettings.SetCors(&types.Cors{
	Origin:      "*",
	Credentials: true,
})
```

`lisansSettings` icin `Origin: "*"` + `Credentials: true` **CORS spec'e aykiridir** (bircok tarayici bunu reddeder, ama yine de gevsek). Fiber tarafinda `AllowOrigins` liste halinde daraltilmis - **Socket.IO tarafinda genisletilmis**. Bu, herhangi bir web sayfasindan tarayici ile lisans paneline baglanip CSRF ile karar gondermeye yol acabilir.

**Duzeltme:** `lisans_kontrol` icin `Origin: "https://fikoyt.com"` (ve panelin gercekten baska origin'den acilacaksa ekle).

### ACIK 4 (YUKSEK) - CORS AllowHeaders `"*"` ve `AllowMethods` TRACE

`kok.go:57` ve `kokDB/kok.go:16`:
```go
AllowHeaders: []string{"*", "Content-Type", "Authorization", "Mode", "cihaz_kimlik", ...},
AllowMethods: []string{"GET", "POST", "HEAD", "PUT", "DELETE", "PATCH", "OPTIONS", "TRACE"},
AllowCredentials: true,
```

`AllowHeaders: "*"` + `AllowCredentials: true` -> herhangi bir header okunabilir. `TRACE` metodu acik (Cross-Site Tracing denemeleri icin).

### ACIK 5 (YUKSEK) - Onel Sifreleme Anahtari

`fikoyt.env.json`:
```json
{
  "sifreleme_kiliti": "FikoYT+1299",
  "mongo_uri": "mongodb://fikoyt:fikoyt1299@mongodb:27017/?authSource=admin&..."
}
```

- MongoDB parolasi dosyada duz metin (`fikoyt1299`)
- `sifreleme_kiliti` sabit ve dosyada
- `mongo_uri` **loglaniyor**:
```go
log.Printf("MongoDB bağlantı adresi: %s", databaseURL)   // fiko_mongo.go:27
```
Parola log'a sizar. Container log'lari docker'da gorunur.

**Duzeltme:** Dosyayi `.gitignore`'a ekle; `mongo_uri`'yi `log.Printf` yerine parolasiz yaz; credentials'i Docker secrets veya environment'a tasi.

### ACIK 6 (ORTA) - `recoverer` Sonrasi Detay Sizintisi Yok ama BodyLimit 2GB

`main.go:32`:
```go
app := fiber.New(fiber.Config{..., BodyLimit: 2000 * 1024 * 1024})
```
**2 GB** body limiti + `StreamRequestBody: true`. Tek bir istek 2 GB RAM yiyebilir. DDoS vektoru.

**Duzeltme:** Lisans/CIHAZ API'leri icin endpoint bazli limit koy (`app.Post("/path", limit.BodyLimit(...))`).

### ACIK 7 (ORTA) - Yetki Sistemi Dagitik, Bazı Uclar Korumasiz

Taranan 20+ yetki kontrolunden cogu **yol bazli** (`FikoYT.AktifKullanici.YetkiVarmi("Super Yonetici")`). Yeni endpoint eklerken kontrol unutulunca sessizce acik kaliyor - merkezi bir `adminOnly` middleware'i yok.

**Duzeltme:** `app.Group("/fapiv1/admin", adminOnly)` gibi merkezi guard.

### ACIK 8 (ORTA) - Redis Adapter Kullanilmiyor

`main.go:118` -> `EnablePrefork: false` (tek process). Redis adapter `fiko_socket_io.go:90-95` kuruluyor ama tek process'te **gereksiz**. Redis konteyneri bos calisiyor + `6379:6379` disariya **acik** (public erisim!).

**Duzeltme:** Redis portunu internal yap (`expose` yerine `ports` kaldir) veya prefork'u aktif edip adapter'i gercekten kullan.

---

## 3. MEVCUT LISANS ALTYAPISI - SUNUCU TARAFI

### 3.1 Su an var olan: `lisans_kontrol` (kill-switch)

`apps/lisans_kontrol/lisans_kontrol.go` (473 satir) - **fikoyt-sunucu icinde calisan Go implementasyonu.**

**Mimari (dogru kurulmus):**
```
fikocad.exe
  └─ Socket.IO /isans namespace'e baglanir
  └─ "merhaba" gonderir: {seri, musteri, bilgisayar, surum, pid, makine[]}
  └─ sunucu: istemciler[uuid] = Istemci  (RAM'de)
  └─ sunucu: varMi ise kararlar[seri] gonderilir
Panel (/lisans-kontrol)
  └─ GET /api/istemciler  -> tablo
  └─ POST /api/karar {kimlik, engelli, mesaj}
       └─ kararImzala(): kanonik govde -> sha256 -> ECDSA -> DER -> raw r||s -> base64
       └─ kararlar[seri] = k, kararlariKaydet() (JSON dosya)
       └─ ist.gonder(k)  -> Socket.IO ile o istemciye
fikocad.exe
  └─ canliKararCoz(json, gomulu ACIK anahtar) -> ECDSA dogrula
  └-> gecerliyse uzakCanliEngelliMi(seri) -> LisansDurum::UzaktanEngellendi
```

**Iyi taraflar:**
1. **Kanonik govde sirasi** Go tarafinda `kanonikKur()` ile C++ tarafinda `canliKararKanonik()` ile **ayni**:
   ```go
   return fmt.Sprintf("engelle=%d\nseri=%s\nmesaj=%s\nzaman=%d\n", e, k.Seri, k.Mesaj, k.Zaman)
   ```
2. **DER -> raw r||s donusumu** (`derToRaw`) dogru uygulanmis - C++ `kripto::imzaDogrula` ham 64 bayt bekliyor, Go `ecdsa.SignASN1` DER uretiyor. Donusum dogru (saga hizalama, one sifir atma).
3. **P-256 kontrolu** var (`ozelAnahtar.Curve != elliptic.P256()` -> imzalama KAPALI).
4. **Anahtar yuklenemezse sessizce karar uretmez** - `kararImzala()` hata doner, API 500 verir.
5. **Kalicilik** - `sistem/lisans_kararlar.json` yaziliyor, yeniden baglanan istemci son karari aninda aliyor.

**Sorunlar:**

| # | Sorun | Satir | Etki |
|---|-------|-------|------|
| 1 | `tokenTamam()` fail-OPEN | 364-375 | **KRITIK** (ACIK 1) |
| 2 | Kararlar JSON dosyada, Mongo'da degil | 204-215 | Lisans gecmisi sorgulanamaz, panel haricinde erisilemez |
| 3 | Istemciler sadece RAM'de | 73-80 | Sunucu restartinda **tum musteri gecmisi kaybolur** |
| 4 | `sistem/lisans_kararlar.json` **imzasiz** | 204-215 | Dosya sistemi erisimi olan biri kararlari degistirebilir (imza uretemez ama karari *silebilir* = fail-open) |
| 5 | Istemci kaydi **dogrulanmiyor** | 238-250 | `merhaba` mesajinda gelen seri/makine degerleri **guvenilir kabul edilmiyor** - panelde gorunuyor ama dogrulama yok |
| 6 | Servis hesabi **yok** | - | Hangi panel islemini hangi admin yapti? `kararlar` kaydinda `admin` alani yok |
| 7 | Uzak politika `.pol` bu sunucuda **degil** | - | Ikinci bir kontrol kanali (`lisans_uzak.cpp`) ayri yerde calisiyor |
| 8 | Socket.IO `SetTransports("polling","websocket","webtransport")` | 387 | Node surumunden farkli - polling acik (daha genis yuzey) |

### 3.2 Ikinci kanal: Uzak politika `.pol`

`motor/cekirdek/src/lisans_uzak.cpp` - **bu sunucu ile ilgisi yok.** Fikocad dogrudan bir URL'den (web host / S3 / GitHub Pages) `.pol` dosyasi cekiyor:

```cpp
constexpr const char* UZAK_URL_VARSAYILAN = "";   // <-- BOS!
constexpr const char* UZAK_URL_AYAR = "lisans_uzak_url";
constexpr i64 DENETIM_ARALIGI = 6 * 3600;
```

Onbellek: `%ProgramData%\FikoCAD\lisans_uzak.pol` (imzali, atomik yazim).

**Iki kanal bagimsiz calisiyor ve birbirini bilmiyor.** Bu, hem guc hem zafiyet:
- Guc: istemci dogrudan sunucuya baglanmasa bile bir kontrol kanali var
- Zafiyet: iki ayri yonetim yuzeyi, iki ayri bakim yuk

**Sorun:** `UZAK_URL_VARSAYILAN` bos. Dagitilan exe'de bu deger dolu olmali, aksi halde `.pol` kontrolu **hic devreye girmiyor** - sadece ayar ile manuel aciliyor. Mevcut haliyle bu kanal **kapali**.

### 3.3 Ucuncu kanal: "Baglanti ZORUNLU"

`lisans_canli.cpp:694-704` - musteri tarafindan kapatilabilir (onceki raporda belgelendi). Bu, fikoyt-sunucu tarafinda `LISANS_ADMIN_TOKEN` ile yonetiliyor ama istemcide kullanici erisiminde.

### 3.4 Lisans **dosyasi** sunucuda degil

Onemli bir nokta: **`.fkl` lisans dosyalari uretici makinede uretiliyor, MongoDB'ye girilmiyor, sunucudan dagitilmiyor.** Sunucu sadece:
- hangi serinin **bagli** oldugunu goruyor
- o seriye engelle/izin karari yoluyor

Yani istediginiz "MongoDB'ye kayit yap, oradan yetki/lisans/komut ver" hedefi icin **mevcut altyapida sifirdan bir katman yazmak gerekiyor.**

---

## 4. HEDEF: UZAKTAN LISANS YONETIMI - MIMARI TASARIM

### 4.1 Istediginiz senaryo ve mevcut durum karsilastirmasi

| Ihtiyac | Mevcut Durum | Eksik |
|---------|--------------|-------|
| Fikocad acilinca MongoDB'ye kayit | Yok - sadece RAM map | **Cihaz/oturum koleksiyonu** |
| Panelden lisans vermek | Uretici makinesinde .fkl uretilir | **Sunucu tarafi imzalama + dagitim** |
| Panelden komut yetkilendirme | Yok | **Lisans semasi + policy endpoint'i** |
| Panelden komut yollama | Yok | **Komut kuyrugu + WS teslim** |
| Sure uzatma | Manuel .fkl yenileme | **Uzaktan sure yenileme** |
| Aninda engelleme | **VAR** (`/lisans-kontrol`) | MongoDB kalicilik |
| Sorgulama/raporlama | Yok | **Analytics koleksiyonlari** |

**Iyi haber:** Imzalama altyapisi (`kararImzala`, `derToRaw`, `kanonikKur`) **zaten calisiyor ve C++ tarafiyla birebir uyumlu.** Uzaktan lisans uretmek icin ayni imzalama kodunu `.fkl` govdesine uygulamak yeterli - yeni kriptografi gerekmiyor.

### 4.2 Hedef Mimari

```
  SATICI PANELI (Flutter/Web)                    fikoyt-sunucu
  ============================                  ============================
  - Cihaz listesi (cihazlar koleksiyonu)  <---->  /fapiv1/admin/lisans/*
  - Lisans olustur / uzat                      <---->  MongoDB (fikoyt db)
  - Komut yetkilendir                                |
  - Komut kuyrugu + sonuc                            +-- lisans_imzala (Go, ECDSA)
  - Kill-switch (mevcut panel)                       +-- policy_imzala (.pol)
                                                    +-- karar_imzala (mevcut)
                                                          |
                                                          v
                                              Socket.IO /isans
                                                          |
                                                          v
                                                     fikocad.exe
                                              (acilis: kayit + policy cek)
                                              (periyodik: heartbeat)
                                              (talep: komut kuyrugu)
```

### 4.3 MongoDB Koleksiyon Semasi

#### A) `lisansCihazlar` - Her fikocad acilisi

```javascript
{
  _id: ObjectId,
  seri: "FKC-2026-0001",           // lisans serisi (yoksa "lisanssiz:<cihazKimlik>")
  cihazKimlik: "a1b2c3d4e5...",   // makineParmakIzi hash'lerinden
  makine: ["<hash1>", "<hash2>"], // node-lock adaylari
  bilgisayar: "AHMED-PC",         // hostname
  musteri: "Akcali Dokum",        // .fkl'den gelen musteri
  surum: "1.0.0",
  pid: 12345,
  ip: "1.2.3.4",
  ilkGorulme: ISODate,            // ilk acilis
  sonGorulme: ISODate,            // son heartbeat
  sonAcma: ISODate,               // son process baslangici (pid degisimi)
  cevrimici: true,
  lisansDurum: "Gecerli",         // LisansDurum enum
  lisansBitis: ISODate,           // .fkl'den
  acikKomutlar: 12,               // o an aktif komut sayisi
  paketler: ["CAM 100/ay"],
  kotaKullanim: { "cam.gkod": 37, "dm.pushpull": 5 },
  yapiHash: "<exe sha256 ilk 32>",
  platform: { "sistem":"Windows 11", "ram": 32, "cpu": "..." },
  // indeksler
}
// INDEX: {cihazKimlik: 1} unique
// INDEX: {seri: 1}
// INDEX: {sonGorulme: -1}   // cevrimdisi tespiti
```

#### B) `lisansKayitlari` - Lisans belgeleri (imzali)

```javascript
{
  _id: ObjectId,
  seri: "FKC-2026-0001",
  musteri: "Akcali Dokum",
  urun: "fikocad",
  seviye: "pro",
  bitis: ISODate,                 // 0/suressiz ise null
  kisitli: true,
  gruplar: ["Geometri", "CAM"],
  featureler: ["dm", "cam"],
  workbenchler: ["Modeling"],
  komutlar: ["geometri.*", "cam.gkod", "dm.pushpull"],
  kotalar: [{ kimlik:"cam.gkod", limit:100, periyot:2592000 }],
  paketler: [{ kimlik:"CAM-PRO", ad:"CAM Pro", bitis:ISODate, komutlar:[...], kotalar:[...] }],
  makineHashleri: ["<hash1>", "<hash2>"],
  makineTolerans: 3,
  yapiHash: "",                   // opsiyonel
  govde: "musteri=...\nseri=...\n...",   // imzalanan duz govde
  imza: "<base64 ECDSA>",
  durum: "Uretildi" | "TeslimEdildi" | "Iptal" | "SuresiDoldu",
  ureten: "<admin ObjectId>",
  uretimZamani: ISODate,
  teslimZamani: ISODate,
  gecerlilik: ISODate,
  ipucu: "2027'ye kadar gecerli"
}
// INDEX: {seri: 1} unique
// INDEX: {musteri: 1}
// INDEX: {bitis: 1}
```

#### C) `lisansOlaylari` - Degisiklik/karsiyol (audit)

```javascript
{
  _id: ObjectId,
  zaman: ISODate,
  tip: "uretildi" | "uzatildi" | "iptal" | "engellendi" |
       "izinVerildi" | "kotaAsildi" | "baglandi" | "koptu" |
       "surumGuncelleme" | "komutCagrildi",
  seri: "FKC-2026-0001",
  cihazKimlik: "a1b2...",
  yetkili: "<admin ObjectId>",     // panelde kim yapti
  detay: { ... },                 // tip-specific
  ip: "1.2.3.4"
}
// INDEX: {zaman: -1}
// INDEX: {seri: 1, zaman: -1}
// TTL: 90 gun (opsiyonel)
```

#### D) `lisansKomutKuyrugu` - Panelden yollanan komutlar

```javascript
{
  _id: ObjectId,
  komutId: "uuid",
  seri: "FKC-2026-0001",           // veya cihazKimlik
  cihazKimlik: "a1b2...",         // hedef makine (seri yerine veya birlikte)
  komut: "dosya.ac",              // Fikocad komut kimligi
  argumanlar: { yol: "C:\\x.step" },
  durum: "Kuyrukta" | "Gonderildi" | "Tamamlandi" | "Hata" | "ZamanAsimi",
  yetkili: "<admin>",
  gonderilme: ISODate,
  yanit: { basarili: true, mesaj: "..." },
  beklemeSn: 300
}
// INDEX: {durum: 1, seri: 1}
// INDEX: {komutId: 1} unique
```

#### E) `lisansPolitikalari` - Kill-switch listeleri (.pol yedegi)

```javascript
{
  _id: ObjectId,
  surum: 5,                        // geri sarma korumasi
  mod: "engelli" | "izin",
  engelliler: ["FKC-2026-0001"],
  izinliler: [],
  mesaj: "Odeme gecikti - lutfen iletisime gecin",
  yayinZamani: ISODate,
  gecerlilik: ISODate,            // null = suresiz
  govde: "surum=5\nzaman=...\nmod=engelli\nengelle=...\nimza=...",
  imza: "<base64>",
  aktif: true
}
// INDEX: {aktif: 1, surum: -1}
```

### 4.4 Yeni API Endpoint'leri

**Guvenli varsayilan: hepsi `/fapiv1/admin/*` altinda + `adminOnly` middleware'i + `yoneticiMi()` kontrolu.**

```
POST /fapiv1/admin/lisans/cihazlar            -> cihaz listesi (filtreli/sayfali)
POST /fapiv1/admin/lisans/cihaz/kimlik        -> tek cihaz detayi + olay gecmisi
POST /fapiv1/admin/lisans/uret                 -> lisans uret (imzalar, DB'ye yazar)
POST /fapiv1/admin/lisans/uzat                -> bitis tarihi uzat (yeni imza)
POST /fapiv1/admin/lisans/iptal               -> lisans iptal + policy'ye engelle ekle
POST /fapiv1/admin/lisans/komutlari            -> musteriye komut yetkilendir
POST /fapiv1/admin/lisans/komutKuyrugaEkle     -> komut yolla
POST /fapiv1/admin/lisans/komutDurumu          -> komut sonucu sorgula
POST /fapiv1/admin/lisans/politika/yayinla     -> .pol imzala + yayinla
POST /fapiv1/admin/lisans/rapor                -> kullanim/kota/cihaz raporu
GET  /fapiv1/admin/lisans/rapor/aylik          -> CSV export
```

**Guvenli karsilastirma icin `adminOnly` middleware (yeni dosya `sistem/kokDB/admin_guard.go`):**
```go
func AdminOnly(c fiber.Ctx) error {
	FikoYT, ok := c.Locals("FikoYTCtx").(*FikoYTCtx.FikoYTCtx)
	if !ok || FikoYT == nil || FikoYT.AktifKullanici == nil {
		return c.Status(401).JSON(fiber.Map{"hata": "Oturum gerekli"})
	}
	if !yoneticiMi(FikoYT) {
		// denetimi de kaydet
		_ = olayKaydet(FikoYT, "yetkisizErisim", map[string]interface{}{
			"yol": c.Path(), "ip": FikoYT.Istek.Ip,
		})
		return c.Status(403).JSON(fiber.Map{"hata": "Yetkiniz yok"})
	}
	return c.Next()
}
```

### 4.5 Istemci Tarafi: Kayit + Komut Alma

**Mevcut `lisans_canli.cpp` genisletilmeli.** Zaten `/isans` namespace'ine baglaniyor ve `merhaba` gonderiyor - sadece zenginlestirilmeli.

**A) `merhaba` mesajini zenginlestir:**
```cpp
// lisans_canli.cpp - sunucuya bildir
json mesaj = {
  {"tip","merhaba"},
  {"seri", o.bilgi.seri},
  {"musteri", o.bilgi.musteri},
  {"bilgisayar", bilgisayarAdi()},
  {"surum", SURUM_METIN},
  {"pid", GetCurrentProcessId()},
  {"makine", makineParmakIzi().hashListesi()},
  {"cihaz", cihazKimlikUret()},          // YENI: tekil cihaz kimligi
  {"yapiHash", uygulamaYapiHash()},        // YENI: exe butunlugu
  {"lisansDurum", durumMetni(d)},          // YENI: anlik durum
  {"lisansBitis", o.bilgi.bitis},         // YENI
  {"kotaKullanim", kotaOzeti()},           // YENI: mevcut kota kullanimi
  {"paketler", paketKimlikleri()}          // YENI
};
```

**B) Yeni event'ler (istemci dinler):**
```cpp
// Sunucudan gelen olaylar
"lisans-policy"   -> imzali .pol icerigi (otomatik uygula)
"lisans-komut"    -> {komutId, komut, argumanlar} -> calistir, sonuc yolla
"lisans-ayar"     -> {ayar: "kotaPaylasimi", deger: false}
"lisans-bilgi"    -> genel bilgilendirme (mesaj goster)
```

**C) Uygulama tarafinda komut calistirma (guvenli olan yol):**
```cpp
// Lisans kapisindan GECEREK calistir - komut yolla bir guvenlik acigi olmamali
void komutSonucYolla(const std::string& komutId, bool basarili, const std::string& mesaj) {
  // ... socket emit
}

// Cagri:
"lisans-komut" handler'inda:
  if (!lisansSistemi().komutIzinli(komut)) { reddet -> "yetkiniz yok" }
  cekirdek.komutCalistir(oge);            // merkezi gate zaten calisir
  komutSonucYolla(...);
```

**Onemli:** Panelden yollanan komutlar **lisans gate'inden gecmelidir**. Aksi halde "lisanssiz musteriye uzaktan komut calistir" aciigi dogar. `lisansSaglikKontrol()` de burada cagrilmali.

**D) Guvenli kanal:** WS uzerinden dogrudan komut yollamak yerine **imzali karar** gibi imzali mesajlar tercih edilmeli. En azindan sunucu bir "yonlendirme komutu" imzalamali ki sahte sunucu (MITM) fikocad'a komut yaptiramasin. Mevcut `kararImzala` ayni deseni kullanir - `komutImzala` ayni sekilde yazilir.

### 4.6 Lisans Uretme: Go Tarafi

`lisans_kontrol.go`daki imzalama zaten calisiyor. `.fkl` uretmek icin:

```go
// yeni dosya: apps/lisans_kontrol/lisans_uret.go
func LisansUret(govdeLisans LisansGovdesi) (imza string, kanonik string, err error) {
    kanonik = lisansKanonikGovde(govdeLisans)   // C++ ile ayni normalizasyon
    h := sha256.Sum256([]byte(kanonik))
    der, err := ecdsa.SignASN1(rand.Reader, ozelAnahtar, h[:])
    if err != nil { return }
    raw, err := derToRaw(der)
    return base64.StdEncoding.EncodeToString(raw), kanonik, nil
}

func lisansKanonikGovde(metin string) string {
    // BOM at, satirlari kirp, bosluk/yorum satirlarini dusur,
    // "imza=" satirini HARIC tut, her alani "anahtar=deger\n" olarak yaz
    // -- C++: lisans_dosya.cpp:39-52 ile BIT BIT ayni olmali
}
```

**Zorunlu:** Go kanoniklestirmesi C++ ile **birebir ayni** olmali. Test icin mevcut C++ testleri kullanilabilir (`test_lisans_dosya.cpp`).

### 4.7 Veri Akisi (Uctan Uca)

**1) Fikocad ilk acilis:**
```
fikocad.exe baslar
 -> lisansYukleVeUygula()  (yerel .fkl yuklenir, gecerlilik belirlenir)
 -> uzakCanliBaslat()      (WS baglantisi)
 -> "merhaba" gonderir (seri, cihaz, yapiHash, durum, kota)
 -> sunucu: lisansCihazlar upsert (ilkGorulme, sonGorulme)
 -> sunucu: lisansOlaylari'na "baglandi" yazar
 -> sunucu: varsa bekleyen karari gonderir
 -> sunucu: varsa bekleyen komut kuyrugunu gonderir
```

**2) Lisans verme (panel):**
```
Panel: musteri + komutlar + sure sec
 -> POST /fapiv1/admin/lisans/uret
 -> sunucu: govde kurar + ECDSA imzalar
 -> lisansKayitlari'na yazar
 -> lisansOlaylari'na "uretildi" yazar
 -> o seriye bagli istemcilere: "lisans-yeni" eventi
 -> fikocad: yerel .fkl'i guncellemez, SUNUCUDAN policy cekmeye gecer
```

**Kritik tasarim karari:** Lisans **dosyasi** hala .fkl olarak kalsin mi, yoksa sunucudan cekilen imzali policy mi olsun?

| Yaklasim | Avantaj | Dezavantaj |
|----------|---------|------------|
| A) .fkl dosyasi kalsin (mevcut) | Offline calisir, mevcut kod degismez | Lisans yenileme = dosya gonderme (destek yuk) |
| B) Sunucudan imzali policy (yeni) | Aninda yenileme, panelden tek tik | Internet gerekir, sunucu kapansa lisansta eski surum |
| C) Hibrit: .fkl + sunucu (onerilen) | Offline taban, online yenileme | Iki kanal birlikte calisir (karmaşıklık) |

**Oneri: Hibrit (C).** .fkl taban haklari verir, sunucudan gelen imzali policy **ek hak** verir veya bitişi **uzatir**. Mevcut `birlestir` mekanizmasi tam da bunun icin yazilmis (`lisansUygula(..., birlestir=true)`) - "GENIS kazanir" kurali bunu destekliyor. Bu, sistemde **zaten tasarlanmis** bir yol.

### 4.8 Socket.IO Olay sozlesmesi (Tam)

**Istemci -> Sunucu:**

| Olay | Yon | Govde |
|------|-----|-------|
| `merhaba` | I->S | `{seri, musteri, bilgisayar, surum, pid, makine[], cihaz, yapiHash, lisansDurum, lisansBitis, kotaKullanim, paketler}` |
| `kalp-atisi` | I->S | `{cihaz, komutSayisi, sonKomut, ram, cpu}` (her 60 sn) |
| `komut-sonuc` | I->S | `{komutId, basarili, mesaj, sureMs}` |
| `lisans-bildirim` | I->S | `{seri, durum, hata}` (lisans yenilendiginde) |

**Sunucu -> Istemci:**

| Olay | Yon | Govde |
|------|-----|-------|
| `lisans-karar` | S->I | `{tip, seri, engelli, mesaj, zaman, imza}` (mevcut) |
| `lisans-komut` | S->I | `{komutId, komut, argumanlar, imza}` (yeni) |
| `lisans-policy` | S->I | `{surum, politika, imza}` (yeni) |
| `lisans-bilgi` | S->I | `{mesaj, tip}` (yeni) |
| `lisans-cevrimdisi` | S->I | `{sure}` (yeni) |

### 4.9 Veri Gizliligi ve Uyum

Bu mimari **musteri makine parmak izlerini ve kullanim aliskanliklarini toplar.** GDPR/KVKK acisindan:

- **Aydinlatma metni** zorunlu (uygulama ilk acilista gosterilmeli)
- **Veri silme hakki**: `POST /admin/lisans/cihaz/sil` -> tum cihaz kayitlari + olaylar silinmeli
- **Saklama suresi**: `lisansOlaylari` 90 gun, `lisansCihazlar` cevrimdisi 1 yil sonra arsivlenmeli
- **Amac siniri**: yalniz lisans yonetimi. Kullanim analitigi yapilacaksa ayrica onay
- **Uretici makinesi disinda** telemetri varsayilan KAPALI olmali

---

## 5. UYGULAMA YOL HARITASI

### Asama 0 - ACIL GUVENLIK (1-2 gun, bloklayici)

Bu olmadan uzaktan yonetim acilirsa **sistem korumasiz olur.**

| # | Is | Dosya | Degisiklik |
|---|---|------|------------|
| 0.1 | `tokenTamam` fail-closed | `lisans_kontrol.go:364` | `adminToken==""` -> `false` + log |
| 0.2 | compose'a token ekle | `docker-compose.yml` | `LISANS_ADMIN_TOKEN=${LISANS_ADMIN_TOKEN:?zorunlu}` |
| 0.3 | `aggregate` endpoint'ine yetki | `kokDB/routes.go` | `adminOnly` + beyaz liste koleksiyon |
| 0.4 | `ekle/guncelle/sil` beyaz liste | `kokDB/routes.go` | `goUyeler` disi her sey icin yonetici zorunlu |
| 0.5 | `.env` gitignore + parola loglama | `fikoyt.env.json` | `mongo_uri` parolasiz loglanir |
| 0.6 | Redis portu internal | `docker-compose.yml` | `6379:6379` -> `expose: ["6379"]` |

**Dogrulama:**
```bash
# Token yokken panel acilmamali
curl https://fikoyt.com:9000/lisans-kontrol/api/istemciler
# -> 401 {"hata":"token"}

# aggregate yetkisiz erisim
curl -X POST https://fikoyt.com:9000/fapiv1/fikoyt.com.FikoYT.sistem.DB.goUyeler.aggregate \
  -H 'Content-Type: application/json' -d '{"aggregate":[{"$match":{}}]}'
# -> 401/403
```

### Asama 1 - Cihaz Kaydi (3-5 gun)

Fikocad acilinca MongoDB'ye yazsin. **En dusuk riskli, en cok deger saglayan adim.**

| # | Is | Taraf |
|---|----|-------|
| 1.1 | `lisansCihazlar` + `lisansOlaylari` koleksiyonlari + indeksler | Go |
| 1.2 | `merhaba` mesajini zenginlestir (cihaz, yapiHash, durum, kota) | C++ |
| 1.3 | Merhaba handler'inda Mongo upsert | Go |
| 1.4 | `kalp-atisi` olayi (60 sn) + `cevrimdisi` tespiti | C++ + Go |
| 1.5 | Panel: cihaz tablosu (arama, filtre, detay) | Flutter/Web |
| 1.6 | Ozellik bayragi: `lisans=1` | CMake |

**Kabul kriteri:** Fikocad ac -> panelde 5 sn icinde gorunur -> kapat -> 60 sn sonra "cevrimdisi" isaretlenir.

### Asama 2 - Lisans Uretme/Uzatma (5-7 gun)

| # | Is | Taraf |
|---|----|-------|
| 2.1 | `lisans_uret.go` - Go kanonik govde + imza (C++ ile ayni) | Go |
| 2.2 | **Crossover testi:** C++ uretir -> Go dogrular, Go uretir -> C++ dogrular | Go + C++ |
| 2.3 | `lisansKayitlari` koleksiyonu | Go |
| 2.4 | `POST /admin/lisans/uret` + `/uzat` + `/iptal` | Go |
| 2.5 | `lisans-yeni` olayi -> fikocad policy ceker | Go + C++ |
| 2.6 | Panel: lisans sihirbazi (mevcut uretici UI'in web versiyonu) | Web |
| 2.7 | Dosya indirme (uretilen .fkl) | Go |

**2.2 kritik.** Kanonik govde normalizasyonu iki dilde iki kez yaziliyor. `test_lisans_dosya.cpp` ve Go testi ayni fixture'lari kullanmali.

### Asama 3 - Komut Yetkilendirme (3-4 gun)

**En degerli ozellik - satis ekibi burada calisir.**

| # | Is | Taraf |
|---|----|-------|
| 3.1 | `POST /admin/lisans/komutlari` (musteriye komut ekle/cikar) | Go |
| 3.2 | `lisans-policy` olayi (imzali, `.pol` formati reuse) | Go |
| 3.3 | Istemci: policy'yi dogrula + `birlestir` ile uygula | C++ |
| 3.4 | Panel: katalog + fiyatlama tablosu + musteri secimi | Web |
| 3.5 | Panel: anlik "bu musteriye su komutu ekle" | Web |

**Tasarim notu:** Mevcut `birlestir` (GENIS kazanir) semantigi bunu **zaten destekliyor** - ek paket lisanslar ilk lisansi bozmadan hak birliyor. Yeni kod yazmaya gerek yok, sadece dagitim mekanizmasi kurulmali.

### Asama 4 - Komut Kuyrugu (5-7 gun, riskli)

Panelden fikocad'a uzaktan komut yollama. **Guvenligi en kritik asama.**

| # | Is | Taraf |
|---|----|-------|
| 4.1 | `lisansKomutKuyrugu` koleksiyonu | Go |
| 4.2 | `komutImzala` (karar imzalama ile ayni desen) | Go |
| 4.3 | `komut` whitelist + imza gerekli | Go |
| 4.4 | Istemci: `lisans-komut` handler + **lisans gate'i gecmeli** | C++ |
| 4.5 | `komut-sonuc` + zaman asimi | C++ + Go |
| 4.6 | Panel: komut gonder + sonuc goster | Web |

**Zorunlu guvenlik kurallari:**
1. Komut **beyaz listede** olmali (`dosya.ac`, `kaydet`, ...). Rastgele calistirma YASAK
2. Istemci komutu **lisans kapisindan gecirerek** calistirmali
3. Komut **imzali** gelmeli (sahte sunucu yaptiramasin)
4. Her komut `lisansOlaylari`'na yazilmali (audit)
5. **Dosya sistemi yazma komutlari (save/export) icin ek onay** - panelde "dikkat" uyarisi
6. `pkill`, `shutdown` gibi komutlar kesinlikle **haric**

**Tavsiye:** Asama 4'u baslatmadan once Asama 0-3'un guvenligi tam oturmali. Uzaktan komut calistirma, korumasiz bir sistemde **uzaktan kod calistirma** demektir.

### Asama 5 - Politika Yayini (.pol) (2-3 gun)

| # | Is | Taraf |
|---|----|-------|
| 5.1 | `lisansPolitikalari` + surum yonetimi | Go |
| 5.2 | `politikaImzala` (CLI ile ayni kanonik) | Go |
| 5.3 | Panel: engelli/izin listesi editoru | Web |
| 5.4 | Statik URL yayini veya `/lisans/politika.pol` ucu | Go |
| 5.5 | Mevcut JSON dosyasindan Mongo'ya gecis (migration) | Go |

**Onemli:** Mevcut `lisans_kararlar.json` dosya sistemi kararlarini tutuyor. Mongo'ya gecince **geri sarma korumasi** (surum) eklenmeli - aksi halde eski bir .pol dosyasi sunucuya yuklenip tum guncellemeleri geri alabilir.

---

## 6. ONCELIKLENDIRME MATRISI

| Oncelik | Is | Etki | Zorluk |
|----------|-----|------|--------|
| **P0** | `tokenTamam` fail-closed | Yuksek (acik panel) | Cok kolay |
| **P0** | `aggregate` yetki kontrolu | Kritik (tam DB erisimi) | Kolay |
| **P0** | compose'a `LISANS_ADMIN_TOKEN` | Yuksek | Cok kolay |
| **P1** | Cihaz kaydi + panel tablosu | Yuksek (temel ozellik) | Orta |
| **P1** | Lisans uretme/uzatma (Go imza) | Cok yuksek (uzaktan satis) | Orta |
| **P1** | Komut yetkilendirme | Cok yuksek | Orta |
| **P2** | Komut kuyrugu | Yuksek ama riskli | Yuksek |
| **P2** | `.pol` Mongo'ya gecis | Orta | Orta |
| **P3** | Raporlama/CSV export | Dusuk | Kolay |
| **P3** | KVKK aydinlatma metni | Yasal zorunluluk | Kolay |

---

## 7. IYI TASHANMASI TARTILMASI

Sunucunun guvenligi kotu yazilmamis, cogu sey bilincli ve dogru:

1. **Imzalama dogru yerde** - ozel anahtar Go sunucusunda, panel API'si yalnizca *imzali* karar uretiyor. Anahtar hicbir API uctan cikmiyor.
2. **Kanal izolasyonu** - lisans Socket.IO'su `/isans.socket.io/` ayri yolda, genel `/socket.io/` ile paylasmiyor. FikoCAD trafigi genel sistemi kirletmiyor.
3. **Anahtar yoksa sessiz kabul yok** - PEM okunamazsa veya P-256 degilse `ozelAnahtar = nil` ve `kararImzala` hata donuyor. Istemci dogrulanmamis karari **redd ediyor**.
4. **C++/Go kanonik uyumu** - `kanonikKur()` ve `canliKararKanonik()` birebir ayni. Bu, iki dilli bir sistemde en hataya acik nokta ve dogru cozulmus.
5. **DER -> raw donusumu** - Go `ecdsa.SignASN1` DER uretiyor, C++ ham r||s bekliyor. Donusum `derToRaw` ile dogru (saga hizalama + one sifir atma). Bu detayin dogru yazilmasi iyi.
6. **Geriye uyum** - `lisansUygula(birlestir=true)` coklu lisans semantigi basindan tasarlanmis ("GENIS kazanir"). Uzaktan paket satisi icin hazir.
7. **Kanonik govde normalizasyonu (C++)** - BOM/CRLF/yorum degisimi imzayi bozmiyor. Musteri Notepad'de acip kaydedince lisans gecerli kalir. Ileri gorulu bir tasarim.
8. **Sessiz kabul yasagi (C++)** - Anahtar gomulu degilse veya kripto basarisizsa dogrulama basarisiz doner, lisans gecerli sayilmaz.

---

## 8. SONUC

**Mevcut lisans kontrolu calisiyor ve guvenlik modeli dogru.** Tek sorun `tokenTamam` fail-open ve generic DB API'nin korumasiz olmasi - ikisi de birkac satirlik duzeltmeler.

**Istediginiz "uzaktan tam lisans yonetimi" icin gereken altyapi %70 hazir:**
- Imzalama var ve calisiyor
- Socket.IO kanali var (/isans)
- Istemci tarafi karar uygulama var (`canliKararCoz`)
- Coklu lisans birlestirme var (`birlestir`)
- Yonetim paneli var (`/lisans-kontrol`) - belki genisletilerek kullanilabilir

**Eksik olan sadece kalicilik ve genislik:** MongoDB semasi, lisans uretme API'si, komut kuyrugu, ve bunlarin paneli.

**En dogru yol:** Once P0 guvenlik duzeltmeleri, sonra Asama 1 (cihaz kaydi) - bu hem en cok deger saglayan hem en dusuk riskli adim ve butun sonraki asamalarin (raporlama, panel, uygulama baslatma) veri tabanini hazirlar.

---

## 9. DOSYA REFERANSI

**Iceledigim dosyalar (fikoyt-sunucu):**
- `docker-compose.yml` (110 satir)
- `merkez.go-server.com/Dockerfile` (27 satir)
- `merkez.go-server.com/fikoyt.env.json` (12 satir)
- `merkez.go-server.com/main.go` (137 satir)
- `merkez.go-server.com/apps/lisans_kontrol/lisans_kontrol.go` (473 satir) - **ana hedef**
- `merkez.go-server.com/sistem/fikoyt_mongo/fiko_mongo.go` (192 satir)
- `merkez.go-server.com/sistem/fikoyt_ctx/fikoyt_ctx.go` (189 satir)
- `merkez.go-server.com/sistem/fikoyt_ctx/fikoyt_kullanici/fikoyt_kullanici.go` (365 satir)
- `merkez.go-server.com/sistem/fikoyt_ctx/fikoyt_istek/fikoyt_istek.go` (58 satir)
- `merkez.go-server.com/sistem/fikoyt_socket_io/fiko_socket_io.go` (808 satir)
- `merkez.go-server.com/sistem/kok/kok.go` (347 satir)
- `merkez.go-server.com/sistem/kok/routes.go` (997 satir)
- `merkez.go-server.com/sistem/kokDB/kok.go` (42 satir)
- `merkez.go-server.com/sistem/kokDB/routes.go` (1126 satir)
- `merkez.go-server.com/sistem/kokDB/guvenlik.go` (118 satir)

**Bagli C++ dosyalar (fikatia-local):**
- `motor/cekirdek/include/fiko/cekirdek/lisans.hpp` (570 satir)
- `motor/cekirdek/src/lisans_dosya.cpp` (364 satir)
- `motor/cekirdek/src/lisans_sayac.cpp` (174 satir)
- `motor/cekirdek/src/lisans_uzak.cpp` (303 satir)
- `motor/cekirdek/src/kripto.cpp` (340 satir)
- `motor/cekirdek/src/makine_kimlik.cpp` (134 satir)
- `uygulama/fikocad/lisans_yukle.cpp` (798 satir)
- `uygulama/fikocad/lisans_canli.cpp` (776 satir)
- `uygulama/fikocad/lisans_uzak.cpp` (420 satir)
- `uygulama/fikocad/lisans_uretici_penceresi.cpp` (72 KB)
- `uygulama/fiko_lisans/main.cpp` (369 satir)
- `sunucu/lisans-canli/server.js` (146 satir) - Node.js alternatif surum

**Bu iki rapor birlikte tam resim veriyor:**
1. `fikatia-local/docs/lisans_guvenlik_denetimi.md` - ISTEMCI tarafi (C++)
2. `docker/fikoyt-sunucu/SUNUCU_INCELEME_RAPORU.md` - SUNUCU tarafi (Go) + mimari tasarim
