# 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": "<p>...</p>" }, "order_index": 0 },
      { "id": 2, "type": "text", "content": { "_width": "half", "label": "EĞİTİM KAPSAMI", "title": "Ne Öğreneceksiniz?", "body": "<ul>...</ul>" }, "order_index": 1 },
      { "id": 3, "type": "text", "content": { "_width": "half", "label": "BAŞVURU ŞARTLARI", "title": "Kimler Katılabilir?", "body": "<ul>...</ul>" }, "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 (
        <div className="grid grid-cols-2 gap-8">
          {item.blocks.map(block => <Block key={block.id} {...block} />)}
        </div>
      );
    }
    return <Block key={item.id} {...item} />;
  });
}
```

---

## 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": "<p>HTML içerik...</p>",
      "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<string, any>;
  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 |
