# 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 ```prisma 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 Article` structured 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) ```prisma 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: ```prisma 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.instagram` alanı zaten PRD'de vardı (handle/URL) — bunu kaynak olarak kullan - Senkron mekanizması: n8n'de günlük (24h) tetiklenen bir workflow — `instagram` dolu olan tüm `Listing`'leri gez, her biri için RapidAPI'yi çağır, sonucu `POST /api/cron/instagram-sync` (secret header ile korunan internal endpoint) üzerinden `InstagramFeedCache`'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 - `fetchedAt` 24 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. ```prisma // Listing modeline eklenecek alan menuUrl String? ``` - Kategoriye göre kod içinde zorlama yok — buton sadece `menuUrl` doluysa 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. ```prisma // 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-pwa` veya 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 1. **Blog + Koleksiyonlar** (2.1) — SEO motoru olmadan geri kalanının önemi düşük 2. **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) 3. **PWA + Analytics** (2.4) — ne zaman uygun olursa, bağımsız işler 4. **Öne Çıkan Listeleme** (2.3) — listeleme sayısı eşiğe ulaşınca devreye al ## Env Değişkenleri (Faz 2 eklentileri) ```env 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 `isLocalApproved` olanları 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