# Progress Log Faz tanımları için [ROADMAP.md](./ROADMAP.md). Bu dosya ne yapıldığını, ne yapılmadığını ve bilinen sınırlamaları takip eder — faz atlarken buraya bakıp neyin gerçek neyin stub olduğunu hatırlamak için. ## App Store Connect + RevenueCat kurulumu (2026-08-20) **App Store Connect** (API ile, gerçek üretim hesabına karşı): - Store metinleri yazıldı: alt başlık, açıklama, anahtar kelimeler, tanıtım metni, destek/pazarlama/gizlilik URL'leri, telif hakkı - Kategori: Food & Drink - En son build (v10) versiyona bağlandı - Subscription group "Menulio Pro" + iki ürün oluşturuldu: `menu_pro_monthly`, `menu_pro_yearly` (Türkçe isim/açıklama ile) - Fiyatlandırma kullanıcı tarafından App Store Connect UI'dan girildi: aylık 250 TL, yıllık 2500 TL - **Kullanıcının tamamlaması gereken:** Yaş derecelendirmesi anketi, en az 1 ekran görüntüsü — API'nin güvenilir şekilde dolduramadığı/dolduramayacağı alanlar **RevenueCat** (proje zaten `proj0d3bc1c1` olarak mevcuttu, API ile tamamlandı): - Gerçek App Store ürünleri (`menu_pro_monthly`, `menu_pro_yearly`) "Menul.io (App Store)" app'ine eklendi - "Menulio Pro" entitlement'ına bağlandı - "default" offering'in Monthly/Yearly paketlerine iliştirildi **Backend:** `POST /subscription/webhook` gerçek mantıkla yazıldı — Authorization header'ı (shared secret) doğruluyor, RevenueCat event tipini `subscriptions.status`'a çeviriyor (`INITIAL_PURCHASE`/`RENEWAL`/`PRODUCT_CHANGE`/`UNCANCELLATION` → active, `BILLING_ISSUE` → grace_period, `EXPIRATION` → suspended; `CANCELLATION` tek başına suspend etmiyor, sadece auto-renew kapanıyor). Gerçek Supabase'e karşı uçtan uca test edildi. **Tamamlandı (devamı, 2026-08-20):** - `REVENUECAT_WEBHOOK_SECRET` env değişkeni API servisine eklendi, RevenueCat Dashboard'da webhook (URL + Authorization header) kullanıcı tarafından yapılandırıldı. - Mobile: `react-native-purchases` SDK'sı kuruldu (`apps/mobile/src/lib/purchases.ts`). `Purchases.configure({ appUserID: restaurantId })` restaurantId'nin bilindiği her noktada (login sonrası, cold-start rehydration, onboarding restoran oluşturma) çağrılıyor — webhook'un `app_user_id`'yi doğru eşleştirmesi için bu şart. - `apps/mobile/src/app/account/subscription.tsx` — paywall ekranı: mevcut entitlement durumu, offering paketleri (gerçek mağaza fiyatlarıyla), satın alma, restore. Hesap ekranından linklendi. **Kalan (henüz yapılmadı):** - Gerçek cihazda satın alma akışı hiç test edilmedi — native modül olduğu için Expo Go'da çalışmaz, EAS/dev-client build gerekiyor (TestFlight build'leri zaten bunu kullanıyor). - Trial süresi / onboarding'de "7 gün ücretsiz dene" akışı henüz kurulmadı — şu an paywall sadece hesap ekranından manuel erişilebiliyor, hiçbir özellik Pro'ya kilitli değil. ## Faz 0 — Altyapı ✅ (2026-08-19) - pnpm monorepo: `apps/api` (Fastify), `apps/web` (Next.js), `apps/mobile` (Expo Router), `packages/shared` - `apps/api`: health check + PRD §23'teki endpointlerin stub'ları - `apps/web`: host-header tabanlı wildcard subdomain middleware, `/menu/[slug]` route - `apps/mobile`: Expo Router iskeleti, onboarding stub ekranları - `supabase/migrations/20260819000000_initial_schema.sql`: PRD §22'deki 17 tablo, RLS açık, owner-scoped + published-menu public read policy'leri - `supabase/seed.sql`: 5 başlangıç teması - Doğrulama: `tsc --noEmit` tüm app'lerde temiz, API `/health` gerçekten çalıştırılıp test edildi ## Faz 1 — Manuel akış ✅ (2026-08-19) Hedef: Restoran sahibi mobil uygulamada elle veri girip gerçek bir QR menüyü yayınlayabilsin. **Karşılandı ve gerçek Supabase Cloud projesine karşı canlı test edildi.** - [x] API: auth middleware (Supabase JWT doğrulama, `requireAuth`/`requireRestaurantMember`) + restaurant CRUD - [x] API: menu/category/item CRUD + publish/unpublish (`menus`, `menu-categories`, `menu-items` route'ları) - [x] API: QR üretimi (PNG/SVG, `/q/:id` stabil redirect URL ile — PRD §12) - [x] API: `/me/restaurant` — mobile cold-start rehydration için - [x] Supabase: Faz 1 RLS policy migration'ı (`20260819010000_public_menu_access.sql`) - [x] Web: gerçek public menü render (Supabase'ten canlı veri, 5 zengin tema desteği, canlı arama, sticky kategori barı, ürün detay modalı) - [x] Web: `/q/[id]` QR redirect route'u - [x] Mobile: auth ekranları (email login/register) + Supabase client (AsyncStorage session) - [x] Mobile: restoran onboarding formu → API'ye bağlı - [x] Mobile: menü editörü (kategori/ürün CRUD, yayınla butonu) — `apps/mobile/src/app/menu/index.tsx` - [x] Mobile: QR ekranı (üret, göster, native share) — `apps/mobile/src/app/menu/qr.tsx` ## Faz 2 — AI Menu Scanner ✅ (2026-08-19) Hedef: Menü fotoğrafını çekip/yükleyip AI ile saniyeler içinde dijitalleştirmek, onaylayıp canlı menüye aktarmak. - [x] Shared: AI çıkarma (`AiExtractedCategory`, `AiExtractedItem`), yanıt (`AiImportResponse`) ve uygulama (`AiImportApplyPayload`) veri sözleşmeleri. - [x] API: `apps/api/src/lib/ai-scanner.ts` — Gemini 1.5 Flash Vision, OpenAI GPT-4o Vision ve akıllı mutfak sezgisel fallback motoru. - [x] API: `POST /menus/:id/import-ai` — menü görselini analiz eder, `ai_imports` ve `ai_import_items` denetim loglarını oluşturur, confidence skorları hesaplar. - [x] API: `GET /ai-imports/:id` — kaydedilmiş import durumunu döner. - [x] API: `POST /ai-imports/:id/apply` — AI Review ekranından onaylanan/düzenlenen kategori ve ürünleri menüye (`menu_categories`, `menu_items`) topluca yazar. - [x] Mobile: `expo-image-picker` entegrasyonu (kamera & galeri izinleri ve fotoğraf seçimi). - [x] Mobile: `apps/mobile/src/app/(onboarding)/scan.tsx` — Menü Fotoğrafı Çek / Galeriden Seç ve aşamalı AI analiz animasyonu ekranı (Adım 2 & 3). - [x] Mobile: `apps/mobile/src/app/(onboarding)/ai-review.tsx` — AI Review & Onay ekranı (Adım 4): - Kategori bazlı ürün listesi - Düşük güven skorlu öğeler için sarı uyarı rozeti (`⚠️ Düşük Güven (Fiyatı Kontrol Edin)`) - Anında ürün adı, fiyat ve açıklama düzenleme - Kategori/ürün silme ve ekleme - "✓ Menüyü Onayla ve Kaydet" butonu ile menüye aktarma - [x] Mobile: `apps/mobile/src/app/menu/index.tsx` içerisine "✨ AI ile Menü Fotoğrafı Tara" tetikleyicisi. - [x] Mobile: `apps/mobile/src/app/account/index.tsx` — Hesabım & Restoran Ayarları ekranı: - Kullanıcı profili ve aktif restoran durumu - Restoran adı, telefon ve adres güncelleme (`PATCH /restaurants/:id`) - Canlı menü linki kopyalama ve tarayıcıda açma - 5 Temadan birini seçip menüye anında uygulama (`GET` / `PUT /restaurants/:id/theme`) - Abonelik plan durumu - Çıkış yapma (Sign out) ve oturum temizleme ## Faz 3 — Web Frontend & 5 Menü Şablonu Engine ✅ (2026-08-20) - [x] Web: `apps/web/src/app/page.tsx` — Lüks Menulio SaaS Landing Page (Hero, 5 Şablon vitrini, Nasıl Çalışır, İstatistikler, Canlı Demo linkleri). - [x] Web: `apps/web/src/lib/theme.ts` — 5 Ayrı Tasarım Şablonu Tanımları: 1. 🌟 **Elegant Gold** (Fine dining & lüks restoranlar - Altın & Krem, serif tipografi) 2. 💎 **Modern Sapphire** (Kafe & Fast-Casual - Mavi safir & beyaz, 2'li grid layout) 3. 🌙 **Luxury Dark** (Gece kulübü & Kokteyl bar - Obsidian & Kehribar lüks mod) 4. ❄️ **Nordic Minimal** (Butik kahveci & fırın - Sade monokrom liste mizanpajı) 5. 🍷 **Classic Bistro** (Meyhane & Trattoria - Toskana bordo & rustik doku) - [x] Web: `apps/web/src/components/TemplateGalleryClient.tsx` & `/templates` — İnteraktif şablon galerisi ve canlı telefon simülatörü. - [x] Web: `apps/web/src/app/demo/page.tsx` — Tam ekran interaktif demo menü. - [x] Mobil & API: Yerel geliştirme ortamına uyumlu URL ve QR mimarisi (`http://localhost:3000/menu/[slug]`). - [x] Mobil: `ThemeSelectorSheet.tsx` — Menü editöründen tek tıkla 5 şablondan birini seçme ve anında aktifleştirme. - [x] Mobil: Ürün Görseli Ekleme & Düzenleme (`expo-image-picker` ile `AddItemModal` ve `ItemDetailSheet` içinde galeri seçimi ve canlı önizleme). - [x] Mobil: `MenuItemCard.tsx` — Menü ürün kartlarında görsel küçük resim (thumbnail) desteği. - [x] Mobil: `AccountScreen.tsx` — Restoran Logosu yükleme/değiştirme ve detaylı restoran bilgileri güncelleme. - [x] Mobil: Alt barda kalıcı "👁️ Önizle" butonu ile tek tıkla canlı menüyü tarayıcıda açma. - [x] Web: `apps/web/src/components/PublicMenuClient.tsx` — Anında arama, masa numarası parametresi (`?table=X`), garson çağır / hesap iste floating barı, ürün detay modalı ve canlı tema değiştirici çekmecesi. **Kapsam dışı bırakılanlar (bilinçli, sonraki fazlara ertelendi):** - Apple/Google login (V1.5+) — sadece email auth - Abonelik/RevenueCat (Faz 5) — bu fazda erişim kısıtı yok ## Production altyapı + canlı hata ayıklama (2026-08-20) Bu tarihte proje production'a alınmış halde bulundu: `menul.io` (Next.js public web), `api.menul.io` (Fastify API), Coolify (host: Traefik değil **Caddy**), Cloudflare (DNS/proxy), gerçek Supabase Cloud projesi (`fwahdopsyvryvjaqande`), git.ayris.tech (self-hosted Gitea, `main`'e push → Coolify otomatik deploy). Custom domain özelliği (`ad.ayris.tech` → `menul.io`) canlıda kurulup test edildi ve çalışır hale getirildi. Bu süreçte bulunup düzeltilen gerçek prod bug'ları: - **API `SUPABASE_SERVICE_ROLE_KEY` placeholder'dı** — `api.menul.io` her auth isteğini 401'liyordu (mobilde sürekli login döngüsüne sokuyordu). Kullanıcı gerçek key'i env'e girdi. - **Fastify default `bodyLimit` 1 MiB** — AI menü fotoğrafı yüklerken "Request body is too large" hatası (model/key ile ilgisiz). `apps/api/src/index.ts`'te 20 MiB'e çıkarıldı. - **`domains.ts` DNS-CNAME doğrulaması proxied domainlerde yapısal olarak asla çalışmaz** — Cloudflare proxy (turuncu bulut) gerçek CNAME hedefini public DNS'ten gizliyor (`ENODATA`). `/verify` her çağrıldığında zaten doğrulanmış bir domain'i "pending"e geri düşürüyordu. Artık zaten verified olan bir domain bir daha downgrade edilmiyor. **Kalıcı çözüm hâlâ eksik:** gerçek doğrulama Cloudflare Custom Hostnames API'sinin `ssl.status`'una bakmalı — bunun için Cloudflare API token + zone ID gerekiyor (henüz alınmadı). - **`apps/web/src/middleware.ts` trailing slash bug'ı** — root path istekleri `/menu//` (sonda slash'lı) üretiyordu, `[slug]` route'u eşleştiremiyordu → her custom domain/subdomain kök isteği "Menü Bulunamadı" veriyordu. Düzeltildi. - **`PUT /restaurants/:id/theme` crash'i** — tanımsız `themeData` değişkeni kullanılıyordu (main'de önceden var olan `tsc` hatası, muhtemelen build type-check adımından geçmeden deploy edilmişti). Eksik `themes` sorgusu eklendi. - **Coolify custom domain routing:** her custom domain, ilgili Next.js servisine Coolify panelinden elle eklenmesi + redeploy gerektiriyor (otomasyon yok). Wildcard subdomain (`*.menul.io`) hiç kurulmadı çünkü **gerekmiyor** — restoran menüleri `menul.io/menu/{slug}` path'i üzerinden çalışıyor, alt-domain mimarisi kullanılmıyor. **Sonraki adım (otomasyon):** Cloudflare API token + zone ID alınırsa, `POST /restaurants/:id/domains` restoran custom domain eklediğinde otomatik Custom Hostname oluşturup gereken DNS talimatlarını döndürecek, `/verify` de Cloudflare'in kendi SSL durumuna bakacak şekilde güncellenebilir — böylece bugünkü manuel Cloudflare dashboard adımları (Fallback Origin, TXT kayıtları, Coolify domain ekleme) her yeni restoran için tekrarlanmaz.