# Frontend (Next.js) — API Entegrasyon Rehberi ## Genel Bilgi Backend: Laravel API, Base URL: `{API_URL}/api/v1` Auth gerektirmeyen tüm public endpoint'ler burada. Frontend SSR/ISR ile fetch edebilir. --- ## Tüm Public Endpoint'ler | Method | Endpoint | Açıklama | |--------|----------|----------| | `GET` | `/v1/settings` | Site ayarları (nested group format) | | `GET` | `/v1/settings/{group}` | Tek grup ayarları | | `GET` | `/v1/categories` | Eğitim kategorileri | | `GET` | `/v1/categories/{slug}` | Kategori detayı | | `GET` | `/v1/courses` | Eğitim listesi (paginated) | | `GET` | `/v1/courses/{slug}` | Eğitim detayı (blocks + schedules dahil) | | `GET` | `/v1/schedules` | Eğitim takvimi | | `GET` | `/v1/schedules/upcoming` | Yaklaşan eğitimler | | `GET` | `/v1/schedules/{id}` | Takvim detayı | | `GET` | `/v1/announcements` | Duyurular | | `GET` | `/v1/announcements/{slug}` | Duyuru detayı | | `GET` | `/v1/hero-slides` | Hero slider (aktif, sıralı) | | `GET` | `/v1/faqs` | SSS listesi | | `GET` | `/v1/faqs/{category}` | Kategoriye göre SSS | | `GET` | `/v1/guide-cards` | Eğitim rehberi kartları | | `GET` | `/v1/menus/{location}` | Menü (header, footer, vb.) | | `GET` | `/v1/pages/{slug}` | Sayfa detayı (blocks dahil) | | `GET` | `/v1/preview/{token}` | Sayfa önizleme (cache bazlı) | | `GET` | `/v1/comments/{type}/{id}` | Yorumlar | | `POST` | `/v1/leads` | Lead/başvuru formu | | `POST` | `/v1/comments` | Yorum gönder | | `GET` | `/v1/sitemap-data` | Sitemap verisi | --- ## Eğitimler (Courses) ### GET /v1/courses — Liste Query parametreleri: - `category` — Kategori slug filtresi (ör: `guverte`, `stcw`, `makine`) - `search` — Başlık/açıklama arama - `sort` — Sıralama: `title`, `-created_at` (varsayılan), `students`, `rating` (- prefix = desc) - `per_page` — Sayfa başına (varsayılan: 15) ``` GET /v1/courses?category=guverte&sort=-rating&per_page=12 ``` Response (paginated): ```json { "data": [ { "id": 1, "category_id": 1, "category": { "id": 1, "slug": "guverte", "label": "Güverte Eğitimleri" }, "slug": "gemici-birlesik-egitimi", "title": "Gemici (Birleşik) Eğitimi", "sub": "STCW / IMO Uyumlu", "desc": "Güverte bölümünde gemici olarak görev yapmak isteyen...", "long_desc": "Detaylı açıklama...", "duration": "32 Gün", "students": 772, "rating": 4.9, "badge": "most_preferred", "badge_label": "En Çok Tercih Edilen", "image": null, "price": "₺14.500", "includes": ["Basılı eğitim materyalleri", "Uygulamalı güverte tatbikatları", "..."], "requirements": ["En az 16 yaşında olmak", "..."], "scope": ["Denizde kişisel güvenlik", "Yangınla mücadele", "..."], "standard": "STCW / IMO Uyumlu", "language": "Türkçe", "location": "Kadıköy, İstanbul", "meta_title": "Gemici (Birleşik) Eğitimi | Boğaziçi Denizcilik", "meta_description": "STCW A-II/4 uyumlu...", "created_at": "2026-03-02T...", "updated_at": "2026-03-23T..." } ], "links": { "first": "...", "last": "...", "prev": null, "next": "..." }, "meta": { "current_page": 1, "last_page": 3, "per_page": 12, "total": 32 } } ``` ### GET /v1/courses/{slug} — Detay Detayda ek olarak `blocks` ve `schedules` array'leri gelir: ```json { "data": { "id": 1, "slug": "gemici-birlesik-egitimi", "title": "Gemici (Birleşik) Eğitimi", "sub": "STCW / IMO Uyumlu", "desc": "...", "long_desc": "...", "duration": "32 Gün", "students": 772, "rating": 4.9, "badge": "most_preferred", "badge_label": "En Çok Tercih Edilen", "image": null, "price": "₺14.500", "includes": ["Basılı eğitim materyalleri", "..."], "requirements": ["En az 16 yaşında olmak", "..."], "scope": ["Denizde kişisel güvenlik", "..."], "standard": "STCW / IMO Uyumlu", "language": "Türkçe", "location": "Kadıköy, İstanbul", "category": { "id": 1, "slug": "guverte", "label": "Güverte Eğitimleri" }, "blocks": [ { "id": 1, "type": "text", "content": { "label": "EĞİTİM HAKKINDA", "title": "Neden Bu Eğitim?", "body": "

...

" }, "order_index": 0 }, { "id": 2, "type": "text", "content": { "_width": "half", "label": "EĞİTİM KAPSAMI", "title": "Ne Öğreneceksiniz?", "body": "" }, "order_index": 1 }, { "id": 3, "type": "text", "content": { "_width": "half", "label": "BAŞVURU ŞARTLARI", "title": "Kimler Katılabilir?", "body": "" }, "order_index": 2 }, { "id": 4, "type": "stats_grid", "content": { "label": "EĞİTİM SÜRECİ", "title": "Başvurudan Belgeye 4 Adım", "stat_1_value": "01", "stat_1_label": "..." }, "order_index": 3 }, { "id": 5, "type": "cards", "content": { "label": "KAZANIMLAR", "title": "...", "card_1_title": "...", "card_1_icon": "award" }, "order_index": 4 }, { "id": 6, "type": "faq", "content": { "title": "...", "faq_1_question": "...", "faq_1_answer": "..." }, "order_index": 5 }, { "id": 7, "type": "cta", "content": { "title": "...", "button_text": "Ön Kayıt Yap", "button_url": "/kayit?course=..." }, "order_index": 6 } ], "schedules": [ { "id": 1, "start_date": "2026-04-07", "end_date": "2026-05-08", "location": "Kadıköy", "quota": 20, "available_seats": 8, "is_urgent": false } ], "meta_title": "...", "meta_description": "..." } } ``` ### Badge Değerleri | badge | badge_label | Kullanım | |-------|-------------|----------| | `most_preferred` | En Çok Tercih Edilen | Kart üstü etiket | | `popular` | Popüler | Kart üstü etiket | | `null` | — | Etiket yok | --- ## Eğitim Blokları (Course Blocks) Bloklar `order_index` sıralı gelir. Her bloğun `type` ve `content` JSON'ı var. **Aynı renderer Page Blocks ile paylaşılabilir.** ### Blok Tipleri | type | Açıklama | content key'leri | |------|----------|------------------| | `text` | Zengin metin | `label`, `title`, `body` (HTML), `_width` | | `cards` | Kart grid | `label`, `title`, `card_N_title`, `card_N_text`, `card_N_icon` | | `stats_grid` | İstatistik/adım | `label`, `title`, `stat_N_value`, `stat_N_label`, `style` | | `cta` | Call-to-action | `title`, `description`, `button_text`, `button_url`, `button_2_text`, `button_2_url` | | `faq` | SSS | `title`, `faq_N_question`, `faq_N_answer` | | `hero` | Hero banner | `breadcrumb`, `title`, `highlight`, `subtitle`, `description` | | `text_image` | Metin + görsel | `label`, `title`, `body`, `image`, `image_alt`, `image_position` | | `gallery` | Görsel galeri | Görsel listesi | | `video` | Video embed | Video URL | | `testimonials` | Referanslar | Yorum kartları | | `html` | Serbest HTML | Ham HTML | ### `_width` Sistemi `content._width` blok genişliğini belirler: - `"full"` (varsayılan, key yoksa otomatik) — tam genişlik - `"half"` — yarım genişlik, ardışık iki half blok yan yana render edilir ```tsx // Blok renderer örneği function BlockRenderer({ blocks }) { const grouped = groupConsecutiveHalfBlocks(blocks); return grouped.map((item) => { if (item.type === 'row') { return (
{item.blocks.map(block => )}
); } return ; }); } ``` --- ## Kategoriler ### GET /v1/categories ```json { "data": [ { "id": 1, "slug": "guverte", "label": "Güverte Eğitimleri", "desc": "...", "image": null, "meta_title": "...", "meta_description": "...", "courses_count": 10, "menu_courses": [ { "title": "ARPA / Radar Simülatör Eğitimi", "slug": "arpa-radar-simulator" }, { "title": "ECDIS Tip Bazlı Eğitim", "slug": "ecdis-tip-bazli-egitim" }, { "title": "GMDSS Genel Telsiz Operatörü (GOC)", "slug": "gmdss-genel-telsiz-operatoru-goc" } ] } ] } ``` **`menu_courses`**: Her kategoriden `menu_order` 1-3 olan kurslar. Mega menu dropdown'unda kullanılır. Kategori slug'ları: `guverte`, `stcw`, `makine`, `yat-kaptanligi`, `yenileme`, `guvenlik` --- ## Sayfalar (Pages + Blocks) ### GET /v1/pages/{slug} Kurumsal sayfalar: `kalite-politikasi`, `hakkimizda`, `vizyon-misyon` ```json { "data": { "id": 1, "slug": "kalite-politikasi", "title": "Kalite Politikamız", "meta_title": "...", "meta_description": "...", "is_active": true, "blocks": [ { "id": 1, "type": "hero", "content": { "breadcrumb": "...", "title": "...", "highlight": "..." }, "order_index": 0 }, { "id": 2, "type": "cards", "content": { "label": "AKREDİTASYONLAR", "..." }, "order_index": 1 }, { "id": 3, "type": "text", "content": { "_width": "half", "..." }, "order_index": 2 }, { "id": 4, "type": "stats_grid", "content": { "_width": "half", "..." }, "order_index": 3 }, { "id": 5, "type": "cta", "content": { "..." }, "order_index": 4 } ] } } ``` Page blocks ve course blocks **aynı type/content yapısını** kullanır. Tek bir `BlockRenderer` bileşeni her ikisi için de çalışır. --- ## Hero Slides ### GET /v1/hero-slides Anasayfa slider: ```json { "data": [ { "id": 1, "title": "Denizcilik Kariyerinize Başlayın", "subtitle": "STCW uyumlu eğitim programları", "button_text": "Eğitimleri İncele", "button_url": "/egitimler", "image": "/storage/uploads/hero-1.jpg", "order_index": 0, "is_active": true } ] } ``` --- ## Eğitim Takvimi (Schedules) ### GET /v1/schedules ```json { "data": [ { "id": 1, "course_id": 1, "course": { "id": 1, "title": "Gemici (Birleşik) Eğitimi", "slug": "gemici-birlesik-egitimi", "..." }, "start_date": "2026-04-07", "end_date": "2026-05-08", "location": "Kadıköy", "quota": 20, "available_seats": 8, "is_urgent": false } ] } ``` ### GET /v1/schedules/upcoming Yaklaşan eğitimler (start_date >= today, sıralı). --- ## Menüler ### GET /v1/menus/{location} Location değerleri: `header`, `footer`, `sidebar` ```json { "data": [ { "id": 1, "label": "Anasayfa", "url": "/", "location": "header", "type": "link", "parent_id": null, "order_index": 0, "is_active": true, "children": [] } ] } ``` --- ## Duyurular ### GET /v1/announcements ```json { "data": [ { "id": 1, "slug": "2026-kayitlari-basladi", "title": "2026 Kayıtları Başladı", "category": "duyuru", "excerpt": "...", "content": "

HTML içerik...

", "image": "/storage/uploads/...", "is_featured": true, "meta_title": "...", "meta_description": "...", "published_at": "2026-03-15" } ] } ``` --- ## SSS (FAQs) ### GET /v1/faqs ```json { "data": [ { "id": 1, "question": "STCW belgesi nedir?", "answer": "...", "category": "genel", "order_index": 0, "is_active": true } ] } ``` Kategoriye göre: `GET /v1/faqs/genel` --- ## Lead Formu (Başvuru) ### POST /v1/leads Rate limited. Request: ```json { "name": "Ad Soyad", "phone": "+90 532 ...", "source": "web", "target_course": "gemici-birlesik-egitimi", "education_level": "lise", "subject": "Eğitim başvurusu", "message": "Bilgi almak istiyorum", "kvkk_consent": true, "marketing_consent": false, "utm_source": "google", "utm_medium": "cpc", "utm_campaign": "denizcilik-2026" } ``` --- ## Sayfa Önizleme (Preview) ### GET /v1/preview/{token} Admin panelden gönderilen önizleme. Auth yok, Next.js SSR ile fetch edilir. 10 dakika geçerli. Bulunamazsa 404. Response formatı `GET /v1/pages/{slug}` ile aynı: ```json { "data": { "id": 1, "slug": "kalite-politikasi", "title": "...", "blocks": [...] } } ``` --- ## Sayfa Bazlı Veri Haritası ### Anasayfa (`/`) | Veri | Endpoint | |------|----------| | Hero slider | `GET /v1/hero-slides` | | Eğitim kartları | `GET /v1/courses?per_page=6&sort=-rating` | | Kategoriler | `GET /v1/categories` | | Yaklaşan eğitimler | `GET /v1/schedules/upcoming` | | SSS | `GET /v1/faqs` | | Site ayarları | `GET /v1/settings` (layout'tan) | ### Eğitimler (`/egitimler`) | Veri | Endpoint | |------|----------| | Eğitim listesi | `GET /v1/courses?category=guverte&per_page=12` | | Kategoriler (filter) | `GET /v1/categories` | ### Eğitim Detay (`/egitimler/{slug}`) | Veri | Endpoint | |------|----------| | Eğitim + bloklar + takvim | `GET /v1/courses/{slug}` | ### Kurumsal Sayfalar (`/kurumsal/{slug}`) | Veri | Endpoint | |------|----------| | Sayfa + bloklar | `GET /v1/pages/{slug}` | ### Duyurular (`/duyurular`) | Veri | Endpoint | |------|----------| | Duyuru listesi | `GET /v1/announcements` | ### İletişim (`/iletisim`) | Veri | Endpoint | |------|----------| | İletişim bilgileri | `GET /v1/settings/contact` | | Harita | `GET /v1/settings/maps` | | Form gönderimi | `POST /v1/leads` | ### Layout (Her Sayfa) | Veri | Endpoint | |------|----------| | Header/Footer/SEO | `GET /v1/settings` | | Menü | `GET /v1/menus/header` + `GET /v1/menus/footer` | | Kategoriler (mega menu) | `GET /v1/categories` | --- ## TypeScript Tipleri ```ts interface Course { id: number; category_id: number; category?: Category; slug: string; title: string; sub: string | null; desc: string; long_desc: string; duration: string; students: number; rating: number; badge: 'most_preferred' | 'popular' | null; badge_label: string | null; image: string | null; price: string; includes: string[]; requirements: string[]; scope: string[]; standard: string | null; language: string | null; location: string | null; blocks?: Block[]; schedules?: Schedule[]; meta_title: string | null; meta_description: string | null; created_at: string; updated_at: string; } interface Category { id: number; slug: string; label: string; desc: string | null; image: string | null; courses_count?: number; menu_courses?: { title: string; slug: string }[]; } interface Block { id: number; type: 'hero' | 'text' | 'text_image' | 'cards' | 'stats_grid' | 'cta' | 'faq' | 'gallery' | 'video' | 'testimonials' | 'html'; content: Record; order_index: number; } interface Schedule { id: number; course_id: number; course?: Course; start_date: string; end_date: string; location: string; quota: number; available_seats: number; is_urgent: boolean; } interface Page { id: number; slug: string; title: string; meta_title: string | null; meta_description: string | null; is_active: boolean; blocks: Block[]; } interface HeroSlide { id: number; title: string; subtitle: string | null; button_text: string | null; button_url: string | null; image: string | null; order_index: number; } interface Announcement { id: number; slug: string; title: string; category: string; excerpt: string | null; content: string; image: string | null; is_featured: boolean; published_at: string; } interface FAQ { id: number; question: string; answer: string; category: string; order_index: number; } interface Lead { name: string; phone: string; source?: string; target_course?: string; education_level?: string; subject?: string; message?: string; kvkk_consent: boolean; marketing_consent?: boolean; utm_source?: string; utm_medium?: string; utm_campaign?: string; } interface MenuItem { id: number; label: string; url: string; location: string; type: string; parent_id: number | null; order_index: number; children: MenuItem[]; } ``` --- ## Image URL'leri Image alanları relative path döner. API base URL ile birleştir: ```ts const getImageUrl = (path: string | null): string | null => { if (!path) return null; if (path.startsWith('http')) return path; return `${process.env.NEXT_PUBLIC_API_URL}${path}`; }; ``` --- ## Cache Stratejisi | Veri | ISR revalidate | |------|---------------| | Settings | 300s (5 dk) | | Categories | 300s | | Courses list | 60s | | Course detail | 60s | | Pages | 300s | | Hero slides | 300s | | Schedules | 60s | | Announcements | 120s | | FAQs | 300s | | Menus | 300s |