43 KiB
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.mddosyası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:
- Ö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.
- 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),Repositoryve en sonControllerileapi.phprotalarını oluştur. Response standartlarına ve Caching kurallarına dikkat et.- 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
userstablosu. Admin panele giriş yapacak personeli temsil eder. - Sisteme Spatie Permission paketi kurularak Role ve Yetki altyapısı tanımlanacaktır (Örn:
super-admin,editor). SoftDeletesaktif olmalıdır.
1.1. categories (Eğitim Kategorileri)
id(PK)slug(string, unique) - Örn: guvertelabel(string) - Örn: Güverte Eğitimleridesc(text, nullable)image(string, nullable) - Sadece görsel path'i tutarmeta_title(string, nullable) - SEO Titlemeta_description(text, nullable) - SEO Descriptioncreated_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/1desc(text) - Kısa açıklamalong_desc(longText) - Detaylı açıklamaduration(string) - Örn: 5 Günstudents(integer, default: 0) - Kayıtlı öğrenci sayısırating(decimal: 2,1, default: 5.0)badge(string, nullable) - Örn: Simülatörimage(string, nullable) - Sadece path tutarprice(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 Titlemeta_description(text, nullable) - SEO Descriptionscope(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 dililocation(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-24end_date(date) - Örn: 2026-02-28location(string) - Örn: Kadıköy veya Onlinequota(integer) - Toplam Kontenjanavailable_seats(integer) - Kalan Koltuk (Otomatikquota - reserved_countmantığı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|eventexcerpt(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 Sertifikasyonutitle(string) - Satır başı için \n desteklidescription(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ğitimeducation_level(string, nullable) - Öğrenim durumusubject(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,rejectednotes(text, nullable) - Admin notlarıis_read(boolean, default: false) - Admin panelde okunmamışları vurgulamak içinsource(string) -hero_form|contact_form|consultation_form|whatsapp_widgetutm(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_quicklinkslabel(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ıralamais_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\\CourseveyaApp\\Models\\Announcementname_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 metniadmin_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ükmemelicreated_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 metnianswer(text) - Cevap metniorder(integer, default: 0) - Kategori içi sıralamais_active(boolean, default: true) - Pasif olanlar önyüzde gösterilmezcreated_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ıralamais_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|guidekey(string, unique)value(text/json, nullable)type(string) -text|textarea|image|boolean|json|richtextis_public(boolean, default: true) - Public API'de görünsün mü? (Örn:hero_form_emailgizli 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=1GET /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=trueolan 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=egitimlerfiltresi 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ı.sourcealanı 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 dinamiksitemap.xmloluşturması için tüm public slug'ları veupdated_attarihlerini 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/pagesCRUD /api/admin/pages/{id}/blocksPOST /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/):
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ı):
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ımimage(Upload Component) -POST /api/admin/uploadstetikleyecek 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)
- Genel Bilgiler:
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_seatsis_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_descriptionpublished_at(Date/Time Picker) - İleri tarihli yayınlanma opsiyonuis_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 = falseolan 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 = trueyapı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) ilePOST /api/admin/menus/reordertetiklenerek 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 = falseolanlar (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|iletisimquestion(Textarea) - Soru metnianswer(Textarea / Rich Text) - Cevap metniorder(Number Input) - Kategori içi sıralamais_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 metniicon(Select) - Lucide icon seçimi (anchor,compass,shield,briefcasevb.)color(Text Input / Color Picker) - Gradient renk sınıfılink(Text Input) - Yönlendirme URL'iorder(Number Input) - Sıralamais_active(Switch)
4.10. Sitenin Genel Ayarları (/settings)
Bu tek bir sayfada çalışır:
- Sayfa ilk açıldığında
GET /api/admin/settingsile tüm satırları çeker. groupverisine 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.
typeverisine 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:
- Çevresel Değişkenler:
.env.localiçineNEXT_PUBLIC_API_URL=http://api.bogazici.test/api/v1eklenmeli. Yüklenen resimleri parse edebilmek içinNEXT_PUBLIC_ASSET_URL=http://api.bogazici.testkonulmalı. - Data Fetching:
- Statik
src/data/*.tsdosyaları silinmeli. - Tüm sayfalarda
fetchkullanılarak (veya Axios) ISR yapısıyla veriler çekilmeli. - Örnek:
const res = await fetch(\${process.env.NEXT_PUBLIC_API_URL}/courses`, { next: { revalidate: 3600 } });`
- Statik
- Form Gönderimi: Hero'daki form submit edildiğinde veriler
POST /api/v1/leadsucuna 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,/sssgibi özel tasarımlı sayfalar frontend'de statik bileşenler olarak kalacak ve verilerini kendi API endpoint'lerinden veyasettingstablosundan ç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ı:
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_descriptioncourses— ✅meta_title,meta_descriptionannouncements— ✅meta_title,meta_description
Kural: Admin panelde bu alanlar boş bırakıldığında,
titleveyaexcerptalanı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.imageveannouncements.imagealanları aynı zamanda OG Image olarak kullanılacaktır.- Frontend'de
generateMetadatafonksiyonunda bu görselleropenGraph.imagesaltı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 (/)
{
"@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})
{
"@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'undajson_ldalanı opsiyonel olarak döndürülebilir veya frontend tarafında oluşturulabilir.
Duyuru Detay Sayfası (/duyurular/{slug})
{
"@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)
{
"@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/faqsendpoint'inden dönen verilerle frontend'de dinamik olarak oluşturulmalıdır.
Tüm Sayfalarda — BreadcrumbList Schema
{
"@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_attarihleriyle döndüren özel endpoint. Frontendsitemap.tsbunu kullanarak dinamik sitemap oluşturacak.- Sitemap
lastModifiedalanları gerçekupdated_attarihlerinden beslenmelidir (şu an tüm sayfalardanew Date()kullanılıyor). - Yeni kurs/duyuru/sayfa eklendiğinde sitemap otomatik olarak güncellenecektir.
Önerilen endpoint response yapısı:
{
"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'dealternates.canonicalzaten desteklenmekte. ✅ - Backend API'den gelen slug'lar ile frontend URL yapısı birebir eşleşmelidir.
coursesslug'ları:/egitimler/{kategoriSlug}/{courseSlug}announcementsslug'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:
editorrolü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
ModelChangedevent'i fırlatılır veClearModelCachelistener 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\Deleteannotation'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 |