v4 - Kapsamli

t-{id} Tema Yapisi

Multi-Tenant Tema Sistemi - SEO, Dark Mode, Leonardo AI, Modul Path'ler

1. Felsefe

t-{id} = Tenant temasi. Sadece ozel dosyalar burada.

simple = Fallback (mevcut, zaten var). t-{id}'de yoksa buradan alir.

Ornek: t-3/homepage.blade.php var → onu kullan, t-3/blog/show.blade.php yok → simple'dan al

2. Klasor Yapisi

resources/views/themes/
|
+-- simple/                         ← FALLBACK (mevcut, dokunma)
|   +-- layouts/
|   |   +-- app.blade.php
|   |   +-- header.blade.php
|   |   +-- footer.blade.php
|   +-- homepage.blade.php
|   +-- ...
|
+-- t-1001/                         ← Muzibu override
|   +-- homepage.blade.php
|   +-- config.json
|
+-- t-2/                            ← Ixtif override
|   +-- homepage.blade.php
|   +-- config.json
|
+-- t-3/                            ← Panjur Tenant
    +-- homepage.blade.php          ← Ozel anasayfa (STANDALONE)
    +-- config.json                 ← Renkler
    +-- (blog/, page/ yok → simple'dan gelir)

ONEMLI: Modul view'lari AYRI konumda! Asagidaki "Modul View Path'leri" bolumune bak.

3. SEO Meta Tag Implementasyonu

Basit Anlatim (Herkes Icin)

SEO etiketleri, Google'in sitenizi anlamasini saglar. Title, description, Open Graph (sosyal medya paylasimlari), Twitter Cards ve Schema.org (zengin sonuclar) hepsini otomatik olusturur.

Teknik Detaylar

1. Kullanim

<!-- head icine ekle -->
<x-seo-meta />

<!-- Otomatik olusturulanlar: -->
<title>Sayfa Basligi</title>
<meta name="description" content="...">
<meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large">
<link rel="canonical" href="...">
<meta property="og:title" content="...">
<meta property="og:description" content="...">
<meta property="og:image" content="...">
<meta name="twitter:card" content="summary_large_image">
<script type="application/ld+json">{Schema.org JSON-LD}</script>

2. Dosya Konumu

resources/views/components/seo-meta.blade.php   ← Component
app/View/Components/SeoMeta.php                 ← Class

3. Desteklenen Meta Tag'ler

Temel:

  • title - Sayfa basligi
  • description - Aciklama
  • robots - Index/noindex
  • canonical_url - Kanonik URL
  • author - Yazar (E-E-A-T)

Sosyal Medya:

  • og_title - Facebook basligi
  • og_image - Paylasilacak gorsel
  • twitter_card - Twitter karti
  • twitter_image - Twitter gorseli

4. Ekstra Ozellikler

  • PWA Meta Tags: mobile-web-app-capable, apple-mobile-web-app-*
  • Theme Color: Dark/light moda gore otomatik degisir
  • Hreflang: Coklu dil destegi
  • Sitemap Link: Otomatik eklenir
  • Schema.org: JSON-LD yapilandirmali veri

4. Dark/Light Mode Implementasyonu

Basit Anlatim

Kullanici tercihini hatirlar. Sistem tercihine gore otomatik baslar, sonra kullanici degistirebilir. Sayfa yenilenince FOUC (yanip sonme) olmaz.

Teknik Detaylar

1. FOUC Onleme (head icinde, script'lerden once)

<script>
    // Dark mode FOUC prevention - CRITICAL: head icinde olmali!
    if (localStorage.getItem('darkMode') === 'true' ||
        (!localStorage.getItem('darkMode') &&
         window.matchMedia('(prefers-color-scheme: dark)').matches)) {
        document.documentElement.classList.add('dark');
    }
</script>

2. Tailwind Config

tailwind.config = {
    darkMode: 'class',  // class bazli - 'media' degil!
    theme: {
        extend: { ... }
    }
}

3. Alpine.js Toggle Butonu

<button
    x-data="{
        dark: localStorage.getItem('darkMode') === 'true' ||
              (!localStorage.getItem('darkMode') &&
               document.documentElement.classList.contains('dark'))
    }"
    @click="
        dark = !dark;
        localStorage.setItem('darkMode', dark);
        document.documentElement.classList.toggle('dark', dark)
    "
    class="..."
>
    <i :class="dark ? 'fa-sun' : 'fa-moon'" class="fas"></i>
</button>

4. CSS Kullanimi

<!-- Tailwind dark: prefix kullan -->
<div class="bg-white dark:bg-slate-900 text-gray-900 dark:text-white">
    <p class="text-gray-600 dark:text-gray-300">Icerik</p>
</div>

<!-- Gradient ornegi -->
<section class="bg-gradient-to-br from-slate-50 to-slate-100
                dark:from-slate-900 dark:to-slate-800">
    ...
</section>

5. Leonardo AI Gorsel Uretimi

Basit Anlatim

Leonardo AI ile gorsel uretip, Spatie Media Library'ye ekleyip, sayfalarda kullanabilirsin. Hero, hizmetler, sayfalar icin ozel gorseller olustur.

Kullanim Adimlari

1. Leonardo'da Gorsel Uret

URL: https://app.leonardo.ai

Prompt Ornekleri:

# Hero Background
Professional shutter repair service, Turkish style building facade,
orange aluminum shutters being installed, technician working,
modern urban setting, Istanbul cityscape background,
photorealistic, high quality, 16:9 aspect ratio

# Service Card
Motorized roller shutter system, remote control operation,
modern smart home integration, clean product photography,
white background, professional lighting, 4:3 aspect ratio

# About Page
Professional Turkish craftsman installing window shutters,
30 years experience, trustworthy appearance,
workshop background with tools, warm lighting

2. Gorseli Indir & Storage'a Kopyala

# Leonardo'dan indirdikten sonra:
scp gorsel.jpg sunucu:/tmp/

# Storage'a tasi:
sudo cp /tmp/gorsel.jpg /var/www/vhosts/tuufi.com/httpdocs/storage/app/public/tenant3/
sudo chown tuufi.com_:psaserv /var/www/vhosts/tuufi.com/httpdocs/storage/app/public/tenant3/gorsel.jpg
sudo chmod 644 /var/www/vhosts/tuufi.com/httpdocs/storage/app/public/tenant3/gorsel.jpg

3. Media Library'ye Ekle (tinker)

$tenant = \App\Models\Tenant::find(3);
tenancy()->initialize($tenant);

// Ornek: Page'e gorsel ekle
$page = \Modules\Page\App\Models\Page::find(2);
$page->addMedia('/var/www/vhosts/tuufi.com/httpdocs/storage/app/public/tenant3/gorsel.jpg')
     ->preservingOriginal()
     ->toMediaCollection('cover');

// Service'e gorsel ekle
$service = \Modules\Service\App\Models\Service::find(1);
$service->addMedia('/tmp/panjur-tamiri.jpg')
        ->preservingOriginal()
        ->toMediaCollection('cover');

4. Blade'de Kullan

{{-- Direkt media URL --}}
<img src="{{ $service->getFirstMediaUrl('cover') }}" alt="...">

{{-- Thumbmaker ile (optimize) --}}
<img src="{{ thumb($service->getFirstMedia('cover'), 800, 600) }}" alt="...">

{{-- WebP format ile --}}
<img src="{{ thumb($service->getFirstMedia('cover'), 800, 600, ['format' => 'webp']) }}" alt="...">

6. Modul View Path'leri

Basit Anlatim

Her modul (Page, Service, Blog) kendi view dosyalarini kendi klasorunde tutar. Ana resources/views degil, Modules klasoru icinde!

Dosya Konumlari

Page Modulu

Modules/Page/resources/views/themes/
|
+-- simple/                        ← Fallback
|   +-- homepage.blade.php
|   +-- page/
|       +-- show.blade.php
|
+-- ixtif/                         ← Ixtif ozel
|   +-- homepage.blade.php
|
+-- muzibu/                        ← Muzibu ozel
|   +-- homepage.blade.php
|
+-- t-3/                           ← Panjur ozel
    +-- homepage.blade.php         (STANDALONE - extends yok)

Service Modulu

Modules/Service/resources/views/themes/
|
+-- simple/                        ← Fallback
|   +-- service/
|       +-- index.blade.php        ← Hizmet listesi
|       +-- show.blade.php         ← Hizmet detay
|
+-- t-3/                           ← Panjur icin ozel istersen
    +-- service/
        +-- index.blade.php
        +-- show.blade.php

Blog Modulu

Modules/Blog/resources/views/themes/
|
+-- simple/                        ← Fallback
    +-- blog/
        +-- index.blade.php
        +-- show.blade.php

View Cozumleme Sirasi

t-3 Tenant icin arama sirasi:

1. Modules/Page/resources/views/themes/t-3/homepage.blade.php     ✓ BULUNDU
2. Modules/Page/resources/views/themes/simple/homepage.blade.php  (fallback)

Service detay icin:

1. Modules/Service/resources/views/themes/t-3/service/show.blade.php  ✗ YOK
2. Modules/Service/resources/views/themes/simple/service/show.blade.php ✓ KULLANILIR

7. Ixtif'ten Alinan Pattern'ler

SEO Component

  • <x-seo-meta />
  • Open Graph meta tags
  • Twitter Cards
  • Schema.org JSON-LD
  • PWA meta tags

Dark Mode

  • FOUC prevention script
  • localStorage persistence
  • System preference detection
  • Alpine.js toggle

FontAwesome Pro

  • Self-hosted (CDN degil)
  • fa-light ikonlar
  • Path: assets/libs/fontawesome-pro@7.1.0/

Tailwind Config

  • Custom primary colors
  • Custom font families
  • darkMode: 'class'

AOS Animations

  • Scroll-based animations
  • data-aos="fade-up"
  • data-aos-delay="100"

Helper Fonksiyonlar

  • setting('key') - Tenant ayarlari
  • thumb($media, w, h) - Gorsel optimize
  • cdn($url) - CDN URL

8. Tespit Edilen Sorunlar ve Cozumler

1. SEO Settings Eksik Kolonlar

Hata: priority_score, seo_score kolonlari yok

Cozum:

ALTER TABLE tenant_xxx.seo_settings
ADD COLUMN priority_score INT DEFAULT 5,
ADD COLUMN seo_score INT DEFAULT 0;

2. Tenant Model Type Mismatch

Hata: Stancl\Tenancy vs App\Models\Tenant

Cozum:

// YANLIS:
$tenant = Tenant::find(3);

// DOGRU:
$tenant = \App\Models\Tenant::find(3);
tenancy()->initialize($tenant);

3. Tinker'da Heredoc Parse Error

Hata: Cok satirli string'lerde parse error

Cozum:

# PHP dosyasina yaz, tinker ile calistir:
php artisan tinker /tmp/script.php

4. Route 404 - Service/Page

Durum: /sayfa/hakkimizda ve /hizmetler/xxx 404 donuyor

Olasi Nedenler:

  • - ModuleSlugService konfigurasyonu
  • - Route cache eski
  • - Tenant route prefix farki

Kontrol Et:

php artisan route:list --path=sayfa
php artisan route:cache && php artisan route:clear

5. Standalone vs Extends

Durum: t-3/homepage.blade.php standalone (tam HTML), ixtif extends kullaniyor

Avantaj: Bagimsizlik, tam kontrol

Dezavantaj: Header/footer degisirse manuel guncelleme gerekir

9. Yeni Tema Checklist

Klasor

Dosyalar

Icerik

Gorseller

Test