
Web Uygulaması

Kullanıcıları içsel bir yolculuğa yönlendiren, çok dilli ve tefekkür odaklı bir web uygulaması. İnsan duygusal durumlarını renklere, sayılara ve Esmâ-ül Hüsnâ'ya eşleyerek psikolojik derinlikte yansımalar sunar.
Uygulamanın mobil karşılığı ayrı bir ürün değil: Expo ile paketlenmiş, aynı web adresini gösteren ince bir WebView sarmalayıcısı — tek kod tabanı, iki dağıtım kanalı.
Tefekkür uygulamalarının çoğu içeriği bir sunucudan çekiyor ve kullanıcının ne seçtiğini kayıt altına alıyor. Burada çözülmesi gereken asıl mesele içerik değil, mahremiyet ile süreklilik arasındaki gerilimdi: kullanıcı ruh halini giriyor — bu, saklanmaya değecek kadar kişisel değil ama yolculuğu yarıda bırakınca kaybolmayacak kadar da değerli. Aynı anda uygulamanın tamamen statik kalması, yani hiçbir kullanıcı verisinin sunucuya ulaşmaması gerekiyordu.
Tek persona, iki bağlamda. Kısa bir mola anında telefonundan girip birkaç dokunuşla bir tefekkür metni almak isteyen kullanıcı: adım sayısı az olmalı, geri dönüş her ekranda mümkün olmalı. Aynı kullanıcı düzenli dönerse önceki yolculuklarını görmek istiyor — ama bunun için hesap açmayacak. Dört dil (TR/EN/DE/ES) aynı akışı, aynı Esmâ metinleriyle kendi dilinde sunuyor.
Tek geliştirici. Eşleme modelinin veri tasarımı, dört dilde içerik yapısı, istemci durum makinesi, Web Audio ile ambiyans sesi, PWA kurulumu, güvenlik header'ları ve Vercel dağıtımı.
Next.js 16 App Router, sunucu tarafı hiç yok: API route'u, veritabanı ve oturum yok. Tüm yerelleştirilmiş rotalar statik üretiliyor. Akış tek bir istemci bileşeninde beş adımlı bir durum makinesi olarak yürüyor — giriş, ruh hali, renk, sayı, Esmâ — ve geçişler useReducer üzerinden yapılıyor. Yönlendirme next-intl ile, varsayılan dilde önek olmadan (localePrefix "as-needed"); öneksiz /privacy yolunda dil çerezi varsa proxy katmanı kullanıcıyı kendi diline yönlendiriyor. Aktif oturum durumu sessionStorage'da, tamamlanmış yolculuk geçmişi localStorage'da tutuluyor.
Ruh hali → renk → sayı → Esmâ zinciri hesaplanan bir şey değil, editoryal bir karar: hangi ruh haline hangi beş rengin ve hangi beş Esmâ numarasının düşeceği elle belirlendi ve sekiz ruh hali için sabit tablolar hâlinde kodda duruyor. Bir kural motoru kurmak, aslında var olmayan bir genelliği taklit etmek olurdu.
Ödünleşimİçeriği değiştirmek — yeni bir ruh hali eklemek, bir Esmâ atamasını güncellemek — kod değişikliği ve yeni bir dağıtım gerektiriyor; panelden yapılamıyor. İkinci bedel akışın kendisinde: sonucu belirleyen yalnızca seçilen sayı, seçilen renk sonuca girmiyor. Renk adımı kullanıcı için anlamlı bir duraklama, sistem içinse yalnızca görsel bir değişken.
Ruh hali kaydı hesap açtırmayı meşrulaştırmayacak kadar sıradan ama sunucuda toplanmayı hak etmeyecek kadar kişisel. Son 10 yolculuk localStorage'a yazılıyor; kullanıcı tek düğmeyle tamamını siliyor. Böylece uygulamanın hiçbir arka ucu olmuyor ve saklanan bir kullanıcı verisi de olmuyor.
ÖdünleşimGeçmiş cihaza bağlı: telefon değişince veya tarayıcı verisi temizlenince geri getirmenin yolu yok. Gizli modda veya kota dolduğunda yazma sessizce başarısız oluyor — kod hatayı yutuyor, çünkü kullanıcıya gösterilecek anlamlı bir kurtarma adımı yok. On kayıt sınırı da keyfi bir tavan; onbirinci yolculuk en eskisini siliyor.
İki ses gerekiyordu: giriş ekranında sakin bir ton, Esmâ ekranında yağmur. İkisi de tarayıcıda üretiliyor — yağmur için pembe gürültü buffer'ı alçak geçiren filtreden, ton içinse azalan genlikli dört harmonik osilatörden. Repoya tek bir ses dosyası girmiyor, dolayısıyla indirilecek medya ve ona izin verecek bir CSP kuralı da yok.
ÖdünleşimSes her oturumda istemcide yeniden üretiliyor: iki saniyelik gürültü buffer'ı örnek örnek dolduruluyor ve bu, düşük güçlü telefonda sesin açıldığı anda hissedilir bir CPU maliyeti. AudioContext kullanıcı hareketi olmadan başlayamadığı için ses ancak düğmeye basıldıktan sonra devreye giriyor. Ve sesi değiştirmek artık tasarım işi değil: yeni bir doku istemek DSP kodu yazmak demek.
Yarıda bırakılan yolculuğun kaldığı adım sessionStorage'da; sunucu bunu bilemez. Sunucunun ürettiği HTML her zaman giriş ekranını içeriyor, kayıtlı durum ancak hidrasyon tamamlandıktan sonra uygulanıyor — useSyncExternalStore ile açık bir hidrasyon bayrağı üzerinden. Böylece her dil için tek bir statik çıktı üretiliyor ve CDN'de olduğu gibi önbelleklenebiliyor.
ÖdünleşimGeri dönen kullanıcı ilk karede giriş ekranını görüyor, hemen ardından bulunduğu adıma atlıyor — kısa ama gerçek bir görsel sıçrama. Alternatif olan sunucu tarafında durum okumak, sayfayı statik olmaktan çıkarıp her istekte çalışan bir render'a dönüştürürdü.
Arka uç olmadığı için stack seçimi tek soruya indi: dört dilli, tamamı statik üretilebilen ve tek bir etkileşimli ada taşıyan bir yapı. next-intl, metadata ve hreflang üretimini rota katmanının kendisine bağlayarak dil başına elle SEO yazmayı ortadan kaldırıyor. Framer Motion adımlar arası geçişte AnimatePresence ile çıkış animasyonunu yönetiyor — ekran değiştikçe bileşen ağaçtan çıktığı için bunu CSS ile yapmak mümkün değildi. Tailwind ve CSS özel değişkenleri, seçilen ruh halinin vurgu renginin tüm arayüze tek değişkenden yayılmasını sağlıyor.
Altı HTTP header'ı next.config.ts'te tanımlı: CSP, nosniff, çerçeveleme engeli, referrer politikası, XSS filtresi ve kamera/mikrofon/konum/ödemeyi kapatan Permissions-Policy. CSP'de connect-src yalnızca Vercel Analytics uçlarına açık, font-src ve worker-src kendi kaynağıyla sınırlı. Uygulamanın saldırı yüzeyi zaten dar: form, oturum, API ucu ve veritabanı yok, hiçbir kullanıcı girdisi cihazdan çıkmıyor. Bilinen zayıflık script-src'nin 'unsafe-inline' içermesi — Next.js'in satır içi bootstrap script'i için açık bırakıldı; nonce tabanlı bir CSP'ye geçmek statik üretimden vazgeçmeyi gerektiriyor. Production'da console çıktısı error ve warn dışında temizleniyor.
Tüm yerelleştirilmiş rotalar statik üretiliyor; ilk boya için sunucu hesaplaması yok. Beş adım ekranı da dynamic import ile ayrı chunk'lara bölündü, yalnızca arka plan ve ilerleme çubuğu ana pakette — bunun bedeli yavaş bağlantıda adım geçişinde chunk'ın ilk kez indirilmesi. @next/bundle-analyzer repoda ANALYZE bayrağıyla hazır duruyor. Bu proje için saklanmış, tarih damgalı bir Lighthouse çıktısı bulunmadığından buraya sayfa hızı skoru yazılmadı.
Renk adımını bugün ya sonuca gerçekten katardım ya da akıştan çıkarırdım. Şu hâliyle kullanıcı bir seçim yapıyor ve o seçim hiçbir şeyi değiştirmiyor; bu, arayüzün verdiği sözü tutmaması demek. İkinci olarak eşleme tablolarını koddan çıkarıp derleme zamanında okunan içerik dosyalarına taşırdım — Gorev Kahramani ve bu portfolyonun kendisinde içerik MDX/JSON olarak dururken şema doğrulamasından geçiyor; aynı yaklaşım burada da içerik değişikliğini kod değişikliği olmaktan çıkarır, üstelik statik üretimden hiçbir şey kaybettirmezdi.
Ne yapmak istediğinizi anlatın; ne kadar süreceğini ve nereden başlanacağını baştan söylerim.