Modules/Blog

AI Blog Creator - Tenant Uygulama Rehberi

ixtif.com'daki AI Blog Draft üretim sistemini diğer tenant'lara nasıl uygulayacağınızı adım adım öğrenin

Hızlı Bakış

2 Aşama
Taslak → Blog
25 Draft
5 grup × 5 taslak
1 Kredi
Taslak veya Blog

1. Sistem Mimarisi

Basit Anlatım (Herkes İçin)

AI Blog Creator, iki aşamalı bir blog üretim sistemidir:

  1. 1 Taslak Üretimi: AI, tenant'ın sektörüne uygun 25 adet blog konusu önerir (başlık + anahtar kelimeler + outline)
  2. 2 Blog Yazımı: Admin seçtiği taslakları onaylar, AI tam blog yazısı + görsel üretir

Her tenant için özel prompt dosyası oluşturulabilir. Bu sayede AI, o tenant'ın sektörüne, ürünlerine ve tonuna uygun içerik üretir.

Teknik Detaylar

İş Akışı

┌─────────────────────────────────────────────────────────────┐
│ Admin Panel: /admin/blog/ai-drafts                          │
└─────────────────┬───────────────────────────────────────────┘
                  ↓
┌─────────────────────────────────────────────────────────────┐
│ [Taslak Üret] → Livewire → GenerateDraftsJob (Queue)       │
│                                                             │
│ CategoryBasedDraftGenerator:                                │
│ ├── buildCategoryGroups() → 5 grup oluştur                 │
│ ├── Her grup için OpenAI API call                          │
│ ├── JSON parse                                              │
│ └── blog_ai_drafts tablosuna kaydet                        │
└─────────────────┬───────────────────────────────────────────┘
                  ↓
┌─────────────────────────────────────────────────────────────┐
│ Admin taslakları görür ve seçim yapar (checkbox)           │
└─────────────────┬───────────────────────────────────────────┘
                  ↓
┌─────────────────────────────────────────────────────────────┐
│ [Seçili Blogları Yaz] → BlogAIBatchProcessor                │
│                                                             │
│ Her seçili taslak için GenerateBlogFromDraftJob:           │
│ ├── BlogAIContentWriter.generateBlogFromDraft()            │
│ │   ├── H2 outline üret (4-5 başlık)                       │
│ │   ├── Her H2 için içerik yaz (500-600 kelime)            │
│ │   ├── FAQ üret (10 soru)                                 │
│ │   ├── HowTo üret (7 adım)                                │
│ │   └── Leonardo AI görsel üret                            │
│ └── blogs tablosuna kaydet                                  │
└─────────────────────────────────────────────────────────────┘

Ana Servisler

  • CategoryBasedDraftGenerator - Taslak üretimi
  • BlogAIContentWriter - Blog yazımı
  • BlogAIBatchProcessor - Toplu işlem
  • TenantPromptLoader - Prompt yönetimi

Veritabanı

  • blog_ai_drafts - Taslaklar
  • blogs - Blog yazıları
  • blog_categories - Kategoriler
  • • Migration: tenant/ klasöründe

2. Dosya Yapısı

Modules/Blog/
├── App/
│   ├── Models/
│   │   ├── Blog.php
│   │   ├── BlogCategory.php
│   │   └── BlogAIDraft.php              ← AI taslak modeli
│   │
│   ├── Services/
│   │   ├── BlogAIDraftGenerator.php     ← Eski taslak üretici
│   │   ├── CategoryBasedDraftGenerator.php ← YENİ! Kategori bazlı
│   │   ├── BlogAIContentWriter.php      ← Blog yazma servisi
│   │   ├── BlogAIBatchProcessor.php     ← Toplu işlem
│   │   └── TenantPrompts/
│   │       ├── TenantPromptLoader.php   ← Prompt yükleyici
│   │       ├── DefaultPrompts.php       ← Varsayılan prompt'lar
│   │       └── Tenants/
│   │           ├── Tenant2Prompts.php   ← iXtif (örnek)
│   │           ├── Tenant4Prompts.php   ← Başka tenant
│   │           └── TenantXPrompts.php  ← YENİ TENANT BURAYA!
│   │
│   ├── Http/Livewire/Admin/
│   │   ├── BlogAiDraftComponent.php     ← Admin UI
│   │   └── BlogAiGuideComponent.php
│   │
│   └── Jobs/
│       ├── GenerateDraftsJob.php        ← Queue job (taslak)
│       └── GenerateBlogFromDraftJob.php ← Queue job (blog)
│
├── database/migrations/tenant/
│   └── 2025_11_14_050744_create_blog_ai_drafts_table.php
│
├── resources/views/admin/livewire/
│   └── blog-ai-draft-component.blade.php
│
└── routes/
    └── admin.php                        ← /admin/blog/ai-drafts

Önemli: Yeni tenant eklerken sadece TenantPrompts/Tenants/ klasörüne TenantXPrompts.php dosyası eklemeniz yeterli. Sistem otomatik algılar!

3. Yeni Tenant'a AI Blog Creator Ekleme

Basit Anlatım

Yeni bir tenant'a AI Blog Creator eklemek için 3 ana adım var:

  1. 1 Migration çalıştır: blog_ai_drafts tablosunu oluştur
  2. 2 Prompt dosyası oluştur: Tenant'a özel AI talimatları yaz (opsiyonel)
  3. 3 AI Provider ayarla: OpenAI API key tanımla
1

Migration Çalıştır

blog_ai_drafts tablosu tenant database'inde oluşturulmalı:

# Tüm tenant'lar için migration çalıştır
php artisan tenants:migrate --force

# Veya belirli tenant için
php artisan tenants:migrate --tenants=X --force

Migration dosyası: Modules/Blog/database/migrations/tenant/2025_11_14_050744_create_blog_ai_drafts_table.php

2

Prompt Dosyası Oluştur (Opsiyonel)

Tenant'a özel prompt dosyası oluşturmazsan DefaultPrompts.php kullanılır. Özel içerik istiyorsan:

# Dosya konumu:
Modules/Blog/App/Services/TenantPrompts/Tenants/Tenant{ID}Prompts.php

# Örnek: Tenant 5 için
Modules/Blog/App/Services/TenantPrompts/Tenants/Tenant5Prompts.php

Şablon dosya için Bölüm 6'ya bak

3

AI Provider Ayarla

Admin panelden AI Provider tanımla veya mevcut olanı kullan:

# Admin Panel:
/admin/ai/providers

# Gerekli alanlar:
- Provider: OpenAI
- API Key: sk-...
- Base URL: https://api.openai.com
- Model: gpt-4o veya gpt-4o-mini
- is_default: true
- is_active: true

4. Tenant Prompt Dosyası Yapısı

TenantPromptLoader Nasıl Çalışır?

// TenantPromptLoader.php - loadTenantPrompts()

$tenantId = tenant('id');  // Örn: 5

// Tenant-specific dosya var mı kontrol et
$tenantClass = "Modules\\Blog\\...\\Tenants\\Tenant{$tenantId}Prompts";
$tenantFile = __DIR__ . "/Tenants/Tenant{$tenantId}Prompts.php";

if (File::exists($tenantFile) && class_exists($tenantClass)) {
    // ✅ Tenant özel prompt kullan
    $this->promptProvider = new $tenantClass();
} else {
    // ⚠️ DefaultPrompts fallback
    $this->promptProvider = new DefaultPrompts();
}

Prompt Dosyası Metodları

getDraftPrompt(): string

Taslak üretimi için AI'a verilen talimatlar

  • • Blog başlığı formatı (soru mu, bilgilendirici mi)
  • • SEO anahtar kelime sayısı
  • • Outline yapısı (H2 başlıklar)
  • • Meta description uzunluğu

getBlogContentPrompt(): string

Blog yazımı için AI'a verilen talimatlar

  • • Kelime sayısı (1500-2000)
  • • HTML formatı (h2, h3, p, ul, strong)
  • • Firma adı kullanım kuralları
  • • Fiyat/yıl yasakları
  • • Ürün bahsetme zorunlulukları

getContext(): array

Tenant bilgileri (firma, iletişim, sektör)

return [
    'company_info' => [
        'name' => 'Firma Adı',
        'title' => 'Site Başlığı',
        'slogan' => 'Slogan',
        'website' => 'https://...',
    ],
    'contact_info' => [
        'email' => 'info@...',
        'phone' => '+90...',
        'address' => '...',
    ],
    'focus' => 'sektör_adı',  // industrial_equipment, music, etc.
    'industry' => 'Sektör Açıklaması',
    'target_audience' => 'Hedef kitle',
];

getFallbackOutline(string $topicKeyword): array

OpenAI başarısız olursa kullanılacak varsayılan H2 başlıkları

return [
    $topicKeyword . ' Nedir?',
    'Özellikler ve Avantajlar',
    'Kullanım Alanları',
    'Seçim Kriterleri',
    'Bakım ve Güvenlik',
    'İletişim ve Destek',
];

buildImagePromptForBlog(string $blogTitle): string (Opsiyonel)

Leonardo AI görsel üretimi için prompt (varsa)

  • • Blog başlığına göre dinamik görsel
  • • Sektöre uygun sahneler
  • • Text ban (görselde yazı olmasın)

5. Uygulama Checklist

Ön Gereksinimler

Veritabanı

AI Provider

Tenant Prompt (Opsiyonel)

Queue Sistemi

Test

6. Şablon Dosyalar

Minimal Şablon (Hızlı Başlangıç)

DefaultPrompts'u kullanır, sadece firma bilgilerini override eder:

<?php

namespace Modules\Blog\App\Services\TenantPrompts\Tenants;

use Modules\Blog\App\Services\TenantPrompts\DefaultPrompts;

/**
 * Tenant X için Blog AI Prompts
 * Dosya: Modules/Blog/App/Services/TenantPrompts/Tenants/TenantXPrompts.php
 */
class TenantXPrompts extends DefaultPrompts
{
    /**
     * Tenant context override
     */
    public function getContext(): array
    {
        $context = parent::getContext();

        // Tenant-specific ek bilgiler
        $context['focus'] = 'your_industry';  // Sektör kodu
        $context['industry'] = 'Sektör Açıklaması';
        $context['target_audience'] = 'Hedef kitle açıklaması';

        return $context;
    }

    /**
     * Tenant için fallback outline
     */
    public function getFallbackOutline(string $topicKeyword): array
    {
        return [
            $topicKeyword . ' Nedir?',
            'Özellikler ve Avantajlar',
            'Kullanım Alanları',
            'Seçim Kriterleri',
            'İletişim ve Destek',
        ];
    }
}

Tam Şablon (Detaylı Kontrol)

Tüm metodları override eder, tam kontrol sağlar:

<?php

namespace Modules\Blog\App\Services\TenantPrompts\Tenants;

use Illuminate\Support\Facades\File;
use Modules\Blog\App\Services\TenantPrompts\DefaultPrompts;

/**
 * Tenant X için Blog AI Prompts (Tam Şablon)
 *
 * Bu dosyayı kopyalayıp tenant ID'ye göre düzenleyin:
 * - Class adını TenantXPrompts yapın (X = tenant ID)
 * - Dosya adını TenantXPrompts.php yapın
 */
class TenantXPrompts extends DefaultPrompts
{
    protected string $promptPath;

    public function __construct()
    {
        // Opsiyonel: Markdown prompt dosyaları için path
        $this->promptPath = base_path('readme/tenant-x-prompts');
    }

    /**
     * Draft (taslak) üretimi için AI prompt
     */
    public function getDraftPrompt(): string
    {
        // Harici dosyadan yükle (varsa)
        $promptFile = $this->promptPath . '/draft-prompt.md';
        if (File::exists($promptFile)) {
            return File::get($promptFile);
        }

        // Inline prompt
        return <<<'PROMPT'
Sen profesyonel bir blog içerik stratejistisin.

**FİRMA:** [Firma Adı]
**SEKTÖR:** [Sektör]

Görevin: [Sektör] konularında SEO uyumlu blog taslakları oluşturmak.

**JSON FORMAT:**
[
  {
    "topic_keyword": "Blog başlığı",
    "meta_description": "150 karakterlik açıklama",
    "seo_keywords": ["kelime1", "kelime2"],
    "outline": ["H2 Başlık 1", "H2 Başlık 2", "H2 Başlık 3"]
  }
]

**KURALLAR:**
- SEO odaklı başlıklar
- Türkçe karakter kullan
- Teknik ve bilgilendirici içerik
PROMPT;
    }

    /**
     * Blog içeriği yazımı için AI prompt
     */
    public function getBlogContentPrompt(): string
    {
        return <<<'PROMPT'
Sen profesyonel bir [sektör] içerik yazarısın.

**FİRMA:** {company_info.name}
**WEB:** {company_info.website}

**ZORUNLU KURALLAR:**

1. **Kelime Sayısı:** 1500-2000 kelime
2. **HTML Format:** <h2>, <h3>, <p>, <ul>, <strong> kullan
3. **Firma Adı:** En az 3 kez kullan
4. **İletişim:** Sonuç bölümünde telefon ve email ver
5. **Fiyat YASAK:** Rakam verme, "iletişime geçin" yönlendir
6. **Yıl YASAK:** 2023, 2024 gibi yıllar kullanma

**JSON FORMAT:**
{
  "title": "Blog başlığı",
  "content": "Tam HTML içerik",
  "excerpt": "Kısa özet (180 karakter)"
}
PROMPT;
    }

    /**
     * Tenant context override
     */
    public function getContext(): array
    {
        $context = parent::getContext();

        // Kısa firma adı kullan (site_title)
        if (!empty($context['company_info']['title'])) {
            $context['company_info']['name'] = $context['company_info']['title'];
        }

        // Tenant-specific ek bilgiler
        $context['focus'] = 'your_industry_code';
        $context['industry'] = 'B2B/B2C Sektör Açıklaması';
        $context['target_audience'] = 'Hedef kitle açıklaması';

        return $context;
    }

    /**
     * Tenant için fallback outline
     */
    public function getFallbackOutline(string $topicKeyword): array
    {
        return [
            $topicKeyword . ' Nedir?',
            'Özellikler ve Avantajlar',
            'Kullanım Alanları',
            'Seçim Kriterleri',
            'Sık Sorulan Sorular',
            'İletişim ve Destek',
        ];
    }
}

Sektör Örnekleri

E-Ticaret

  • focus: 'ecommerce'
  • industry: 'B2C Online Satış'
  • target_audience: 'Online alışveriş yapan tüketiciler'

Turizm

  • focus: 'tourism'
  • industry: 'Turizm ve Seyahat'
  • target_audience: 'Tatilciler, iş seyahati yapanlar'

Hukuk

  • focus: 'legal'
  • industry: 'Hukuki Danışmanlık'
  • target_audience: 'Bireysel ve kurumsal müvekkiller'

Sağlık

  • focus: 'healthcare'
  • industry: 'Sağlık Hizmetleri'
  • target_audience: 'Hastalar, sağlık arayan bireyler'

Hızlı Komutlar

# Migration çalıştır (tüm tenant'lar)
php artisan tenants:migrate --force

# Belirli tenant için migration
php artisan tenants:migrate --tenants=5 --force

# Cache temizle
php artisan cache:clear && php artisan config:clear

# Queue worker başlat (blog-ai queue'su için)
php artisan queue:work --queue=blog-ai

# Horizon (tüm queue'lar)
php artisan horizon

# Prompt loader debug (tinker)
php artisan tinker
>>> tenancy()->initialize(5);
>>> app(\Modules\Blog\App\Services\TenantPrompts\TenantPromptLoader::class)->getProviderClass();