
Web Uygulaması

4–12 yaş çocukların günlük alışkanlıklarını oyunlaştırma ile destekleyen ebeveyn kontrollü bir web uygulaması. Çocuklar görev tamamlar, yıldız ve XP kazanır, karakterini geliştirir ve rozet toplar. Ebeveynler görevleri yönetir, onay süreçlerini yürütür ve gelişimi takip eder.
Ebeveynler çocuklarının günlük alışkanlıklarını takip etmek için ya kağıt çizelge ya da yetişkinlere göre tasarlanmış görev uygulamaları kullanıyor. İkisi de aynı yerde tıkanıyor: çocuk kendi ödülünü kendi onaylayabiliyor, dolayısıyla sistem güvenilirliğini kaybediyor. Uygulamanın çözmesi gereken asıl mesele arayüz değil, yetki ayrımıydı.
İki ayrı kullanıcı, tek üründe. 4–12 yaş çocuk: okuma-yazması sınırlı, dokunma hedefleri büyük olmalı, ödül geri bildirimi anında görünmeli. Ebeveyn: görev tanımlar, tamamlananları onaylar veya koçluk notuyla geri çevirir, haftalık gelişimi görür — ve çocuğun bu akışa müdahale edemeyeceğinden emin olmak ister.
Tek geliştirici. Ürün kapsamı, veri modeli, Supabase şeması ve RLS politikaları, Server Action katmanı, iki ayrı arayüz (çocuk/ebeveyn), PWA kurulumu, KVKK çerez akışı ve Vercel dağıtımı.
Tek Next.js 16 App Router uygulaması. Okuma yolu Server Component → lib/dal/*; yazma yolu Server Action → Zod doğrulama → Supabase. Yetki üç katmanlı: proxy.ts'te session kontrolü, Postgres RLS politikaları ve Server Action içinde ek guard. Çocuk bağlamı (activeChild) Zustand'da tutulur, sunucu verisi store'a kopyalanmaz. Streak uzlaştırması /api/cron/reconcile-streaks üzerinden zamanlanmış görevle yapılır. Sistemin ikinci istemcisi ayrı bir repoda duruyor: SwiftUI ile yazılmış bir iOS uygulaması. Bu istemci ayrı bir arka uç taşımıyor — aynı Supabase şemasına bağlanıyor, yani yetki kuralları ve RLS politikaları web ile birebir aynı. Bugünkü olgunluğu iskelet seviyesinde: ebeveyn girişi, çocuk seçimi ve panel ekranlarının akışı kurulu, Supabase istemci yapılandırması opsiyonel bir yükleyici olarak duruyor — yapılandırma yoksa uygulama çöküyor değil, bağlantısız çalışıyor ve ekranlar örnek verilerle doluyor. Yani mimari karar verilmiş ve doğrulanmış durumda, veri bağlama işi henüz bitmedi.
Ebeveyn aynı görevi iki sekmede onaylarsa veya çocuk butona iki kez dokunursa ödül iki kez yazılabiliyordu. Güncelleme, beklenen mevcut değerle karşılaştırmalı yapılıyor; ikinci yazma reddediliyor.
ÖdünleşimÇakışma anında kullanıcıya "tekrar dene" göstermek gerekiyor; sessiz birleştirme yok. Düz bir UPDATE'e göre daha fazla kod ve daha fazla hata yolu demek.
Çocuk profili PIN'i tarayıcıya inseydi kardeş veya çocuğun kendisi kolayca geçerdi. verify_child_pin RPC hash karşılaştırmasını sunucuda yapıyor ve ardışık hatalı denemeyi sayarak brute-force'u kesiyor.
ÖdünleşimHer profil geçişi bir ağ turu maliyeti getiriyor ve çevrimdışıyken profil değiştirilemiyor.
Cihaz saati ve saat dilimi güvenilir değil; çocuk cihazın tarihini değiştirerek seri kazanabilirdi. Seri, sunucu tarafında zamanlanmış görevle yeniden hesaplanıyor.
ÖdünleşimSeri, cron çalışana kadar geç güncellenebiliyor; kullanıcı anlık değişim görmüyor.
Supabase, yetkilendirmenin kritik kısmının — bir çocuğun yalnız kendi görevlerini görebilmesi — uygulama kodunda değil, veritabanı politikası olarak ifade edilebilmesi için seçildi: uygulama katmanında bir hata olsa bile veri sızmıyor. Zod tek şema olarak hem Server Action girdisinde hem form tarafında kullanılıyor. Zustand yalnız kısa ömürlü istemci durumu için; sunucu verisinin kaynağı her zaman sunucu.
İki bağımsız yetki katmanı: Postgres RLS ve Server Action içi guard — biri atlansa diğeri durduruyor. PIN hash'lenmiş ve brute-force sayaçlı. Cloudflare Turnstile kayıt, giriş ve çocuk→ebeveyn geçişinde devrede. Ebeveyn işlem kilidi şifre doğrulamasıyla geçici açılıyor. Güvenlik header'ları ve Report-Only CSP next.config.ts'te tanımlı. Google Analytics yalnız çerez onayı verildikten sonra ve yalnız production'da yükleniyor (KVKK).
PWA olarak kurulabiliyor; service worker ve /offline geri düşüş sayfası mevcut. Vitest ile 26 test dosyası, ağırlıklı olarak onay ve ödül akışlarının eşzamanlılık davranışında. Lighthouse mobil (kendi ölçümüm): 100/100 — Eylül 2026. Aynı ölçümde LCP medyanı 1666 ms, toplam engelleme süresi 1 ms ve CLS 0.
Eşzamanlılığı bugün uygulama katmanında CAS ile değil, doğrudan veritabanı kısıtı olarak kurardım. Ustura'da randevu çakışmasını Postgres exclusion constraint ile çözdüm; o yaklaşım daha az kod yazdırıyor ve garantiyi uygulamanın dışına, veritabanının kendisine taşıyor. İkinci olarak CSP'yi Report-Only'de bırakmak yerine yayından önce enforce moduna geçirirdim — rapor toplamak ihlali durdurmuyor.
Ne yapmak istediğinizi anlatın; ne kadar süreceğini ve nereden başlanacağını baştan söylerim.