update deploy

This commit is contained in:
bulut
2026-03-27 10:41:54 +03:00
parent 69d19c0176
commit 6f6448aa06
422 changed files with 37956 additions and 0 deletions

802
backend_ve_admin_dokuman.md Normal file
View File

@@ -0,0 +1,802 @@
# 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** |