🤖 AI Workflow Sistem Analizi - Tenant 2 (iXTİF)

📅 Tarih: 2025-11-22 | 🎯 Konu: FlowExecutor, Node Sistemi, Tenant-Specific Logic | 👤 Sistem: Endüstriyel Ekipman (Forklift/Transpalet)

📋 İçindekiler

1. Workflow Akış Sistemi

Akış Mimarisi

FlowExecutor (Modules/AI/app/Services/Workflow/FlowExecutor.php) ana orchestrator'dır. Akış, JSON tabanlı flow tanımı ile çalışır.

START (Welcome Node) ↓ CATEGORY DETECTION ↓ PRODUCT SEARCH (HybridSearch) ↓ STOCK SORTER ↓ CONTEXT BUILDER ↓ AI RESPONSE (Claude/OpenAI) ↓ MESSAGE SAVER ↓ END

Akış Özellikleri

Tenant-Aware Paralel Execution Cache-Enabled JSON-Based
Özellik Açıklama
Tenant Awareness Her node, tenancy() konteksti içinde çalışır. Tenant-specific node'lar otomatik yüklenir.
Node Chaining Edge tanımları üzerinden, node'dan node'a sırayla geçiş. Conditional branching destekli.
Context Passing Her node, context array'i alır ve extend eder. Sonraki node'a ek bilgiler aktarılır.
Parallel Groups Birden fazla node paralel çalışabilir (ParallelNodeExecutor). Sonuçlar merge edilir.
Caching Category detection ve history loading cache'lenir. ai_response ve product_search cache'lenmez.

Flow Tanımı (JSON)

{ "id": "ixtif-main-flow", "tenant_id": 2, "name": "iXTİF Endüstriyel Ürün Satış Akışı", "start_node": "welcome", "nodes": [ { "id": "welcome", "type": "welcome", "config": {} }, { "id": "category_detection", "type": "category_detection", "config": {} }, { "id": "product_search", "type": "product_search", "config": { "search_limit": 50, "use_meilisearch": true } }, { "id": "stock_sorter", "type": "stock_sorter", "config": { "exclude_out_of_stock": false } }, { "id": "context_builder", "type": "context_builder", "config": {} }, { "id": "ai_response", "type": "ai_response", "config": { "stream": false, "provider": "anthropic", "max_tokens": 500, "temperature": 0.7 } }, { "id": "message_saver", "type": "message_saver", "config": {} }, { "id": "end", "type": "end", "config": {} } ], "edges": [ { "from": "welcome", "to": "category_detection" }, { "from": "category_detection", "to": "product_search" }, { "from": "product_search", "to": "stock_sorter" }, { "from": "stock_sorter", "to": "context_builder" }, { "from": "context_builder", "to": "ai_response" }, { "from": "ai_response", "to": "message_saver" }, { "from": "message_saver", "to": "end" } ] }

Akış Yürütme Adımları

  1. FlowExecutor::execute() çağrılır - flow tanımı ve initial context geçilir
  2. Parallel Groups keşfedilir - eğer varsa paralel node'lar tespit edilir
  3. Node'lar sırayla çalıştırılır:
    • NodeExecutor::execute() çağrılır
    • NodeFactory node instance'ı oluşturur
    • Node::execute() çalışır ve sonucu döndürür
    • Sonuç context'e merge edilir
  4. Sonraki node bulunur - edges'teki from/to ilişkisinden
  5. End node'a ulaşılır - akış tamamlanır

2. Node Türleri ve Fonksiyonları

WelcomeNode (Başlangıç)

Dosya: Modules/AI/app/Services/Workflow/Nodes/WelcomeNode.php

Basit pass-through node. Flow başlatma işlevi görür.

Giriş: Initial context Çıkış: Context (değişiklik yok)

CategoryDetectionNode (Kategori Tespiti)

Dosya: Modules/AI/app/Services/Workflow/Nodes/CategoryDetectionNode.php

Global olarak generic kategori tespiti yapılır, ama Tenant 2 için özel mantık yok. Tenant2ProductSearchService içinde real kategori tespiti yapılır.

Girdi İşlev Çıktı
user_message Fallback: Generic kategori tespiti (mostly null) detected_category: null (Tenant2 servisi override eder)

ProductSearchNode (Ürün Arama)

Dosya: Modules/AI/app/Services/Workflow/Nodes/ProductSearchNode.php

Tenant-specific arama servisi kullanır. Tenant 2 için Tenant2ProductSearchService otomatik yüklenir.

Girdi İşlev Çıktı
user_message 1. Tenant2ProductSearchService::search() çağrılır
2. HybridSearchService (Meilisearch + Vector) kullanılır
3. Yedek parça filtresi uygulanır (isSparePartRequest)
4. Ürün listesi döndürülür
products: Collection<ShopProduct>
products_found: int
detected_category: int|null
Önemli Mantık: Yedek Parça Filtreleme

Arama sonuçlarından yedek parça ürünleri filtreler. Temizleme kriterleri:

  • devirdaim, şamandıra, çatal, rulman, tekerlek, direksiyon...
  • geri ikaz, silindir, piston, pompa, filtre, balata, fren...
  • kablo, sensör, conta, kayış, zincir, mil, yatak, kaplin...
  • motor yedek, yedek parça, spare, aksesuar

Fakat: isSparePartRequest = true ise, yedek parça tekrar gösterilir.

StockSorterNode (Ürün Sıralama)

Dosya: Modules/AI/app/Services/Workflow/Nodes/StockSorterNode.php

Professionel 6-katmanlı sıralama sistemi.

Sıra Kriter Yön
🥇 1. Vitrin Ürünleri (show_on_homepage = 1) DESC (1 önce)
🥈 2. Stok Durumu (current_stock > 0) DESC (stoklu önce)
🥉 3. Kategori Sıraması (sort_order) ASC (küçük önce)
4. Fiyat Durumu (base_price > 0) DESC (fiyatlı önce)
5. Fiyat Değeri (base_price) ASC (ucuz önce)
Girdi: products (unsorted collection) Çıkış: products (sorted), high_stock_count, in_stock_count, with_price_count

ContextBuilderNode (Bağlam İnşası)

Dosya: Modules/AI/app/Services/Workflow/Nodes/ContextBuilderNode.php

Ürünleri Markdown formatında, AI'nin anlayacağı şekilde hazırlar.

Girdi İşlev Çıktı
products: Collection 1. USD → TRY conversion
2. Ürün başlığını temizle (2. Ton → 2 Ton)
3. Markdown formatında ürün listesi oluştur
4. Kategori etiketi ekle (<[KATEGORI]>)
5. Fiyat gösterimi (KDV hariç, sembol koruması)
product_context: Markdown string
products_found: int
## 📦 Mevcut Ürünler: ### İXTİF EPT20-2T Li-Ion Forklift - 📷 Görsel: https://... - **52.948 TL** ≈ $1.250 - [Ürünü İncele](/shop/ixtif-ept20-2t) (Diğer ürünler...)
Kritik Kurallar:
  • Fiyatsız ürünlerde FİYAT SATIRI GÖSTERILMEZ (duplicate prevention)
  • Stok bilgisi ASLA verilmez (istek gelmedi)
  • Başlık temizliği: "2. Ton" → "2 Ton"
  • USD fiyatları TRY'ye çevrilir (exchange_rate: 42.0 fallback)

AIResponseNode (AI Yanıtı Üretme)

Dosya: Modules/AI/app/Services/Workflow/Nodes/AIResponseNode.php (341 satır!)

En karmaşık node. Sistem prompt'u dinamik olarak oluşturur.

Sistem Prompt Oluşturma Aşamaları:

  1. Directive'den temel system prompt yükle (chatbot_system_prompt)
  2. Tenant2PromptService kurallarını ekle (Tenant 2 için özel)
  3. Universal Rules ekle (TÜM TENANTLAR için)
  4. Tenant 2 iXTİF Rules ekle (Endüstriyel ekipman spesifik)
  5. Ürün Bağlamı ekle (product_context - Markdown)
  6. Yapı kuralları ekle (format, markdown, emoji)

Ürün Varsa vs. Ürün Yoksa:

products_found > 0:
  • Belirsiz istek kontrol kuralları ekle
  • Ürün listeleri döndür
  • Format kuralları (markdown liste, emoji, link)
products_found = 0:
  • Welcome variations (random) kullan
  • Müşteri temsilcisi yönlendirmesi yap
  • İletişim bilgilerini ver (setting'den)
  • Hiç ürün uydurma!
// Tenant 2 prompt'u sistemine ekle if (in_array($tenantId, [2, 3])) { $tenant2Service = new Tenant2PromptService(); $tenantPrompt = implode("\n", $tenant2Service->buildPrompt()); $systemPrompt = $tenantPrompt . "\n\n" . $systemPrompt; }

AI Çağrısı

OpenAI (gpt-4.1-mini model kullanılıyor)

Parametre Değer
model gpt-4.1-mini
max_tokens 500 (directive'den değişebilir)
temperature 0.7
streaming false (default)

MessageSaverNode (Mesaj Kaydedici)

Dosya: Modules/AI/app/Services/Workflow/Nodes/MessageSaverNode.php

Placeholder node. Gerçek kaydetme, controller tarafından yapılır.

EndNode (Bitiş)

Flow sonu işareti.

3. Tenant 2 Özel Mantığı

Tenant 2 Özellikleri

  • Domain: ixtif.com & ixtif.com.tr (ID: 2 & 3)
  • Sektör: Endüstriyel ekipman (forklift, transpalet, reach truck, vb.)
  • Database: tenant_2_db (bağımsız)
  • Ürün Kategorileri: 6 ana kategori

Tenant2ProductSearchService (Ürün Arama)

Dosya: Modules/AI/app/Services/Tenant/Tenant2ProductSearchService.php (837 satır!)

Ana Fonksiyon: search()

public function search( string $userMessage, int $limit = 50, ?int $categoryId = null ): array

Kategori Haritalanması:

Kategori ID Adı Anahtar Kelimeler
1 Forklift forklift, fork lift, portif, akülü forklift, elektrikli forklift
2 Transpalet transpalet, trans palet, palet jack, pallet truck
3 İstif Makinesi istif makinesi, istif, stacker
4 Sipariş Toplama sipariş toplama, order picker, picking
5 Otonom Sistemler otonom, autonomous, agv, otomatik, robot
6 Reach Truck reach truck, reach, dar koridor

Yedek Parça Filtresi

Şu ürün adı anahtar kelimeler içeriyorsa yedek parça olarak işaretlenir:

devirdaim, şamandıra, çatal, rulman, tekerlek, direksiyon, geri ikaz, silindir, piston, pompa, filtre, balata, fren, kablo, sensör, conta, kayış, zincir, mil, yatak, kaplin, motor yedek, yedek parça, spare, aksesuar

Fakat: isSparePartRequest() = true ise, yedek parça gösterilir.

Tenant2PromptService (Özel Kurallar)

Dosya: Modules/AI/app/Services/Tenant/Tenant2PromptService.php (822 satır!)

Tenant 2 (iXTİF) için tüm AI davranış kurallarını içerir.

Ana Kurallar (buildPrompt() dizi)

  1. MEGA KRİTİK BELİRSİZ İSTEKTE SORU SOR!
    • "Transpalet istiyorum" → BELİRSİZ (tonnaj/tip yok)
    • "1.5 ton elektrikli transpalet" → BELİRLİ (tonnaj + tip var)
    • Belirsiz istekte: "Kaç ton?" + "Elektrikli mi tercih edersiniz?" sor
    • Bütçe SORMA!
  2. MEGA KRİTİK CONTEXT'TEKİ FİYATLARI KULLAN!
    • Context'te "52.948 TL" yazıyorsa → cevabında "52.948 TL" yaz (AYNEN!)
    • Asla fiyat uydurma!
    • Asla "Fiyat bilgisi için iletişime geçin" yazma (context'te fiyat varsa)
  3. ULTRA KRİTİK ÖNCEKİ KONUŞMAYA ATIF YAPMA!
    • "Önceki konuşmamızda..." → YASAK!
    • "Daha önce ... arıyordunuz" → YASAK!
    • "Hatırlıyorum..." → YASAK!
    • Her mesaj YENİ BAŞLANGIÇ! History sadece context için.
  4. SATIŞ TONU - Doğal ve Profesyonel
    • İNSAN gibi konuş, robot gibi değil!
    • "harika", "mükemmel" kullanmayı abartma
    • Doğal ifadeler: "İyi bir seçenek", "Popüler model", "Çok tercih ediliyor"
    • DAIMA "SİZ" kullan (asla "sen")
  5. HİTAP - SAMİMİ VE SICAK
    • Emoji AZALT (mesaj başına 1-2 yeterli)
    • Profesyonel ama samimi
  6. KATEGORİ HAFIZASI
    • Kullanıcı "transpalet" dedi → konuşma boyunca transpalet kategorisinde kal
    • "Başka ne var?" → AYNI kategoriden diğer ürünler göster
    • Kategori ASLA karışma! (transpalet ≠ forklift)
  7. ÜRÜN ÖNCELİKLENDİRME
    • YEDEK PARÇA GÖSTERME! (çatal, tekerlek, rulman vb.)
    • Homepage ürünleri (show_on_homepage=1) önce
    • Stok durumuna göre
    • Kategori sort_order'a göre
  8. FİYAT VE STOK POLİTİKASI
    • Fiyatsız ürün (base_price=0): Ürünü göster ama "Müşteri temsilcilerimizle iletişime geçerek teklif alabilirsiniz"
    • Stoksuz ürün (current_stock=0): Ürünü göster ama "Tedarik süresi için iletişime geçin"
    • Hiçbir ürün gizleme!
    • "Stokta yok", "Tükendi" ASLA DEME!
  9. TELEFON TOPLAMA STRATEJİSİ
    • İletişim sorusu gelirse → DİREKT numara ver
    • Ürün sorusu gelirse → Önce ürün göster, sonra telefon iste
    • Pazarlık varsa → Müşteri temsilcisi yönlendir
  10. MARKDOWN FORMAT - ZORUNLU!
    • Soru sorarken Markdown liste (`-`) kullan
    • Her soru AYRI SATIRDA
    • Ürün başlıkları (###) öncesi/sonrası BOŞ SATIR
    • Fiyat ASLA özellik listesinde (AYRI PARAGRAF)

Bilgi Bankası ve Öğrenme

FileLearningService.buildLearningContext() kullanıcı tercihlerini ekledi.

Örneğin: "F4 1.5 Ton transpalet" en çok satılan ürün ise, arama sonuçlarında ilk sıraya koyul.

4. Arama Sistemi (HybridSearch)

HybridSearchService Mimarisi

Dosya: app/Services/AI/HybridSearchService.php

İki arama tekniğini birleştirerek en iyi sonuçlar sunar.

İki Tabaka Arama:

Arama Tipi Motor Ağırlık Özellikleri
Keyword Search Meilisearch 70% Hızlı, typo-tolerant, exact match, stemming
Semantic Search Vector DB (embeddings) 30% Anlamsal eşleşme, benzer ürünler bulma

Arama Adımları:

1. Query'yi synonym'larla genişlet "elektrikli" → "elektrikli li-ion akülü lityum bataryalı" 2. Meilisearch (keyword) → top 50 sonuç - is_active = true filtresi - Kategori filtresi (opsiyonel) 3. Vector search (semantic) → top 50 sonuç - Embeddings'ten benzer ürünler 4. Hybrid Score Hesapla - Keyword score: position-based (first=1.0, last=0) - Semantic score: position-based - Hybrid = (keyword*0.7) + (semantic*0.3) 5. Sıralama Kuralları (Önem Sırasına Göre) 1. show_on_homepage = 1 (vitrin ürünleri) 2. sort_order (kategori içi sıra) 3. current_stock > 0 (stok durumu) 4. base_price > 0 (fiyat durumu) 5. Hybrid score (arama uygunluğu) 6. Kategori Filtresi - Kategori belirtilmişse, sadece o kategorideki ürünler 7. Limit Uygulanması - Varsayılan: 50, ProductSearchNode'dan geçirilen değer

Meilisearch Konfigürasyonu

Index Name: shop_products_tenant_2 (Tenant 2 için) Filter: is_active = true AND category_id = {categoryId} Limit: 50 (initial search) Typo Tolerance: Otomatik - "transpalet", "trans palet", "transpalat" hepsi bulunur Stemming: Türkçe desteği - "elektrikli" → "elektrik" bulur

Arama Akışı (ProductSearchNode'dan)

ProductSearchNode::execute() ↓ Tenant2ProductSearchService::search() ↓ detectCategoryId($userMessage) ↓ HybridSearchService::search() ↓ isSparePartRequest() KONTROL ↓ Yedek Parça Filtreleme ↓ Ürünleri Döndür

Örnek Senaryo

Kullanıcı: "1.5 ton elektrikli transpalet istiyorum" 1. Category Detection: - "transpalet" bulundu → Category ID = 2 2. HybridSearchService::search(): - Query: "1.5 ton elektrikli transpalet" - Synonym genişletme: "... li-ion akülü lityum ..." - Meilisearch: category_id=2 ile ara - Vector: Semantik ara - Hybrid score ile sırala 3. Spare Part Filter: - isSparePartRequest() = false (yedek parça söylenmedi) - Yedek parça ürünleri filtrele 4. Sonuç: [ EPL153 1.5T Li-Ion Transpalet, F4 1.5T Li-Ion Transpalet, TX1500 1.5T Elektrikli Transpalet, ... ]

5. Bağlam İnşası (Context Building)

Context Flow

ProductSearchNode ↓ (products: Collection) StockSorterNode ↓ (products: sorted Collection) ContextBuilderNode ↓ (product_context: Markdown) AIResponseNode ↓ (AI reads product_context) Output: AI Response

ContextBuilderNode İşlemi

Adım İşlem Çıktı
1. Hazırlık Ürünleri Collection'a dönüştür $products = collect(...)
2. Currency USD → TRY çeviri (exchange_rate: 42.0) $priceInTRY = $basePrice * 42
3. Başlık Temizliği "2. Ton" → "2 Ton" preg_replace('/(\d+)\.\s+(Ton)/u', '$1 $2', $title)
4. Markdown Oluşturma Her ürün için Markdown format ### Ürün Adı\n- Özellik\n- Fiyat\n[Link]
5. Görsel Ekleme Spatie Media Library'den first image 📷 Görsel: {URL}
6. Fiyat Gösterimi Fiyatlı ürünlerde format: "52.948 TL ≈ $1.250" - **{price} {currency}** ≈ {original}
7. Link Ekleme Ürün slug'ından shop link - [Ürünü İncele](/shop/{slug})
## 📦 Mevcut Ürünler: ### İXTİF EPT20 - 2 Ton Li-Ion Forklift - 📷 Görsel: https://... - **52.948 TL** ≈ $1.250 - [Ürünü İncele](/shop/ixtif-ept20-2t) ### İXTİF F4 - 1.5 Ton Li-Ion Transpalet - 📷 Görsel: https://... - **38.200 TL** ≈ $909 - [Ürünü İncele](/shop/ixtif-f4-15t) (Fiyatsız ürün - fiyat satırı YOK!) ### İXTİF Reach Truck - 2.5 Ton - 📷 Görsel: https://... - [Ürünü İncele](/shop/ixtif-reach-truck-25t)

Kritik Kurallar

Fiyatsız Ürünler:

Ürün gösterilir, fiyat SATIRI ATLANIR. Nedeni: Context'te hiç fiyat satırı yoksa AI "Fiyat bilgisi için iletişime geçin" mesajı verir.

Stok Bilgisi:

ASLA verilmez. Stok durumu AI'nin belirsiz talep kontrolüne yardımcı olmaması için gizlenir.

Kategori Etiketi:

Meilisearch'ten gelen ürünlerin kategorisine göre [TRANSPALET], [FORKLIFT] vb. etiketi eklenir.

6. Kritik Karar Noktaları

1. Belirsiz İsteklerde Soru Sorma

Tetikleyiciler (BELİRSİZ):
  • "Transpalet istiyorum" (sadece kategori)
  • "Forklift var mı?" (sadece kategori)
  • "Reach truck modelleri hakkında bilgi" (sadece kategori)
Sonuç:

AI 1-2 temel soru sorar (Tonnaj + Elektrikli mi?). Hiç ürün göstermez.

Tetikleyiciler (BELİRLİ):
  • "1.5 ton elektrikli transpalet" (tonnaj + tip)
  • "2 ton Li-Ion forklift" (tonnaj + tip)
  • "En ucuz transpalet" (fiyat kriteri)
Sonuç:

AI hemen ürün listesi gösterir. Soru ASLA sorması.

Uyarı: Bu kontrol AIResponseNode'da yapılır. Context'te ürünler varsa bile, belirsiz istekte soru sorma kuralı devreye girer!

2. Yedek Parça Filtreleme

Kural: Varsayılan olarak yedek parça gösterilmez. Şu durumlarda gösterilir:
  • Kullanıcı "yedek parça" söyledi
  • Kullanıcı "çatal", "tekerlek", "rulman" vb. parça adı söyledi
Filtreleme Yeri:
  • Tenant2ProductSearchService::search() içinde
  • HybridSearchService'den gelen sonuçlara filtre uygulanır
Neden?

Müşteri "forklift istiyorum" dediğinde, çatal, rulman gibi parçalar gösterilmemeli. Confusing!

3. Fiyat Gösterimi Kuralları

Normal Ürün (base_price > 0):

Fiyat MUTLAKA gösterilir. Format: "- **52.948 TL** ≈ $1.250"

Fiyatsız Ürün (base_price = 0):

Context'te FİYAT SATIRI YOK. AI "Müşteri temsilcilerimizle iletişime geçerek teklif alabilirsiniz" der.

Stoksuz Ürün (current_stock = 0):

Context'te ürün gösterilir ama stok bilgisi YOK. AI "Tedarik süresi için iletişime geçin" der.

KDV Notasyonu:

ASLA "(KDV dahil)" yazılmaz. Tüm fiyatlar KDV HARİÇ.

Önemli: Tenant2PromptService::buildPrompt() içinde tekrar vurgulanıyor: "Context'teki fiyatları BİREBİR AYNEN kullan!"

4. Kategori Bellekleme

Kural: Konuşma boyunca kategori bellenmesi gerekir. Senaryo:
  • Kullanıcı: "Transpalet istiyorum"
  • AI: [Transpalet ürünleri gösterir]
  • Kullanıcı: "Başka ne var?"
  • ✅ Beklenen: TRANSPALET kategorisinden başka ürün göstermek
  • ❌ ASLA: Forklift göstermek
Nasıl Sağlanır?

Conversation history'deki mesajlar AIResponseNode'a geçilir. AI, önceki mesajlardan konteksti anlar ve AYNI kategoride kal.

Not: Bu Tenant2PromptService'de "KATEGORİ HAFIZASI - KRİTİK!" başlığı altında yazılıyor.

5. Telefon Toplama Stratejisi

Kural 1: İletişim Sorusu Gelirse

Kullanıcı "WhatsApp", "telefon", "numara", "iletişim" yazarsa → DİREKT numara ver! Ürün sorusu SORMA!

Kural 2: Ürün Sorusu Gelirse

Kullanıcı ürün arıyorsa → Önce ürün göster (MUTLAKA linkle!), sonra ilgilendiyse "Telefon numaranız?" sor.

Kural 3: Pazarlık Durumu

Kullanıcı "İndirim var mı?" derse → Müşteri temsilcisine yönlendir. "Size özel fiyat için telefon numaranızı alabilir miyim?"

Fallback:

Numara alamazsan → Bizim WhatsApp linkini ver: wa.me/{cleanWhatsapp}

Kritik: Telefon/WhatsApp numaraları settings'den gelir (hardcode yok!). AISettingsHelper::getContactInfo()

6. Conversation History Kullanımı

History Nereye Geçer?

AIResponseNode::prepareMessages() içinde, system prompt'tan sonra, user message'dan önce.

History Nasıl Filtreler?

Eğer şu anki aramalda ürün yoksa, eski ürün önerileri history'den çıkarılır (clean up).

KRITIK KURAL: Atıf Yapma!
  • ❌ "Önceki konuşmamızda ... arıyordunuz"
  • ❌ "Daha önce ..."
  • ❌ "Hatırlıyorum ..."
  • ✅ "Her mesaj YENİ BAŞLANGIÇ"
Neden?

Kullanıcı, önceki konuşmayı hatırlamayabilir. Karışıklık yaratır.

7. Bulunun Sorunlar ve Boşluklar

🔴 ISSUE 1: API Key Yönetimi (Debug Code)

Dosya: AIResponseNode.php (satır 239-245)

Sorun: API key'in environment'tan yüklenmesine dair debug logging var.

\Log::emergency('🔑 Loading API Key - FIXED', [ 'key_exists' => !empty($apiKey), 'key_length' => strlen($apiKey ?? ''), 'key_preview' => $apiKey ? substr($apiKey, 0, 15) . '...' : 'EMPTY', ... ]);

Etki: Production'da log spam. Security risk (API key preview).

Çözüm: Debug logging'i kaldır. Setting'den alınan API key kullanılmalı.

🔴 ISSUE 2: Temp Debug Dosyaları

Dosya: AIResponseNode.php (satır 279-284)

Sorun: AI messages'ı /tmp/ai_messages_debug.txt'ye yazılıyor.

file_put_contents('/tmp/ai_messages_debug.txt', date('Y-m-d H:i:s') . " - Total: " . count($fullMessages) . "\n" ... FILE_APPEND );

Etki: Production'da /tmp spam. Gizlilik riski.

Çözüm: Debug dosya yazımını kaldır. Log::info() kullan.

🟡 ISSUE 3: Parallal Execution (Kullanılmıyor)

Dosya: FlowExecutor.php (satır 57, 88-100)

Sorun: ParallelNodeExecutor var ama aktif değil. Flow'da parallel groups tanımlanmıyor.

Etki: Potansiyel performans artışı kaybediliyor. (ProductSearch + History loading paralel çalışabilir)

Çözüm: Flow JSON'da paralel node grupları tanımla.

🟡 ISSUE 4: Context Bağlamı Eksikliği

Dosya: ProductSearchNode.php, ContextBuilderNode.php

Sorun: Category label eklenmesine rağmen (satır 61-64, ContextBuilder), ürünlerin kategorisi AI'ye açık şekilde söylenmiyor.

Etki: AI, "TRANSPALET" + "FORKLIFT" kategorisinde ürünler mix'lediyse, önerileri optimize edemez.

Çözüm: AI prompt'una kategori context'i ekle. "[TRANSPALET] EPL153 transpalet" gibi.

🟡 ISSUE 5: HybridSearchService - Kategori Filtresi After Sorting

Dosya: HybridSearchService.php (satır 260-264)

Sorun: Semantic search, farklı kategoriden ürünler getiriyor olabilir. Kategori filtresi SONRADAN uygulanıyor.

// Kategori filtresi - SONRA uygulanıyor! if ($categoryId) { $topProducts = $topProducts->filter( function ($product) use ($categoryId) { return $product->category_id == $categoryId; } )->values(); }

Etki: İyi skorlanan ürünler silinebilir. Sonuç sayısı azalabilir.

Çözüm: Kategori filtresi BAŞTAN (Meilisearch AND clause) uygulanmalı, sonradan değil.

🟡 ISSUE 6: Tenant2PromptService - Çok Uzun (822 satır)

Dosya: Tenant2PromptService.php (ALL)

Sorun: Tüm kurallar bir dosyada. Bakım ve test zorlaşıyor.

Etki: Maintenance burden. Tekrar eden kurallar.

Çözüm: Kuralları kategorilere böl:

  • BelirsizIstek.php
  • FiyatStokPolitikasi.php
  • TelefonToplama.php
  • MarkdownFormat.php

🟡 ISSUE 7: Cache Stratejisi Eksik

Dosya: NodeExecutor.php (satır 132-167)

Sorun: ProductSearchNode cache'lenmesi DISABLED (satır 139). "Cache was causing wrong products" yorum var.

Etki: Performans kaybı. HybridSearch çalıştırılıyor her saat.

Çözüm: Cache key'i gözden geçir. user_message + tenant_id + timestamp(hour) olmalı.

🟡 ISSUE 8: Error Handling Eksikliği

Dosya: Tüm Node'lar

Sorun: Hata kontrolü minimal. Exception'lar throw edilmiyor, fallback'e geçiliyor.

Etki: Hata debugging zor. Silent failures.

Çözüm: Try-catch ile proper error handling ekle. User-friendly fallback mesajları sun.

🟡 ISSUE 9: Streaming Support (Aktif Değil)

Dosya: AIResponseNode.php (satır 164-178)

Sorun: Streaming konfigürasyonu var (stream: true), ama default false. Streaming logic'i test edilmemiş.

Etki: Real-time responses kullanılmıyor. UX gecikmiş hissediliyor.

Çözüm: Streaming'i test et ve default true yap.

🟡 ISSUE 10: Conversation History Cleanup İmperfect

Dosya: AIResponseNode.php (satır 620-633)

Sorun: Eski ürün önerileri "###" ve "**Fiyat:**" aranarak temizleniyor. Yanlış positive olabilir.

Etki: Meşru mesajlar silinebilir.

Çözüm: History'ye metadata flag ekle. "is_product_recommendation: true" gibi.

🟢 IMPROVEMENT 1: Learning System Integration

Dosya: Tenant2PromptService.php (satır 738-756)

Durum: FileLearningService.buildLearningContext() tercih edilen ürünleri AI'ye söylüyor.

Mevcut: System prompt'a ekleniyor (line 742-743)

Suggestion: Bu özelliği genişlet. Daha sophisticated ranking yapılabilir.

🟢 IMPROVEMENT 2: Knowledge Base Support

Dosya: Tenant2PromptService.php (satır 729)

Durum: AISettingsHelper::buildKnowledgeBasePrompt() sistema ekleniyor.

Potential: FAQ, teknik bilgiler sistem prompt'a eklenebilir.