update deploy
This commit is contained in:
629
prompts/frontend-api-integration.md
Normal file
629
prompts/frontend-api-integration.md
Normal file
@@ -0,0 +1,629 @@
|
||||
# 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 |
|
||||
Reference in New Issue
Block a user