📦 Shop Product AI Content System v3

📅 Tarih: 2025-11-27 (Final) | 🎯 Hedef: Sadece Yedek Parça + Variant Olmayan Ana Ürünler | ⚡ Strateji: Mevcut İçerik Kontrolü → Farklı Akış

🎯 ÜRÜN FİLTRELEME KURALLARI

⚠️ SADECE BU ÜRÜNLER İŞLENECEK

  • Kategori: Yedek Parça (category_id = 7 veya parent category = 7)
  • Variant: Ana ürün (parent_id IS NULL veya parent_id = 0)
  • Variant ürünler: İŞLENMEZ (child products skip edilir)
  • Forklift/Transpalet: İŞLENMEZ (sadece yedek parça!)
// Filtreleme sorgusu ShopProduct::where('category_id', 7) // Yedek Parça kategorisi ->orWhereHas('category', fn($q) => $q->where('parent_id', 7)) ->where(function($q) { $q->whereNull('parent_id') ->orWhere('parent_id', 0); }) ->get(); // Açıklama: // - category_id = 7: Direkt yedek parça kategorisinde // - parent category = 7: Alt kategoride ama yedek parçaya ait // - parent_id IS NULL: Ana ürün (variant değil)

DOĞRU HİYERARŞİ - KARAR AKIŞI

📊 Sistem Akış Şeması

BAŞLANGIÇ: Kullanıcı "Generate AI Content" butonuna tıklar
ADIM 1: Ürün filtreleme
  • Kategori = Yedek Parça mı? ✅/❌
  • Variant değil mi? (parent_id IS NULL) ✅/❌
  • Her ikisi de ✅ ise devam, değilse DURDUR
ADIM 2 (KRİTİK): Mevcut içerik kontrolü
$hasContent = !empty($product->body['tr']) && strlen($product->body['tr']) > 100; if ($hasContent) { // BRANCH A: Mevcut içerik VAR } else { // BRANCH B: Mevcut içerik YOK }

🟢 BRANCH A: Mevcut İçerik VAR

A1: Mevcut içeriği parse et
  • Teknik detayları çıkar (boyut, ağırlık, voltaj, malzeme)
  • Primary specs varsa al
  • Mevcut FAQ varsa al
A2: GPT-4 Prompt (Geliştirme Modu)
"IMPROVE and EXPAND this existing content: {$existingBody} EXISTING SPECS: {$extractedSpecs} RULES: ✅ KEEP all technical details ✅ EXPAND descriptions ✅ ADD SEO keywords ✅ Pattern v4 HTML ❌ NO price information Bilingual: TR + EN"
A3: Content üret + Görseller
  • GPT-4 response → Parse
  • Leonardo AI 2 görsel (context)
  • Embed images + SEO tags

🔴 BRANCH B: Mevcut İçerik YOK

B1: Sadece başlık + kategori al
  • Title: {$product->title}
  • Category: {$category->name}
  • Başka BİLGİ YOK!
B2: GPT-4 Prompt (Güvenli Mod)
"Generate GENERAL product content: Title: {$title} Category: Forklift Yedek Parça RULES: ✅ General description ONLY ❌ NO specific dimensions/weight/voltage ❌ NO price information ✅ Use phrases: 'contact for details' ✅ SEO keywords ✅ Pattern v4 HTML Bilingual: TR + EN"
B3: Content üret + Görseller
  • GPT-4 response → Parse
  • Leonardo AI 2 görsel (context)
  • Embed images + SEO tags
SON ADIM: Validation + Save
  • Fiyat keywords kontrolü ❌
  • Branch B ise teknik detay kontrolü ❌
  • SEO keyword yoğunluğu ✅
  • Database save + Cache clear

🚨 KRİTİK KURALLAR

⚠️ KURAL 1: FİYAT BİLGİSİ ASLA VERİLMEZ

  • ❌ "500 TL", "1000 $", "fiyat 100-500 TL"
  • ✅ "Fiyat için arayın", "Güncel fiyat için iletişime geçin"

⚠️ KURAL 2: TEKNİK DETAY (Sadece Mevcut İçerik Varsa)

  • Branch A (Mevcut VAR): ✅ Teknik detayları KORU ve kullan
  • Branch B (Mevcut YOK): ❌ Spesifik sayı/ölçü VERME

⚠️ KURAL 3: GOOGLE SEO ÖNCELİKLİ

  • ✅ Başlıkta keyword (örn: "Forklift Akson Kapağı")
  • ✅ Long-tail keywords (örn: "forklift arka dingil yedek parça")
  • ✅ LSI keywords (bakım, onarım, servis, montaj)
  • ✅ FAQ = Google arama sorguları

⚠️ KURAL 4: GÖRSEL STRATEJİSİ

  • ❌ Ürünü birebir oluşturma!
  • ✅ Foto 1: Kullanım ortamı (montaj, atölye)
  • ✅ Foto 2: Sallantılı teknik çizim (blueprint)

Yapılacaklar - Adım Adım

📝 ADIM 1: Product Filter Service

Dosya: Modules/Shop/app/Services/ProductFilterService.php

Sorumluluk: Sadece yedek parça + variant olmayan ürünleri filtrele

class ProductFilterService { public function getEligibleProducts(): Collection { return ShopProduct::where('category_id', 7) ->orWhereHas('category', fn($q) => $q->where('parent_id', 7)) ->where(function($q) { $q->whereNull('parent_id') ->orWhere('parent_id', 0); }) ->get(); } public function isEligible(ShopProduct $product): bool { // Yedek parça kategorisi mi? if ($product->category_id != 7 && $product->category->parent_id != 7) { return false; } // Variant ürün mü? if ($product->parent_id && $product->parent_id > 0) { return false; } return true; } }

📝 ADIM 2: Content Strategy Router

Dosya: Modules/Shop/app/Services/ContentStrategyRouter.php

Sorumluluk: Mevcut içerik kontrolü → Branch A veya B

class ContentStrategyRouter { public function route(ShopProduct $product): string { $hasContent = !empty($product->body['tr']) && strlen($product->body['tr']) > 100; return $hasContent ? 'expand' : 'create'; } public function extractExistingData(ShopProduct $product): array { // Mevcut içerikten teknik detayları çıkar $body = $product->body['tr'] ?? ''; return [ 'specs' => $this->extractSpecs($body), 'existing_body' => $body, 'primary_specs' => $product->primary_specs, 'faq_data' => $product->faq_data, ]; } protected function extractSpecs(string $body): array { // Regex ile boyut, ağırlık, voltaj vb. çıkar // "150mm", "2.5 kg", "220V" gibi } }

📝 ADIM 3: AI Content Service (Updated)

Dosya: Modules/Shop/app/Services/ShopProductAIContentService.php

Sorumluluk: Strategy'ye göre farklı prompt

class ShopProductAIContentService { public function generate(ShopProduct $product): array { $strategy = $this->router->route($product); if ($strategy === 'expand') { return $this->expandExistingContent($product); } else { return $this->createNewContent($product); } } protected function expandExistingContent($product): array { $existing = $this->router->extractExistingData($product); $prompt = "IMPROVE this content: {$existing['existing_body']} KEEP: {$existing['specs']} ADD: SEO keywords NO PRICE!"; return $this->callGPT4($prompt); } protected function createNewContent($product): array { $prompt = "CREATE general content: Title: {$product->title} Category: Yedek Parça NO SPECS! NO PRICE! General description only."; return $this->callGPT4($prompt); } }

📝 ADIM 4: Content Validator (Updated)

Dosya: Modules/Shop/app/Services/ContentValidator.php

public function validate($content, $strategy): array { $errors = []; // Fiyat kontrolü (HER ZAMAN) if ($this->containsPrice($content)) { $errors[] = 'Content contains price'; } // Teknik detay kontrolü (SADECE Branch B) if ($strategy === 'create' && $this->containsTechnicalSpecs($content)) { $errors[] = 'New content should not have specs'; } return $errors; }

🖥️ ADIM 5: Livewire Admin Component (Updated)

UI Değişiklikleri:

  • Sadece yedek parça kategorisinde göster
  • Variant ürünlerde disable et
  • Mevcut içerik varsa göster: "✅ Mevcut içerik geliştirilecek"
  • Mevcut içerik yoksa göster: "⚠️ Yeni içerik oluşturulacak (genel tanıtım)"

📸 ADIM 6: Image Generator (Aynı)

Görsel stratejisi değişmedi - context görseller üretecek

Test Senaryoları

Test 1: Ürün Filtreleme

  • Forklift ürünü seç → ❌ "Bu ürün uygun değil (sadece yedek parça)"
  • Variant ürün seç → ❌ "Bu bir variant ürün (sadece ana ürünler)"
  • Yedek parça ana ürün seç → ✅ "İşleme devam"

Test 2: Branch A (Mevcut İçerik VAR)

  • Ürün: Body dolu olan yedek parça
  • Beklenen: Teknik detaylar korundu mu?
  • Beklenen: İçerik genişledi mi?
  • Beklenen: Fiyat YOK mu?

Test 3: Branch B (Mevcut İçerik YOK)

  • Ürün: Body boş olan yedek parça
  • Beklenen: Genel tanıtım var mı?
  • Beklenen: Spesifik sayı/ölçü YOK mu?
  • Beklenen: Fiyat YOK mu?

Test 4: Batch Mode

  • 100 yedek parça ürünü seç
  • Variant olanlar otomatik skip edildi mi?
  • Her ürün doğru branch'e gitti mi?
  • Rate limiting çalışıyor mu?

Database Sorguları

Yedek Parça Ana Ürünleri Bul

-- Direkt yedek parça kategorisinde SELECT * FROM shop_products WHERE category_id = 7 AND (parent_id IS NULL OR parent_id = 0); -- Alt kategori ama yedek parçaya ait SELECT p.* FROM shop_products p JOIN shop_categories c ON p.category_id = c.id WHERE c.parent_id = 7 AND (p.parent_id IS NULL OR p.parent_id = 0); -- İkisini birleştir (Union) SELECT * FROM shop_products WHERE category_id = 7 AND (parent_id IS NULL OR parent_id = 0) UNION SELECT p.* FROM shop_products p JOIN shop_categories c ON p.category_id = c.id WHERE c.parent_id = 7 AND (p.parent_id IS NULL OR p.parent_id = 0);

Mevcut İçerik Kontrolü

-- Mevcut içeriği olan yedek parçalar SELECT COUNT(*) FROM shop_products WHERE category_id = 7 AND (parent_id IS NULL OR parent_id = 0) AND JSON_LENGTH(body, '$.tr') > 100; -- Mevcut içeriği olmayan yedek parçalar SELECT COUNT(*) FROM shop_products WHERE category_id = 7 AND (parent_id IS NULL OR parent_id = 0) AND (body IS NULL OR JSON_LENGTH(body, '$.tr') < 100);

Başarı Kriterleri

✅ Sistem Başarılı Sayılır Eğer:

  • ✅ Sadece yedek parça kategorisi işleniyor
  • ✅ Variant ürünler otomatik skip ediliyor
  • ✅ Mevcut içerik varsa teknik detaylar KORUNUYOR
  • ✅ Mevcut içerik yoksa genel tanıtım yapılıyor
  • ✅ HİÇBİR ÜRÜNDE fiyat bilgisi YOK
  • ✅ Branch B ürünlerinde spesifik teknik detay YOK
  • ✅ SEO keywords her üründe mevcut
  • ✅ Görseller context sağlıyor (exact değil)
  • ✅ Lightbox + SEO tags çalışıyor
  • ✅ Batch mode rate limiting ile çalışıyor

Uygulama Sırası

Sıra Dosya/Bileşen Süre
1 ProductFilterService.php 1 saat
2 ContentStrategyRouter.php 2 saat
3 ContentValidator.php 1 saat
4 ShopProductAIContentService.php 3 saat
5 ShopProductImageGenerator.php 2 saat
6 GenerateProductImagesJob.php 1 saat
7 ProductAIContentGenerator Livewire 4 saat
8 Test + Debug 3 saat

⏱️ Toplam Tahmini Süre: 17-19 saat