9.1 KiB
Faz 2 Planı — Marmaris Local
Önceki: prd.md (MVP — tamamlandı)
Bu doküman: MVP sonrası geliştirme sırası
Sıralama mantığı: önce trafik getiren şey (içerik/SEO), sonra geleni tutan şey (etkileşim), sonra parayı getiren şey (gelir modeli — ama listeleme sayısı bir eşiğe ulaşmadan anlamsız), en altta her an eklenebilecek düşük efor altyapı işleri.
Faz 2.1 — İçerik / SEO Motoru (öncelik: yüksek, ilk başlanacak)
Directory sitesi tek başına trafik çekmez — kürasyonlu içerik olmadan sadece Google'ın zaten indekslediği işletmelerin bir kopyası olursun. Bu faz olmadan diğerlerinin anlamı sınırlı.
Blog
model BlogPost {
id String @id @default(cuid())
slug String @unique
titleTr String
titleEn String
titleRu String
contentTr String // MDX/rich text
contentEn String
contentRu String
coverImage String? // Openinary
tags String[]
relatedListingIds String[] // Listing'lere internal link için
publishedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime?
}
- Route:
/blog,/blog/[slug] - Admin:
/admin/blog— rich text editör (Tiptap öneri, shadcn ile uyumlu) - Her yazıda ilgili
Listing'lere otomatik link kartı (internal linking = SEO) schema.org Articlestructured data
İlk içerik önerisi (mock/gerçek karışık başlanabilir): "Marmaris'te Nerede Yenir 2026", "Gün Batımı İçin 5 Mekan", "İçmeler mi Yat Limanı mı — Nerede Kalınır"
Kürasyon Listeleri (Koleksiyonlar)
model Collection {
id String @id @default(cuid())
slug String @unique
titleTr String
titleEn String
titleRu String
descriptionTr String
descriptionEn String
descriptionRu String
coverImage String?
listings Listing[] @relation("CollectionListings")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
- Route:
/seckiler,/secki/[slug] - Admin:
/admin/collections— listeleme seç (multi-select), sürükle-bırak sıralama - Örnek koleksiyonlar: "Aile Dostu 5 Restoran", "Bütçe Dostu Mekanlar", "Deniz Kenarında Kahvaltı"
- Bu, "Yerel Onaylı" mührünün doğal uzantısı — tekil rozetten küratörlü gruplamaya geçiş
RSS
/feed.xml— blog yazıları + yeni eklenen "Yerel Onaylı" listelemeler- Öncelik gerekçesi: kendi başına trafik kanalı değil ama Google News / ileride newsletter otomasyonu (n8n) için altyapı — blog ile aynı sprintte, 1 saatlik ek iş
Faz 2.2 — Etkileşim (öncelik: orta, 2.1 ile paralel gidebilir)
Auth gerektirmeyen, dönüşümü ucuza artıran işler.
Favorilere Ekle
- Backend yok — client-side localStorage,
savedListingIds: string[] - Route:
/kaydedilenler— localStorage'daki ID'leri okuyup listeler - Paylaşılabilir link:
/kaydedilenler?ids=abc,def,ghi— arkadaşla link paylaşımı, auth şart değil
WhatsApp Paylaş
- Her listeleme detay sayfasında
wa.me/?text=...deep link buton - Şema değişikliği yok, ~30 dakikalık iş
Instagram Feed (her listeleme sayfasında)
Sadece anasayfa değil — Instagram hesabı olan her listeleme (kategori fark etmez) kendi detay sayfasında son gönderilerini gösterir + profile giden link.
Veri kaynağı: RapidAPI üzerinden bir Instagram scraper endpoint'i (ör. "Instagram Scraper API2" / "Instagram Data" — RapidAPI marketplace'te birden fazla sağlayıcı var, fiyat/limit karşılaştırıp seçilecek). Instagram'ın resmi Graph API'si business-verified hesap + Facebook app review gerektirdiği için, işletme sahiplerinden bu izni almak pratik değil — RapidAPI scraper daha az sürtünmeli.
Canlı istekte RapidAPI çağırma — YAPMA. Her sayfa görüntülemesinde çağırırsan hem yavaş hem RapidAPI faturası trafiğe bağlı, öngörülemez olur. Bunun yerine 24 saatte bir çalışan bir arka plan job'ı ile önbelleğe al:
model InstagramFeedCache {
id String @id @default(cuid())
listingId String @unique
handle String
posts Json // [{ imageUrl, caption, permalink, postedAt }]
fetchedAt DateTime @default(now())
listing Listing @relation(fields: [listingId], references: [id])
}
Listing.instagramalanı zaten PRD'de vardı (handle/URL) — bunu kaynak olarak kullan- Senkron mekanizması: n8n'de günlük (24h) tetiklenen bir workflow —
instagramdolu olan tümListing'leri gez, her biri için RapidAPI'yi çağır, sonucuPOST /api/cron/instagram-sync(secret header ile korunan internal endpoint) üzerindenInstagramFeedCache'e yaz. n8n zaten elinde (auto2.ayris.tech), bu tam onun işi. - Frontend sadece DB'den okur, hiçbir zaman canlı RapidAPI çağrısı yapmaz — sayfa yükü hızlı kalır
fetchedAt24 saatten eskiyse UI'da sessizce eski veriyi göstermeye devam et (job bir sonraki döngüde tazeleyecek), kullanıcıya hata gösterme
Menüyü Gör Butonu
Restoran/bar/club tarzı kategorilerde, işletmenin kendi menü sayfası/PDF'i varsa, listeleme detay sayfasında "Menüyü Gör" butonu → yeni sekmede işletmenin kendi sitesine/menü linkine gönderir.
// Listing modeline eklenecek alan
menuUrl String?
- Kategoriye göre kod içinde zorlama yok — buton sadece
menuUrldoluysa görünür, admin doğal olarak bunu sadece ilgili kategorilerde dolduracak - Admin formunda (
/admin/listings/[id]) yeni alan: "Menü Linki (opsiyonel)"
"Yeni Eklenenler" Widget
- Şema değişikliği yok —
Listing.findMany({ orderBy: createdAt desc, take: 6 }) - Anasayfa + kategori sayfalarında taze içerik sinyali
Faz 2.3 — Gelir Modeli: Öne Çıkan Listeleme (öncelik: koşullu — belirli bir listeleme sayısına ulaşınca anlamlı)
Ön koşul: En az ~30-40 aktif "Yerel Onaylı" listeleme olmadan bu faza girmeye gerek yok — az listelemeyle "öne çıkan" kavramının hiçbir ayırt edici gücü olmaz.
// Listing modeline eklenecek alanlar
isFeatured Boolean @default(false)
featuredUntil DateTime? // otomatik süre dolumu için
- Kategori/anasayfa sıralamasında
isFeaturedönce gelir - Admin toggle + tarih seçici (
/admin/listings/[id]) - Gelir mekanizması: Ayris Tech'in mevcut 40+ müşteri ilişkisiyle doğal satış kanalı — ayrı bir ödeme altyapısı MVP'de gerekmez, manuel faturalama yeterli
Faz 2.4 — Altyapı (öncelik: düşük efor, istenilen an araya sokulabilir)
PWA
manifest.json+ service worker (next-pwaveya manuel)- "Ana ekrana ekle" — turist telefonda kullanıyor, pratik fark yaratır
Analytics
- Kendi VPS'teki self-hosted panel (Plausible-tarzı, zaten var) — yeni SaaS ödemesi gerekmiyor
- Takip edilecek event'ler: favori ekleme, WhatsApp paylaşım tıklaması, QR kaynak trafiği, kategori bazlı arama
Önerilen Sıra
- Blog + Koleksiyonlar (2.1) — SEO motoru olmadan geri kalanının önemi düşük
- Menü butonu + Instagram feed + Favoriler + WhatsApp paylaş + Yeni Eklenenler (2.2) — düşük-orta efor, hızlı kazanım, 2.1 ile aynı sprint'te bile yapılabilir. Instagram feed'in n8n cron tarafı ayrı bir iş parçası olarak planlanmalı (senkron job önce kurulmalı, sonra frontend)
- PWA + Analytics (2.4) — ne zaman uygun olursa, bağımsız işler
- Öne Çıkan Listeleme (2.3) — listeleme sayısı eşiğe ulaşınca devreye al
Env Değişkenleri (Faz 2 eklentileri)
RAPIDAPI_KEY=""
RAPIDAPI_INSTAGRAM_HOST="" # seçilen sağlayıcıya göre (ör. instagram-scraper-api2.p.rapidapi.com)
CRON_SECRET="" # /api/cron/instagram-sync endpoint'ini korumak için
Kararlar (önceki açık sorulardan)
- Blog içeriği: DeepSeek ile üretilip otomasyonla (n8n) yayınlanacak — akış detayı ayrıca kurulacak
- Koleksiyon kapak görselleri: stok veya yerinde çekim fark etmiyor, ikisi de kullanılabilir
- Öne çıkan listeleme fiyatlandırması: aylık sabit ücret (süre bazlı değil)
- RapidAPI sağlayıcısı: free-tier bir model kullanılacak
Free-tier RapidAPI konusunda dikkat edilecek nokta: RapidAPI'deki Instagram scraper'ların çoğunda (ör. "Instagram Scraper API2", "Instagram Looter2") free/basic plan genelde aylık ~50-100 istek civarında sınırlı. 24 saatte bir senkron ile bile, listeleme sayısı arttıkça (30-40 listeleme × günlük = ~900-1200 istek/ay) free tier hızla yetersiz kalır. Pratik yaklaşım:
- Az listelemeyle (MVP/Faz 2 başlangıcı) free tier rahatça yeter
- Listeleme sayısı büyüdükçe ya senkron sıklığını düşür (24h yerine 48-72h), ya sadece
isLocalApprovedolanları senkronla, ya da o noktada ücretli tiere geç - İlk kurulumda 2-3 free-tier sağlayıcıyı denemek (aynı endpoint şeklini farklı sağlayıcıdan alacağın için
InstagramFeedCacheşeması sağlayıcıdan bağımsız kalacak şekilde tasarlandı) makul bir başlangıç
Açık Sorular
- Free-tier adaylarından hangisi seçilecek — birkaçını test edip (aynı listeleme üzerinde) veri kalitesi/limit karşılaştırması yapılabilir