# FIKO-AI — İLERLEME TAKİP DOSYASI

> "Kaldığım yer" kaydı. Spec: `../PROJE.MD` · REST sözleşmesi: `API.md`
> İşaretler: `[x]` bitti · `[~]` yarım · `[ ]` başlanmadı · `[!]` sorunlu

## OTURUM PROTOKOLÜ
1. Bu dosyayı oku (özellikle SONRAKİ ADIM ve NOTLAR).
2. **Komple tarama:** `fiko-ai/` altındaki tüm dosyaları listele (node_modules hariç), checklist ile karşılaştır. Dosya var ama içi boş/yarımsa `[~]`. **Kod bu dosyayla çelişiyorsa KOD doğrudur**, dosyayı düzelt.
3. Her dosya bitince hemen işaretle (oturum yarıda kesilse de durum kaybolmasın).
4. Oturum sonunda OTURUM GÜNLÜĞÜ'ne tarih + yapılanlar + SONRAKİ ADIM yaz.

## DURUM ÖZETİ
- **Aktif faz (kod taramasıyla güncellendi): P1–P9 kodda tamam; P10'da bellek çekirdeği + ajan/REST bağlaması yazıldı (derlenmedi).** Kalan: derleme/test turu, Hafıza paneli, canlı doğrulamalar (kullanıcı tarafı).
- Tamamlanan: P1 (Go+Angular+Mongo+WS+Ollama), P2 (context manager), P3 (Skill Registry + embedding + semantik arama), Faz 4b (Tool arayüzü + uzak tool'lar + SSRF), Faz 5 (tool geçmişi, skill retrieval), Faz 6 (STT), Faz 7 (TTS + barge-in).
- Ses tarafı **motor bağımsız**: STT `whispercpp`/`openai`, TTS `openai`/`piper`; `.env` anahtarıyla seçilir.
- Açık işler: STT/TTS motorunun seçilip `.env`'e yazılması, gerçek tarayıcı mikrofon testi. Kod ve testler hazır.

- **2026-10-04 (BİLDİRİM ARACI — BAŞLADI, ilerledikçe yazılıyor).** Kullanıcı: "AI diğer kullanıcılara soru sorabilsin + bildirim yollayabilsin; bunun için tool istiyorum."
  - **TASARIM (kod okumasından; `memory.ask` + `ws.BroadcastToUser` kalıbı yeniden kullanılıyor):** yeni paket `internal/notify` (model, depo, servis, tool'lar). Bildirim ALICIYA ait kalıcı kayıttır (çevrimdışı kullanıcı sonra görür); çevrimiçiyse WS ile anlık itilir. Türler: `info` (bildirim), `question` (soru; seçenekli ve/veya serbest metin), `answer` (soranın gelen kutusuna düşen yanıt).
  - **Tool'lar:** `notify.users` (alıcı ara), `notify.send` (bildirim gönder), `notify.ask` (soru sor, asenkron), `notify.answers` (sorduğum soruların yanıtları). Kullanıcı kimliği executor'dan gelir (`tl.Config["userId"]`), model değiştiremez.
  - **Güvenlik:** gönderen adı HER ZAMAN gösterilir ("X adına"); gönderen başına saatlik sınır + alıcı başına bekleyen soru sınırı; devre dışı kullanıcıya gönderilmez; yanıt yalnızca sorunun sahibi tarafından verilebilir. AÇIK RƒİSK: model dolaylı istemle (web içeriği vb.) başkalarına mesaj attırılabilir → şimdilik yalnızca sınırlarla azaltıldı, onay formu YOK.
  - **PLAN (sırayla):** (1) notify paketi + bellek deposu, (2) tool'lar + toolrank kuralları, (3) WS olayı + hub köprüsü, (4) REST uçları, (5) main.go bağlantısı, (6) Mongo deposu, (7) ön yüz (zil + gelen kutusu), (8) testler. Her adım bitince bu satır güncellenecek.

- **2026-10-04 (BİLDİRİM ARACI — adım 1 BİTTİ: paket + depo + servis + testler).**
  - **YAPILDI:** `internal/notify` paketi: `model.go` (Kind/Option/Message/New+doğrulama), `repository.go` (Repository sözleşmesi), `memstore.go` (bellek içi depo), `service.go` (sınırlar + katılım denetimi + Sink), `service_test.go` (12 test, `go test ./internal/notify/` oku). `go build ./...`, `go vet ./...`, `go test ./... -count=1` tamamı yeşil.
  - **TASARIM (kod ile sabitlendi):** türler `info` / `question` / `answer`. Kayıt tek alıcıya aittir (`ToUserID`); toplu gönderim N kayıt yazar. **Gelen kutusu ikiye ayrıldı:** `inbox` (bana gelen bildirim/soru) ve `sent` (benim gönderdiklerim **+ bana gelen yanıtlar**). Yanıtın `FromUserID`'si yanıtlayandır; bu yüzden yanıt soranın `sent` kutusuna girer, inbox'a girmez (gürültü olurdu).
  - **SINIRLAR (config ile ayarlanabilir, varsayılan güvenli):** gönderen başına **saatte 20**; alıcı başına **10 bekleyen soru**; tek gönderide **10 alıcı**. Sınır kontrolü **kaydetmeden önce** yapılır — reddedilen bildirim depoya da yazılmaz (testle sabitli: "saatlik sınır aşılınca gönderim reddedilmeli" + "depoda 2 kayıt olmalı").
  - **KAPSAM (kod ile sabitlendi):** gönderen kimliği executor'dan gelir (henüz bağlı değil — adım 2/5). `Ask` türü sunucuda `KindQuestion`'a SABİTLENİR (model "bilgi" diyemez). Yanıtı **yalnızca sorunun alıcısı** verebilir; gönderen bile kendi sorusunu onaylayamaz. Ad çözülemezse bildirim **yine gider**, gönderen adı boş kalır (kimseye yanlış ad gösterilmez). Süresi dolan soru `ErrNotFound` olur (sonsuza dek beklemez).
  - **BULUNAN TASARIM HATASI (test yakaladı, düzeltildi):** kutular `FromUserID == ben` diye tanımlıydı; yanıt kaydının göndereni **yanıtlayan** olduğu için "bana gelen yanıtlar" hiç görünmüyordu — yani kullanıcı tam olarak beklediği şeyi göremezdi. `matchesBox` yeniden yazıldı; `TestDepo_KutuAyrimi` bunu sabitliyor.
  - **SONRAKİ ADIM (adım 2):** `notify.tools` (4 tool) + `toolrank.go` anahtar sözcük kuralları. Tool'ların `tl.Config["userId"]` ile gerçek kimliği okuması zorunlu (model alıcıyı yazamaz, `notify.users` aramasıyla bulur).

- **2026-10-04 (BİLDİRİM ARACI — adım 2 BİTTİ: 4 tool + toolrank kuralları).**
  - **YAPILDI:** `internal/notify/tools.go` — `notify.users` (alıcı ara) · `notify.send` (bildirim) · `notify.ask` (soru, asenkron) · `notify.answers` (bana gelen yanıtlar). `tools_test.go` (14 test). `agent/toolrank.go` → 4 kural + öncelik listesi (29-32). `gofmt -l` boş; `go build/vet/test ./...` yeşil.
  - **GÜVENLİK (testlerle kanıtlandı):** kimlik **yalnızca** `tl.Config["userId"]`'den okunur; model girdiye `fromUserId`/`sender`/`userId` enjekte etse de gönderen **değişmez** (`TestTools_GonderenKimligiSabit`). Kimlik yoksa **hiçbir** tool çalışmaz ve **hiçbir şey kaydedilmez** (`TestTools_KimlikYoksaCalismaz`). `notify.users` modele **sadece `id`+`displayName`** verir (e-posta/rol sızmaz — `TestTools_UsersSadeceKimlikVerir`). Alıcı bulunamazsa modele "KİMLİĞİ UYDURMA" uyarısı gider. Alıcı listesi bağlı değilse `notify.users` **sunulmaz** (sunulsuz hali "bulamadım" hatası verirdi).
  - **ASYENKRON DAVRANIŞ AÇIKÇA BİLDİRİLİR:** `notify.ask` çıktısında "Tur bitiyor, cevap gelene kadar cevaplanmadı" yazar; `notify.answers` boş döndüğünde "SORUYU TEKRAR SORMA" der. Aksi halde model aynı turda `notify.answers` çağırıp "kimse cevap vermedi" derdi.
  - **BULUNAN TUTARSIZLIK (test yakaladı, düzeltildi):** kendine bildirim **çoklu** yolda sessizce eleniyordu ama **tek** yolda sunucuya gidiyor ve hata dönüyordu. İki yolun davranışı ayrışmıştı. Kural netleştirildi: tek alıcı = **hata** (dürüst: "gönderdim" denmez), çoklu = **sessiz eleme** (elenen varsa diğerleri gönderilir). `TestTools_CokluGonderimKendiniEler` bunu sabitliyor.
  - **toolrank AYIRMA KURALI:** "soru sor" hem `notify.ask` hem `ui.form`'a uyar. **Kendine** soran kalıplar ("bana sor", "soru sor") `ui.form`'da bırakıldı; **kime** soran kalıplar ("kime sor", "arkadaşıma sor") `notify.ask`'e kondu. Karışırsa model "bana bildirim gönderdim" deyip hiçbir şey yapmaz.
  - **SONRAKİ ADIM (adım 3+4+5):** WS olayı (`notify.received` / `notify.answer`) + `hub.SetNotify` köprüsü (pending sorular bağlantı kurulunca geri yüklenir) → REST uçları (`/api/notifications`) → `main.go` bağlantısı (`RegisterTools` + `UserResolver`/`Recipients` adaptörleri: `user` paketinden görünen ad ve aktif kullanıcı listesi).

- **2026-10-04 (BİLDİRİM ARACI — adım 3 BİTTİ: WS olayları + hub köprüsü).**
  - **YAPILDI:** `protocol.go` → `ClientNotifyAnswer` (istemci) + sunucu türleri `notify.received` / `notify.answered` / `notify.unread`; payload tipleri (`NotifyPayload`, `NotifyAnswerPayload`, `NotifyUnreadPayload`, `NotifyAnswerInput`). `ws/session.go` → `notifyBridge` + `Hub.SetNotify` + `handleNotifyAnswer` + `replayNotifications` + `sendUnread` + `Deliver`/`markNotificationRead`. `notify.Service.SetSink` (thread-safe). `ws/notify_test.go` (9 test). `protocol.ts` eşitlendi.
  - **GERİ YÜKLEME (canlı hata sınıfı):** `notify.received` ANLIK olaydır; kullanıcı çevrimdışıyken gönderilirse WS düşer ve bildirim kaybolur. `replayNotifications` bağlantı kurulunca inbox + sent kutularını ve zil sayacını yeniden gönderir (`TestNotify_BaglantiKuruluncaGeriYuklenir`). Bellek sorularındaki aynı ders.
  - **ZİL AYRIMI:** `notify.received` → zil çalar. `notify.answered` (sana cevap geldi) → **zil çalmaz**. Ayrım SUNUCUDA yapılır; arayüz olayı alıp karar verseydi WS düşmesinde zil yanlış çalardı.
  - **YARIM KÖPRÜ KABUL EDİLMEZ:** `SetNotify` list/answer/counts eksikse akışı tamamen KAPALI sayar. Yarım bağlı köprü bildirimleri sessizce kaybettirirdi (`TestNotify_EksikKopruKabulEdilmez`).
  - **BULUNAN HATA 1 (test yakaladı):** soru kimliği boş gidiyordu — `questionId` alanına `m.QuestionID` konuyordu, ama soru kaydında kimlik **`m.ID`** alanındadır (`QuestionID` yalnızca YANIT kaydında "hangi soruya ait" bilgisini taşır). Alıcının cevabı hep "bulunamadı" ile dönerdi. `notifyPayloadOf` soru türünde `qid = m.ID` kullanıyor.
  - **BULUNAN HATA 2 (protokol testi yakaladı):** `notify.answer` **hem istemci hem sunucu** türüydü → `TestNoDuplicateWireNames` reddetti. İstemci `notify.answer`, sunucu **`notify.answered`** olarak ayrıldı. Çakışma olsaydı istemci olayı sunucu olayı sanılır, bildirim sessizce kaybolurdu.
  - **BULUNAN HATA 3 (parity testi yakaladı):** `protocol.ts` güncellenmemişti (Go↔TS eşleşme testi). Ayrıca `tsUnion` regex'i **yorum içindeki tırnakları da** union üyesi sayıyordu; yorumda geçen `notify.answer` hayalet değer üretiyordu. Yorumdan tırnak kaldırıldı.
  - **SONRAKİ ADIM (adım 4+5):** REST uçları (`GET /api/notifications?box=inbox|sent`, `POST /api/notifications/:id/read`, `DELETE /api/notifications/:id`, `POST /api/notifications/:id/answer`) → `main.go` bağlantısı: `SetSink(hub)` + `SetNotify(...)` + `notify.NewToolSet(...).Definitions()` ile `RegisterTools` + `user` paketinden `UserResolver`/`Recipients` adaptörleri.

- **2026-10-04 (BİLDİRİM ARACI — adım 6 BİTTİ: Mongo deposu).** Kalıcılık artık çözüldü.
  - **YAPILDI:** `storage.NotificationsCollection` = `notifications` + `DB.Notifications()` + `ensureIndexes` (notify_inbox, notify_sent, notify_pending, **notify_ttl**). `mongostore/notify_repo.go` → `NotifyRepo` (memory.Repository uygulaması, `var _` ile sözleşme zorlaması). `notify_repo_test.go` (6 test, **GERÇEK Mongo'ya karşı** çalıştırıldı: `MONGO_TEST_URI` ile 6/6 oku).
  - **TTL INDEX (kritik):** sorular/yanıtlar `expiresAt` ile süreli; `notify_ttl` (expireAfterSeconds=0) Mongo'nun KENDİ periyodik temizliğidir → **uygulama kapalıyken bile** cevaplanmayan sorular birikmez. Bellek içi deponun "list sırasında temizle" davranışının kalıcı karşılığıdır; farkı bakım gerektirmemesidir.
  - **ATOMİK YARIŞ GÜVENLİĞİ (asıl teknik karar):** `Answer` "oku, sonra yaz" DEĞİL — `FindOneAndUpdate` + `answeredAt $exists:false` filtresi. İki sekme aynı anda yanıtlarsa **ikinci istek sıfır belge döner** → "zaten yanıtlandı". Bellek içi depoda `mu` kilidi bunu sağlıyordu; Mongo'da kilit yok, tek garantiyi koşul verir. Test 5 goroutine ile **tam 1 yazımı** doğruluyor (`TestNotifyRepo_AnswerKatilimVeYaris`). Yanıt yazımı başarısız olursa soru **GERİ ALINIR** (answeredAt temizlenir) → yarım kalmış durum olmaz.
  - **KUTU AYRIMI depoda da aynı:** `boxFilter` — inbox `toUserId` + `kind != answer`; sent `(fromUserId = ben) VEYA (kind = answer AND toUserId = ben)`.
  - **BULUNAN HATA 1 (gerçek Mongo testi yakaladı):** `notify_sent` ve `notify_quota` index'leri **AYNI anahtar dizisini** (fromUserId+createdAt) farklı isimle tanımlıyordu → `IndexOptionsConflict: index already exists with a different name` ve **tüm depolar açılamıyordu**. Kotalaya `notify_sent` index'i de hizmet ettiği için ayrı index kaldırıldı.
  - **BULUNAN HATA 2 (yazım hatası, kendi hatam):** PowerShell `Set-Content` ile dosya yazınca UTF-8 Türkçe karakterler bozuldu (257 karakter) — `docs/ILERLEME.md`'de bu tam olarak yasaklanmış bir hata ("PowerShell ile dosya DÖNGÜSÜ YAPMA"). Kod derlendi ama tüm Türkçe yorumlar/mesajlar bozuktu. Edit aracıyla temizlendi, **0 bozuk karakter** doğrulandı. **KURAL: PowerShell asla dosya İÇERİĞİ yazmaz, yalnızca derleme/test çalıştırır.**
  - **SONRAKİ ADIM (adım 4):** REST uçları (`GET /api/notifications?box=`, `POST /:id/read`, `DELETE /:id`, `POST /:id/answer`) → **adım 5:** `main.go` bağlantısı (`NewNotifyRepo` seçimi + `SetSink(hub)` + `SetNotify(...)` + `RegisterTools` + `user` paketinden `UserResolver`/`Recipients` adaptörleri). Sonra canlı iki kullanıcı denemesi.

- **2026-10-04 (BİLDİRİM ARACI — adım 4+5 BİTTİ: REST uçları + main.go bağlantısı. CANLI DOĞRULANDI).** Backend artık uçtan uca çalışıyor; ön yüz (adım 7) kaldı.
  - **YAPILDI:** `api/notifications.go` → 5 uç: `GET /api/notifications?box=inbox|sent&pending=true`, `GET /:id`, `POST /:id/read`, `POST /:id/answer`, `DELETE /:id` (her biri `currentUser` ile; katılım `failNotify` → 404). `api.Deps.Notify` eklendi. `cmd/server/notify.go` → `notifyUsers`/`notifyRecipients` uyarlamaları + `registerNotifyTools` + `notifyBridgeFor`. `main.go` → `stores.notifications` (Mongo/bellek), `notifySvc` kurulumu, `SetSink(hub)`, `SetNotify(...)`, `RegisterTools`.
  - **HATA DÜZELTMESİ (köprü alanları):** `ws.notifyBridge` alanları önce `list/answer/counts` (küçük harf, paket içi) idi; main.go bu yapıyı DOLDURMAK zorunda olduğu için `List/Answer/Counts/MarkRead/DisplayName` yapıldı ve `type NotifyBridge = notifyBridge` alias'ı eklendi. Alias tek başına yetmezdi — **dışa açık olmayan alanlarla struct literal oluşturulamaz** (derleyici reddetti), alanların da dışa açılması gerekti.
  - **HATA DÜZELTMESİ (sıra):** `notifyUsers` `userSvc`'ye bağlı olduğu için bildirim bloğu `newUserService`'ten SONRA kurulmalıydı; blok bellek bloğunun yanına (önce) konunca `undefined: userSvc` derleme hatası verdi. Blok taşındı.
  - **CANLI DOĞRULAMA (gerçek Mongo, iki kullanıcı):** `admin` + `veli` kayıt → `notify.users` (yalnızca `id`+`displayName` döndü, e-posta/rol **SIZMADI**) → `notify.ask` (soru gitti, asenkron uyarısı geldi) → Veli `GET /api/notifications?box=inbox` (soru + 2 seçenek göründü) → `POST /:id/answer` (bekleyen soru 1→0) → Admin `?box=sent` (**hem soru hem yanıt** göründü) → **izolasyon: admin Veli'nin sorusunu yanıtlamayı denedi → HTTP 404**. Mongo'da 2 kayıt + 4 index (`notify_inbox`, `notify_sent`, `notify_pending`, `notify_ttl`) doğrulandı. Test verileri temizlendi.
  - **REST + WS NEDEN İKİSİ?** WS anlıktır (bildirim gider), REST KALICI kaynağı okur (sayfa yenilenince/çevrimdışıyken kaçan bildirim ancak buradan gelir). `POST /:id/answer` WS `notify.answer` olayının REST karşılığıdır — **ikisi de aynı servisi çağırır**, yani katılım denetimi ve yarış koruması (tek yazım) ayı yoldan geçer; ikinci yol güvenlik açığı DEĞİLDİR.
  - **KALAN:** adım 7 (ön yüz: zil rozeti, gelen/gönen kutusu, soru kartı + seçenek butonları, WS dinleyicisi). Sonra adım 8 (canlı iki kullanıcı denemesi tarayıcıda).

- **2026-10-05 (BİLDİRİM ARACI — adım 7 BİTTİ: ön yüz. Adım 8 = API düzeyinde doğrulandı).**
  - **YAPILDI:** `core/notification.logic.ts` (saf mantık: iki kayıt dönüştürücüsü, birleştirme, rozet, kart kuralları) · `core/notification.store.ts` (kökte tek örnek: WS dinleyicisi + REST + sayaçlar) · `features/notify/notification-panel.{ts,html,scss}` (panel) · `core/api.service.ts` (4 uç) · `models/protocol.ts` (tipler + 3 yeni sunucu olayı) · sidebar "Bildirim" düğmesi + rozet · topbar zili (her ekranda görünür). Panel `@defer (on immediate)` ile **tembel** yükleniyor (12 kB ayrı parça).
  - **BULUNAN SÖZLEŞME HATASI (canlı JSON okunarak yakalandı):** WS `notify.received` gövdesi `pending`+`at` gönderiyor; **REST kaydı ise `createdAt`/`answeredAt`/`readAt` gönderiyor ve `pending` alanı YOK**. İlk yazımda tek tip varsayılmıştı → her soru "cevaplanmış" görünür ve **hiçbir soru yanıtlanamazdı**. Çözüm: iki ayrı tip (`NotifyRecord`, `NotifyPayload`) + ikisini de aynı `NotificationView`'a normalleyen iki saf fonksiyon. Test bu tuzağı kalıcı olarak kilitliyor.
  - **BULUNAN HATA 2 (birleştirme sırası):** liste birleştirmesinde canlı satır `{...server, ...live}` ile yayılınca, WS'ten gelen geçici yanıtın **boş `id`'si sunucunun kalıcı kimliğini eziyordu**; satır bir daha silinemez/okundu işaretlenemez olurdu. Düzeltme: **sunucu verisi kazanır**, canlıdan yalnızca yerel `answering` bayrağı taşınır.
  - **BULUNAN HATA 3 (çift kayıt):** yanıt satırının WS'teki geçici kimliği (`answer:<soruId>`) ile REST'teki kalıcı kimliği (`nt_…`) farklıydı → sayfa yenilenince aynı yanıt **iki kez** görünürdü. Çözüm: listede tekillik `id` değil **`key`**; yanıtlarda `key = answer:<questionId>`. REST/WS aynı satıra düşer.
  - **WS HATA YOLU:** `notify.answer` gönderirken **istemci istek kimliği** üretilir; sunucu reddederse `error` olayı aynı kimliği `replyTo` ile taşır → **yalnızca ilgili kart** beklemeye geri alınır (iyimser "cevaplandı" gösterimi yanlış olmaz). Not: sunucu hata kimliğini `replyTo` taşır, `id` değil.
  - **DOĞRULAMA:** `npx tsx checks/notification.logic.check.ts` → **60 kontrol geçti** (her iki yolun sözleşmesi, çift kayıt, birleştirme, rozet, kart kuralları). `tsc -p tsconfig.app.json` ve `-p tsconfig.spec.json` temiz; `ng build` **uyarısız**. Canlı iki kullanıcı (`check_notify_e2e.ps1`): `notify.users` yalnızca `id`+`displayName` → `notify.send` → `notify.ask` → alıcı gelen kutusu rozetler dolu → alıcı yanıtladı (pending 1→0) → gönderen `sent` kutusunda **hem soru hem yanıt** → gönderen ikinci kez yanıtlamayı denedi → **reddedildi ve kayıt değişmedi** (`once=6 sonra=6`).
  - **NOT (tarayıcı):** ekranda iki kullanıcılı elle deneme yapılmadı; panelin görünümü `ng build` + şablon denetimiyle doğrulandı, davranışı canlı API üzerinden doğrulandı. Ayrıca `angular.json` initial bütçe uyarısı 600→640 kB yükseltildi (özellik sonrası 602 kB).
  - **SONRAKİ ADIM:** tarayıcıda iki kullanıcı ile elle deneme (rozet, soru kartı, yeniden bağlanma sonrası geri yükleme).

- **2026-10-05 (BİLDİRİM ARACI — WS YOLU CANLI DOĞRULANDI; test verisi temizlendi).**
  - **NEDEN YAPILDI:** Ön yüz yanıtı önce **WS'e** gönderir (REST yedeği yalnızca WS kapalıyken). WS yolu hiç test edilmemişti; yani ekrandaki "Gönder" düğmesinin birincil yolu doğrulanmamıştı.
  - **DOĞRULANDI (iki kullanıcı, canlı sunucu, `check_notify_e2e.ps1` bölüm 2):** `notify.received` **anlık** teslim · `notify.unread` sayaçları anlık · alıcı `notify.answer` gönderdi → sorana `notify.answered` **anlık** gitti → kayıt **kalıcı** yazıldı (`answeredAt` doldu) · **replay**: alıcı çevrimdışıyken giden bildirim yeniden bağlanınca **geri yüklendi** + sayaçlar geldi · **hata yolu**: gönderen alıcıya ait soruyu yanıtlayınca `permission_denied` ve hata **istemci istek kimliğiyle (`replyTo`) eşleşti** (arayüzün kartı geri alması buna dayanıyor).
  - **TEST TUZAKI (kendi testimi zorladı):** ilk koşuda `notify.answered` kontrolü **yanlış sorunun** olayını yakaladı (bağlantıda bekleyen eski bir replay) ve test yine de "geçti" dedi. Eşleşme artık **sorunun kimliğine** göre yapılıyor (`questionId === canlıId`); bu olmadan test yanlış güvence verirdi.
  - **WS OKUMA HATASI (test altyapısı):** `Start-ThreadJob` bu makinede yok. Kareler zaten WebSocket tamponuna yazıldığı için **engelleyici okuma + bekleyen `ReceiveAsync` görevini saklama** deseni kullanıldı: arka plan işi gerekmiyor, sonuç **belirleyici**. İptal edilmiş alıcı soketi bozabildiği için `CancellationToken` iptali **kullanılmıyor**.
  - **BULUNAN DAVRANIŞ (paylaşılan belge) — arayüz düzeltildi:** bildirim/soru **tek** Mongo belgesidir (`fromUserId` + `toUserId`). Gönderen "Gönderilen" kutusundan silerse **alıcının kutusundan da düşer**. Test verisi temizlenirken bu fark edildi (Ayşe 27 kaydı sildi → Mert'in gelen kutusu da boşaldı). Silme düğmesi bu yüzden gizlenmedi, **onay metni dürüstleştirildi**: gönderilen kutusunda "Alıcının kutusundan da silinir. Emin misin?" + tooltip. Ayrıca `TestNotifyRepo_GonderenSilinceAliciKaybolur` ile kural teste bağlandı (gerçek Mongo, 7/7 yeşil).
  - **TEST VERİSİ TEMİZLENDİ:** `ayse`/`mert` hesaplarının tüm bildirimleri silindi (saatlik gönderim kotası elle denemeyi engellemesin diye). Kullanıcı hesapları korundu.
  - **SON DURUM:** `go build/vet/test ./...` 25 paket yeşil · `tsc` (app+spec) temiz · `ng build` uyarısız · 60 mantık kontrolü + `notification.logic.spec.ts` (vitest stili, koşucu bozuk olduğu için çalıştırılamıyor ama tip denetimi geçiyor).
  - **KALAN:** yalnızca **tarayıcıda iki kullanıcılı GÖRSEL deneme**. Kod, sözleşme, WS ve REST yolları canlı olarak doğrulandı; ekranda bakılacak tek şey düzen ve el hissi.

- **2026-10-04 (AYARLAR: model seçimi unutuluyor — DÜZELTİLDİ, derleme/test kullanıcı tarafında bekliyor).** Kullanıcı: "ayarlarda seçtiğim model unutuluyor, ilk açılışta hep varsayılan model (muse glimber) çalışıyor; ayarlara girince aktif model görünmüyor, son seçilen hatırlanmıyor."
  - **KÖK NEDEN 1 (kanıtlı, kod okuması): ayarlar yalnızca bellekte.** `settings.Service` bellek içi; `main.go` her açılışta `settings.Values{Model: cfg.Ollama.Model}` (`OLLAMA_MODEL`, .env) ile kuruyordu → arayüzden seçilen model sunucu yeniden başlayınca kayboluyordu. `Set()` ayrıca `ConfirmMode`'u da taşımıyordu (o da sıfırlanıyordu).
  - **KÖK NEDEN 2 (kod okuması; tarayıcıda DOĞRULANMADI): `settings-panel.ts` model `<select [value]>`.** Option'lar `@for` ile select'ten SONRA üretildiği için `[value]` atandığında liste boş; taslak değişmediği için bağ yeniden çalışmıyor → açılışta aktif model yerine ilk seçenek görünüyordu.
  - **YAPILDI:** `settings.go` → `EnablePersistence(path)` + `persist()` (JSON, geçici dosya + rename; `Update` sonrası yazar; dosya .env başlangıç değerlerinin ÜSTÜNE yüklenir; yazma hatası Update'i bozmaz, yalnızca uyarı). `config.go` → `SettingsPath` (`SETTINGS_PATH`, varsayılan `data/settings.json`). `main.go` → `set.EnablePersistence(cfg.SettingsPath)` `set.Set(...)` sonrasında. `settings-panel.ts` → option'lara `[selected]="m.name === d.model"` eklendi (`[value]` korundu).
  - **BEKLEYEN:** `go build ./... && go vet ./... && go test ./internal/settings/...` + `gofmt -w backend/config/config.go` (struct alanı hizası); `persist` için birim testi yazılmadı; `.env.example`/API.md'ye `SETTINGS_PATH` eklenmedi; `data/settings.json` .gitignore'da mı kontrol et. Elle doğrulama: modeli değiştir → Kaydet → sunucuyu yeniden başlat → Ayarlar'ı aç, seçili model görünmeli.

- **2026-10-04 (ARAÇ GÜVENİLİRLİĞİ turu — BAŞLADI, aşağıya ilerledikçe yazılıyor).** Kullanıcı: "ajan araçları bulamıyor/çalıştıramıyor, dolar kurunu bulamıyor, projeleri silemiyor; en düşük model bile düzgün kullansın."
  - **KÖK NEDEN 1 (kanıtlı, kod okuması): `MaxToolSpecs=20` + ada göre sıralı kesme.** Modele sunulabilir 28 tool var (biz×7, calc, date×3, fiko×2, fs×5, memory×4, text, unit×2, web×3). `toolSpecs()` listeyi `[:20]` kesiyor; liste ada göre sıralı → `memory.remember/update`, `text.stats`, `unit.*` ve **`web.fetch/web.search/web.exchange_rate` HİÇ SUNULMUYOR**. Dolar kuru bu yüzden bulunamıyordu.
  - **KÖK NEDEN 2: `biz.add/biz.delete` onay formu hiçbir zaman otomatik tamamlanmıyor.** Araç `confirmed` yoksa HER ZAMAN form döndürüyor; ajan politika "form gerekmez" derse (risky modda ekleme, `never` modu) formu modele ham sonuç diye veriyor, kayıt YAPILMIYOR. Ayrıca `confirmed` modelden süzülmüyor (yorumda geçen `confirmFromUser` kodda YOK) → model kendi `confirmed:true` yollayıp onayı atlayabilir.
  - **KÖK NEDEN 3: `biz.delete` HIGH risk + `delete` izni** → varsayılan politikada modele hiç sunulmuyor (proje silinemiyor).
  - **KÖK NEDEN 4: `EnsureBuiltin` mevcut kaydı EZMİYOR; `SyncBuiltinFields` yalnızca bellek tool'larında çağrılıyor** → Mongo'daki eski builtin tanımları (izin/açıklama/şema) kodla senkron değil.
  - **KÖK NEDEN 5: skill retrieval tool listesini ÖZEL olarak daraltıyor (`filterTools`)** → yanlış skill eşleşirse doğru tool listeden düşer.

- **2026-10-04 (devam, 2) — DOĞRULAMA TURU ÇALIŞTIRILDI + önceki satırdaki YANLIŞ bulgu düzeltildi.**
  - **DÜZELTME:** aşağıdaki «FIKO_BOOTSTRAP_* ETKİSİZ» bulgusu YANLIŞTI (arama aracının kırpılmış çıktısına güvenmiştim).
    `cmd/server/main.go` `newUserService` bootstrap yöneticiyi ZATEN bağlıyor (`EnsureBootstrap`: yoksa `admin` oluşturur, varsa dokunmaz).
    Gerçekten etkisiz olan YALNIZCA `FIKO_SESSION_TTL` idi (`ServiceOptions{}` boş geçiliyordu) → **bağlandı** (`sessionTTL()` + `session_ttl_test.go`, 9 durum).
    API.md / MIMARI.md / `.env.example` buna göre düzeltildi. Ayrıca hesaplar Mongo yoksa bellek içi depoya düşüyor (`MONGO_URI` zorunlu DEĞİL) — dokümandaki iddia düzeltildi.
  - **KANIT (komut çıktısı):** `go build ./...` exit 0 · `go vet ./...` exit 0 · `gofmt -l .` boş ·
    `go test ./... -count=3` → **25 paket ok, FAIL yok** (P10 bellek kodu da derlendi/geçti) ·
    `ng test --watch=false` → **29 dosya / 442 test geçti** · `ng build` → temiz (initial 568 kB).
    Mongo'ya bağlı testler `MONGO_TEST_URI` yoksa ATLANIR; gerçek Mongo'ya karşı bu turda koşulmadı.
  - **Düzeltilen gerçek hata:** `app.spec.ts` `boot(system: unknown)` → `flush()` tip hatası (TS2345) yüzünden **`ng test` hiç derlenmiyordu**. `object` yapıldı.
  - **ESKİ NOT:** yukarıdaki «SONRAKİ ADIM — Angular» maddeleri kodda ZATEN YAPILMIŞ: `auth.store.ts` (`me`, `logout`), `auth.interceptor.ts`,
    `login.ts` (+spec), `ws.service.ts` (`?token=`), `features/admin/users-panel.ts` (+`admin.store.ts`, `app.html`'de bağlı), `permissions-box` (`canEdit()` ile üyede salt okunur), sidebar «Çıkış yap».
    GOREV-UYELIK.md bitiş kriterlerinden backend testleriyle kanıtlananlar: iki kullanıcı izolasyonu + başlıkla taklit yok (`TestTwoUsersIsolationAndNoHeaderImpersonation`),
    yönetici kısıtı (`TestPermissionsAdminOnly`), çıkış (`TestLogoutInvalidatesToken`), `/api/system` kimlik durumu (`TestSystemReportsUsersEnabled`), gerçek sunucu (`TestAuthRealServer`).
  - **HÂLÂ YAPILMADI (kullanıcı tarafı):** tarayıcıda canlı deneme (iki gerçek kullanıcı, sayfa yenilemede oturum), Hafıza paneli elle doğrulama, P10 canlı doğrulama, bellek/soru aracı açık maddeleri (aşağıdaki 2026-10-04 BELLEK kaydı).

- **2026-10-04 (devam) — ÜYELİK DOKÜMANTASYONU kodla uzlaştırıldı (yalnızca dosya okuma/yazma; derleme/test ÇALIŞTIRILMADI).**
  Kod okunarak yazıldı: `api/auth.go`, `session.go`, `middleware.go`, `permissions.go`, `health.go`, `user/model.go`, `config.go`.
  - **Yapıldı:** `docs/API.md` → baş not düzeltildi, eski «kullanıcı bazlı oturum kapsam dışı» cümlesi kaldırıldı, yeni bölüm
    **«Üyelik ve oturum»** (kimlik çözümleme sırası, `/api/auth/*`, roller, `/api/admin/users`, WS `?token=`, `/api/system` → `auth.users`).
    `docs/MIMARI.md` → **§10 Kimlik modeli** (kimlik/rol/araç yetkisi ayrımı, akış, güvenlik kararları, sınırlar).
    `backend/.env.example` → `FIKO_USERS_ENABLED` eklendi (daha önce hiç yoktu).
  - **YENİ BULGU (kod doğrudur): `FIKO_BOOTSTRAP_USER`, `FIKO_BOOTSTRAP_PASSWORD`, `FIKO_SESSION_TTL` ETKİSİZ.** `config.Users`
    bunları okuyor ama `cmd/` altında hiçbir yerde kullanılmıyor; oturum ömrü `user/service.go` içindeki sabit (30 gün).
    Dokümanda «çalışıyor» diye YAZILMADI. Karar bekliyor: ya `main.go`'ya bağla (`user.Options.TTL`, bootstrap hesap) ya da config'den sil.
  - **GÖREV-UYELIK.md ESKİ:** §2 ve §3.4 («WS Bearer/çerez eklenmeli») backend'de artık yapılmış durumda. Brief yeniden yazılmadı; yalnızca Angular maddeleri (§3.2, §3.3 arayüz) geçerli.
  - **SONRAKİ ADIM (değişmedi):** Angular — `auth.service.ts` (register/login/logout/me), `auth.store.ts` (token + `me()`), interceptor Bearer,
    `login.ts` Giriş/Kayıt sekmeleri, çıkış düğmesi, `ws.service.ts` URL'ine `?token=`, yönetici üye-yetki ekranı, `permissions-box` üye için salt okunur.
    Önce `cd backend; go build ./... ; go vet ./... ; go test ./... -count=3` ile P10 + üyelik kodunun derlendiğini doğrula.

- **2026-10-04 — ÜYELİK 2. dilim (BAŞLADI): kod okuması 4 GERÇEK HATA buldu (1. dilimdeki "eski akış bozulmaz" iddiası YANLIŞTI).**
  `FIKO_USERS_ENABLED=true` iken: (1) global `resolveUser` `/api/health`, `/api/system`, `/api/models` ve CORS `OPTIONS`'a da
  uygulanıyor → token yoksa 400 "giriş gerekli"; ön yüz `/api/system`'i okuyamaz, giriş gerekli mi bilemez.
  (2) `isAuthPath` erken dönüyor → `/api/auth/me` ve `/logout` için Locals hiç set edilmiyor → `/me` HER ZAMAN 401.
  (3) `authorize` + `FIKO_API_KEY` doluyken geçerli oturum token'ı olan üye de `X-Fiko-Auth` istenip 401 alır.
  (4) `PUT /api/permissions` kendi politikasını değiştirir → herhangi bir üye kendine delete/system verebilir (admin kısıtı yok).
  Ayrıca: WS `?token=` brief'te "kabul ediyor" deniyordu ama kodda YOK; oturumlar bellekte (sunucu yeniden başlayınca düşer).
  Düzeltme sırası: önce Go testleri (`internal/api/auth_flow_test.go`), sonra middleware/admin uçları, sonra Angular.
  - **BACKEND TAMAM (kanıt: `go build`/`go vet` temiz, `gofmt -l` boş, `go test ./... -count=1` FAIL yok, 25 paket ok):**
    `internal/api/session.go` (yeni: açık yollar, rol, `adminOnly`, `viaSession`), `middleware.go` (token HER yolda çözülür;
    açık uçlar + OPTIONS kimlik istemez; oturum sorunları 400 değil **401**; geçerli token API anahtarının yerini tutar;
    geçersiz token + doğru anahtar REDDEDİLİR), `auth.go` (`/ws?token=` YALNIZCA `/ws` yolunda), `health.go`
    (`/api/system` -> `auth.users`; izin özeti anonime verilmez), `permissions.go` (ÜYELİK AÇIKKEN `PUT /api/permissions`
    yalnızca yönetici, üyeye 404; yanıtta `admin` bayrağı; üye kimlik listesi yalnızca yöneticiye),
    **yeni uçlar:** `GET /api/admin/users`, `PUT /api/admin/users/:id/permissions` (yalnızca admin, üyeye 404).
    `user.Service.Register`: **hiç hesap yokken açılan İLK hesap yönetici** olur (başka türlü `.env`'e
    `FIKO_BOOTSTRAP_PASSWORD` yazmadan admin olmazdı). 11 yeni test `internal/api/auth_flow_test.go`'da.
  - **İŞLETME NOTU:** `.env`'de `FIKO_API_KEY` ve `FIKO_USERS_ENABLED` dolu. Sunucu **yeniden başlatılmalı**.
    Oturumlar bellekte tutulur (`user.Service.sessions`): sunucu yeniden başlayınca herkes yeniden giriş yapar.
  - **SIRADA:** Angular (auth.store token + `me()`, interceptor Bearer, login/kayıt sekmeleri, çıkış, WS `?token=`,
    yönetici üye-yetki ekranı, `permissions-box` üye için salt okunur). Sonra `docs/API.md`, `MIMARI.md`, `.env.example`.

- **2026-10-04 — ÜYELİK / GERÇEK KİMLİK DOĞRULAMA, 1. dilim (backend kısmen hazır).**
  Kullanıcı isteği: parolayla gerçek giriş + üyelik + oturum + üye bazlı araç yetkisi. Önceki yorum
  (`X-Fiko-User` ile "kullanıcı bazlı") yetersizdi: bu kimlik doğrulama değil, yalnızca sahiplik ayrımı;
  başlık istemciye açık olduğundan herkes başkasının adını yazıp kutusuna girebilir.
  - **Yapıldı:** `internal/user/` (model, service, store, 8 test): bcrypt parola, kullanıcı adı kuralları,
    giriş hatasında tek mesaj, zamanlama dengesi; oturum token'ı sunucuda **özet (hash)** olarak saklanır.
    MongoDB kullanıcı deposu (benzersiz `username` indeksi). Uçlar: `/api/auth/register|login|logout|me`.
    Middleware sırası: `token → API anahtarı → geliştirme başlığı (X-Fiko-User)`.
  - **Doğrulama:** `go build`, `go vet`, `gofmt -l` temiz; `go test ./...` 27 paket yeşil.
  - **Arayüz yeni uçları HENÜZ kullanmıyor.** `FIKO_USERS_ENABLED=true` `.env`'de açık; eski akış çalışmaya
    devam eder, uygulama bozulmaz.
  - **Önemli tespit:** araç yetkisi zaten üye bazlı — `GrantStore.PolicyFor(userID)` (`internal/tool/permission.go`).
    Altyapı hazır; yalnızca arayüz + bağlantı kaldı. `permission.go` ve `executor.go`'ya DOKUNMA.
  - **Devralan için brief: `docs/GOREV-UYELIK.md`** (görev, mevcut durum, güvenlik kuralları, bitiş kriterleri).
  - **SONRAKİ ADIM:** (1) giriş/kayıt ekranı + çıkış + oturum kalıcılığı (Angular), (2) üye bazlı araç yetkisi
    arayüzü, (3) WebSocket'e Bearer token/çerez desteği (`/ws` şu an yalnızca `?key=` bakıyor),
    (4) canlı test: iki kullanıcı, biri diğerinin verisini görmemeli.

- **2026-10-04 (19. oturum) — 5 yeni tool: `fs.list`, `fs.search`, `fs.stat`, `calc.eval`, `text.stats`.**
  Gerekçe: ajan araç kutusunun "near-universal" katmanı incelendi (agentfieldbook.org,
  agentlist.io). `fs.read_text` vardı ama **dosyayı bulmanın yolu yoktu** — yol bilinmeliydi,
  yani `ls`/`grep` yoktu; "notlarımı bul" denince ajanın yapabileceği tek şey `../..` denemekti.
  Hesaplama da hiç yoktu. Hepsi düşük riskli, yalnızca `read`/`execute` ister, yan etki üretmez.
  - `calc.eval` **bilerek `eval` kullanmaz**: özyinelemeli çözümleyici + sabit anahtarlı
    fonksiyon `switch`'i. `import`/`open`/`eval` ifadeleri hata döner (10 saldırı denemesiyle sınandı).
    Derinlik 64 sınırı (stack taşması yok), yuvarlama 15 basamağa çıkarıldı.
  - `fs.search` gezinmesi 5000 girdiyle sınırlı; kesildiğinde `(sonuçlar sınırlandı, ~N girdi tarandı)`
    yazar — sessiz veri kaybı olmaz. İkili (geçersiz UTF-8) dosyalar atlanır.
  - UI ön ek yerine tanımda açık: `fs.list`/`fs.search` → table, `fs.stat`/`calc.eval`/`text.stats` → form.

- **2026-10-04 (19. oturum) — Test ikinci bakışında İKİ GERÇEK HATA (cache gizlemişti).**
  İlk turda "her şey yeşil" denmişti; `go clean -testcache` + 25 kenar durumuyla zorlayınca:
  (1) `1e5` **hata veriyordu** — bilimsel gösterim yoktu, `e` değişken adı sanılıyordu.
  (2) `1/3` **bozuluyordu** — 10 basamağa yuvarlama `0.3333333333` kesiyordu (5 basamak kayıp).
  İkisi de düzeltildi; artık kalıcı testlerle korunuyor. Ayrıca `fs.search` boş `path`
  reddediyordu (tüm kök taranamıyordu) — o da düzeltildi.

**Ortam notu:** `-race` çalıştırılamıyor — Go kurulumu cgo'suz derlenmiş
(`go: -race requires cgo; enable cgo by setting CGO_ENABLED=1`). Eşzamanlılık testi için
C derleyicisi (gcc) gerekir. Ortam kısıtıdır, kod hatası değildir.
## PHASE 1 — Backend
### İskelet / temel
- [x] Klasör yapısı (cmd, internal/*, pkg, config)
- [~] `backend/go.mod` — *(eski not)* fiber/websocket/mongo-driver "yok" deniyordu; **artık üçü de kurulu** (bkz. NOTLAR: Fiber v2.52.6 + `contrib/websocket` v1.3.3, `compress` v1.17.9'da sabit)
- [x] `config/config.go` — env tabanlı config (HTTP, Mongo, Ollama, Chat, WS, Log) + Validate
- [x] `pkg/id/id.go` — önekli rastgele ID
- [~] `internal/event/bus.go` — MemoryBus tamam; olay tipleri 5 tane (sonra genişlet)
- [~] `internal/conversation` — model, `Repository` arayüzü, `Service` (sahiplik, otomatik başlık, mesaj kaydı), `MemoryRepo` + `RepositoryContract`
  - [x] `conversation/contract.go` — sözleşme **üretim dosyasına taşındı** (`_test.go` içindeyken mongostore erişemiyordu)
- [x] **Mongo Repository** (`internal/storage/mongostore`) — sözleşmenin 5 alt testinin tamamı gerçek Mongo 8.2'ye karşı; + index kurulumu, konuşma silinince mesaj silinmesi, duplicate-id testleri. Bellek içi depo ile **aynı sözleşme**, kalıcılık canlı doğrulandı
- [x] `internal/storage/storage.go` — Mongo bağlantısı (ping + index + retryWrites/RetryReads), URI log'da maskeli; `MONGO_ENABLED=false` ile bellek içi düşüş

### Yapılacak
- [x] `internal/protocol/protocol.go` — WS şemaları; JSON round-trip + golden JSON, kenar durumları (null/bozuk/bilinmeyen), `Valid()` tüm sabitler, **Go ↔ `protocol.ts` eşlik testi** (AST + reflect; TS yoksa skip)
- [x] `internal/llm/provider.go` — Provider arayüzü, Request/Result/Options, ProviderError
- [x] `internal/llm/ollama/ollama.go` — `/api/chat` NDJSON stream, iptal (kısmi içerik döner), ListModels · `ollama_test.go` 8 test
- [x] `internal/prompt` — `prompt.go` + test
- [x] `internal/agent` — `agent.go` (tek tur chat, konuşma başına tek aktif üretim, Cancel/interrupt, kısmi içerik kaydı, timeout, graceful Close) + 9 test
- [x] `internal/settings` — model/temperature/topP/maxTokens/contextSize + `GET/PUT /api/settings`; ajan `OptionsFunc` ile **üretim anında** güncel ayarları okur
- [x] `internal/audit` — JSON satırı, 0600 + append; yazma hatası akışı durdurmaz (loglar); `Sanitize` ile özet; `AUDIT_LOG_PATH` boşsa stdout
- [x] Testler — `config_test.go` 13, `pkg/id` 4, `event/bus_test.go` 9 (kuyruk dolmama, panic izolasyonu, kapanış boşaltma, eşzamanlılık)
- [x] `internal/api` — Fiber uygulaması (`api.go`), CORS + panic recovery + istek logu + kullanıcı çözümleyici, JSON hata gövdesi + Fiber→HTTP eşlemesi; uçlar: health, conversations CRUD, messages, models, settings; `ws.Mount` ile `/ws`; `X-Fiko-User` + `Config.DefaultUserID`
## PHASE 1 — Frontend
- [x] Angular iskeleti (`ng new` çıktısı; Angular 22, vitest) — artık varsayılan şablon değil
- [x] `models/protocol.ts` — Go `protocol.go` ile birebir uyumlu tipler + `isClientType`/`isKnownServerType`; `protocol.spec.ts` 6 test liste eşitliğini sabitler
- [x] `core/config.ts` — adres çözümleme (`window.__FIKO_CONFIG__` → varsayılan `ws://localhost:8080/ws`)
- [x] `core/api.service.ts` — REST istemcisi (HttpClient + `X-Fiko-User`), `provideHttpClient(withFetch())`
- [x] `core/ws.service.ts` — üstel backoff reconnect, uygulama düzeyi heartbeat (ping/pong + ölü bağlantı tespiti), gönderim kuyruğu (mesaj kaybolmaz), `onEvent`, `NgZone` dışı ağ işleri
- [x] `core/chat.store.ts` — signals tabanlı durum
- [x] `layout/sidebar.ts` — konuşma listesi, yeni sohbet, ayarlar
- [x] `features/chat/*` — mesaj listesi (streaming balonu), composer (kayıt/iptal)
- [x] `features/settings/settings-panel.ts` — model/temperature/topP/maxTokens/contextSize
- [x] Doğrulama: `ng test` + `ng build` yeşil

## PHASE 3 — Frontend Skill ekranı (kod tamam, elle doğrulama bekliyor)
- [x] `models/skill.ts`, `core/skill.store.ts`, `core/skill.logic.ts` (+ `.spec` testleri)
- [x] `features/skills/skills-panel.ts` — liste + editör + doğrulama
- [x] Sidebar'da "🧠 Skill'ler" düğmesi
- [ ] **Panel bileşen testi** (şimdilik yalnızca mantık + store testli; arayüz elle doğrulanacak)

## PHASE 4b — Frontend Tool ekranı (kod tamam, elle doğrulama bekliyor)
- [x] `models/tool.ts`, `core/tool.store.ts`, `core/tool.logic.ts` — `ToolForm` ↔ sunucu gövdesi, `parseJsonObject`, `runBlockedReason`, `needsRiskApproval`
- [x] `features/tools/permissions-box.ts` — izin kutucukları (`execute` kilitli), high/critical risk kapıları, Düzenle→Uygula/Vazgeç
- [x] `features/tools/tools-panel.ts` — solda liste (arama + risk süzgeci + izin kutusu), sağda editör, 400 ms debounce doğrulama, **Çalıştır** bölümü, builtin'da Kapat/Etkinleştir
- [x] Sidebar'da "🔧 Tool'lar" düğmesi; skill panelinde tool adı datalist'i
## PHASE 2–10
- [~] P2 Conversation memory / Context manager
  - [x] `internal/ctxmgr/ctxmgr.go` — kayan pencere: sistem istemi + son mesaj zorunlu, geçmiş eskiye doğru, user ile başlar, atılınca bağlam notu; son mesaj sığmazsa baş+son korunup ortası kırpılır; muhafazakâr token tahmini (ASCII 1/3, Türkçe/Latin-ext 1/2, CJK 1). 12 test `-count=3` yeşil
  - [x] agent entegrasyonu: `buildMessages` → `ctxmgr.Fit`; pencere = ayarlardaki `contextSize` (0 ise `CHAT_DEFAULT_CONTEXT_TOKENS`, varsayılan 4096); kırpma olunca slog INFO. Config + `.env.example` + testler güncellendi (<512 reddedilir)
  - [x] agent testleri (3): uzun geçmiş pencereye sığar, `contextSize` varsayılanı ezer, kısa konuşma dokunulmadan gider
- [x] P3 Skill Registry + CRUD + embedding + vector search (backend tamam; frontend Skill ekranı kod olarak tamam — bkz. "PHASE 3 — Frontend")
  - [x] `skill/skill.go` alan modeli + `Repository` arayüzü + bellek içi repo (8 alt test, üretim dosyasında `contract.go`)
  - [x] `skill/service.go` — Registry: Register/Update/SetStatus/Duplicate/Delete/Get/List/Validate; kimlik/zaman damgası/embedding sunucuya ait; `SkillCreated/Updated/Deleted` olayları
  - [x] `skill/skill_test.go` — MemoryRepo sözleşmesi, Validate/Normalize tabloları, Service testleri; `-count=10` yeşil
  - [x] **Mongo skill deposu** (`skill_repo.go`) — 8 alt test gerçek Mongo'da (`-count=3`), benzersiz index, 8 eşzamanlı Create'ten 1'i, embedding saklama. `skill_name_unique` index; `regexp.QuoteMeta` ile düz metin sorgu
  - [x] **REST + bağlama** (`api/skills.go`) — list/get/create/update/status/duplicate/delete/validate; hata eşlemesi 400/409/404; `openStores` (konuşma+skill aynı karar), `Deps.Skills` nil→503; 10 test; **canlı**: kalıcılık, denetim kaydı, `API.md` güncellendi
  - [x] **Düzeltilen hata:** `parseLimit`/`parsePaging` `fail(...)` ile nil dönüp 400 sonrası liste ile gövdeyi eziyordu → artık `*fiber.Error`. Regresyon: `TestPagingErrorBodyIsError`
  - [x] **Faz 3b — embedding + arama:** `llm.Embedder` + `ollama.Client.Embed` (`/api/embed`, `OLLAMA_EMBED_MODEL`); `skill/search.go` (`EmbeddingText`, `Search` semantic/keyword/hybrid %80+%20, `Reindex(force)`); kayıt hatası **kaydı düşürmez**; hybrid'de sağlayıcı çökerse anahtar kelimeye düşer (200), semantic'te 502/503. REST: `POST /api/skills/search`, `/reindex[?force=]`; `setupSkillEmbedding` pre-warm. 17+6 test; **canlı hata yolları doğrulandı**
- [x] P4 Tool Registry / Tool Executor / Permission (backend TAMAM; canlı doğrulandı — arayüz 4b'de)
  - [x] `internal/schema` — JSON Schema alt kümesi (`Validate`, `ApplyDefaults`; hata sırası alan adına göre kararlı)
  - [x] `internal/tool/model.go` — alan modeli, `Status`/`Kind`/`Risk`, derin `Clone`
  - [x] `internal/tool/permission.go` — bit maskesi, `Policy.Authorize`, **Risk kapıları**, `GrantStore`
  - [x] `internal/tool/validate.go` — `Normalize` + `Validate` (ad deseni, izin kümesi, zaman aşımı/retry, şema boyutu)
  - [x] `internal/tool/registry.go` — CRUD + çalışma zamanı handler (`Bind`/`Resolve`/`Executable`), `EnsureBuiltin` (var olan ezilmez)
  - [x] `internal/tool/executor.go` — zincir: çöz→kapalı→doğrula→yetki→süre→çalıştır(retry)→denetim; panic kurtarma, iptal
  - [x] `internal/tool/errors.go` — `ErrNotFound/Disabled/NotExecutable/Builtin`, `ValidationError`, `InputError`, `FailedError`
  - [x] `internal/tool/contract.go` + bellek içi repo — 8 alt test; **canlı Mongo aynı sözleşmeden geçiyor** (`tool_name_unique`, 8 eşzamanlı Create→1)
  - [x] `internal/tool/builtin` — `fiko.echo`, `fiko.now`, `fs.read_text/write_text/delete` (sandbox'lı), `sys.exec` (izin listesi + kabuksuz, kapalı varsayılan)
  - [x] `skill/execute.go` — `ToolChecker` + `ToolExecutor` (`ExecuteSkill`)
  - [x] `api/tools.go` + `api/permissions.go` — CRUD + execute + izin GET/PUT; 403/501/409/502/400 eşlemesi
  - [x] `cmd/server/tools.go` — DI: builtin kaydı, izin deposu, Executor + `bindSkillTools`; auditLog önce açılır
  - [x] `config.Tools` + `.env.example`
  - [x] **Canlı doğrulama:** echo çalıştırma, yetkisizde 403, geçersiz girdi 400+`fields`, izin açma→yazma→okuma, **sandbox kaçışı reddi** (`../../windows/...`→502), kullanıcı izolasyonu, yeniden başlatmada kalıcılık, denetim kaydı ayrımı
- [x] Doğrulama: `ng test` **8 dosya, 119/119 yeşil**; `ng build` uyarısız
- [x] P5 Agent Engine / tool calling / execution tracking
- [x] P6 STT / VAD / continuous voice
- [x] P7 TTS / barge-in
- [~] P8 Knowledge / RAG
  - [x] `knowledge/` model, parser, chunker, `Repository` + `MemoryRepo` + `RepositoryContract`, `Service` (Ingest, arka plan embedding, Resume, Reindex), `search.go` (semantic/keyword/hybrid %80+%20, Türkçe katlama, ifade bonusu + belge başına çeşitlilik sınırı)
  - [x] REST `api/knowledge.go`: `GET/POST /api/knowledge/documents` (JSON ya da multipart `file`), `GET .../:id`, `GET .../:id/chunks`, `DELETE .../:id`, `POST /api/knowledge/search`, `POST /api/knowledge/reindex[?force=]`; `Deps.Knowledge` nil→503; `main.go` bağlandı (`Resume` + `Close`)
  - [ ] **`search_test.go`** (katlama, hibrit ağırlık, ifade bonusu, çeşitlilik sınırı) — kullanıcı "testleri sonra" dedi
  - [ ] **api/knowledge_test.go** (`-count=3`, Fiber havuz kuralı)
  - [x] **Mongo deposu** (`mongostore/knowledge_repo.go`): koleksiyonlar `knowledge_documents` + `knowledge_chunks`; index'ler `kb_doc_user_hash_unique` (benzersiz), `kb_doc_user_created`, `kb_doc_status`, `kb_chunk_doc_index`, `kb_chunk_user_project`. `RepositoryContract` 10 alt testin tamamı **gerçek Mongo'da** (`-count=3`) + index testi; `go test ./...` tümü yeşil. Mongo yoksa bellek içi depoya düşer (WARN'da belgeler de anılır)
  - [x] **Ajan entegrasyonu:** `agent/knowledge.go` (`KnowledgeRetriever`, tool'dan BAĞIMSIZ, 4 sn zaman aşımı, 3 alıntı / 2400 karakter tavanı), `prompt/knowledge.go` (alıntılar "veri" olarak çerçevelenir, içindeki talimatlara uyulmaz), `cmd/server/knowledge.go` (adaptör; boş bilgi tabanında embedding üretilmez), `knowledgeMinScore=0.35` **ayarsız ilk tahmin**
  - [x] **Canlı doğrulama (2026-10-03, gerçek Mongo + qwen3-embedding):** belge ekle → `indexing` → 5 sn içinde `ready` (embeddedCount 1/1); Türkçe katlama ("tezgahi" ↔ "tezgâhı") hibritte bulundu; aynı içerik tekrarında **409**; silme sonrası liste 0. **Ölçülen skorlar (tek belge, tek veri noktası):** ilgili sorgu hibrit **0.710**, ilgisiz sorgu **0.202**, keyword **1.0** → `knowledgeMinScore=0.35` bu iki nokta arasında kalıyor (makul), ama **tek belgeyle** ölçüldü; çok belgeli gerçek veriyle yeniden bak
  - [x] **Mongo `$vectorSearch` (22. oturum, kod + birim testleri; canlı mongot doğrulaması YAPILMADI — kullanıcı Docker/elle testi atladı):** `knowledge/vector.go` (isteğe bağlı `VectorSearcher`/`VectorIndexer`, `ErrVectorUnavailable`), `knowledge/vector_search.go` (`scoreByVector`), `search.go` aday yolu ikiye ayrıldı (`scoreByVector` → olmazsa `scoreByScan`), `mongostore/knowledge_vector.go` (index kurulum/boyut güncelleme/sorgulanabilir bekleme, `$vectorSearch` boru hattı, devre kesici 30 sn, `UnembeddedChunks`), `cmd/server/knowledge.go` `setupKnowledgeVectorSearch` (boyutu sondayla ölçer, arka planda kurar). Config: `KNOWLEDGE_VECTOR_SEARCH=auto|on|off`, `KNOWLEDGE_VECTOR_INDEX_TIMEOUT`. Testler: `vector_test.go` 8, `mongostore/knowledge_vector_test.go` 9, `config_knowledge_test.go` 4; `go test ./... -count=1` yeşil, `go vet ./...` temiz.
  - [ ] **mongot'a karşı canlı doğrulama** (index kurulumu, `queryable`, skor ölçeği, `$vectorSearch` süzgeci) — elle yapılacak; `auto` modunda mongot yoksa log "skorlama Go tarafında" der ve eski davranış sürer
  - [ ] Ajanın sohbette alıntıyı gerçekten kullandığının canlı testi (log: "bilgi tabanından alıntı eklendi"), agent/prompt RAG testleri
  - [ ] `docs/API.md` bilgi tabanı bölümü
- [x] P9 Agent Builder / Workflow *(kod taramasıyla uzlaştırıldı; bu not oturumlarda yazılmamıştı — testler bu taramada ÇALIŞTIRILMADI)*
  - [x] Backend `internal/workflow/` — `model.go` (10 düğüm türü, sınırlar: 100 düğüm/300 kenar/200 adım/50 yineleme), `validate.go` (kaydet esnek, çalıştır katı), `engine.go`, `execution.go` (adım adım kayıt), `service.go` (MaxConcurrent, RunTimeout, Recover, Close), `memory.go` + `contract.go` (sözleşme), testler: `engine_test`, `memory_test`, `service_test`, `validate_test`
  - [x] `storage/mongostore/workflow_repo.go` (+ test), `api/workflows.go` (+ test), `cmd/server/workflows.go` (yetenek bağlama), `main.go` (Recover, Close, OnFinish log)
  - [x] Frontend: `models/workflow.ts`, `core/workflow.{logic,store}.ts` (+ logic spec), `features/workflows/workflows-panel.ts` (+ spec), sidebar'da "⧉ Akışlar"
  - [ ] `docs/API.md` akış bölümü / `MIMARI.md` güncellemesi (doğrulanmadı)
  - [ ] Canlı doğrulama: gerçek bir akışı tarayıcıdan çiz → kaydet → çalıştır (kullanıcı tarafı)
- [~] P10 Advanced memory / multi-agent / provider yönetimi *(kod taramasıyla uzlaştırıldı)*
  - [x] Gelişmiş bellek ÇEKİRDEĞİ: `internal/memory/` (model, service: Add/Update/Delete/Search/Recall/Reindex, `extract.go` + `learner.go` otomatik öğrenme, `text.go`, `contract.go`, `memory_test.go`) + `storage/mongostore/memory_repo.go` (+ test)
  - [x] **Bağlama (bu oturum, KOD YAZILDI — derleme/test ÇALIŞTIRILMADI):** `config.Memory` (`MEMORY_ENABLED/AUTO_LEARN/MAX_PER_USER/RECALL_MIN_SCORE/LEARN_MODEL` + `config_memory_test.go` 3 test, `.env.example`); `prompt/memory.go` (`Memories` parçası: "bilinenler", veri olarak çerçeve, çelişkide kullanıcının son sözü) + test 4; `agent/memory.go` (`MemoryRecaller`/`MemoryLearner`, `SetMemory`, getirme bilgi tabanıyla PARALEL, tur sonunda `learn` arka planda, `Close` iptal eder+bekler) + `agent_test` 9 test; `cmd/server/memory.go` (adaptörler, `setupMemory`/`closeMemory`) + `main.go` (`stores.memories`, Mongo/bellek içi, `Deps.Memory`); `api/memory.go` (`/api/memories`: list/get/create/update/delete, `DELETE ?confirm=true` = "beni unut", `search`, `reindex`) + `api/memory_test.go` 8 test
  - [ ] **Bir sonraki adım:** `go build ./... && go vet ./... && go test ./... -count=3` (Fiber kuralı) — yazılan kod HENÜZ derlenmedi; hata çıkarsa ilk burada çıkar
  - [ ] Arayüzde "Hafıza" paneli (liste, elle ekle/düzenle/sil, "beni unut"); `docs/API.md` bellek bölümü
  - [ ] Canlı doğrulama: "Ben Angular kullanıyorum" yaz → log `anı öğrenme tamamlandı` → yeni sohbette "hangi framework?" → log `kalıcı bellekten anı eklendi`. `MEMORY_RECALL_MIN_SCORE=0.35` ayarsız ilk tahmin
  - [ ] multi-agent, provider yönetimi — başlanmadı

---

## TARAMA BULGULARI (2026-10-02, ilk tarama)
- `PROJE.MD` 1164 satır; bir **prompt/spesifikasyon** (kod değil). "Önce mimari + klasör yapısı, sonra Phase 1" diyor.
- Backend'de yalnızca 5 dosya yazılmıştı: config.go, conversation/model.go, event/bus.go, pkg/id/id.go, go.mod.
- `config.go` `godotenv` import ediyor ama go.mod'da require yok → derlenmiyordu.
- Frontend `ng new` sonrası dokunulmamıştı. `docs/` boştu.

## NOTLAR / KARARLAR
**Mimari / kapsam**
- Spec "Angular 21+" diyor; kurulu Angular 22.1 — kalıyor.
- Spec "mümkün olduğunca Angular Material kullanma" → **kendi bileşenlerimizle** gidilecek.
- İlk versiyonda Redis yok; session/cache MongoDB ile.
- CATIA'ya özel kod yok; Tool sistemi generic (Faz 4).
- **WS sınırında payload tipi KAYBOLUR (kritik):** `agent` olayları Go tipleriyle üretir ama `ws/session.go` `json.Marshal` edip yollar → `o.Payload.(protocol.TextFinalPayload)` **panic** verir, tip `map[string]any`'dir. WS testlerinde `payloadAs[T](t, o)` kullanılır.
- **Flaky test kuralı:** "olayın tetiklenmesine" dayanan testlerde akış bitmemeli (`neverEndingStream` kullan, `echoStream` yazma döngüsünü boşa düşürür). Yeni eşzamanlı testten sonra `go test -count=5`, mümkünse `go test ./... -count=3`.
- **Flaky kök neden (bulundu/düzeltildi):** Fiber `app.Test()` `Ctx`'i havuzdan ödünç alıyor; `io.ReadAll` sonrası dönen `[]byte` **havuza bağlı** kalıyor, ikinci koşuda bozuluyordu. Çözüm: `raw = append([]byte(nil), raw...)`. Middleware'de ayrıca `c.Locals(key, nil)` ile temizlenir. **Kural: Fiber `app.Test()` ile çalışan her test `-count>1` ile doğrulanmalı** — `-count=1` yeşil olan test flaky olabilir.
- Kapanış sırası **agent.Close → hub.Close → http.Shutdown** testle sabitlendi; bir bileşen hata verse de zincir kırılmaz.
- **Mongo:** `mongo-driver` **v1.17.2** (v2 öneriliyor ama v1 Go 1.23 ile sorunsuz). `go get` sonrası **`go mod tidy` şart** (yoksa `missing go.sum entry`). Bu makinede Docker'da `:27017` (fikoyt/fikoyt1299, authSource=admin). Mongo testleri `MONGO_TEST_URI` yoksa **skip**. `cmd /c "set X=..."` trailing space ekler → PowerShell'de `$env:X=...` kullan. Bileşik index'te anahtarlar `map[string]any` **OLMAZ**, `bson.D` olmalı (yoksa "multi-key map passed for ordered parameter keys").
- **`RepositoryContract` üretim kodunda olmalı** (`contract.go`): `_test.go` içindeyken dış paketler erişemez.
- **FIBER v2 KOPYALANMAMIŞ STRING TUZAĞI (gerçek üretim hatası, 13. oturum):** `c.Get()`/`c.Params()`/`c.Query()` istek tamponuna işaret eden **kopyalanmamış** string döner; handler bitince tampon yeniden kullanılır. Değer istek ömrünü aşan yere girerse (bellek içi depo sahibi, asenkron `bus.Publish`) **sessizce bozulur**. Çözüm: `strings.Clone(...)`.
- **Retry sınırı sessizce öldürebilir (15. oturum):** `MaxAttempts` boşken 1'e sabitleniyordu; `retry.maxAttempts` hiç işlemiyordu. **Kural:** "yoksa güvenli" seçimi sessiz kısıtlamaya yol açabilir; **tavan uygula, 1'e çökme**.
- **Tool güvenliği varsayılanları (Faz 4):** yalnızca `execute`; `read/write/delete/system` ve `high/critical` kullanıcıdan açıkça istenir. `sys.exec` iki kapı (`TOOL_EXEC_ENABLED` + izin listesi) ve kabuksuz. Dosya tool'ları `TOOL_FS_ROOT` altına sandozlanır.
- **`llm.Provider` ARAYÜZÜNE TOOL EKLENMEZ (Faz 5):** isteğe bağlı `llm.ToolProvider` alt arayüzü (embedding ile aynı desen); desteklemeyen sağlayıcıda ajan sessizce tek tura düşer.
- **Tool çağrısı geçmişe DÜZ METİN yazılır (Faz 5):** `llm.Message`'a `ToolCalls` eklemek mesajı karşılaştırılamaz yaptı, `ctxmgr` testlerini kırdı. Geçmişe `→ fiko.echo({…})` (asistan) + `[fiko.echo tool sonucu] {…}` (kullanıcı) yazılır.
- **Model kendi çağrısını görmezse TEKRARLAR (canlı testle bulundu):** yalnızca sonucu geçmişe koyunca model 4 tur aynı tool'u aynı argümanla çağırdı. Çözüm: **çağrı satırı da** geçmişe yazılır.
- **"Düzeltmiştim" yetmez — canlı test kararsızdır:** aynı senaryo iki oturumda tekrarlandı, ikisinde de 4 turda aynı çağrı tekrarlandı. Gerçek çözüm üç katman: sistem istemi (`prompt.ToolUsage()`) + geçmişe çağrı yazımı + sunucuda **aynı (araç, girdi) çiftinin yeniden çalıştırılmaması**. **Kural:** kararsız davranışı düzeltmeyi sistemde zorla (tekrarı engelle) ve testle sabitle.
- **Aynı (araç, girdi) = aynı iş:** tekrar koruması GİRDİ metnine bakar (hash değil → açıklanabilir, çakışma yok). Farklı girdi = farklı iş.
- **Tool kaydı mesajın ALANIdır, ayrı mesaj değil (18. oturum):** `conversation.Message.ToolRuns`. Yeni `role: tool` eklemek geçmiş kurma/listeleme/sayaç davranışını değiştirdi; alan eklemek geriye dönük uyumlu ve "bu cevapta ne çalıştı" anlamını doğrudan verir. `omitempty` eski mesajları etkilemez.
- **Emit tur başına saklanmalı, global olamaz (Faz 5):** global `agent.emit` iki konuşma eşzamanlıyken tool olaylarını **yanlış oturuma** yollardı. Çözüm: `agent.begin(ctx, convID, emit)` emit'i `run` yapısında saklar.
- **Ollama `tool_calls` argümanları NESNE veya JSON METNİ olabiliyor:** ikisi de kabul edilir; bozuk metin sessizce boş girdiye **dönüşmez** (`llm.ArgsError`).
- **PowerShell ile dosya DÖNGÜSÜ YAPMA (17. oturumda pahalıya mal oldu):** `Get-Content -Raw | Set-Content` toplu metin değişikliği **UTF-8 Türkçe karakterleri bozdu** (mojibake) ve dosya elle yeniden yazıldı. Dosya düzenlemesinde **her zaman Edit aracını** kullan; PowerShell'i yalnızca derleme/test çalıştırmak ve çıktı süzmek için kullan. (Ekranda mojibake görünmesi normaldir — dosya bozuk değildir.)
- **Motor/entegrasyon seçimi kullanıcının kararıysa ARAYÜZÜ motor bağımsız yaz (18. oturum):** `stt.Recognizer` arayüzü + örnek uygulama; `STT_URL` ile değişir, yeni motor WS/ayar/UI'a dokunmadan eklenir.
- **Embedding modeli ilk çağrıda BELLEĞE YÜKLENİR (18. oturum, canlı):** `qwen3-embedding` (4.6 GB) soğuk yükleme **13 sn**; `OLLAMA_REQUEST_TIMEOUT=30s` iken ilk arama 504 oluyordu. Çözüm: açılışta **pre-warm** (`embedding modeli ısıtıldı sure=13s`) + timeout 30s → **90s**.
- **Retrieval "daraltma" kanıtı logdan okunur (Faz 5c):** `plan()` daralttığında `tool listesi skill'e göre daraltıldı skillers=[…] onceden=N sonra=M` yazar. **Tool çağrısı görülmemesi kanıt DEĞİLDİR** (model gereksiz tool'u kendi de seçmeyebilir) — ilk denemede sorgu ayırt edici değildi, kod değil. Doğru kanıt: ayırt edici skill + log satırı.
- **`muse-glimmer:30b` bir THINKING modelidir (2026-10-05, canlı):** Ollama yanıtı `message.thinking` alanına da yazar; `message.content` **düşünme bitene kadar boş** kalır. Küçük `num_predict` (ör. 16) bütçesi tamamen düşünmeye harcanır → `content` boş, `done_reason=length` → **kullanıcı boş yanıt görür**. Uygulama yalnız `content`'i okur (düşünmeyi akışa basmaz — bu DOĞRU davranış). `llm.MaxTokens=0` iken `num_predict` hiç gönderilmez (sınırsız) → sorun yalnız **küçük MaxTokens ayarı**dır. Teşhis: `/api/generate`'a `num_predict` küçük verip `thinking` alanına bak.
- **WS metin alanları `delta` / `content`dir, `text` DEĞİL (2026-10-05):** `assistant.text.delta → {messageId, delta}`, `assistant.text.final → {messageId, content, status, …}`. Elle WS okuyan bir betik `payload.text` okursa **delta'lar boş görünür** ve "model cevap vermiyor" sanılır (böyle bir hata yaşandı). Ön yüz (`chat.store.ts`) doğru okuyor: `appendDelta(p.messageId, p.delta)`.
- **PowerShell 5.1'de `Task.IsCompletedSuccessfully` YOKTUR (2026-10-05):** .NET Framework 4.x'te bulunmadığı için özellik `$null` döner ve `-not $task.IsCompletedSuccessfully` her zaman doğru olur → WebSocket okuma döngüsü **ilk adımda çıkıp "sunucu cevap vermiyor" gibi görünür**. Çözüm: `$task.IsFaulted` + `$task.Result` kullan, ya da bekleyen görevi değişkende saklayıp `$task.Wait(ms)` ile bekle (iptal ETME: iptal alıcı soketi bozabilir).
- **Bellek geri çağırma canlıda DOĞRULANDI (2026-10-05, açık madde 3 kapandı):** elle yazılan an (`POST /api/memories`, `kind: long_term`) → log `kalıcı bellekten anı eklendi anı=1` → aynı soru sohbette soruldu → model **1 sn**'de anının içeriğini verdi ("PostgreSQL, port 5433"). "Anı prompt'ta olsa da bulamadım" davranışı **tekrarlanmadı**; muhtemel neden o oturumdaki eski sunucuydu (log notu: "düzeltmeler çalışan sunucuda yok").
- **`POST /api/memories` türleri `long_term|semantic|episodic`:** `kind: "preference"` **400** döner (sunucu listeyi zorlar). Panel bu üç türü sunar; elle istek yapanlar için not.
- **Boş string `truthy`'dir (2026-10-05, gerçek tarayıcı testi):** `badgeLabel(0,0)` → `"0"` döner; `@if (badge())` rozeti **her zaman** açık tutuyordu. **Kural:** sayaç döndüren fonksiyonla görünürlük kararını AYRI fonksiyona böl (`hasBadge`), şablonda yalnız onu kullan. Aynı hata "0 kart" durumunda da tekrarlayabilir.
- **Rol/izin kontrolünü ARAYÜZDE de yap (2026-10-05):** yanıt düğmeleri sunucu kurallarını yansıtmalı. Yanıtı yalnızca ALICI verebilir; gönderen kendi sorusundaki "Gönder"e basınca hata alıyordu. Ekranda da engelle (yanlış kutu → "Yanıt bekleniyor…").
- **Node ile CDP: `waiting` gibi genel adları iki kez KULLANMA (2026-10-05):** `const waiting = new Map()` (kuyruk) ile aynı kapsamda `const waiting = await evaluate(...)` → TDZ, `ws.onmessage` içinde patlar. Betik hatası uygulama hatası sanılır; adı daralt.
## SONRAKİ ADIM
> Durum: 2026-10-03, 20. oturum sonrası. **P1–P7 tamam.** Kalan yalnızca kullanıcı tarafı doğrulamalar.

0. **(Sen)** Elle doğrulama: `localhost:4200` → "Echo aracını 'merhaba' ile çağır" yaz → rozetleri izle (çalışıyor → N ms). Tool'lar panelinden `read` iznini aç → dosya okuyan istek dene. Kapatılan tool listeden düşüp modele de sunulmaz.
1. **(Sen)** Gerçek tarayıcı testi: mikrofonla konuş → yanıt → hoparlör düğmesiyle sesli dinle → tekrar mikrofona dokununca asistanın susması (barge-in). Otomatik testler `MediaRecorder`/ses cihazını kapsamaz.
2. ~~Faz 5b kalıcı tool geçmişi~~ → **TAMAMLANDI** (`Message.ToolRuns`, 2 KB önizleme, cevap başına 16 kayıt).
3. ~~Faz 5c SKILL RETRIEVAL~~ → **TAMAMLANDI** (`agent.SkillRetriever`, `turnPlan`, `prompt.SkillSelector`; boş/hatalı retrieval davranışı değiştirmez).
4. ~~Faz 4b′ uzak tool'lar~~ → **TAMAMLANDI** (`kind: http` + SSRF). Yerel CATIA için `TOOL_HTTP_ALLOW_PRIVATE=true` — **üretimde kapalı kalsın**.
5. ~~Faz 6 STT~~ → **ALTYAPI HAZIR, motor seçimi senin**: `STT_PROVIDER=whispercpp` (yerel) veya `openai` (bulut). TTS için de `openai`|`piper`.
6. ~~Panel bileşen testleri~~ → **TAMAMLANDI** (`permissions-box` 6, `tools-panel` 6, `skills-panel` 4). İki gerçek hata çıktı ve düzeltildi.
7. ~~Faz 7 TTS~~ → **TAMAMLANDI** (`tts.mode`/`tts.stop`/`tts.audio`/`tts.done` + hoparlör düğmesi + barge-in).
8. ~~Embedding modeli~~ → **ÇÖZÜLDÜ**: `qwen3-embedding` zaten kurulu, `.env`'de etkin. Pre-warm eklendi.

## OTURUM GÜNLÜĞÜ

- **2026-10-05 (ÜYE SAYFASI TAMAMLANDI: `/hesabim`, üyenin kendi salt okunur sayfası).** Kullanıcı: "üyeler sayfasını yapıyorduk yarım kaldı."
  - **TARAMA (kod doğrudur):** yönetici tarafı ZATEN bitmişti (`/uyeler` liste → `/uyeler/:id` üye sayfası, `member.logic.ts`, spec'ler) ve backend de hazırdı (`GET /api/me/page`, `api/me.go` + `me_test.go`, `api.go`'da bağlı). Yarım kalan yalnız üyenin KENDİ sayfasıydı: sidebar'da hesap adı `<button class="who who-btn">` + `(profile)` çıktısı yazılmıştı, ama (1) `.who-btn` CSS'i yoktu (tarayıcının varsayılan düğme görünümü çıkardı), (2) `(profile)` `app.html`'de HİÇ bağlı değildi (tıklama sessizce hiçbir şey yapmazdı, hata da vermezdi), (3) `/hesabim` rotası ve sayfası yoktu.
  - **YAPILDI:** `models/auth.ts` → `MyBehavior`, `MyPageResponse` (Go `myPageResponse` ile birebir) · `ApiService.myPage()` · `features/account/account-page.ts` (SALT OKUNUR: izinler açık/kapalı, risk kapıları, "özel/varsayılan yetki", kişisel + ortak davranış; ortak profil `ortak profil` etiketli; hata + "Tekrar dene"; Esc/"← Sohbete dön") · `account-route.ts` (kapı: üyelik AÇIK ve oturum VAR; yönetici olmak gerekmez) · `app.routes.ts` (`/hesabim`, tembel) · `app.html` (`(profile)="openRoute('/hesabim')"`) · `sidebar.ts` (`.who-btn`: düğme sıfırlaması; `font` kısaltması BİLEREK yok, `.who`'nun 0.75rem boyutunu ezerdi).
  - **GÜVENLİK:** sayfa kimlik GÖNDERMEZ (sunucu oturumdan alır; başka üyenin sayfası istenemez); düzenleme kontrolü yok, sunucuda da düzenleme ucu yok (`TestMyPage_DuzenlemeUcuYok`). Yanıtta başka üyenin kimliği yok (`TestMyPage_KendiYetkisiVeDavranisi`). Rota kapısı yalnız arayüz rahatlığıdır; asıl koruma sunucuda (oturumsuza 401).
  - **BAYAT METİN DÜZELTİLDİ:** `member-page.ts` ipucu "yeni üye varsayılan olarak yalnızca execute" diyordu; sunucu varsayılanı `TOOL_DEFAULT_PERMISSIONS` ile ayarlanır ve boşsa `tool.DefaultPolicy()` = read+write+execute (04.10 CANLI HATA sonrası). Metin artık belirli bir küme iddia etmiyor.
  - **DOĞRULAMA (komut çıktısı):** `tsc` app + spec exit 0 · `ng test --watch=false` → **36 dosya / 569 test geçti** (yeni: `account-page.spec.ts` 9, `app.routes.spec.ts` +4 `/hesabim` + tembel yükleme listesine eklendi, `app.spec.ts` +3: hesap adı düğmesi user/admin için `/hesabim` açar + geri döner) · `ng build` UYARISIZ, initial **443,10 kB**, `account-route` tembel parça 8,61 kB.
  - **YAPILMADI:** (1) gerçek tarayıcıda elle bakılmadı; `.who-btn`'in eski `span` görünümünü gerçekten koruduğu GÖZLE doğrulanmadı (jsdom'da CSS yargılanmaz). (2) Go testleri bu turda yeniden koşturulmadı (`me_test.go` önceki turda geçmişti). (3) Üye yönetici ekranında ("Üyeler") üyeye atanmış PROFİL adı gösterimi hâlâ yok.
  - **NOT:** `users-panel` artık iki sekmeli DEĞİL, yalnız üye listesi (üstteki "PROFİLLER + ÜYELER TEK EKRAN" kaydı eskidi). `personas-panel.*` dosyaları temizlikte SİLİNDİ (tüm `src`'de yalnız kendine referans vardı; `tsc` app+spec temiz).
  - **SONRAKİ ADIM:** `ng serve` yeniden başlat; üye hesabıyla gir → sidebar altındaki ad: eski görünümde mi, üzerine gelince vurgu var mı → tıkla → `/hesabim`: izinler, davranış (yönetici bir üyeye kişisel + ortak profil atayıp karşılaştır), "← Sohbete dön", Esc, sayfa yenileme.

- **2026-10-05 (PROFİLLER + ÜYELER TEK EKRAN).** Kullanıcı: "profiller ve üyeler ayrı ayrı saçma olmuş, bir edelim."
  - **YAPILDI:** `/uyeler` artık tek yönetici ekranı, iki sekmeli: **Araç yetkileri** (eski Üyeler içeriği) ve **Davranış profilleri** (eski Profiller içeriği). `PersonasPanelComponent` bağımsız ekran olmaktan çıktı, `UsersPanelComponent` içine gömülü sekme (kendi başlığı, `×`/Esc ve `close` çıktısı kaldırıldı; stilleri gömülü düzene çevrildi). Sidebar'daki "Profiller" düğmesi ve `(personas)` çıktısı kalktı; `personas-route.ts` silindi. `/profiller` adresi `/uyeler`'e YÖNLENİR (yer imleri kırılmasın). Backend DEĞİŞMEDİ (uçlar aynı: `/api/admin/users`, `/api/admin/personas`).
  - **KARAR:** gömülü profiller sekmesi üye listesini yalnız BOŞSA yükler; yoksa üst ekranın "Yükleniyor…" durumu tetiklenir ve sekmeler arası geçişte seçili üye/taslak giderdi.
  - **DOĞRULAMA (komut çıktısı):** `tsc` app+spec exit 0 · `ng test` → 34 dosya / **547 test geçti** (3 `/profiller` rota testi kalktı; sekme testi + yönlendirme testi eklendi) · `ng build` uyarısız, initial 442,21 kB.
  - **YAPILMADI:** tarayıcıda elle bakılmadı. `/uyeler` → iki sekme, profil oluştur/ata/sil, `/profiller` yönlenmesi. İsteğe bağlı sonraki adım: üye satırında/editöründe o üyeye atanmış profilin adını göstermek (şu an atama yalnız profil sekmesinden yapılıyor).

- **2026-10-05 (TAM SAYFA GEÇİŞİ — KOD TARAMASIYLA TAMAMLANDI DOĞRULANDI; alttaki "KALAN: Akışlar, Bilgi, ... hâlâ yan panel" notları ESKİ).** Kullanıcı: "yan panel geçişi yarım kalmıştı, devam."
  - **TARAMA (kod doğrudur):** `tools/_fullpage-apply.mjs` zaten çalıştırılmış; 12 ekranın TÜMÜ tam sayfa: Akışlar, Araçlar, Skiller, Ayarlar, Üyeler, İstem (inline `.ts`), Bilgi, Bildirimler, Sistem, Profiller (`.html/.scss`) + Hafıza ve Şirket. Hiçbirinde `.backdrop`/`aside`/`×` düğmesi kalmadı; hepsinde `<section class="panel">` + "← Sohbete dön" + `page-fade`.
  - **YAPILDI (artık parça temizliği):** `skills`, `settings`, `users` panellerinde kullanılmayan eski `@keyframes slide` (translateX) silindi. Skills panelinde iki açıklama satırı kaldırıldı. `angular.json` `anyComponentStyle` uyarı eşiği 6→7 kB (hata eşiği 8 kB aynı): skills paneli tam sayfa kuralları eklenince 6,13 kB'a çıkmıştı.
  - **DOĞRULAMA (komut çıktısı):** `tsc` app+spec exit 0 · `ng test --watch=false` → **34 dosya / 548 test geçti** · `ng build` UYARISIZ, initial **442,74 kB**.
  - **YAPILMADI:** gerçek tarayıcıda elle bakılmadı. `ng serve` yeniden başlat; 12 adresi tek tek aç (`/akislar`, `/hafiza`, `/bildirimler`, `/bilgi`, `/sirket`, `/skiller`, `/araclar`, `/sistem`, `/ayarlar`, `/uyeler`, `/istem`, `/profiller`): sütun genişliği, "← Sohbete dön", Esc, dar pencerede taşma. Özellikle **Akışlar** (sütun 4000px = fiilen tam genişlik, tuval) ve **Araçlar/Skiller** (iki sütunlu düzen, 760px altı tek sütun) gözle bakılmalı.

- **2026-10-05 (ŞİRKET TAM SAYFA — Hafıza ile aynı kalıp).** Kullanıcı: "aynısını şirket içinde yap."
  - **YAPILDI:** `/sirket` ekranı da yan panelden (1100px sağ panel + arka perde) tam sayfaya çevrildi. `company-panel.html`: perde ve `aside` kalktı, `<section class="page">`; `×` yerine üstte **"← Sohbete dön"** (sınıf `.x` korundu, Esc hâlâ kapatır). `company-panel.scss`: `:host` `fixed inset:0` + `--fiko-bg`, sidebar'ın da üstünü kaplar; tablo geniş olduğu için içerik **1400px**'e kadar ortalanır (`--gutter`; Hafıza'da 960px). Araç çubuğu, özet, form ve liste dolguları `--gutter`'a bağlandı; liste içindeki `.pad` iletileri çift dolgu almasın diye `.list > .pad { padding-inline: 0 }`. Davranış/mantık (koleksiyon, arama, CSV, form, silme) DEĞİŞMEDİ. Metinler bu dosyanın ASCII üslubuna uyduruldu (`&larr; Sohbete d&ouml;n`).
  - **DOĞRULAMA (komut çıktısı):** `tsc -p tsconfig.app.json` exit 0 · `ng test --watch=false` → **34 dosya / 548 test geçti** · `ng build` uyarısız, initial **442,74 kB**, `company-route` lazy parça 30,73 kB.
  - **YAPILMADI:** gerçek tarayıcıda elle bakılmadı. `ng serve` yeniden başlat; `localhost:4200/sirket`: tam sayfa, tablo genişliği, "← Sohbete dön", Esc, CSV yükle/indir, satır açma.
  - **KALAN:** tam sayfa olanlar Hafıza + Şirket. Akışlar, Bilgi, Bildirimler, Skiller, Araçlar, Sistem, Ayarlar ve yönetici ekranları hâlâ yan panel.

- **2026-10-05 (HAFIZA TAM SAYFA — yan panel değil).** Kullanıcı: "hafıza side bar olarak açılmasın, tam sayfa yönlensin."
  - **YAPILDI:** `/hafiza` rotası zaten vardı ama ekran hâlâ sağdan kayan 560px'lik yan panel + arka perdeydi. `features/memory/memory-panel.ts` TAM SAYFA düzenine çevrildi: arka perde ve `aside.panel` kalktı; `:host` `fixed inset:0` ve `--fiko-bg` ile sidebar'ın da üstünü kaplıyor; üst çubukta **"← Sohbete dön"** düğmesi (eski `×` yerine; sınıf adı `.x` korundu), içerik geniş ekranda 960px'e ortalanıyor (`--gutter`), anı kartları iki sütun (`auto-fill, minmax(420px)`), dar ekranda tek sütun. Esc hâlâ kapatır. Mantık/şablon işlevi DEĞİŞMEDİ (form, arama, silme, "Beni unut" aynı). `memory-route.ts` yalnız yorum güncellendi.
  - **KAPSAM:** yalnız Hafıza. Akışlar ve diğer paneller (skiller, araçlar, ayarlar...) hâlâ yan panel; istenirse aynı kalıpla tam sayfaya alınır.
  - **DOĞRULAMA (komut çıktısı):** `tsc -p tsconfig.app.json` exit 0 · `ng test --watch=false` → **34 dosya / 548 test geçti** · `ng build` uyarısız, initial **442,74 kB**, `memory-route` lazy parça 22,18 kB.
  - **YAPILMADI:** gerçek tarayıcıda elle bakılmadı (yalnız birim + build). `ng serve` yeniden başlatılmalı (bayat bundle), sonra `localhost:4200/hafiza`: tam sayfa mı, "← Sohbete dön" ve Esc çalışıyor mu, dar pencerede tek sütun mu.

- **2026-10-05 (ROTALAR 2. dilim — KALAN TÜM DÜĞMELER ROTAYA TAŞINDI; alttaki "diğer paneller bilerek olduğu gibi" kararı GEÇERSİZ).** Kullanıcı: "tamam butonlarada uygula bu rotaları."
  - **YAPILDI:** Sağdan açılan HER panel rota oldu (12 adres; eşleme `app.routes.ts` başındaki tabloda): `/bildirimler`, `/bilgi`, `/sirket`, `/skiller`, `/araclar`, `/sistem`, `/ayarlar` + yönetici `/uyeler`, `/istem`, `/profiller` (önceden `/akislar`, `/hafiza`). Her biri için ince sarmalayıcı `*-route.ts` (tembel). `app.ts`: 10 panel sinyali + importlar + `openPanel` silindi; `app.html`: tüm sidebar çıktıları ve üst çubuktaki **zil** ile **dişli** `openRoute('/...')`; çok sayıda `@if` bloğu yerine TEK `<router-outlet />`.
  - **KARARLAR:** (1) Yönetici ekranlarının kapısı rotada (CanActivate) değil EKRANDA: `features/admin/admin-access.ts` → `users() && isAdmin()` ekran ÇİZİLİRKEN uygulanır, yetkisiz `/`'e döner. Neden: sayfa yenilenince oturum geri yüklenmeden kapı çalışırsa yönetici de "yetkisiz" görünür, adres kaybolurdu; outlet yoklama bitmeden çizilmediği için burada durum kesindir. Güvenlik sınırı değildir (sunucuda `adminOnly` yetkisizde 404). (2) Ayarlar sarmalayıcısı `logout` çıktısını da taşır (`auth.logout()` → sayfa yenile; App.logout ile aynı iş). (3) Artık aynı anda tek panel açıktır (eskiden üst üste açılabiliyordu); bu davranış değişikliği bilinçli, rota modelinin sonucu.
  - **DOĞRULAMA (komut çıktısı):** `tsc` app+spec exit 0 · `ng test --watch=false` → **34 dosya / 548 test geçti** · `ng build` uyarısız, initial toplam **442,74 kB** (önceki dilimde 578 kB, bundan önce ~602 kB). Yeni testler: `app.routes.spec.ts` tablo tabanlı (9 panel: açılır + `close()` ile `/`'e döner; 3 yönetici ekranı × 3 durum: yönetici / yönetici olmayan üye / üyelik kapalı; hepsinin tembel olduğunu sabitleyen test) + `app.spec.ts`'e zil/dişli testi.
  - **YAPILMADI:** gerçek tarayıcıda elle bakılmadı. `ng serve` yeniden başlatılmalı (bayat bundle).
  - **SONRAKİ ADIM:** her düğmeye tıkla, adresi yapıştırıp yenile, geri tuşunu dene; yönetici olmayan hesapla `/uyeler` yaz → ana ekrana dönmeli.

- **2026-10-05 (AKIŞLAR + HAFIZA AYRI ROTAYA ALINDI — ön yüz; arka uç DEĞİŞMEDİ).** Kullanıcı: "Akışları ve hafızayı ayrı rotaya alalım."
  - **KAPSAM KARARI (kod okumasından):** arka uçta zaten ayrı gruplar var (`/api/workflows`, `/api/memories`; ayrı paketler `internal/workflow`, `internal/memory`; `api/workflows.go`, `api/memory.go`). Eksik olan ön yüzdü: `app.routes.ts` BOŞTU ve iki ekran `app.html` içinde sinyalle (`workflowsOpen`/`memoryOpen`) açılan overlay panellerdi. Bu yüzden "rota" = Angular adresi olarak yorumlandı. Arka uç yeniden düzenlenmedi.
  - **YAPILDI:** `/akislar` ve `/hafiza` rotaları, ikisi de **tembel** (`loadComponent`). Panellerin kendisine DOKUNULMADI (rotadan habersiz, yalnız `close` yayar); araya ince sarmalayıcılar kondu: `features/workflows/workflows-route.ts`, `features/memory/memory-route.ts` (kapatınca `/`'e döner; × , dış tık ve Esc hepsi bu yoldan). `app.ts`: `workflowsOpen`/`memoryOpen` sinyalleri ve iki panel importu kaldırıldı, `openRoute(path)` + `showRoutes` eklendi. `app.html`: iki `@if` bloğu yerine tek `<router-outlet />`; sidebar `(workflows)`→`/akislar`, `(memory)`→`/hafiza`.
  - **KARARLAR:** (1) `showRoutes = auth.ready() && !showLogin()` — adres artık doğrudan açılabildiği için panel, oturumdan ÖNCE yüklenip 401'li istek atmasın; eski akışta panel yalnız giriş sonrası tıklamayla açıldığından bu risk hiç yoktu. (2) `''` rotası bileşensiz ama `title: 'FIKO · AI'` taşıyor: başlıksız rotaya dönüşte Angular belge başlığını SIFIRLAMAZ, "Akışlar · FIKO" ana ekranda takılı kalırdı (testle sabitli). (3) Bilinmeyen adres `**` → `''`. (4) Diğer paneller (ayarlar, skill, tool, bildirim, bilgi, şirket, sistem, yönetici) bilerek OLDUĞU GİBİ bırakıldı; istenirse aynı kalıpla taşınır.
  - **DOĞRULAMA (komut çıktısı):** `tsc` app+spec exit 0 · `ng test --watch=false` → **34 dosya / 529 test geçti** · `ng build` uyarısız, initial toplam **578,28 kB** (yukarıdaki 602 kB notuna göre ~24 kB düştü: Akışlar paneli eskiden `@defer`'sız ilk bundle'daydı). Yeni lazy parçalar: `workflows-route` 38 kB, `memory-route` 22 kB. Yeni testler: `app.routes.spec.ts` (7: adres→panel, × ve Esc ile kapanış, bilinmeyen adres, başlık sıfırlama, tembel yükleme) + `app.spec.ts`'e 4 kabuk testi (sidebar düğmesi→adres, × ile dönüş, giriş ekranı açıkken derin bağlantıda panel ÇİZİLMEZ ve istek GİTMEZ, giriş olunca açılır).
  - **TEST HATASI (kendi hatam, düzeltildi):** kapanış sonrası `routeNativeElement` null olur; `?.querySelector(...)` `undefined` döndürür ve `toBeNull()` onu reddeder → `?? null` eklendi. Üretim koduna dokunmayı gerektirmedi.
  - **YAPILMADI:** gerçek tarayıcıda elle bakılmadı (yalnız birim/entegrasyon + build). `ng serve` bayat bundle sunabiliyor (bkz. persona notu) — önce yeniden başlat.
  - **SONRAKİ ADIM:** `start-all.bat` ile aç; `localhost:4200/akislar` ve `/hafiza` adreslerini doğrudan yaz, sayfayı yenile, geri tuşunu dene.

- **2026-10-05 (GERÇEK TARAYICI DOĞRULAMASI — son kalem kapandı; 3 hata bulundu ve düzeltildi).**
  - **ARAÇ:** Playwright/Puppeteer kurulu DEĞİL; Chrome'un CDP'si Node'un **yerleşik WebSocket'i** ile sürüldü → ek paket yok. `frontend/tools/notify-ui.mjs` (token alır, `sessionStorage['fiko.token']` eker, düğmeye GERÇEKTEN tıklar, DOM okur, ekran görüntüsü alır). Çalıştırma: `node tools/notify-ui.mjs <token> shot.png`.
  - **NASIL YAPILDI (kök sıralama):** token'ı sayfa YÜKLENDİKTEN SONRA yaz, sonra reload. Önce yazarsan `sessionStorage` henüz yoktur (SecurityError).
  - **SONUÇ:** gönderen (Ayşe) 15 kontrol ✅ · alıcı (Mert) 19 kontrol ✅. Gerçek tıklamayla "Uretim" seçeneği gönderildi → **rozet 7→5 düştü**, o sorunun seçenekleri kayboldu, sunucuya kalıcı yazıldı.

  - **BULUNAN HATA 1 — rozet sıfırda bile görünüyordu.** `badgeLabel(0,0)` → `"0"` döner; boş olmayan string `truthy` olduğu için `@if (badge())` **her zaman** kırmızı rozeti açık tutuyordu ("Hepsi okundu" yazarken bile kırmızı 0). Çözüm: gösterim kararı ayrı fonksiyona (`hasBadge`), iki şablonda da `@if (showBadge())`. Regresyon testi eklendi.

  - **BULUNAN HATA 2 — yanıt kartlarında gönderen "Bilinmeyen" idi (BACKEND).** `Service.Answer`, `Send`/`Ask` gibi gönderen adını ÇÖZMEDEN depoyu çağırıyordu; depo katmanı kullanıcı tablosunu bilmediği için `fromName` **kalıcı olarak boş** yazılıyordu. Ekran görüntüsü bunu ortaya çıkardı (yanıtlar "Bilinmeyen" ile görünüyordu). Çözüm: `Repository.Answer` imzasına `fromName` eklendi, **servis** adı çözüp depoya veriyor (bağımlılık yönü korunur: notify → user yine yok). Yeni testler: `TestNotifyRepo_AnswerAdiYazilir` (gerçek Mongo) + servis testi. Canlı doğrulandı: `fromName="Mert Kaya"`. **ESKİ kayıtlar adı boş kalır** (düzeltme öncesi yazılanlar) — sıfırlama/geri dönüş gerekir, ama özellik yeni olduğu için üretimde veri yok.

  - **BULUNAN HATA 3 — gönderen kendi sorusuna "Gönder" görüyordu (UX).** Bekleyen soru hem gelen hem gönderilen kutusunda çiziliyor ve seçenek düğmeleri her ikisinde de çıkıyordu; oysa yanıtı yalnızca ALICI verebilir (sunucu `ErrForbidden` döner). Gönderen "Gönder"e basıp hata alıyordu. Çözüm: yanıt kontrolleri **yalnız gelen kutusunda**; gönderilen kutusunda "Yanıt bekleniyor…" yazısı. Tarayıcı testi her iki rolü ayrı doğruluyor.

  - **TESTİN KENDİ TUZAKLARI (yanlış "hata" dedirdi, düzeltildi):** (1) Rol algılama "Gelen sekmesi seçili"ye bakıyordu — oysa gönderenin gelen kutusu da seçilir ama boştur; artık **kart sayısına** bakılıyor. (2) "Seçenekler bitti" kontrolü çok sorulu kutuda yanlış negatif veriyordu → "**AZALDI**" kontrolüne çevrildi. (3) `waiting` değişkeni hem CDP kuyruğunda hem DOM kontrolünde kullanılıyordu → TDZ hatası; yeniden adlandırıldı.
  - **KALAN:** yok. Bildirim özelliği backend + ön yüz + tarayıcı düzeyinde doğrulandı.

- **2026-10-05 (SİSTEM KONTROLÜ — bildirim sonrası sağlık taraması; bellek açık maddesi kapatıldı).**
  - **Sistem sağlığı:** backend `ok` (uptime ~70 dk) · SearXNG `8181` → 152 sonuç · Mongo `27017` (bildirim testleri gerçek Mongo'da yeşil) · Redis `6379` · Ollama `11434`. `.env`'deki `muse-glimmer:30b` ve `qwen3-embedding` **kurulu**; `qwen2.5:7b` artık yok (eski notlardaki 7B artık geçerli değil). Çalışan sunucu **tüm üretim kodunu içeriyor** (exe 01:13; son üretim kaynağı 01:08) → yeniden derleme gerekmiyordu.
  - **AÇIK MADDE 3 KAPANDI (bellek geri çağırma):** "model anı prompt'ta olsa da *hafızamda bulamadım* diyebiliyor" → canlı test: anı yazdım → log `kalıcı bellekten anı eklendi anı=1` → aynı soruyu sohbette sordum → model **1 sn**'de "Kullanıcının tercih ettiği veritabanı PostgreSQL'dir ve portu 5433'tür" dedi. **Davranış tekrarlanmadı.** O oturumdaki notla uyumlu: sorun eski sunucuydu.
  - **MODEL TİPİ BULGUSU:** `muse-glimmer:30b` bir **thinking modeli** — Ollama `message.thinking` alanına da yazıyor, `message.content` düşünme bitene kadar **boş**. Küçük `num_predict` bütçesi tamamen düşünmeye harcanınca kullanıcı boş yanıt görür. Uygulama yalnız `content` okuduğu için doğru davranıyor; `MaxTokens=0` (varsayılan) iken `num_predict` hiç gönderilmiyor. Yani **kod hatası yok**, risk yalnız "Sistem panelinden MaxTokens küçük ayarlanırsa" ortaya çıkıyor → not düşüldü.
  - **İKİ TEST HATAM (kendi ölçümüm yanlış "boş yanıt" dedirdi):** (1) PowerShell 5.1'de `Task.IsCompletedSuccessfully` yok → WS döngüsü ilk adımda çıkıyor, "sunucu cevap vermiyor" görüntüsü üretiyordu; (2) WS metin alanları `delta`/`content`, ben `payload.text` okuyordum. Ölçümü düzelttikten sonra sohbet **15 sn** (soğuk) / **1 sn** (sıcak) içinde yanıt verdi. Ön yüzün okuma kodu doğru (`appendDelta(p.messageId, p.delta)`).
  - **YAN BAĞLANTI (doğrulandı):** WS'e yeni bağlanan kullanıcıya `notify.received` ×4 + `notify.answered` ×2 + `notify.unread` **replay** edildi — yeniden bağlanma sonrası geri yükleme gerçekten çalışıyor.
  - **TEST VERİSİ:** yazılan test anı ve bildirimler silindi (kullanıcı hesapları korundu); geçici betik/çıktı dosyaları temizlendi. `docs/ILERLEME.md` "tekrar etmeyin" bölümüne 5 kalıcı not eklendi.

- **2026-10-04 — BELLEK + SORU ARACI HATA AYIKLAMA.** Kullanıcı: "soru aracı ve hafıza düzgün çalışmıyor", "güncelledim diyor ama hafıza değişmiyor".
  - **Doğrulama:** `go build/vet/test ./...` yeşil; sunucu canlı, 4 memory tool'u etkin. Sorun çalışma zamanındaydı. Canlı WS tanı aracı: `frontend/tools/dbg-mem.mjs` (`FIKO_PORT`, izole `dbgmem` kullanıcısı, sonda temizler).
  - **Hata 1 (düz metin çağrı):** qwen2.5:7b tool çağrısını sohbet metni olarak yazıyordu (`memory.ask {...}`) → çağrı çalışmıyor, kart yok, balonda ham metin. Çözüm `agent/textcall.go` (`parseTextToolCall` + `callSniffer`): çağrıya benzeyen başlangıç akıtılmaz, sonda çağrıya çevrilir; yalnız o turda sunulan tool adları kabul edilir. Canlıda TETİKLENMEDİ (model o koşuda doğru çağırdı), yalnız birim testli.
  - **Hata 2 (çağrı kaybı):** `ollama/tools.go` çağrıları ada göre haritada topluyordu → aynı turda aynı tool iki kez çağrılınca biri kayboluyordu. Artık sıralı liste, yalnız birebir aynı çağrı tekilleşir.
  - **Hata 3 ("güncelledim" yalanı):** elle yazılmış (OriginUser) kayıt otomatik yazmayla ezilmez, `Add` eskiyi `unchanged` döner; ama tool çıktısına İSTENEN yeni metni yazıyordu → model "güncelledim" diyordu. Çözüm `memory/tools.go`: `writeResult` depodaki gerçek metni döner, değişmediyse `blocked`; `finishWrite` bu durumda onay kartını SUNUCU açar (`asked`), model `memory.ask`'ı çağırmak zorunda değil. Koruma kuralı DEĞİŞMEDİ (karar kullanıcıda).
  - **Açık:** (1) memory.ask'ı model kendiliğinden çağırmıyor (7B); (2) otomatik öğrenme çöp anı yazabiliyor ("Kullanıcının adı ne."); (3) model anı prompt'ta olsa da "hafızamda bulamadım" diyebiliyor; (4) düzeltmeler çalışan sunucuda yok, yeniden derleme gerek; (5) kart akışı tarayıcıda elle doğrulanmadı.

- **2026-10-03 (yeni oturum; numara kayıp — 22'den sonra en az bir oturum günlüksüz kalmış) — NOT UZLAŞTIRMA + P10 BAĞLAMA.** Kullanıcı: "kaldığımız yerden devam".
  - **Tarama bulgusu:** bu dosya kodun gerisindeydi. Kodda ZATEN VAR ama notlarda yoktu: P9 (workflow motoru, REST, Mongo, Akışlar paneli), UI dilimi 2 (sidebar çekmecesi, yeniden adlandırma, sohbet arama, kod renklendirme `highlight.ts`, boş ekran örnek istemleri `(suggest)`), P10 bellek çekirdeği (`internal/memory`, `mongostore/memory_repo.go`, index'ler). Protokol gereği **KOD DOĞRUDUR**: P9 `[x]`, P10 `[~]` yapıldı.
  - **Ne YAPILMAMIŞTI:** bellek `main.go`'ya bağlı değildi, `/api/memories` yoktu, ajan her turda getirmiyor/öğrenmiyordu → bu oturumda yazıldı (ayrıntı: P10 maddeleri).
  - **Tasarım kararları:** (1) Öğrenme **yalnızca `complete` turdan** ve **kullanıcı mesajından** (asistan cevabı verilmez: model kendi uydurmasını "kullanıcı gerçeği" diye kaydetmesin). (2) Getirme bilgi tabanıyla paralel; ikisi de sorgu embedding'i üretiyor. (3) Anilar prompt'a "kesin gerçek" değil "bilinenler" diye girer. (4) "Beni unut" `?confirm=true` ister. (5) Anı içeriği audit/log'a YAZILMAZ, yalnızca kimlik/sayı. (6) `MEMORY_ENABLED=false` ile tümü kapanır (`Deps.Memory` nil → 503).
  - **AÇIK Rƒ∞SK (canlıda bak):** Öğrenme, sohbet modeliyle ek bir `Generate` çağrısıdır. 20. oturumda `30b` modelin 1,1 token/sn olduğu ve Ollama+TTS+STT'nin VRAM için yarıştığı ölçüldü → çıkarım bir sonraki mesajı geciktirebilir. Hafifletme: `LooksMemorable` kapısı + `MEMORY_LEARN_MODEL` (küçük model) + `MEMORY_AUTO_LEARN=false`. Canlı süreyi ölç.
  - **Doğrulama durumu:** bu oturumda SADECE dosya okuma/yazma aracı vardı; `go build`/`go test`/`ng test` ÇALIŞTIRILAMADI. Yazılan her şey okuma yoluyla karşılaştırıldı (imzalar, importlar, gofmt hizası) ama **derlenmiş sayılmaz**.
  - **Sonraki adım:** `go build ./... ; go vet ./... ; go test ./... -count=3` → sonra Hafıza paneli (frontend) → `docs/API.md` bellek+akış bölümleri.

- **2026-10-03 (22. oturum) — MONGO `$vectorSearch` (P8).** Kullanıcı: "mongo vector search kullanalım, Docker'daki ve kullanıcı testlerini atla, hepsini kodla".
  - **Tasarım:** `Repository` arayüzü DEĞİŞMEDİ. İsteğe bağlı `knowledge.VectorSearcher` (llm.ToolProvider ile aynı desen); Mongo deposu uygular, bellek deposu uygulamaz. `Service.Search` önce vektör yolunu dener, **hazır değil / hata / mongot yok** durumunda eski Go tarafı taramaya (`scoreByScan`) düşer → `$vectorSearch` yokken davranış birebir aynı.
  - **Skor tutarlılığı:** `$vectorSearch` kosinüs skoru `(1+cos)/2`; `similarityFromScore` bunu Go'daki `cosine()` ölçeğine çevirir. Böylece `knowledgeMinScore=0.35` kalibrasyonu ve `MinScore` iki yolda aynı anlama gelir.
  - **İzolasyon:** `userId` + `embedModel` HER sorguda `$vectorSearch` ön süzgecinde (sonradan değil); `userId` index'te `filter` alanı. Boş `UserID` Mongo'ya gitmeden boş döner.
  - **Hibrit farkı (bilinçli):** anahtar kelime skoru yalnızca vektör havuzundaki (limit×4, en az 50, en çok 200) adaylara + vektörsüz parçalara (`UnembeddedChunks`) uygulanır. Havuz dışında kalan salt-sözcük eşleşmesi bulunmaz; tam tarama bulurdu.
  - **Index:** `kb_chunk_vector`, boyut açılışta embedding sondasıyla ölçülür (modele göre değişir); boyut değişirse `UpdateOne` ile güncellenir (eski boyutlu vektörler için `Reindex(force)` gerekir). Kurulum + `queryable` bekleme ARKA PLANDA; devre kesici gerçek hatadan sonra 30 sn `$vectorSearch` denemez.
  - **Yapılmadı (bilinçli):** docker-compose/mongot kurulumu ve canlı mongot testi (kullanıcı atladı). Index'in replikasyon gecikmesi sırasında yeni embed edilen parça vektör sonuçlarında geçici görünmeyebilir.
  - **Doğrulama:** `go build ./...`, `go vet ./...`, `go test ./... -count=1` yeşil; yeni testler `-count=3` yeşil. `gofmt -l` yalnızca eskiden kalma `knowledge/contract.go`'yu listeliyor (bu oturumda dokunulmadı).
  - **Sonraki adım:** mongot'lu bir Mongo'da `KNOWLEDGE_VECTOR_SEARCH=on` ile açılıp log'ta `MongoDB $vectorSearch ETKİN` görülmeli; sonra aynı sorgu `off` ile karşılaştırılıp skor farkı bakılmalı.

- **2026-10-03 (21. oturum) — ARAYÜZ İYİLEŞTİRME, 1. dilim (TTS ölçümü bilinçli ertelendi).**
  - **Markdown:** `core/markdown.ts` (bağımlılıksız; önce kaçışlar, yalnızca http(s) bağlantı; kod bloğu — kapanmamış olanı da —, satır içi kod, kalın/italik, başlık, liste, alıntı) + `markdown.pipe.ts`. Yalnızca **asistan** balonu işlenir; kullanıcı metni düz kalır. 11 test.
  - **Mesaj listesi:** akışta **otomatik kaydırma** (kullanıcı yukarı çıktıysa çekmez, "↓ en alta git" düğmesi çıkar; konuşma değişince/kullanıcı gönderince her zaman alta iner), kod bloğunda **kopyala**, mesaj başına **kopyala**. `message-list.spec.ts` 6 test (render, XSS, pano, akışta düğme yok).
  - **Composer:** textarea yazdıkça büyür (180 px'e kadar), gönderince tek satıra döner ve odak geri gelir.
  - **Doğrulama:** `ng test` 13 dosya **177/177**, `ng build` uyarısız. Tarayıcıda elle bakılmadı.
  - **Sonraki UI adayları:** dar ekranda sidebar çekmecesi (şu an gizli, yalnızca ⚙ kalıyor), konuşma yeniden adlandırma/arama, "yeniden üret", boş ekranda örnek istemler, kod renklendirme, orb'u küçültme.
  - **Ertelenen:** TTS/`bench-rt` tam ölçümü (VRAM boşaltılıp alınacaktı) — kullanıcı şimdilik bıraktı.

- **2026-10-03 (20. oturum) — PERFORMANS OPTİMİZASYONU.** Ölçüm araçları eklendi (`frontend/tools/bench-rt.mjs`, `dbg-ws.mjs`): TTFT, token/sn, ilk cümle/ses gecikmesi.
  - **Ollama:** `keep_alive=30m` (model boşaltılmıyor → sohbet arası 20-60 sn yükleme beklemesi bitti), `num_ctx` tavanı 8192 (karttan 131072 geliyordu, KV cache VRAM'i yiyordu), bağlantı havuzu (MaxIdleConnsPerHost 2→64), `num_gpu/num_batch`.
  - **Embedding `num_ctx=512`:** kart bağlamı 40960 yüzünden model **12 GB** VRAM tutuyordu → 5,1 GB.
  - **Akışlı TTS:** ses artık `text.final`'ı beklemiyor; cümle metin akışı sırasında kuyruğa giriyor (`assistant.thinking`'de kuyruk açılır, `feedSpeech` cümle sonu bulunca alır, `finishSpeech` kalanı boşaltır). Tek goroutine seri üretir; `stopSpeaking` kuyruğu kapatıp bekler. **3 test eklendi**: akış sırasında gönderim, noktalamasız son cümle, "3.14" bölünmemesi.
  - **Frontend:** delta'lar `requestAnimationFrame`'de toplu uygulanıyor (yüzlerce tam liste kopyası yerine tek); base64 dönüşümü bloklu; ses kuyruğu sınırlı.
  - **Skill embedding LRU önbelleği** (TTL 10 dk, 512 kayıt; `SetEmbedder` değişince temizlenir, `Reindex(force)` atlar). 4 test eklendi.
  - **TTS sunucusu:** TF32 + cudnn.benchmark (kıyaslama aracında zaten vardı, sunucuda yoktu), ilk cümle kısa parça (110 kr), `--compile` (CUDA graph) bayrağı — Triton yoksa **sessizce eager'a düşüyor** (ilk denemede her istek 500 veriyordu).
  - **STT:** `cuda/float16` + otomatik düşüş, `condition_on_previous_text=False` (halüsinasyon), TR `initial_prompt`. Varsayılan **CPU/int8** yapıldı (GPU çakışması).
  - **`DefaultMaxChars` 500→160** (gerçek zamanlı: 500 kr'lik cümle ~25 sn sürüyordu).
  - **Ölçülen:** TTFT **12,1 sn → 382 ms** (`keep_alive`). TF32 ile RTF **1,92 → 1,53**. STT CUDA/float16'da 1,0 sn'de yüklendi.
  - **Çevresel sorun:** Ollama+TTS+STT aynı 4090'ı kullanınca motorlar birbirini kovuyor — tek cümle TTS 1,6 sn yerine **131 sn** (RTF 30). `num_ctx` tavanları + embedding penceresi ile çözüldü. `30b` model 1,1 token/sn ile gerçek zamanlı **kullanılamaz** (180 sn zaman aşımı); `qwen2.5:7b` **140,9 token/sn**. Kullanıcı kararı: model UI'dan seçilecek, kod değişikliği yapılmayacak.
  - **Bekleyen:** VRAM boşaltılarak tam `bench-rt` ölçümü alınıp buraya yazılacak.
- **2026-10-03 (19. oturum) — SES MOTORLARI KURULDU; `start-all.bat` hazır.** STT: faster-whisper + `tools/stt_server.py` (kütüphaneye OpenAI-uyumlu uç yazıldı), model `faster-whisper-small`. TTS: piper + `tr_TR-dfki-medium.onnx`. **TAM ZİNCİR CANLI TESTİ GEÇTİ:** WAV → tanındı → Ollama yanıtladı → 4 cümle seslendirildi. `.gitignore`'a `models/` eklendi (521 MB).
  - **Çıkan 4 gerçek sorun:** (1) Piper 1.8 uç adı `/synthesize` (1.2'de `/api/tts`) → sırayla dene, 404 dışı hatada tekrar etme. (2) Multipart ayrıştırma: gövde olduğu gibi diske yazılıyordu → sınır işaretlerinden içerik ayrıştırıldı. (3) Windows dosya kilidi (PyAV) → `safe_unlink()` kilitli dosyayı bırakır. (4) Zorlanan dil tuzağı: `language=tr` başka dilde **boş metin** döndürüyordu → varsayılan otomatik algılama.
- **2026-10-02 (18. oturum) — Panel bileşen testleri; İKİ GERÇEK HATA.** Bulunan: (1) izin kutusunda çoklu değişiklik kayboluyordu (`allowed` kilidi eksikti), (2) `skill.store.validate` sunucu alan hatalarını yutuyordu. İkisi düzeltildi. Aynı oturumda Faz 4b′ (uzak tool'lar), Faz 5b (kalıcı execution tracking) tamamlandı.
- **2026-10-02 (17. oturum) — Faz 5a** Agent tool çağırma döngüsü tamamlandı, canlı doğrulandı.
- **2026-10-02 (16. oturum) — Faz 4b** Tool arayüzü tamamlandı.
- **2026-10-02 (15. oturum) — Faz 4** Tool Registry/Executor/Permission backend tamamlandı.
- **2026-10-02 (14. oturum) — Frontend Skill ekranı** yapıldı (kod tamam, elle doğrulama bekliyor).
- **2026-10-02 (13. oturum) — Faz 3b** embedding + vektör arama tamamlandı.
- **2026-10-02 (12. oturum) — Faz 3a** Skill Registry (depo + REST) tamamlandı.
- **2026-10-02 (10. oturum) — Küçük testler + settings + audit** tamamlandı. **Flaky test avlandı:** `TestConversationIsolation` Fiber `app.Test()` havuz sorunu yüzünden kararsızdı → bağımsız kopya alındı.
- **2026-10-02 (8. oturum) — Dokümantasyon** tamamlandı (kök README, API.md, MIMARI.md).
- **2026-10-02 —** PROJE.MD okundu, `fiko-ai/` tarandı, bu takip dosyası oluşturuldu.
- **İki skill aynı tool'a bağlıysa ikincisi elenir** (`selectSkills`): prompt şişmesin diye.
- Conversation şemasına Skill/Tool/Context alanları baştan eklendi (migrasyon gerekmesin) — **dokunma**.
- Event bus yayıncıyı bloklamaz; kuyruk dolarsa olay düşer (bilinçli tasarım).

**Go / Fiber tuzakları (tekrar etmeyin)**
- Go 1.23.2 kurulu. Fiber **v2.52.6** + `gofiber/contrib/websocket` **v1.3.3** (v3/güncel sürümler Go ≥1.25 ister). `klauspost/compress` **v1.17.9'a sabit** (v1.20.x Go 1.25 ister). `go mod tidy`'yi daima `$env:GOTOOLCHAIN='local'` ile çalıştır; yoksa go.mod `go 1.25`'e çıkar ve go1.26.8 toolchain iner. (Bir keresinde `compress@v1.17.9` mod cache'te yarım çıkmıştı — yalnızca `testdata`; klasör + `cache\download\...\v1.17.9.zip/.ziphash` silinip yeniden indirildi.)
- Fiber v2: `*fiber.App` üzerinde **`Locals()` yoktur** (yalnızca `*fiber.Ctx`'te). `cors.Config.AllowOrigins` **string**'dir (virgülle ayrılmış), `[]string` değil. `fiber.ErrServerClosed` **yoktur** — kapanışta `http.ErrServerClosed` döner.
- **Kritik: Fiber `Use(path, kontrol)` + `Get(path, websocket.New(...))` WS'i bozar.** `IsWebSocketUpgrade(c)` her istekte 426 döner, `/ws` hiç bağlanmaz. Çözüm: kontrol ve route **tek `Use(path, ...)` içinde**; handler doğrudan `websocket.New(...)(c)`. Bu hata ancak **gerçek el sıkışma testiyle** yakalanır (426 testi geçiyordu) → `TestWSUpgradeHandshake` eklendi (gerçek `net.Listen` + `fasthttp/websocket.Dialer`).

**REST / protokol sözleşmesi**
- Hata gövdesi WS ile aynı: `{"error":{"code","message"}}`; `not_found`/`unauthorized` eklendi. Mesaj listesi **son N**'dir.
- `X-Fiko-User` çok kullanıcılı denemeyi sağlar; WS ve REST **aynı** çözümleyiciyi kullanır (`s.resolveUserID`). `conversation.Service.SetTitle` create gövdesindeki `title` için eklendi.
- **WS istemcisi sunucu `Ping`'ini göremez** (tarayıcı pong'u otomatik cevaplar, göstermez) → **uygulama düzeyi heartbeat**: istemci `{"type":"ping"}` yollar, `pong` gelmezse bağlantı ölmüş sayılıp kapatılır.
- **Konuşma kimliği KAREDE gelir, payload'da değil.** `Inbound.ConversationID` güvenilir yer; ses işleyicisi payload'dan okuyunca "conversationId gerekli" ile düşer.

**Ortam tuzakları (bu makine)**
- **PowerShell:** `go test/build 2>&1 | Out-String` hata çıktısını yutuyor (NativeCommandError). Çözüm: `cmd /c "... go test ./... 2>&1" | Select-String -Pattern 'FAIL|^ok |\.go:[0-9]+'`. `cmd /c` ortam değişkenlerini de basıyor; filtrelemeden okuma.
- **Arka planda çalışan istemci testi:** `ng test` ~35 s; tek komutta beklemek 30 sn zaman aşımına takılıyor. Desen: `Start-Process cmd /c "npx ng test > t.log"`, sonra `Start-Sleep` + `t.log` süz.
- **npm:** kullanıcı `.npmrc`'de `omit=optional` → Angular native paketleri kurulmaz. Proje `.npmrc`'si `include=optional` ile geçersiz kılar. `@angular/build` kendi `sass-embedded`'ını taşır; kökte ayrıca kurmak sürüm çakışması yaratır.
- **Edit aracı:** `insert_line` satır sayısı kaydıkça fonksiyon gövdesinin ortasına ekleme yapabiliyor ("expected '(', found TestX"). Ekleme sonrası mutlaka `go build`/`go test` çalıştır; şüphede `gofmt -l .` + satır aralığı oku.

## KULLANICI PROFİLLERİ (persona) — yönetici davranış tanımı

**Ne yapar?** Yönetici, "Proje Yöneticisi" gibi bir **profil** yazar ve onu
bir veya birden çok kullanıcıya atar. Atanmış kullanıcıyla konuşulduğunda profil
kuralları sistem istemine eklenir; yapay zekâ o kurallara uyar:

> Profil: Proje Yöneticisi — Bu kişi proje yöneticisidir.
> Davranış: Proje eklerken ad, sorumlu, başlangıç ve bitiş tarihi, bütçe ve açıklamayı eksiksiz sor; eksik alan varsa kaydetmeden önce uyar.

**Neden şablon + atama ayrı?** Aynı profili 5 kişiye atarsınız; metni bir kez
düzeltirsiniz, hepsi güncellenir. "Not" alanı ayrıdır: profil metnini değiştirmeden
yalnız o gruba ince ayar verilir.

### Dosyalar
| Dosya | Görev |
|---|---|
| `backend/internal/persona/model.go` | Profil tipi, sınırlar, doğrulama, depo arayüzü |
| `backend/internal/persona/service.go` | İş kuralları; `Active` **hata döndürmez** |
| `backend/internal/persona/memstore.go` | Bellek içi depo (test + MONGO kapalı) |
| `backend/internal/storage/mongostore/persona_repo.go` | Mongo deposu + indexler |
| `backend/internal/prompt/persona.go` | Profili istem bölümüne çevirir |
| `backend/internal/agent/persona.go` | `PersonaSource` arayüzü, `SetPersonas` |
| `backend/internal/api/personas.go` | Yönetici REST uçları |
| `cmd/server/persona.go` | persona → agent köprüsü (notify bridge deseni) |
| `frontend/src/app/core/persona.logic.ts` | Saf mantık (doğrulama, temizleme, dirty) |
| `frontend/src/app/features/admin/personas-panel.*` | Yönetici paneli |

### Uçlar (yalnız yönetici)
`GET/POST /api/admin/personas`, `PUT/DELETE /api/admin/personas/:id`
- Yetkisiz → **404** (bilinçli: `adminOnly` varlık sızdırmaz)
- Doğrulama → **400** + alan bazlı `{field,message}`
- Özellik kapalıysa → **503**

### Güvenlik kararları
1. **Sıra:** Profil, güvenlik kurallarından SONRA gelir → profil "veri uydurma"
   kuralını ezemez (test: `TestPersonas_GuvenlikKurallariProfildenOnce`).
2. **İzolasyon:** Profil yalnız atandığı kullanıcının istemine girer
   (`TestAgent_ProfilSadeceO_kullaniciyaGirer`).
3. **Sınırlar:** Ad 80, rol 200, talimat 4000, not 1000 karakter (istem şişmez).
4. **Hata yutmama:** Depo hatası sohbeti düşürmez; profil kuralları eklenmez.
5. **Yetki tek yerde:** Arayüz yalnız yöneticiye düğme gösterir; asıl koruma sunucuda.

### Doğrulama (2026-10-05)
- `go build/vet/test ./...` → **27 paket yeşil, 0 FAIL** (Mongo testleri
  `MONGO_TEST_URI` ile canlı `fiko_ai` veritabanında da koştu).
- Frontend: `tsc` (app+spec) temiz, `npx tsx checks/persona.logic.check.ts`
  → **37/37**, `ng build` → hatasız.
- Canlı API: giriş → profil oluştur (201) → güncelle (200) → sil (204) →
  tekrar sil (404). Doğrulama hatası alan bazlı ve Türkçe.

### Gerçek tarayıcı doğrulaması (CDP, ek paket yok)
| Araç | Kapsam | Sonuç |
|---|---|---|
| `tools/personas-ui.mjs` | Yönetici paneli: aç, doğrula, yaz, ata, kaydet, düzenle, sil | **21/21** |
| `tools/persona-chat.mjs` | Profil **gerçekten davranışı değiştiriyor mu** | **5/5** |

`persona-chat.mjs` sonuç hattını kanıtlar. Mert'e "Projeye yeni bir proje eklemek
istiyorum." yazıldı; model profildeki kuralı birebir uyguladı:

> Lütfen şu alanları eksiksiz belirtin: **Proje Adı / Sorumlu Kişi /
> Başlangıç Tarihi / Planlanan Bitiş Tarihi / Bütçe / Açıklama**  → 5/5 alan

**Bulunan ve düzeltilen gerçek hatalar**
1. `ng serve` bayat bundle sunuyordu (yeni bileşen derlenmemiş) → yeniden başlatıldı.
   *Sonraki oturumlarda önce `ng serve` yeniden başlatılmalı.*
2. Şablonda `[maxlength]` özellik bağlama geçersiz (`NG8002`) → sabit değere çevrildi.
3. Teşhis aracında `-password` dalı erken çıkışta hiç çalışmıyordu → tek
   argüman taramasında birleştirildi (aynı hata `-delete`'de de vardı).

### Notlar
- `backend/tools/*.go` teşhis araçlarıdır; `//go:build ignore` ile üretime girmez.
  `promote_admin.go`: kullanıcı listeler, `-promote` (yönetici yap),
  `-password <k> <yeni>` (parola sıfırla), `-delete <k>` (hesap sil).
- Profil kavramı **tool iznini, veri erişimini veya güvenlik kurallarını değiştirmez**;
  yalnız davranış/üslup yönlendirmesidir. Arayüz bunu açıkça yazar.
- Test sonrası geçici profil ve `patron*` hesapları silindi; veritabanı eski
  durumuna döndü (admin, ayse, mert).

## PHASE 1 — Dokümantasyon
- [x] `docs/API.md` — REST sözleşmesi, hata kodları, WS akış örneği, çalıştırma
- [x] `README.md` (kök) — hızlı başlangıç, test komutları, proje yapısı, env tablosu
- [x] `docs/MIMARI.md` — katman diyagramı, mesajın yolculuğu, kesinti/kapanış, depolama, protokol, kararlar, test stratejisi
- [x] `internal/api/ws/session.go` — Hub + session (Conn arayüzü, read/write döngüsü, ping/pong, giden kuyruk backpressure, sahiplik kontrollü cancel, panic recovery, drain ile Close) + 13 test
- [x] `internal/api/ws/fiber.go` — `fiberConn` (metin çerçeveleri, binary yok sayılır, ReadLimit, nazik 1000 kapanış) + `Mount` (upgrade→426, UserResolver→401, origin listesi); `TestWSUpgradeHandshake` (gerçek `net.Listen`)
- [x] `internal/api/ws/session_test.go` — 13 test: ping→pong, geçersiz JSON/unknown tür, text.message tam akışı, payload'sız mesaj, bilinmeyen konuşma, cancel sahipliği, disconnect→iptal, ping düzenli/pong uzatır, yazma hatası, yavaş istemci, eşzamanlılık sınırı, Hub.Close
- [x] `cmd/server/main.go` — DI (elle), slog (text/json), sinyal kök bağlamı, Ollama kontrolü, belgelenmiş kapanış sırası (agent→hub→http) + 2 test
- [x] `backend/.env.example` — tüm ortam değişkenleri açıklamalı