# FikoYT Engineering Platform — ECS + Event-Sourced Çekirdek (Tasarım)

Tarih: 2026-07-04
Durum: Onaylı — uygulamaya hazır

## Amaç

fikatia-local'ı **merkezi, modüler, ölçeklenebilir, event-takipli ve
pluginable** bir platforma dönüştürmek. Toolbar'dan ürün ağacına kadar her
yetenek bir **Modül**'ün çekirdeğe kaydettiği katkıdır. Durum bir **ECS
Dünya**'da yaşar; her mutasyon **Olay Günlüğü** omurgasından geçerek
izlenebilir, geri alınabilir ve replay edilebilir olur. Native performans
(zero-alloc sıcak yol, f64 geometri / f32 render) korunur.

### Kararlar (kullanıcı onaylı)
- **Plugin modeli:** Hibrit — şimdi derleme-zamanı statik modüller + registry;
  `Modul` arayüzü ve registry'ler ileride DLL/script'in takılacağı dikiş.
- **Event takibi:** Uygulama-içi tipli bus + canlı denetçi paneli + diske
  kalıcı olay günlüğü (`.fikolog`). Go backend telemetri YOK (şimdilik).
- **Disk yıpratma politikası (ÖNEMLİ):** Diske HER olay yazılmaz. Canlı omurga
  RAM'deki halka tampondur (sıfır disk). Diske yazma: (a) FİLTRELİ — her olay
  tipinde `kalici` bayrağı; yüksek-frekanslı geçici olaylar (hover, ara-sürükleme,
  kamera) asla persist edilmez, sadece anlamlı mutasyonlar; (b) ARTIMLI — son
  yazılan `sira`'dan sonrası eklenir, tüm günlük değil; (c) CHECKPOINT tabanlı —
  `.fikocad` otokayıt/Ctrl+S ile aynı cadence'te, ayrı stream değil; (d) opsiyonel
  — tamamen kapatılabilir. Sürükleme bırakınca TEK `Islem` → kalıcı akış zaten
  kullanıcı-eylemi hızında. Undo/redo tamamen RAM, disk gerektirmez.
- **Olay-kaynak modeli:** Hibrit — ECS Dünya = canlı durum; mutasyon SADECE
  `Islem` üzerinden; her Islem olay yayınlar. Günlük undo/redo/audit/replay
  kaynağı, Dünya materyalize görünüm. Snapshot ile hızlı.
- **Kapsam:** Omurga + ilk gerçek modül olarak M5 Doküman.

## Mimari

```
                    ┌─────────────── Cekirdek ───────────────┐
                    │  Dunya (ECS)   OlayGunlugu   Kayitlar   │
                    └────┬───────────────┬──────────────┬─────┘
   Girdi/UI ─► Islem ────┘               │              │
   (command)   │  1. Dunya'yı mutasyona uğratır         │
               │  2. Olay yayınlar ──► OlayGunlugu ──────┤
               │                        ├─► Sistemler (mesh/GPU upload, seçim vurgu)
               │                        ├─► OlayDenetci (canlı zaman çizelgesi)
               │                        └─► DiskGunlugu (.fikolog: replay/audit)
   Ctrl+Z ─► KomutYigini.geriAl() ─► Islem.geriAl() ─► ters olay
```

### İlkeler
- Mutasyon tek kapıdan: `Islem`. UI/girdi doğrudan Dünya yazmaz.
- Sıcak yol zero-alloc: olaylar POD; handler'lar tip-indeksli `vector`.
- OCCT/GPU yalnız gerçekten değişince çalışır (taşıma/döndürme brep'i
  yeniden hesaplamaz — sadece matris push-constant).
- Türkçe adlandırma; `fiko` namespace; RAII; statik lib + `fiko::` alias.
- Her adım: derlenir + testler yeşil + `fikocad.exe --oto-test` geçer.

## Modül: `motor/cekirdek` (statik lib `fiko::cekirdek`)

Başlıklar `include/fiko/cekirdek/` altında. Dört bağımsız parça + glue:

### 1. `olay.hpp` — Olay tipleri + OlayGunlugu (bus + log)

Tipli publish/subscribe. Her olay derleme-zamanı bilinen bir struct; her
olayın kararlı bir `OlayTuru` enum değeri var (denetçi/disk için). Yayın
sıcak yolda tahsis yok: her tür için abone listesi tip-indeksli.

```cpp
namespace fiko {

enum class OlayTuru : u16 {
  VarlikEklendi, VarlikSilindi, DonusumDegisti, BrepDegisti,
  GorunurlukDegisti, RenkDegisti, SecimDegisti, KipDegisti,
  DokumanAcildi, DokumanKaydedildi, Diger
};

// Denetçi/disk için tek-tip kayıt (payload'dan bağımsız özet)
struct OlayKaydi {
  u64 sira;            // monoton artan
  f64 zaman;           // uygulama saati (s)
  OlayTuru tur;
  u32 varlik = 0;      // ilgiliyse
  char ozet[48] = {};  // kısa insan-okur açıklama (tahsissiz)
};

// Somut olay struct'ları (POD). Her biri OlayTuru döndüren static tur().
struct VarlikEklendi   { u32 varlik; static constexpr OlayTuru tur() { return OlayTuru::VarlikEklendi; } };
struct VarlikSilindi   { u32 varlik; static constexpr OlayTuru tur() { return OlayTuru::VarlikSilindi; } };
struct DonusumDegisti  { u32 varlik; static constexpr OlayTuru tur() { return OlayTuru::DonusumDegisti; } };
struct BrepDegisti     { u32 varlik; static constexpr OlayTuru tur() { return OlayTuru::BrepDegisti; } };
struct GorunurlukDegisti { u32 varlik; bool gorunur; static constexpr OlayTuru tur() { return OlayTuru::GorunurlukDegisti; } };
struct RenkDegisti     { u32 varlik; static constexpr OlayTuru tur() { return OlayTuru::RenkDegisti; } };
struct SecimDegisti    { static constexpr OlayTuru tur() { return OlayTuru::SecimDegisti; } };
struct KipDegisti      { u32 kip; static constexpr OlayTuru tur() { return OlayTuru::KipDegisti; } };

class OlayGunlugu {
public:
  // Abonelik: belirli olay struct'ına tip-güvenli handler.
  template <class Olay>
  void abone(std::function<void(const Olay&)> h);

  // Yayın: handler'ları çağırır + halka tampona OlayKaydi yazar.
  // ozetVer: olaydan ozet[] üretir (varsayılan tür adı).
  template <class Olay>
  void yayinla(const Olay& o, const char* ozet = nullptr);

  // Denetçi/replay erişimi
  const std::vector<OlayKaydi>& kayitlar() const;   // halka tampon (kapasite sabiti)
  u64 sonrakiSira() const;
  void diskeYaz(std::string_view yol) const;        // .fikolog (append/flush)
  void zamanAyarla(f64 s);                           // uygulama saatini besle

private:
  // her OlayTuru için handler vektörleri (type-erased ama tür-başına ayrık)
  // halka tampon: std::vector<OlayKaydi> sabit kapasiteyle
};

}
```

Kısıt: `abone`/`yayinla` şablonları tür-başına statik depoya map'lenir (örn.
`OlayTuru` indeksli `std::vector<std::function<...>>` + `reinterpret` yerine
tür-güvenli sarım). Yayında `std::function` çağrısı dışında tahsis olmaz.

### 2. `dunya.hpp` — ECS Dünya

Generic entity/component storage (sparse-set benzeri). `Varlik` = `u32`
kimlik (0 = geçersiz). Bileşenler ayrık, cache-dostu dizilerde. Bu parça
`fiko::core`'dan başka bağımlılık İÇERMEZ — ağır bileşenler (BrepBilesen,
MeshBilesen) migrasyon Adım 2'de geometri/render ile eklenir.

```cpp
namespace fiko {

using Varlik = u32;
constexpr Varlik VARLIK_YOK = 0;

// Temel bileşenler (Adım 1). Ağır olanlar sonra.
struct AdBilesen        { std::string ad; };
struct DonusumBilesen   { Donusumd donusum; };
struct GorunurBilesen   { bool gorunur = true; };
struct RenkBilesen      { Vec3f renk{0.55f, 0.65f, 0.8f}; };

// Sparse-set deposu: O(1) ekle/sil/eris, yoğun iterasyon.
template <class B>
class Depo {
public:
  B& ekle(Varlik v, B b = {});
  void sil(Varlik v);
  bool var(Varlik v) const;
  B* bul(Varlik v);
  const B* bul(Varlik v) const;
  // yoğun iterasyon: for (auto& [v, b] : depo)
  // (varlik id + bileşen çiftleri)
};

class Dunya {
public:
  Varlik olustur();          // yeni benzersiz kimlik
  void yokEt(Varlik v);      // tüm bileşenlerini siler
  bool yasiyor(Varlik v) const;
  const std::vector<Varlik>& varliklar() const;

  template <class B> Depo<B>& depo();          // tür-başına depo
  template <class B> const Depo<B>& depo() const;

  // kısayollar
  template <class B> B& ekle(Varlik v, B b = {}) { return depo<B>().ekle(v, std::move(b)); }
  template <class B> B* bul(Varlik v)            { return depo<B>().bul(v); }

private:
  Varlik sonraki_ = 1;
  std::vector<Varlik> yasayan_;
  // tür-silme'yi tür-erased sarımla yöneten depo kaydı (yokEt için)
};

}
```

### 3. `islem.hpp` — Islem arayüzü + KomutYigini (undo/redo)

Durumu değiştiren tek yol. Her `Islem` uygula/geriAl çifti; uygula ve geriAl
uygun olayları yayınlar. `KomutYigini` do/undo geçmişi.

```cpp
namespace fiko {

class Dunya;         // fwd
class OlayGunlugu;   // fwd

class Islem {
public:
  virtual ~Islem() = default;
  virtual const char* ad() const = 0;
  virtual void uygula(Dunya&, OlayGunlugu&) = 0;
  virtual void geriAl(Dunya&, OlayGunlugu&) = 0;
};

class KomutYigini {
public:
  // Islem'i uygular ve geçmişe iter; redo dalını geçersizleştirir.
  void calistir(std::unique_ptr<Islem> islem, Dunya&, OlayGunlugu&);
  bool geriAlinabilir() const;
  bool yinelenebilir() const;
  void geriAl(Dunya&, OlayGunlugu&);   // Ctrl+Z
  void yinele(Dunya&, OlayGunlugu&);   // Ctrl+Y
  void temizle();
  size_t derinlik() const;

private:
  std::vector<std::unique_ptr<Islem>> gecmis_;
  size_t imlec_ = 0;   // gecmis_[imlec_..] = redo dalı
};

}
```

### 4. `kayit.hpp` + `cekirdek.hpp` — Registry'ler + Modül + Cekirdek

Katkı registry'leri: modüller UI/araç katkılarını buraya kaydeder. Çekirdek
döngüsü registry'leri gezerek çizer.

```cpp
namespace fiko {

// Dockable ImGui paneli
struct Panel {
  std::string kimlik;                    // "urun_agaci"
  std::string baslik;                    // "Ürün Ağacı"
  int sira = 0;                          // yerleşim/menü sırası
  std::function<void(Cekirdek&)> ciz;    // her kare içerik
  bool varsayilanAcik = true;
};
class PanelKaydi { public: void ekle(Panel); const std::vector<Panel>& hepsi() const; };

// Toolbar / menü öğesi (gruplu, sıralı)
struct MenuOge {
  std::string grup;      // "Dosya","Geometri","Boolean","Görünüm"
  std::string ad;        // "Kutu Ekle"
  std::string simge;     // "◼" (toolbar)
  int sira = 0;
  std::function<void(Cekirdek&)> calistir;
  std::function<bool(Cekirdek&)> etkinMi = nullptr;   // opsiyonel
};
class MenuKaydi { public: void ekle(MenuOge); /* grup-sıralı erişim */ };

// Ürün ağacı sağlayıcısı: ağaç düğümlerini modüller katkılar
struct AgacDugum { std::string etiket; Varlik varlik = VARLIK_YOK; std::vector<AgacDugum> cocuklar; };
class AgacSaglayiciKaydi {
public:
  void ekle(std::function<void(Cekirdek&, std::vector<AgacDugum>&)> saglayici);
  void topla(Cekirdek&, std::vector<AgacDugum>& kok) const;
};

// Viewport etkileşim aracı (seçim, ölçüm, sketch...)
struct Arac {
  std::string kimlik;
  std::string ad;
  std::function<void(Cekirdek&)> etkinlestir;
  std::function<void(Cekirdek&)> pasiflestir;
  // girdi geri çağrımları migrasyon Adım 3'te genişletilir
};
class AracKaydi { public: void ekle(Arac); void etkinlestir(const std::string&); /* aktif arac */ };

// Modül arayüzü — hibrit plugin dikişi
class Modul {
public:
  virtual ~Modul() = default;
  virtual const char* kimlik() const = 0;   // "geometri"
  virtual const char* ad() const = 0;        // "Geometri"
  virtual void kur(Cekirdek&) = 0;           // sistem + katkı kaydı
  virtual void kaldir(Cekirdek&) {}
  virtual void arayuzCiz(Cekirdek&) {}       // opsiyonel per-frame (panel dışı)
};

// Merkezi bağlam: her şeyin sahibi, modül yaşam döngüsü sürücüsü
class Cekirdek {
public:
  Dunya& dunya();
  OlayGunlugu& olaylar();
  KomutYigini& komutlar();
  PanelKaydi& paneller();
  MenuKaydi& menuler();
  AgacSaglayiciKaydi& agac();
  AracKaydi& araclar();

  // kısayol: Islem'i KomutYigini üzerinden çalıştır
  void uygula(std::unique_ptr<Islem> islem);

  void modulEkle(std::unique_ptr<Modul>);   // kur() çağırır
  void moduleriKur();                        // tümünü kur (bağımlılık sonrası)
  const std::vector<std::unique_ptr<Modul>>& moduller() const;

private:
  Dunya dunya_;
  OlayGunlugu olaylar_;
  KomutYigini komutlar_;
  PanelKaydi paneller_;
  MenuKaydi menuler_;
  AgacSaglayiciKaydi agac_;
  AracKaydi araclar_;
  std::vector<std::unique_ptr<Modul>> moduller_;
};

}
```

## Dizin yerleşimi

```
motor/cekirdek/
  include/fiko/cekirdek/{olay,dunya,islem,kayit,cekirdek}.hpp
  src/{olay,dunya,islem,kayit,cekirdek}.cpp
  test/{test_olay,test_dunya,test_islem,test_cekirdek,test_main}.cpp
  CMakeLists.txt          → fiko::cekirdek (PUBLIC fiko::core), CTest hedefi
motor/moduller/           → dahili modüller (Adım 3)
motor/dokuman/            → DokumanModul (M5, Adım 5)
uygulama/fikocad/main.cpp → Cekirdek bootstrap + modül kaydı + döngü sürücüsü
```

`motor/sahne/Sahne` → `Dunya`'ya evrilir (Dugum alanları bileşenlere ayrışır).
`motor/geometri`, `motor/render`, `motor/ui` DEĞİŞMEZ — bileşen/sistem olarak
sarılır.

## Geçiş stratejisi (her adım derlenir + testler yeşil + çalışır)

1. **Çekirdek iskelet** (`motor/cekirdek`): Dunya + OlayGunlugu + Islem/
   KomutYigini + registry'ler + Modul/Cekirdek + testler. main.cpp henüz eski.
   → *Paralel ajanlarla:* Olay, Dunya, Islem bağımsız; Cekirdek/Kayit glue
   entegrasyonda ana thread'de.
2. **Sahne→Dunya migrasyonu**: ağır bileşenler (BrepBilesen, MeshBilesen,
   SecimBilesen) eklenir; mevcut render döngüsü Dünya'yı okuyacak şekilde
   köprülenir. Görsel çıktı birebir aynı kalır.
3. **main.cpp'yi dahili modüllere böl**: GeometriModul, SecimModul,
   GorunumModul, DosyaModul, UrunAgaciModul, OzelliklerModul, KomutPaletiModul,
   PusulaModul, OlayDenetciModul. Döngü registry-sürücülü olur.
4. **Undo/redo + OlayDenetci paneli + disk günlüğü** uçtan uca bağlanır.
5. **DokumanModul (M5)**: feature DAG + .fikocad + otokayıt, omurga üstüne.

## Test

`fiko_test.hpp` mini çatısı ile:
- **Dunya**: olustur/yokEt benzersizlik, Depo ekle/sil/bul/iterasyon, yokEt tüm
  bileşenleri siler.
- **Islem/KomutYigini**: uygula→geriAl round-trip durumu geri getirir; redo
  dalı yeni işlemle geçersizleşir; derinlik doğru.
- **OlayGunlugu**: abone→yayınla handler çağrılır; tip-güvenlik (yanlış tür
  handler'ı çağrılmaz); halka tampon kapasitesi; sıra monoton artar.
- **Cekirdek**: modulEkle→kur çağrılır; registry katkıları görünür.

## Riskler / notlar
- **En büyük risk Adım 2** (Sahne→Dunya): görsel regresyon. Azaltım: Adım 2
  sonunda `--oto-test` + göz kontrolü, render kodu değişmez sadece veri kaynağı.
- Olay struct'ları POD kalmalı (sıcak yol). Ağır payload gerekiyorsa varlık
  id + Dünya'dan okuma tercih edilir.
- KomutYigini bellek: uzun oturumda üst sınır (örn. 200 işlem) + en eskiyi at.
