
Görev Kahramanı
Web Uygulaması
Kısaca
- Ebeveynler alışkanlık takibi için kâğıt çizelge ya da yetişkinlere göre yapılmış uygulamalar kullanıyordu; çocuk kendi ödülünü kendisi onaylayabildiği için sisteme güven kalmıyordu.
- Çocuk görevlerini kendi ekranında tamamlıyor, onay ve ödül ise yalnızca ebeveynin elinde; uygulama telefona kurulabiliyor ve çevrimdışı da açılabiliyor.
- Aynı görev iki kez onaylansa da ödül bir kez veriliyor; çocuk profiline geçiş şifresi sunucuda kontrol ediliyor ve cihazın saatini değiştirmek seri kazandırmıyor.

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.
Kullanılan Teknolojiler
Öne Çıkan Özellikler
- Çocuk modu: görev akışı, yıldız/XP, seviye ve karakter evrimi
- Ebeveyn paneli: görev yönetimi, onay/red ve koçluk notu
- Ödül kataloğu yönetimi ve ödül talep sistemi
- PWA desteği — çevrimdışı kullanım ve ana ekrana yükleme
- Aynı anda yapılan güncellemelerde puan kaybı olmaması ve PIN güvenliği
Geliştirme Süresi
Problem
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ı.
Kullanıcılar
İ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.
Rolüm
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ı.
Mimari
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.
- Web uygulaması
- Zustand · activeChild
- proxy.ts
- Okuma yolu
- Yazma yolu
- Supabase · Postgres
- /api/cron/reconcile-streaks
- iOS istemcisi · SwiftUI
Kritik Kararlar
Yıldız ve XP güncellemelerinde CAS tarzı eşzamanlılık koruması
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.
PIN doğrulaması istemcide değil, veritabanı fonksiyonunda
Ç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.
Streak'i istemci hesaplamıyor, cron uzlaştırıyor
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.
Teknoloji Seçimi
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.
Güvenlik
İ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).
Performans
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.
Sonuçlar
- 2026-03 → 2026-07 · 39 commit
- Çift onay çift ödül üretemiyor
- 26
- 139
- Web (PWA) + native iOS istemcisi
Bugün Ne Farklı Yapardım
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.
Nereden başlayacağınızı birlikte bulalım
Ne yapmak istediğinizi anlatın; ne kadar süreceğini ve en mantıklı ilk adımı baştan söylerim.