803 lines
43 KiB
Markdown
803 lines
43 KiB
Markdown
# 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ı açı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** |
|
||
|