Files
bogazici-api/prompts/frontend-api-integration.md
2026-03-27 10:41:54 +03:00

16 KiB
Raw Blame History

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 ı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):

{
  "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ıı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:

{
  "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 ı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
// 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

{
  "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

{
  "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:

{
  "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

{
  "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

{
  "data": [
    {
      "id": 1,
      "label": "Anasayfa",
      "url": "/",
      "location": "header",
      "type": "link",
      "parent_id": null,
      "order_index": 0,
      "is_active": true,
      "children": []
    }
  ]
}

Duyurular

GET /v1/announcements

{
  "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

{
  "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:

{
  "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ı:

{
  "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

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:

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