Files
bogazici-api/backend_ve_admin_dokuman.md
2026-03-27 10:41:54 +03:00

803 lines
43 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Boğaziçi Denizcilik - Backend (Laravel) & Admin Panel (Next.js) Gereksinim Dökümanı (v2)
Bu döküman, mevcut Next.js (Frontend) projenizin dinamik veri altyapısını bir **Laravel API**'sine bağlamak ve bu verileri yönetmek için tamamen ayrı bir **Next.js Admin Panel** geliştirmek üzere hazırlanmıştır.
*(v2 Güncellemesi: Gelişmiş Setting altyapısı, Pagination standartları, Modüler Page Builder API'leri, Soft Deletes, Caching, Audit Logs, Rate Limiting ve Çok Dilli (i18n) destek notları eklenmiştir.)*
> **Çok Dilli (i18n) Altyapı Notu:** Şimdilik v1 aşamasında tek dil (TR) olarak çıkılacaktır. Ancak v2+ versiyonları için i18n (Çoklu dil) planlanıyorsa, veritabanı tablolarında JSON field veya harici translations tablosu yaklaşımı değerlendirilecektir.
> **🤖 GitHub Copilot (VS Code) İçin Geliştirme Talimatı (Master Prompt):**
> *Laravel Herd ile kendi oluşturduğunuz projeyi VS Code'da açtıktan sonra, Copilot Chat'e (veya Cursor/Cline'a) şu mesajı yazmanız yeterlidir:*
>
> "Merhaba Copilot, bu projeyi **Laravel 12+** ile geliştireceğiz. Lütfen ana dizindeki **`backend_ve_admin_dokuman.md`** dosyasını dikkatlice baştan sona oku ve mimariyi kavra.
> Ardından şu işlemleri benim onayımı alarak **adım adım** kodlamaya başla:
> 1. Önce "1. Veritabanı Şeması" bölümündeki tüm tablolar için Laravel Migration, Model ve Factory dosyalarını oluştur. Önemli tablolarda SoftDeletes kullan. Bu adımı bitirince onayımı bekle.
> 2. Ardından "REST API" ve "Klasör Mimarisi" bölümüne geç. Kesinlikle spagetti controller yazma. Her modül için sırayla; `FormRequest`, `DTO`, `Action (Service)`, `Repository` ve en son `Controller` ile `api.php` rotalarını oluştur. Response standartlarına ve Caching kurallarına dikkat et.
> 3. Her modülü (Örn: Courses, Categories) tek tek kodla ve her modül bitiminde bana bilgi ver. Asla tüm projeyi tek seferde yazmaya çalışma."
---
## 1. Veritabanı Şeması (Laravel Modelleri & Migrations)
*(Güvenlik: Kaza eseri veri kayıplarını önlemek için yetki, kurs, kategori ve lead tablolarında `SoftDeletes` kullanılacaktır.)*
### 1.0. `users` & `roles` (Yetkilendirme / Auth)
- Laravel'in standart `users` tablosu. Admin panele giriş yapacak personeli temsil eder.
- Sisteme **Spatie Permission** paketi kurularak Role ve Yetki altyapısı tanımlanacaktır (Örn: `super-admin`, `editor`).
- `SoftDeletes` aktif olmalıdır.
### 1.1. `categories` (Eğitim Kategorileri)
- `id` (PK)
- `slug` (string, unique) - *Örn: guverte*
- `label` (string) - *Örn: Güverte Eğitimleri*
- `desc` (text, nullable)
- `image` (string, nullable) - *Sadece görsel path'i tutar*
- `meta_title` (string, nullable) - *SEO Title*
- `meta_description` (text, nullable) - *SEO Description*
- `created_at`, `updated_at`, `deleted_at` *(SoftDeletes)*
### 1.2. `courses` (Eğitimler/Kurslar)
- `id` (PK)
- `category_id` (FK -> categories.id)
- `slug` (string, unique)
- `title` (string)
- `sub` (string, nullable) - *Örn: STCW II/1*
- `desc` (text) - *Kısa açıklama*
- `long_desc` (longText) - *Detaylııklama*
- `duration` (string) - *Örn: 5 Gün*
- `students` (integer, default: 0) - *Kayıtlı öğrenci sayısı*
- `rating` (decimal: 2,1, default: 5.0)
- `badge` (string, nullable) - *Örn: Simülatör*
- `image` (string, nullable) - *Sadece path tutar*
- `price` (string, nullable)
- `includes` (json, nullable) - *Fiyata dahil olanlar listesi. Örn: `["Eğitim materyali", "Sertifika ücreti", "İkram"]`*
- `requirements` (json, nullable) - *Katılım koşulları/gereksinimler listesi. Örn: `["18 yaşını doldurmuş olmak", "Lise mezunu olmak"]`*
- `meta_title` (string, nullable) - *SEO Title*
- `meta_description` (text, nullable) - *SEO Description*
- `scope` (json, nullable) - *Eğitim kapsamı konu başlıkları dizisi. Örn: `["Ana makine sistemleri", "Yağlama ve soğutma sistemleri", "Yakıt sistemleri"]`*
- `standard` (string, nullable) - *Uyum standardı. Örn: `"STCW / IMO Uyumlu"`*
- `language` (string, nullable, default: `"Türkçe"`) - *Eğitim dili*
- `location` (string, nullable) - *Kursun varsayılan lokasyonu. Örn: `"Kadıköy, İstanbul"`*
- `created_at`, `updated_at`, `deleted_at` *(SoftDeletes)*
### 1.3. `course_schedules` (Takvim / Planlanan Eğitimler)
- `id` (PK)
- `course_id` (FK -> courses.id)
- `start_date` (date) - *Örn: 2026-02-24*
- `end_date` (date) - *Örn: 2026-02-28*
- `location` (string) - *Örn: Kadıköy veya Online*
- `quota` (integer) - *Toplam Kontenjan*
- `available_seats` (integer) - *Kalan Koltuk (Otomatik `quota - reserved_count` mantığıyla çalışmalı veya admin üzerinden manuel update edilmeli. Proje ilerleyişine göre netleşecek).*
- `is_urgent` (boolean, default: false) - *Sınırlı Kontenjan uyarısı*
- `created_at`, `updated_at`
### 1.4. `announcements` (Duyurular & Haberler)
- `id` (PK)
- `slug` (string, unique)
- `title` (string)
- `category` (string, enum) - *Tutarsızlığı önlemek için Enum kullanılmalı: `announcement` | `news` | `event`*
- `excerpt` (text)
- `content` (longText)
- `image` (string, nullable)
- `is_featured` (boolean, default: false)
- `meta_title` (string, nullable)
- `meta_description` (text, nullable)
- `published_at` (timestamp) - *Frontend'deki day/month yerine gerçek tarih tutulmalı*
- `created_at`, `updated_at`
### 1.5. `hero_slides` (Ana Sayfa Slider)
- `id` (PK)
- `label` (string) - *Örn: STCW Sertifikasyonu*
- `title` (string) - *Satır başı için \n destekli*
- `description` (text)
- `image` (string, nullable)
- `order` (integer, default: 0)
- `is_active` (boolean, default: true)
- `created_at`, `updated_at`
### 1.6. `leads` (Ön Kayıtlar / Form Başvuruları)
- `id` (PK)
- `name` (string)
- `phone` (string)
- `target_course` (string, nullable) - *İlgilenilen eğitim*
- `education_level` (string, nullable) - *Öğrenim durumu*
- `subject` (string, nullable) - *İlgilenilen konu (Danışmanlık formu için Örn: stcw, kaptanlik, belge, diger)*
- `message` (text, nullable) - *Ziyaretçinin ek mesajı (Danışmanlık formu için)*
- `status` (string, default: 'new') - *`new`, `contacted`, `enrolled`, `rejected`*
- `notes` (text, nullable) - *Admin notları*
- `is_read` (boolean, default: false) - *Admin panelde okunmamışları vurgulamak için*
- `source` (string) - *`hero_form` | `contact_form` | `consultation_form` | `whatsapp_widget`*
- `utm` (json, nullable) - *`utm_source`, `utm_campaign`, vb.*
- `consent_kvkk` (boolean, default: false)
- `consent_text_version` (string, nullable)
- `created_at`, `updated_at`, `deleted_at` *(SoftDeletes)*
### 1.7. `menus` (Dinamik Menü & Navigasyon Yönetimi)
Tüm site üst (Navbar) ve alt (Footer) bağlantılarının, Mega Menü içeriklerinin admin panelinden yönetilebilmesi için.
- `id` (PK)
- `location` (string) - *Örn: `header_main`, `footer_corporate`, `footer_education`, `footer_quicklinks`*
- `label` (string) - *Menüde Gözükecek Metin Örn: "Hakkımızda"*
- `url` (string) - *Örn: "/kurumsal/hakkimizda"*
- `type` (string, default: 'link') - *`link` (Normal Link) | `mega_menu_education` (Özel Hover Mega Menü) | `mega_menu_calendar` (Takvim Dropdown)*
- `parent_id` (integer, nullable) - *Alt menüler için (Self Referencing FK)*
- `order` (integer, default: 0) - *Sıralama*
- `is_active` (boolean, default: true)
- `created_at`, `updated_at`
### 1.8. `comments` (Eğitim ve Blog Yorumları / Soru-Cevap)
*Kullanıcıların üye olmadan, sadece Ad, Soyad ve Telefon numarası girerek Eğitimlere veya Duyurulara/Bloglara yorum yapabileceği ve adminlerin cevaplayabileceği sistem.*
- `id` (PK)
- `commentable_id` (integer) - *Hangi eğitime/duyuruya yapıldı? (Polymorphic Relation)*
- `commentable_type` (string) - *`App\\Models\\Course` veya `App\\Models\\Announcement`*
- `name_surname` (string) - *Kullanıcının Adı Soyadı*
- `phone` (string) - *Kullanıcının Telefon Numarası (Soru sorana ulaşmak gerekirse)*
- `body` (text) - *Yorum / Soru metni*
- `admin_reply` (text, nullable) - *Admin'in verdiği cevap (Önyüzde Admin Yanıtı olarak gözükecek)*
- `is_approved` (boolean, default: false) - *Admin onaylamadan sitede gözükmemeli*
- `created_at`, `updated_at`, `deleted_at` *(SoftDeletes)*
### 1.9. `faqs` (Sıkça Sorulan Sorular)
*Frontend'deki `/sss` sayfası ve anasayfadaki FAQ bileşeni için. Adminler soru-cevapları kategorili olarak yönetebilir.*
- `id` (PK)
- `category` (string) - *`egitimler` | `kayit` | `iletisim` (Tab bazlı filtreleme için)*
- `question` (text) - *Soru metni*
- `answer` (text) - *Cevap metni*
- `order` (integer, default: 0) - *Kategori içi sıralama*
- `is_active` (boolean, default: true) - *Pasif olanlar önyüzde gösterilmez*
- `created_at`, `updated_at`
### 1.10. `guide_cards` (Eğitim Rehberi Kartları)
*Frontend'deki `/egitim-rehberi` sayfasındaki kariyer yönlendirme kartları için. Admin panelden yönetilebilir.*
- `id` (PK)
- `title` (string) - *Örn: "Yeni Başlayanlar", "Yat Kaptanları"*
- `description` (text) - *Kart içeriği açıklaması*
- `icon` (string) - *Lucide icon adı (Örn: `anchor`, `compass`, `shield`, `briefcase`)*
- `color` (string) - *Gradient renk sınıfı (Örn: `from-blue-500 to-blue-700`)*
- `link` (string) - *Yönlendirme URL'i (Örn: `/egitimler/stcw`)*
- `order` (integer, default: 0) - *Sıralama*
- `is_active` (boolean, default: true)
- `created_at`, `updated_at`
### 1.11. `settings` (Sistem Ayarları)
*Admin panelinde otomatik tab/sekme yapısı kurmak ve public/private yalıtımı sağlamak için güçlendirilmiş yapı. Logo, sosyal medya linkleri gibi statik veriler buradan yönetilir.*
- `id` (PK)
- `group` (string) - *`general` | `contact` | `social` | `seo` | `forms` | `footer` | `guide`*
- `key` (string, unique)
- `value` (text/json, nullable)
- `type` (string) - *`text` | `textarea` | `image` | `boolean` | `json` | `richtext`*
- `is_public` (boolean, default: true) - *Public API'de görünsün mü? (Örn: `hero_form_email` gizli kalmalıdır).*
- `created_at`, `updated_at`
**Önerilen Settings Key Listesi (Otomatik Seeder ile Girecekler):**
- **Genel:** `site_name`, `site_logo`, `footer_logo`, `favicon`
- **Anasayfa İçerikleri (Sabit Alanlar):** `home_about_title`, `home_about_text`, `home_about_image_1`, `home_about_image_2`, `home_stats_students`, `home_stats_instructors`, `home_stats_courses` (Anasayfadaki "Biz Kimiz", "Kurum Hakkında" veya istatistik alanlarındaki resim/yazıların yönetimi için).
- **İletişim:** `contact_email`, `contact_cc_emails`, `phone_1`, `phone_2`, `whatsapp_phone`, `address`, `google_maps_embed_url`, `working_hours`
- **Sosyal Medya (Dinamik Logolar / Linkler):** `instagram_url`, `facebook_url`, `tiktok_url`, `x_url`, `youtube_url`, `linkedin_url` (Bu alanlar boş bırakılırsa önyüzde iconlar gizlenmelidir).
- **SEO:** `default_meta_title`, `default_meta_description`, `canonical_base`, `og_default_image`, `robots_indexing_enabled`
- **Formlar / KVKK / Kampanya:** `lead_notify_email`, `kvkk_text`, `privacy_policy_url`, `newsletter_title`, `newsletter_desc` (E-bülten ve "Sana özel kampanyalar" kutusundaki metinler).
- **Eğitim Rehberi:** `guide_page_title`, `guide_page_subtitle`, `guide_cta_title`, `guide_cta_text`, `guide_cta_button_text`, `guide_cta_button_url` (Eğitim Rehberi sayfasındaki başlık, alt metin ve CTA alanlarının yönetimi).
- **Danışmanlık:** `consultation_page_title`, `consultation_page_subtitle`, `consultation_form_title` (Danışmanlık sayfasının başlık ve açıklama alanlarının yönetimi).
---
## 2. Laravel REST API Uç Noktaları (Endpoints) & Standartları
**Cevap (Response) Format Standardı:**
Frontend tarafının hızlı ilerlemesi için tüm başarılı API listeleme talepleri paginate ve metadata içermeli, Laravel Resource üzerinden standartlaştırılmalıdır.
- Liste endpoint'leri: `{ "data": [], "meta": { "total": 0 }, "links": { } }`
- Tekil endpoint'ler: `{ "data": { } }`
**Parametrik Arama, Filtreleme, Sıralama:**
- `GET /api/v1/courses?category=guverte&search=stcw&sort=title&page=1`
- `GET /api/v1/announcements?category=news&featured=1&sort=-published_at&page=1`
### Public API (Frontend İçin - `api/v1/...`)
*(Performans için aktif olan sık kullanılan Public GET endpoint'leri **Laravel Cache / Redis** arkasında çalıştırılmalıdır. Veri Admin Panel'den güncellenince Cache Event ile temizlenmelidir.)*
- `GET /api/v1/settings` -> `is_public=true` olan ayarları döner.
- `GET /api/v1/hero-slides` -> Aktif slider içeriklerini sıralı getirir.
- `GET /api/v1/menus` -> Header ve Footer navigasyon ağacını hiyerarşik getirir.
- `GET /api/v1/categories` -> Kategorileri listeler.
- `GET /api/v1/courses` -> Eğitimleri listeler.
- `GET /api/v1/courses/{slug}` -> Tekil eğitim detayı.
- `GET /api/v1/schedules` -> Yaklaşan takvim eğitimlerini getirir. (Tarihe göre sıralı)
- `GET /api/v1/announcements` -> Duyuruları (featured olanlar dahil) getirir.
- `GET /api/v1/announcements/{slug}` -> Tekil duyuru detayı.
- `GET /api/v1/comments/{type}/{id}` -> Bir kursun veya blogun onaylanmış (`is_approved=true`) yorumlarını ve admin cevaplarını getirir.
- `POST /api/v1/comments` -> Ziyaretçiden yeni yorum/soru kaydı alır (Spam/Rate Limiting zorunlu).
- `GET /api/v1/faqs` -> Aktif SSS verilerini kategorili olarak getirir. `?category=egitimler` filtresi desteklenmeli.
- `GET /api/v1/guide-cards` -> Eğitim Rehberi kartlarını sıralı getirir.
- `GET /api/v1/pages/{slug}` -> Page builder bloklarını sırayla (`order_index`) getirir. *(Sadece `/page/` altındaki dinamik sayfalar için)*
- `POST /api/v1/leads` -> Ön kayıt formu alımı. `source` alanı ile form kaynağı (`hero_form`, `contact_form`, `consultation_form`) belirlenir. *(Spam koruması için IP bazlı Rate Limiting - Throttle uygulanmalıdır. Dakikada maks 2-3 gibi)*
- `GET /api/v1/sitemap-data` -> Frontend'in dinamik `sitemap.xml` oluşturması için tüm public slug'ları ve `updated_at` tarihlerini döner. *(Bkz: Bölüm 7.4)*
### Protected API (Admin Panel İçin - `api/admin/...`)
Tüm yetkili işlemler burada yalıtılmıştır.
- `POST /api/admin/login` -> Bearer token döndürür (Sanctum/Passport).
- `GET /api/admin/me` -> Giriş yapan admin detaylarını + Spatie Permission rollerini/izinlerini döner.
- `POST /api/admin/uploads` -> Multipart/form-data kabul eder. Standart resim yükleme ucudur. DB'ye URL değil **path** kaydeder. Response: `{ "path": "uploads/...", "url": "https://.../uploads/..." }`
- Modüller için tüm standart `POST` (Oluşturma), `PUT/PATCH` (Güncelleme), `DELETE` (Silme) uçları.
- Menü Yönetimi:
- `CRUD /api/admin/menus` -> Menü ekleme ve ağaç dökümü
- `POST /api/admin/menus/reorder` -> Sürükle-Bırak sonrası hiyerarşiyi (parent_id ve order) toplu güncelleme
- SSS (FAQ) Yönetimi:
- `CRUD /api/admin/faqs` -> Soru ekleme, düzenleme, silme, listeleme
- Eğitim Rehberi Kartları:
- `CRUD /api/admin/guide-cards` -> Kart ekleme, düzenleme, silme, listeleme
- Page Builder Admin uçları:
- `CRUD /api/admin/pages`
- `CRUD /api/admin/pages/{id}/blocks`
- `POST /api/admin/pages/{id}/blocks/reorder` -> Sürükle bırak ile sıra (`order_index`) güncelleme.
---
## 3. Laravel Katmanlı Mimari (Repository Pattern) Uygulama Standartları
Backend kodlanırken kesinlikle **Spagetti Controller** (Controller içine direkt `Course::create()` yazmak) kullanılmayacaktır. Tüm iş mantığı ve veritabanı sorguları şu katmanlara ayrılmalıdır:
**Önerilen Devasa (Enterprise) Klasör Mimarisi (`app/`):**
```text
app/
├── Http/
│ ├── Controllers/
│ │ └── Api/
│ │ └── CourseController.php # HTTP İsteğini alır, DTO'yu oluşturup Action'a yollar. Geriye Response döner.
│ ├── Requests/
│ │ └── StoreCourseRequest.php # Gelen verilerin validasyon zorunluluklarını (required, string) yapar.
│ └── Resources/
│ └── CourseResource.php # {YENİ} Frontend'e gidecek JSON formatını filtreler ve standartlaştırır (Presenter).
├── DTOs/
│ └── CourseData.php # Validasyonu geçmiş temiz veriyi, tiplendirilmiş Nesneye (DTO) dönüştürür.
├── Actions/ (veya Services/)
│ └── Course/
│ └── CreateCourseAction.php # Tüm "İş Mantığı". İndirim hesapla, Event fırlat, Repository'e yolla.
├── Repositories/
│ ├── Contracts/
│ │ └── CourseRepositoryInterface.php # Sınırlar ve Kurallar (Interface)
│ └── Eloquent/
│ └── CourseRepository.php # Veritabanı (DB) sorguları sadece buradadır (Course::create()).
├── Models/
│ └── Course.php # Tablo yapısı, İlişkiler (Relations)
├── Enums/
│ └── CourseStatus.php # Güvenli Sabitler
├── Events/
│ └── CourseCreatedEvent.php # Asenkron Olaylar (Decoupling için) -> Cache temizleme vb. burada ateşlenir.
├── Listeners/
│ └── NotifySubscribersListener.php # Olayı dinleyen arka plan işlemleri
├── Policies/
│ └── CoursePolicy.php # Yetki ve Rol kontrolleri (Örn: Yetkisiz kişi kurs silemez)
├── Exceptions/
│ └── CourseFullException.php # Domain'e özel hata sınıfları (400)
```
**Kusursuz (Ultimate) Veri Akış Yönü:**
`Route``Middleware (Auth)``Policy (Yetki)``FormRequest (Validasyon)``Controller``DTO``Action``Repository (Interface)``Model``DB`
*(İşlem Başarılıysa)*`Action => Event Fırlatır / Activity Log Atılır`
*(Controller Çıkışı)*`API Resource (JSON Formatlama)``Next.js FrontEnd`
**Audit Log / Kullanıcı İşlem Kayıtları Notu:**
Sisteme yetkili girişler yapılacağı için (Super Admin, Editor vs) veri güncellemelerini, silmeleri (SoftDelete edilen datalar) izlemek amacıyla projeye `spatie/laravel-activitylog` paketi kurulması, oluşan Transaction'ların tutulması önerilir.
---
## 4. Next.js Admin Panel Mimarisi Önerisi
Admin Paneli tamamen ayrı bir Next.js projesi olarak (Örn: `admin.bogazicidenizcilik.com` veya `localhost:3001` portunda) kurulmalıdır.
### **Mimari Prensip (Katmanlı Mimari - Layered Architecture):**
Kodların tek bir klasöre yığılmasını önlemek için Frontend kodları işlevselliğe göre ayrılmalıdır. Örnek `src/` mimarisi:
- `src/app/`: Sadece sayfalar (Routing) ve sayfa Layout'ları.
- `src/components/`: Ortak kullanılan UI elementleri (Button, Input, Table, **Ortak ImageUpload Bileşeni**).
- `src/features/`: Modül bazlı klasörleme (Örn: `features/courses/components`, `features/courses/api`, `features/courses/types`).
- `src/lib/`: Axios instance, yardımcı fonksiyonlar.
### Önerilen Klasör Dizilimi (`src/app/` Route Alanı):
```text
src/app/
├── (auth)/
│ └── login/page.tsx # Giriş ekranı (Kullanıcı Adı, Şifre -> Laravel Sanctum Token)
├── (dashboard)/
│ ├── layout.tsx # Sol Sidebar ve Üst Header kapsayıcısı (Role-based menu gösterimi)
│ ├── page.tsx # Dashboard Özeti (İstatistik kartları: Toplam Öğrenci, Yeni Formlar)
...
```
### Tüm Admin Modülleri ve Ekran Detayları
#### 4.1. Kategoriler (`/categories`)
- **`page.tsx`:** Kategori Tablosu (Resim, Kategori Adı, İşlemler (Düzenle/Sil)).
- **`[id]/page.tsx` (Ekleme / Düzenleme Formu):**
- `label` *(Text Input)* - Kategori Adı
- `slug` *(Text Input)* - (Girilen isimden otomatik slug yaratılmalı)
- `desc` *(Textarea)* - Kısa Tanıtım
- `image` *(Upload Component)* - `POST /api/admin/uploads` tetikleyecek tek kullanımlık standart bileşen
- **SEO Alanı:** `meta_title`, `meta_description` *(Text Input)*
#### 4.2. Eğitimler (`/courses`)
- **`page.tsx`:** Eğitimler Tablosu (Kategorisine göre filtrelenebilir, Öğrenci Sayısı vs.).
- **`[id]/page.tsx` (Ekleme / Düzenleme Formu):**
- **Genel Bilgiler:**
- `title`, `sub`, `category_id`, `price`, `duration`, `badge`
- **İçerik Editörü:**
- `desc` *(Textarea)*
- `longDesc` *(Rich Text Editor - CKEditor/Quill/Notion-stile Editor)*
- `image` *(Upload Component)*
- **Dinamik Diziler (Field Arrays / Repeaters):**
- `includes` *(Dynamic Input Array)* - "Fiyata Dahil Olanlar" (+)
- `requirements` *(Dynamic Input Array)* - "Kayıt Şartları" (+)
- **SEO Alanı:** `meta_title`, `meta_description` *(Text Input)*
#### 4.3. Eğitim Takvimi / Planlama (`/schedules`)
- **`page.tsx`:** Takvim Tablosu (Kurs Adı, Başlangıç, Bitiş, Kontenjan).
- **`[id]/page.tsx` (Ekleme / Düzenleme Formu):**
- `course_id`, `start_date`, `end_date`, `location`, `quota`, `available_seats`
- `is_urgent` *(Switch / Checkbox)* - "Son 3 Gün" uyarı ateşleyicisi
#### 4.4. Duyurular ve Haberler (`/announcements`)
- **`page.tsx`:** Olayların Tablosu.
- **`[id]/page.tsx` (Ekleme / Düzenleme Formu):**
- `title`, `category` (Seçim ile), `excerpt`, `content` (RTE), `image` (Upload), `meta_title`, `meta_description`
- `published_at` *(Date/Time Picker)* - İleri tarihli yayınlanma opsiyonu
- `is_featured` *(Switch)* - "Ana Sayfada Manşet Yap" onay kutusu
#### 4.5. Ön Kayıt Başvuruları (CRM) (`/leads`)
- **`page.tsx`:** Form başvuruları listesi. **`is_read = false` olan kayıtlar kalın (bold) veya fosforlu arka planla ayırt edici gösterilmelidir.**
- **`[id]/page.tsx` (Görüntüleme Müşteri Detayı):**
- Gelen veriler: *Adı, Telefon, Durumu, İlgilendiği Eğitim, Kaynak (Source), UTMEketleri, KVKK Onay Vrs.* (Salt Okunur - Read/Only).
- Yalnızca Tıklandığında backend'e PATCH isteği atılıp `is_read = true` yapılır.
- Admin işlemleri:
- `status` *(Select)* - (Yeni, Arandı, Kayıt Oldu, İptal)
- `notes` *(Textarea)* - Admin/Müşteri Temsilcisi iç notları. Form POST ile güncellenir.
#### 4.6. Menü ve Navigasyon Yönetimi (`/menus`)
- **`page.tsx`:** Menü lokasyonlarına (`header_main`, `footer_corporate`, `footer_education`, vb.) göre sekmeli (tab) bir liste. Her lokasyon için alt alta ağaç (tree) görünümlü kayıtlar. Sürükle-bırak (Drag & Drop) ile `POST /api/admin/menus/reorder` tetiklenerek sıralama ve parent/child ilişkisi hızlıca kurulabilmeli.
- **`[id]/page.tsx` (Ekleme / Düzenleme):**
- `location` *(Select)* - Header Ana Menü mü Yoksa Footer mı?
- `label` *(Text Input)* - "Eğitimler"
- `url` *(Text Input)* - "/egitimler"
- `type` *(Select)* - Normal Link mi (`link`), Eğitim Mega Menüsü mü (`mega_menu_education`), Takvim mi (`mega_menu_calendar`)
- `parent_id` *(Select)* - Bir ana menünün altına eklenecekse o ana menü seçilir.
- `is_active` *(Switch)*
#### 4.7. Yorum / Soru-Cevap Yönetimi (`/comments`)
- **`page.tsx`:** Kullanıcılardan (üye olmadan) Eğitim ve Bloglara gelen tüm soruların/yorumların düştüğü ekran. `is_approved = false` olanlar (yeni gelenler) belirgin şekilde listelenir.
- **`[id]/page.tsx` (Yorum Onay ve Yanıtlama):**
- Gelen veriler: *Adı Soyadı, Telefon Numarası, Yorum Yapılan İçerik (Kurs Adı vs), Yorum Metni* (Read-Only).
- `admin_reply` *(Textarea)* - Yorum/soruyu cevaplamak için adminin dolduracağı alan.
- `is_approved` *(Switch)* - Yorumun sitede herkes tarafından gözüküp gözükmeyeceği.
#### 4.8. SSS / Sıkça Sorulan Sorular Yönetimi (`/faqs`)
- **`page.tsx`:** FAQ Tablosu (Kategori, Soru, Aktif/Pasif durumu). Kategoriye göre filtrelenebilir.
- **`[id]/page.tsx` (Ekleme / Düzenleme Formu):**
- `category` *(Select)* - `egitimler` | `kayit` | `iletisim`
- `question` *(Textarea)* - Soru metni
- `answer` *(Textarea / Rich Text)* - Cevap metni
- `order` *(Number Input)* - Kategori içi sıralama
- `is_active` *(Switch)* - Aktif/Pasif
#### 4.9. Eğitim Rehberi Kartları Yönetimi (`/guide-cards`)
- **`page.tsx`:** Rehber kartlarının listesi (Başlık, Icon, Link, Sıra).
- **`[id]/page.tsx` (Ekleme / Düzenleme Formu):**
- `title` *(Text Input)* - Kart başlığı (Örn: "Yeni Başlayanlar")
- `description` *(Textarea)* - Açıklama metni
- `icon` *(Select)* - Lucide icon seçimi (`anchor`, `compass`, `shield`, `briefcase` vb.)
- `color` *(Text Input / Color Picker)* - Gradient renk sınıfı
- `link` *(Text Input)* - Yönlendirme URL'i
- `order` *(Number Input)* - Sıralama
- `is_active` *(Switch)*
#### 4.10. Sitenin Genel Ayarları (`/settings`)
Bu tek bir sayfada çalışır:
- Sayfa ilk açıldığında `GET /api/admin/settings` ile tüm satırları çeker.
- `group` verisine göre yatay ya da dikey Tabs (Sekmeler) oluşturur (Genel, Anasayfa, İletişim, Sosyal Medya, SEO, Formlar, Eğitim Rehberi, Danışmanlık).
- **Anasayfa Sekmesi:** Anasayfadaki "Neden Biz", "Biz Kimiz", info/görsel alanlarındaki başlıklar (`home_about_title`), metinler (`home_about_text`) ve resimlerin (`home_about_image_1`) yönetimi.
- **Sosyal Medya Sekmesi:** Tüm hesapların (Instagram, Facebook, Tiktok, LinkedIn vb.) linkleri buraya girilir. Frontend, boş olmayan değerleri render eder.
- **Eğitim Rehberi Sekmesi:** Eğitim rehberi sayfasının başlık, alt metin ve CTA (Call to Action) alanlarının yönetimi.
- **Danışmanlık Sekmesi:** Danışmanlık sayfasının başlık ve açıklama metinleri.
- `type` verisine göre ekranda Text Input, Textarea veya Toggle Switch render eder. Kaydederken array olarak tek bir PATCH isteğinde sunucuya yollar.
---
## 5. Mevcut Frontend Projesi (Boğaziçi) Entegrasyon Adımları
Backend ve Admin Panel hazır olduğunda, mevcut statik yapınızda şu işlemler gerçekleştirilecektir:
1. **Çevresel Değişkenler:** `.env.local` içine `NEXT_PUBLIC_API_URL=http://api.bogazici.test/api/v1` eklenmeli. Yüklenen resimleri parse edebilmek için `NEXT_PUBLIC_ASSET_URL=http://api.bogazici.test` konulmalı.
2. **Data Fetching:**
- Statik `src/data/*.ts` dosyaları silinmeli.
- Tüm sayfalarda `fetch` kullanılarak (veya Axios) ISR yapısıyla veriler çekilmeli.
- *Örnek:* `const res = await fetch(\`\${process.env.NEXT_PUBLIC_API_URL}/courses\`, { next: { revalidate: 3600 } });`
3. **Form Gönderimi:** Hero'daki form submit edildiğinde veriler `POST /api/v1/leads` ucuna JSON olarak yollanmalı.
---
## 6. Dinamik Sayfalar İçin Headless Page Builder (`/page/` Rotası)
> **Kapsam Notu:** Page Builder sistemi **yalnızca** `/page/` rotası altında oluşturulan dinamik sayfalar için kullanılacaktır. Kurumsal sayfalar (`/kurumsal/hakkimizda`, `/kurumsal/vizyon-misyon`, vb.) ve `/danismanlik`, `/egitim-rehberi`, `/sss` gibi özel tasarımlı sayfalar frontend'de statik bileşenler olarak kalacak ve verilerini kendi API endpoint'lerinden veya `settings` tablosundan çekeceklerdir.
Admin panelden yeni landing page'ler, kampanya sayfaları veya özel içerik sayfaları oluşturmak için **Modüler Blok Sistemi** kullanılacaktır.
### Mevcut Frontend (Boğaziçi Denizcilik) Tarafında Okunması
**Örnek `src/app/page/[slug]/page.tsx` Kullanımı:**
```tsx
export default async function DynamicPage({ params }: { params: { slug: string } }) {
// 1. Laravel'den sayfanın aktif bloklarını çek
const page = await fetch(`.../api/v1/pages/${params.slug}`).then(r => r.json());
return (
<main>
{/* 2. Gelen blokları (Lego parçalarını) sırası ve tipine göre render et */}
{page.blocks.map((block) => {
switch (block.type) {
case 'hero':
return <HeroBlock key={block.id} data={block.content} />;
case 'stats_grid':
return <StatsBlock key={block.id} data={block.content} />;
case 'text_image':
return <StoryBlock key={block.id} data={block.content} />;
default:
return null;
}
})}
</main>
);
}
```
> **Özet Tavsiye:** Geliştirme süresi uzasa da, bir kere kurulduğunda kodlamaya bir daha dokunmadan şirketin sayısız ve benzersiz tasarımda yeni sayfalar veya landing page'ler üretmesini sağlar. Endüstri standardı bir çözümdür.
---
## 7. SEO & Yapısal Veri (Structured Data) Standartları
Sitenin arama motorlarında üst sıralarda yer alabilmesi için backend API'nin aşağıdaki SEO gereksinimlerini eksiksiz karşılaması gerekmektedir.
### 7.1. Meta Alanları (Her Modülde Zorunlu)
Aşağıdaki tablolarda `meta_title` ve `meta_description` alanları mevcuttur ve **zorunlu olarak** doldurulmalıdır:
- `categories` — ✅ `meta_title`, `meta_description`
- `courses` — ✅ `meta_title`, `meta_description`
- `announcements` — ✅ `meta_title`, `meta_description`
> **Kural:** Admin panelde bu alanlar boş bırakıldığında, `title` veya `excerpt` alanından otomatik üretilmelidir (Frontend veya Backend tarafında fallback mantığı ile).
### 7.2. OpenGraph Görsel Desteği
Sosyal medyada paylaşıldığında güzel bir önizleme kartı oluşturabilmek için:
- `courses.image` ve `announcements.image` alanları aynı zamanda **OG Image** olarak kullanılacaktır.
- Frontend'de `generateMetadata` fonksiyonunda bu görseller `openGraph.images` altına eklenmelidir.
- Görseller **minimum 1200x630px** boyutunda olmalıdır. Admin panelde resim yüklerken bu uyarı gösterilmelidir.
### 7.3. JSON-LD Yapısal Veri Şemaları (Schema.org)
Google Rich Snippets, Knowledge Panel ve zengin arama sonuçları için aşağıdaki JSON-LD blokları frontend'de render edilmelidir:
#### Ana Sayfa (`/`)
```json
{
"@context": "https://schema.org",
"@type": "EducationalOrganization",
"name": "Boğaziçi Denizcilik",
"url": "https://www.bogazicidenizcilik.com.tr",
"logo": "...",
"description": "...",
"address": { "@type": "PostalAddress", ... },
"contactPoint": { "@type": "ContactPoint", ... },
"sameAs": ["instagram", "facebook", "youtube", ...]
}
```
*(Mevcut frontend'de zaten var ✅ — Veriler settings API'den çekilmeli)*
#### Eğitim Detay Sayfası (`/egitimler/{kategori}/{slug}`)
```json
{
"@context": "https://schema.org",
"@type": "Course",
"name": "STCW Temel Güvenlik (BST)",
"description": "...",
"provider": {
"@type": "Organization",
"name": "Boğaziçi Denizcilik",
"sameAs": "https://www.bogazicidenizcilik.com.tr"
},
"hasCourseInstance": {
"@type": "CourseInstance",
"courseMode": "onsite",
"duration": "P5D",
"location": { "@type": "Place", "name": "Kadıköy, İstanbul" }
}
}
```
> **Backend Notu:** API'den `GET /api/v1/courses/{slug}` response'unda `json_ld` alanı opsiyonel olarak döndürülebilir veya frontend tarafında oluşturulabilir.
#### Duyuru Detay Sayfası (`/duyurular/{slug}`)
```json
{
"@context": "https://schema.org",
"@type": "NewsArticle",
"headline": "...",
"datePublished": "2026-02-15",
"author": { "@type": "Organization", "name": "Boğaziçi Denizcilik" },
"image": "...",
"publisher": { "@type": "Organization", "name": "Boğaziçi Denizcilik", "logo": "..." }
}
```
#### SSS Sayfası (`/sss`) — **FAQPage Schema (Çok Önemli)**
```json
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "Eğitimleriniz hangi kurumlar tarafından onaylıdır?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Tüm eğitimlerimiz Ulaştırma ve Altyapı Bakanlığı onaylıdır..."
}
}
]
}
```
> ⚠️ **Google FAQPage Rich Result**: SSS sayfasında bu şema kullanılırsa arama sonuçlarında soru-cevaplar **doğrudan** gösterilir. Bu `GET /api/v1/faqs` endpoint'inden dönen verilerle frontend'de dinamik olarak oluşturulmalıdır.
#### Tüm Sayfalarda — **BreadcrumbList Schema**
```json
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Anasayfa", "item": "https://..." },
{ "@type": "ListItem", "position": 2, "name": "Eğitimler", "item": "https://.../egitimler" },
{ "@type": "ListItem", "position": 3, "name": "STCW Temel Güvenlik" }
]
}
```
### 7.4. Dinamik Sitemap (API Destekli)
Mevcut `sitemap.ts` statik datayla çalışmaktadır. Backend hazır olduğunda:
- `GET /api/v1/sitemap-data` → Tüm public slug'ları, `updated_at` tarihleriyle döndüren özel endpoint. Frontend `sitemap.ts` bunu kullanarak dinamik sitemap oluşturacak.
- Sitemap `lastModified` alanları gerçek `updated_at` tarihlerinden beslenmelidir (şu an tüm sayfalarda `new Date()` kullanılıyor).
- Yeni kurs/duyuru/sayfa eklendiğinde sitemap otomatik olarak güncellenecektir.
**Önerilen endpoint response yapısı:**
```json
{
"courses": [{ "slug": "stcw-temel-guvenlik", "kategori": "stcw", "updated_at": "2026-02-15" }],
"announcements": [{ "slug": "kayitlar-basladi", "updated_at": "2026-02-10" }],
"pages": [{ "slug": "kampanya-bahar-2026", "updated_at": "2026-02-01" }]
}
```
### 7.5. Canonical URL'ler
- Tüm sayfalarda `<link rel="canonical">` bulunmalıdır. Mevcut frontend'de `alternates.canonical` zaten desteklenmekte. ✅
- Backend API'den gelen slug'lar ile frontend URL yapısı **birebir eşleşmelidir**.
- `courses` slug'ları: `/egitimler/{kategoriSlug}/{courseSlug}`
- `announcements` slug'ları: `/duyurular/{slug}`
### 7.6. Hızlı SEO Kontrol Listesi (Checklist)
| Öğe | Durum | Açıklama |
|---|---|---|
| `<title>` tag — Her sayfada benzersiz | ✅ | `generateMetadata` ile dinamik |
| `<meta description>` — Her sayfada benzersiz | ✅ | DB'den `meta_description` alanı |
| `<link rel="canonical">` | ✅ | `alternates.canonical` ile |
| OpenGraph tags (og:title, og:description, og:image) | ✅ | Dinamik sayfalarda var |
| Twitter Card tags | ✅ | Layout'ta global tanımlı |
| `robots.txt` | ✅ | `/api/` bloklanmış |
| XML Sitemap | ✅ | Dinamik hale getirilecek (7.4) |
| JSON-LD EducationalOrganization | ✅ | Ana sayfada mevcut |
| JSON-LD Course | ⚠️ | Detay sayfasına eklenmeli |
| JSON-LD NewsArticle | ⚠️ | Duyuru detay sayfasına eklenmeli |
| JSON-LD FAQPage | ❌ | SSS sayfasına eklenmeli |
| JSON-LD BreadcrumbList | ❌ | Tüm sayfalara eklenmeli |
| `<html lang="tr">` | ✅ | Layout'ta mevcut |
| Semantic HTML (h1, h2, article, nav) | ✅ | Tüm sayfalarda uygulanmış |
| Image alt attributes | ✅ | Görsellerde title kullanılıyor |
| Lazy loading images | ✅ | İlk 6 eager, geri kalan lazy |
| `generateStaticParams` (SSG) | ✅ | Tüm dinamik rotalarda var |
| ISR / Revalidate | ⚠️ | API entegrasyonunda `revalidate` eklenecek |
> **Öncelik Sırası:** FAQPage schema → BreadcrumbList schema → Course JSON-LD → NewsArticle JSON-LD → Dinamik Sitemap
---
## 8. Backend Uygulama Durumu (Implementation Status)
> *Bu bölüm, yukarıdaki gereksinimlere göre Laravel backend'de yapılan tüm implementasyonları belgelemektedir.*
### 8.1. Veritabanı & Model Katmanı
| Bileşen | Sayı | Durum | Detay |
|---------|------|-------|-------|
| Migration | 22 | ✅ | users, cache, jobs, permission_tables, activity_log (×3), personal_access_tokens, soft_deletes_users, categories, courses, course_schedules, announcements, hero_slides, leads, menus, comments, faqs, guide_cards, settings, pages, page_blocks |
| Model | 14 | ✅ | User, Category, Course, CourseSchedule, Announcement, HeroSlide, Lead, Menu, Comment, Faq, GuideCard, Setting, Page, PageBlock |
| Factory | 13 | ✅ | Tüm modeller için (User dahil) |
| Enum | 8 | ✅ | AnnouncementCategory, FaqCategory, LeadSource, LeadStatus, MenuLocation, MenuType, SettingGroup, SettingType |
| Seeder | 5 | ✅ | DatabaseSeeder, RolePermissionSeeder, AdminUserSeeder, SettingSeeder, RoleSeeder (artık kullanılmıyor) |
### 8.2. Katmanlı Mimari (Repository Pattern) Bileşenleri
Dökümanın 3. bölümünde belirtilen mimari tam olarak uygulanmıştır:
```
Route ➔ Middleware (Auth) ➔ Policy (Yetki) ➔ FormRequest (Validasyon) ➔ Controller ➔ DTO ➔ Action ➔ Repository (Interface) ➔ Model ➔ DB
```
| Katman | Sayı | Kapsam |
|--------|------|--------|
| Repository Interface | 13 | BaseRepositoryInterface + 12 modül |
| Repository Eloquent | 13 | BaseRepository + 12 modül |
| DTO (Data Transfer Object) | 11 | Tüm CRUD modülleri |
| Action (Service) | 34 | Create/Update/Delete × 11 modül + UpdateSettingsAction |
| FormRequest | 25 | Store/Update × 11 modül + LoginRequest + ReorderMenuRequest + UpdateSettingsRequest |
| API Resource | 13 | Tüm modüller + PageBlockResource |
| Controller | 28 | 13 Public (V1) + 15 Admin |
| Policy | 11 | Category, Course, CourseSchedule, Announcement, HeroSlide, Lead, Menu, Comment, Faq, GuideCard, Page |
### 8.3. Yetkilendirme & Permission Sistemi (Spatie Permission v7)
#### Roller
| Rol | Açıklama |
|-----|----------|
| `super-admin` | Tüm 48 permission'a sahip |
| `editor` | Silme (`delete-*`) hariç 36 permission'a sahip |
#### Permission Yapısı (12 Modül × 4 Aksiyon = 48 Permission)
| Modül | `view-*` | `create-*` | `update-*` | `delete-*` |
|-------|----------|------------|------------|------------|
| category | ✅ | ✅ | ✅ | ✅ |
| course | ✅ | ✅ | ✅ | ✅ |
| schedule | ✅ | ✅ | ✅ | ✅ |
| announcement | ✅ | ✅ | ✅ | ✅ |
| hero-slide | ✅ | ✅ | ✅ | ✅ |
| lead | ✅ | ✅ | ✅ | ✅ |
| menu | ✅ | ✅ | ✅ | ✅ |
| comment | ✅ | ✅ | ✅ | ✅ |
| faq | ✅ | ✅ | ✅ | ✅ |
| guide-card | ✅ | ✅ | ✅ | ✅ |
| setting | ✅ | ✅ | ✅ | ✅ |
| page | ✅ | ✅ | ✅ | ✅ |
> **Not:** `editor` rolü `delete-*` permission'larından hariç tutulmuştur. Tüm policy dosyaları `hasPermissionTo()` ile çalışmaktadır (rol kontrolü değil, permission kontrolü).
### 8.4. API Rotaları
Toplam **97 rota** kayıtlıdır.
#### Public API — `GET /api/v1/...`
| Endpoint | Controller | Açıklama |
|----------|-----------|----------|
| `GET /api/v1/categories` | CategoryController@index | Kategorileri listeler |
| `GET /api/v1/categories/{slug}` | CategoryController@show | Tekil kategori |
| `GET /api/v1/courses` | CourseController@index | Eğitimleri listeler |
| `GET /api/v1/courses/{slug}` | CourseController@show | Tekil eğitim detayı |
| `GET /api/v1/schedules` | ScheduleController@index | Takvim eğitimleri |
| `GET /api/v1/schedules/upcoming` | ScheduleController@upcoming | Yaklaşan eğitimler |
| `GET /api/v1/schedules/{id}` | ScheduleController@show | Tekil takvim kaydı |
| `GET /api/v1/announcements` | AnnouncementController@index | Duyurular |
| `GET /api/v1/announcements/{slug}` | AnnouncementController@show | Tekil duyuru |
| `GET /api/v1/hero-slides` | HeroSlideController@index | Aktif slider |
| `POST /api/v1/leads` | LeadController@store | Ön kayıt formu (Rate Limit: 3/dk) |
| `GET /api/v1/comments/{type}/{id}` | CommentController@index | Onaylı yorumlar |
| `POST /api/v1/comments` | CommentController@store | Yeni yorum (Rate Limit: 3/dk) |
| `GET /api/v1/menus/{location}` | MenuController@index | Menü ağacı |
| `GET /api/v1/faqs` | FaqController@index | SSS listesi |
| `GET /api/v1/faqs/{category}` | FaqController@index | Kategoriye göre SSS |
| `GET /api/v1/guide-cards` | GuideCardController@index | Rehber kartları |
| `GET /api/v1/settings` | SettingController@index | Public ayarlar (`is_public=true`) |
| `GET /api/v1/pages/{slug}` | PageController@show | Dinamik sayfa (Page Builder) |
| `GET /api/v1/sitemap-data` | SitemapController@index | Sitemap verileri |
#### Admin API — `POST|GET|PUT|DELETE /api/admin/...` (Sanctum Auth)
| Endpoint | Controller | Açıklama |
|----------|-----------|----------|
| `POST /api/admin/login` | AuthController@login | Giriş → Bearer Token |
| `GET /api/admin/me` | AuthController@me | Giriş yapan admin bilgisi |
| `POST /api/admin/logout` | AuthController@logout | Çıkış |
| `POST /api/admin/uploads` | UploadController@store | Dosya yükleme |
| `CRUD /api/admin/categories` | AdminCategoryController | apiResource |
| `CRUD /api/admin/courses` | AdminCourseController | apiResource |
| `CRUD /api/admin/schedules` | AdminScheduleController | apiResource |
| `CRUD /api/admin/announcements` | AdminAnnouncementController | apiResource |
| `CRUD /api/admin/hero-slides` | AdminHeroSlideController | apiResource |
| `CRUD /api/admin/leads` | AdminLeadController | apiResource (store hariç) |
| `POST /api/admin/menus/reorder` | AdminMenuController@reorder | Menü sıralaması |
| `CRUD /api/admin/menus` | AdminMenuController | apiResource |
| `CRUD /api/admin/comments` | AdminCommentController | apiResource (store hariç) |
| `CRUD /api/admin/faqs` | AdminFaqController | apiResource |
| `CRUD /api/admin/guide-cards` | AdminGuideCardController | apiResource |
| `GET /api/admin/settings` | AdminSettingController@index | Tüm ayarlar |
| `GET /api/admin/settings/group/{group}` | AdminSettingController@group | Grup bazlı |
| `PUT /api/admin/settings` | AdminSettingController@update | Toplu güncelleme |
| `CRUD /api/admin/pages` | AdminPageController | apiResource |
| `POST /api/admin/pages/{page}/blocks/reorder` | AdminBlockController@reorder | Blok sıralaması |
| `CRUD /api/admin/pages/{page}/blocks` | AdminBlockController | Nested apiResource |
### 8.5. Cache & Event Sistemi
| Bileşen | Dosya | Açıklama |
|---------|-------|----------|
| Event | `app/Events/ModelChanged.php` | Tüm CRUD Action'larda dispatch edilir |
| Listener | `app/Listeners/ClearModelCache.php` | ModelChanged event'ini dinler, ilgili cache key'lerini temizler |
**Cache Uygulanan Repository'ler:**
| Repository | Cache Key | TTL | Açıklama |
|-----------|-----------|-----|----------|
| SettingRepository | `settings:public` | 1 saat | Public ayarlar |
| HeroSlideRepository | `hero_slides:active` | 1 saat | Aktif slider |
| GuideCardRepository | `guide_cards:active` | 1 saat | Aktif rehber kartları |
| MenuRepository | `menus:{location}` | 1 saat | Lokasyona göre menü |
| FaqRepository | `faqs:{category}` | 1 saat | Kategoriye göre SSS |
> Admin panelden veri güncellendiğinde `ModelChanged` event'i fırlatılır ve `ClearModelCache` listener ilgili cache key'lerini otomatik olarak temizler.
### 8.6. Güvenlik & Middleware
| Özellik | Durum | Detay |
|---------|-------|-------|
| Sanctum Token Auth | ✅ | Admin API koruması (`auth:sanctum`) |
| Rate Limiting | ✅ | `leads`: 3/dk, `comments`: 3/dk (IP bazlı) |
| Global API Throttle | ✅ | 60 istek/dk (`bootstrap/app.php`) |
| Stateful API | ✅ | SPA oturumu için |
| CORS | ✅ | `max_age: 86400` |
| 404 Handler | ✅ | API isteklerinde JSON hata dönüşü |
| SoftDeletes | ✅ | users, categories, courses, leads, comments |
| Spatie Activity Log | ✅ | `spatie/laravel-activitylog` kurulu |
### 8.7. Swagger / OpenAPI Dökümantasyonu
- **Paket:** `darkaonline/l5-swagger v10.1.0`
- **Erişim:** `GET /api/documentation`
- **Ana Annotation Dosyası:** `app/Http/Controllers/SwaggerAnnotations.php`
- **Toplam Path:** 45+ endpoint, 77+ operasyon
- Tüm controller'larda `@OA\Get`, `@OA\Post`, `@OA\Put`, `@OA\Delete` annotation'ları mevcuttur.
### 8.8. Teknik Altyapı
| Paket | Versiyon | Kullanım |
|-------|----------|----------|
| PHP | 8.4 | Runtime |
| Laravel Framework | v12 | Ana framework |
| Laravel Sanctum | v4 | Token auth |
| Spatie Permission | v7.2 | RBAC (48 permission, 2 rol) |
| Spatie Activity Log | v4.12 | Audit log |
| darkaonline/l5-swagger | v10.1 | API dökümantasyonu |
| Pest | v4 | Test framework |
| Laravel Pint | v1 | Kod formatlama |
| Laravel Herd | - | Yerel sunucu |
### 8.9. Dosya Özeti
| Kategori | Sayı |
|----------|------|
| Migration | 22 |
| Model | 14 |
| Enum | 8 |
| Controller | 28 (+2 base/swagger) |
| FormRequest | 25 |
| API Resource | 13 |
| Repository Interface | 13 |
| Repository Eloquent | 13 |
| Action | 34 |
| DTO | 11 |
| Policy | 11 |
| Event | 1 |
| Listener | 1 |
| Seeder | 5 |
| Factory | 13 |
| **Toplam** | **~214 dosya** |