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

630 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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ıı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 |