114 lines
11 KiB
Markdown
114 lines
11 KiB
Markdown
# 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.
|
||
|
||
**Kalan (henüz yapılmadı):**
|
||
- Mobile'da `react-native-purchases` SDK'sı hiç kurulu değil — paywall ekranı, `Purchases.configure({ appUserID: restaurantId })` çağrısı, satın alma akışı yazılmadı. Webhook'un `app_user_id`'yi restoran ID'si olarak eşleştirebilmesi için bu SDK entegrasyonu **zorunlu**.
|
||
- RevenueCat Dashboard'da webhook URL'i (`https://api.menul.io/subscription/webhook`) ve Authorization header değeri (`Bearer test_MoTphXMYyNDmzeBCbvYVhfrcCjl`) henüz elle girilmedi.
|
||
- API servisine `REVENUECAT_WEBHOOK_SECRET` env değişkeni henüz prod'a eklenmedi (local `.env`'de var, Coolify'a taşınmadı).
|
||
|
||
## 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/<slug>/` (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.
|