

PTLog
SaaS · PWASpor salonları için çok kiracılı yönetim platformu ve üye PWA’sı.
TEKNOLOJİ
PTLog, ClinicPulse, HuntLine IQ ve PeakUp’tan: kiracı izolasyonu RLS’te, yetki testleri SQL’de, barındırma Vercel ya da Cloudflare’de.
KISA CEVAP
AMG Yazılım SaaS ürünlerinde arayüzü Next.js ile, veritabanı, kimlik ve Edge Function katmanını Supabase ile kuruyor ve kiracı izolasyonunu uygulama filtresine değil Postgres RLS’e bırakıyor. ClinicPulse’ta on tablo ve 34 RLS politikası, PTLog’da oturum JWT’sine yazılan kiracı claim’leri, HuntLine IQ’da 28 migration ve 25 Edge Function bu yaklaşımın örnekleri.
İkisini birlikte kullandığımız projeler ile yalnız birini kullananları ayırmak gerekiyor, çünkü teknoloji listesi her projede aynı değil:
Bu ayrım önemli, çünkü aşağıdaki RLS ve test pratiklerinin bir kısmı ozelokul.com ve RichlyMe’den geliyor. Onlar Supabase tarafının kanıtı, Next.js tarafının değil. Next.js tarafında kiracı çözümleme, cron rotaları ve barındırma için PTLog, ClinicPulse, HuntLine IQ ve kendi sitemiz örnek.
Çok kiracılı bir SaaS’ta ilk soru, bir isteğin hangi kiracıya ait olduğunun nerede belirlendiği. Projelerimizdeki cevap: kiracı bilgisi oturuma yazılıyor, izolasyonu veritabanı uyguluyor.
PTLog’da her spor salonu tek bir kod tabanında bir kiracı. Next.js middleware’i gym.ptlog.dev ya da özel alan adını kiracıya çözüyor; Supabase’in custom_access_token_hook’u kiracı, rol ve izin claim’lerini oturum JWT’sine yazıyor. Markalama motoru her ana makine adı için ayrı PWA manifest’i ve sharp ile üretilen ikonlar sunuyor; üye, salonun kendi uygulamasını ana ekranına ekliyor.
ClinicPulse’ta kiracı izolasyonu on tablo ve 34 RLS politikasında; uygulama kodunun where clinic_id = … yazmayı hatırlamasına güvenilmiyor. Yeni bir klinik eklemek tek bir satır, ayrı dağıtım yok. Hassas alanlar AES-256-GCM ile şifreleniyor ve anahtar yoksa uygulama açılmıyor.
ozelokul.com’da kiracı marka, kampüs ise markanın içinde FK ile bağlı bir kapsam. Roller enum değil, 56 izin anahtarı; bütün kontrol private.has_perm() fonksiyonunda toplanıyor ve üyelik ile kapsam tek bir işlemde yazılıyor.
Bir politikayı okuyup doğru olduğuna karar vermek test değil. Testlerimiz istemcinin rolüne geçip yasaklı işlemi gerçekten deniyor:
BEGIN … ROLLBACK içinde; test.as_user() JWT claim’lerini ayarlıyor, test.throws() beklenen SQLSTATE’i (çoğunlukla 42501) doğruluyor. Yapısal testler "RLS’i kapalı tablo yok" ve "anon hiçbir şeye erişemiyor" kurallarını sonradan eklenen tablolar için de denetliyor.authenticated rolüyle koştuğunu doğruluyor, çünkü süper kullanıcı RLS’i baypas eder ve her şey boşuna geçer. Mutasyon testinde has_perm’den kampüs kapsamı silinince paket 5 iddiada kırmızıya döndü.supabase test db ile; CI her push’ta çalışıyor.pnpm dogrula kapısında.RLS satırı korur, kolonu korumaz. ozelokul.com’daki yetki denetiminde "kullanıcı kendi profilini güncelleyebilir" politikasının satırın tamamını açtığını canlı bir denemeyle gösterdik: bir veli hesabı tek bir PATCH isteğiyle kendi account_type alanını platform yapabiliyordu. Aynı sınıftan beş yer, kolon GRANT’ları ve bir tetikleyiciyle kapatıldı. Velinin iletişim bilgisi ise bir görünümde case when contact_revealed ile maskeleniyor.
İkinci tuzak politikaların kendisi. Private şemadaki fonksiyonlardan EXECUTE yetkisi alınınca her politika permission denied verdi; çözüm yalnız politikalarda adı geçen 9 fonksiyona yetki vermek oldu. Başka bir RLS’li tabloya bakan politika 42P17 sonsuz döngü hatası verdi ve o erişim SECURITY DEFINER bir fonksiyona taşındı.
Üçüncüsü ekran ile API arasındaki fark. RichlyMe’de bulanık gösterilen bir kanıtın akış satırı sahibinin adını ve saniye hassasiyetindeki yayın zamanını hâlâ taşıyordu: ekran gizliyor, API veriyordu. Plan farkında da aynı ilke geçerli; ozelokul.com’da kilitli bölüm private.section_visible() yüzünden sorguda hiç dönmüyor.
Veritabanı testleri sunucu fonksiyonlarını kapsamadığı için ozelokul.com’da ayrıca 80 mutasyon ucu kapılarına göre haritalandı ve 30’u gerçek JWT’lerle canlı sömürü denemesinden geçti.
RichlyMe’de iş kuralı SQL’de, kimlik ve girdi doğrulaması ince Edge Function kabuklarında duruyor: kimliği doğrula, girdiyi doğrula, tek bir RPC çağır. 17 fonksiyonun 9’u yalnız service role ile çağrılabiliyor. Next.js projelerinde de benzer bir düzen kuruyoruz:
--no-verify-jwt ile dağıtılıyor; kalan 23 fonksiyon üyenin token’ını doğruluyor. Günlük cron Next.js tarafındaki /api/cron/* rotalarından tetikleniyor.api/cron/reminders rotasından gidiyor, gönderim ucu dakikada on istekle sınırlı.x-peakup-cron başlığındaki ortak sırla bağlanıyor; edge_cagri_sagligi(24) son 24 saatin 401 ve 5xx sayısını paneldeki sistem durumu kartına veriyor. Eksik vault sırrı cron işini hata verdirerek durduruyor, hiçbir şey sessizce ölmüyor.FOR UPDATE SKIP LOCKED ile alıyor. Etkinlik, davet ve kredi tek bir veritabanı işleminde oluşturuluyor ve aynı istek kimliğiyle tekrar denemek güvenli.İkisinde de çalışan ürünümüz var. HuntLine IQ’nun Next.js 14 web uygulaması Vercel’de yayında ve native mobil uygulamalar aynı Supabase verisini kullanıyor. Viralance’ta medya Cloudflare R2’den sunuluyor, Vercel yedek olarak duruyor.
Kendi sitemiz amgsoftwarestudio.com, Next.js 16 App Router kodunu vinext ile derleyip tek bir Cloudflare Worker olarak çalıştırıyor. Worker, anonim GET isteklerindeki herkese açık HTML’i Cache API’de 300 saniye tutuyor ve önbellek anahtarına yayın sürümü kimliğini ekliyor; her yeni yayın kendi anahtarıyla başladığı için temizleme adımı yok. 31 Ekim 2026’da tek bir konumdan aldığımız küçük örnekte önbellekten dönen sayfaların ilk bayt süresi 0,15–0,25 saniyeydi. Workers’ta Next.js görsel optimizasyonuna güvenmek yerine görseller derleme anında yedi genişlikte üretiliyor ve özel bir yükleyiciyle eşleniyor.
Kendi sitemizde yayın bilinçli olarak elle yapılıyor: GitHub Actions yalnız tip kontrolü, lint, testler ve üretim derlemesini doğruluyor ve CI’da Cloudflare dağıtım sırrı yok. Müşteri projelerinde barındırma seçimi keşifte yapılıyor; alan adı, sunucu, veritabanı ve servis hesapları müşterinin adına açılıyor.
Kalır, ama ikinci hat olarak. ozelokul.com’da her tablo RLS’li doğuyor ve uygulama kontrolü ikinci savunma. Veritabanı testleri sunucu fonksiyonlarını kapsamadığı için 80 mutasyon ucu kapılarına göre haritalandı ve 30’u gerçek JWT’lerle denendi. Sömürülen dört bulgunun ikisinin RLS tarafında da karşılığı yoktu; onlar için ayrıca ikinci bir savunma hattı eklendi.
Evet. ozelokul.com’da müşterinin elinde tamamen sahte veriyle çalışan, yaklaşık 53 rota ve 50.000 satırlık bitmiş bir tasarım vardı. İstek, tek bir piksele dokunmadan altına üretim seviyesinde bir backend kurmaktı. Sahte verinin her alanı önce şemaya eşlendi, sonra seed migration olarak yüklendi; bugün 139 migration var. Bu projenin arayüzü Next.js değil, Vite + TanStack Start.
Çok kiracılı kurulduğunda gerekmiyor. ClinicPulse’ta yeni bir klinik tek bir satır ve ayrı dağıtım yok. PTLog’da her spor salonu aynı kod tabanında kendi alt alan adı ya da özel alan adıyla açılıyor ve kendi markalı PWA’sını alıyor. Plan farkı da ozelokul.com’da olduğu gibi kodda değil, plan_features satırlarıyla tanımlanabiliyor.
Ürüne göre değişiyor. HuntLine IQ’da Stripe ve RevenueCat webhook’ları Edge Function olarak çalışıyor; Kutylawsuit’te Stripe Checkout webhook doğrulamasıyla kurulu; EntMoment’ta Stripe ve haftalık ödeme cron’u var. ozelokul.com’da ise müşteri kararıyla ödeme sağlayıcısı yok: akış havale/EFT üzerine kurulu ve yönetici onayı faturayı, aboneliği ve denetim kaydını tek işlemde güncelliyor.
Evet, kendi sitemiz böyle çalışıyor. amgsoftwarestudio.com’un Next.js 16 kodu vinext ile Vite üzerinden derlenip tek bir Worker paketine giriyor; React Server Components ve sunucu tarafı HTML aynı pakette. Yönlendirmeler ve küçük API uçları uygulamaya ulaşmadan Worker giriş dosyasında çözülüyor. Ücretli Cloudflare Images bağımlılığı yok; görseller derleme anında hazırlanıyor.
Evet, birkaç projede böyle çalışıyoruz. HuntLine IQ’nun Expo uygulaması web platformuyla aynı veri modelini ve Supabase projesini kullanıyor; yetki veritabanında RLS ile uygulanıyor. PeakUp’ın Next.js 16 paneli mobil uygulamayla aynı şemayı ve @peakup/shared iş kurallarını paylaşıyor. Karaman’da müşteri mobil uygulaması, restoran paneli ve merkezi yönetim paneli aynı Supabase projesinde.
Size. Alan adı, sunucu, veritabanı ve servis hesapları sizin adınıza açılır. Teslimde kaynak kodun tamamını, tasarım dosyalarını ve tüm erişimleri size devrederiz.
Hayır. Kullanıcı ekranlarını ve yönetim paneli ekranlarını projenize özel olarak tasarlayıp sıfırdan geliştiririz. Böylece panel, sizin iş akışınıza göre çalışır.
İLGİLİ STÜDYO NOTLARI


Spor salonları için çok kiracılı yönetim platformu ve üye PWA’sı.


Çok kiracılı klinik yönetim sistemi.


Konumunu ifşa etmeden av hareketliliği içgörüsü veren platform.


Spor stüdyosu yönetimi ve üye takibi, tek uygulamada.


Özel okul, kolej ve üniversite keşif platformu; veli merkezi ve okul panelleriyle.


Bir özçekim, o gün çekilmiş bütün fotoğraflarını buluyor.
Bir tanışma görüşmesiyle başlarız. Kapsamı ve takvimi birlikte netleştirir, size yazılı bir teklif göndeririz.
hello@amgsoftwarestudio.com