Bu serinin yazarı Güray: AI geliştirmecisi, prompt ve analiz mühendisi. Kodun büyük kısmını bir LLM ajanıyla pair programming yaparak yazıyorum. Seri, kafa1milyon.com'un perde arkasını mühendis gözüyle belgeliyor. Bölüm 1'de genel mimariyi anlatmıştım.
Önce dürüst bir uyarı: bu bir revizyon günlüğü
Bu yazıdaki her şey tek bir günde eklendi ve tamamı deneysel. Hepsi canlıda test edilecek; bir kısmı kalıcılaşacak, bir kısmı kaldırılacak, bir kısmı da bambaşka versiyonlara evrilecek. Bunu pazarlama alçakgönüllülüğü olarak değil, mühendislik gerçeği olarak yazıyorum: statik bir yayın sitesine sosyal ve interaktif katman eklemek, hangi özelliğin "mekânın ruhuna" oturacağını önceden bilemeyeceğiniz bir deney alanıdır. Ölçüp, izleyip, budayacağız.
Günün sonunda üç büyük blok çıktı ortaya:
- Okur katmanı: vurgulama, not, okuma modu, sözlük, filtreler, sesli oynatıcı ve bir dizi "sessiz" etkileşim.
- Park Bankı: aynı yazıyı okuyan iki anonim okuru eşleştiren mikro sohbet.
- Caz Kulübü: masalara oturulan, müzik paylaşılan, sesli sohbete geçilebilen dijital bir mekân. (Gün biterken kapısına kilit vurup rezervasyon moduna aldık; birazdan anlatacağım.)
Kısıt seti: veritabanı yok, WebSocket yok, hesap yok
Site tamamen statik HTML + nginx + Cloudflare. Bu revizyonda da kural bozulmadı. Sosyal özelliklerin tamamı şu üç ilkeyle yazıldı:
-
Bellek içi Python backend'ler (stdlib-only,
ThreadingHTTPServer): park bankı ve kulüp API'leri süreç belleğinde yaşar. Süreç yeniden başlarsa masalar boşalır. Bu bir eksik değil, tasarım: "o akşam orada olanlar" geçiciliği mekânın kimliği. -
WebSocket yerine kısa yoklama (short polling): 2-3 saniyede bir
GET. Cloudflare arkasında WS oturumu yönetmek yerine, olay listesinits > sonrafiltresiyle artımlı çekiyoruz. 30 eşzamanlı kullanıcı tavanında bunun maliyeti saniyede ~15 hafif JSON isteği; nginx bunu esner bile. - Kimlik = sessionStorage'daki rastgele uid: kayıt yok, e-posta yok, çerez yok. Sekme kapanınca kimlik de gider.
istemci (vanilla JS) ──2 sn'de bir──> nginx /bar/api/ ──> 127.0.0.1:8796
bellek içi durum:
MASALAR, KISILER,
BEKLEYEN, SINYAL
Okur katmanı: metnin üstüne bir kat daha
Makale sayfalarına bir günde eklenen etkileşim seti:
-
Vurgulama + not:
window.getSelection()ile seçim,<mark>sarma, DOM yolu + metin ofsetiyle LocalStorage'a yazma. Sayfa yeniden yüklendiğinde vurgular yeniden uygulanıyor. Sunucu hiçbir şey görmüyor. - Okuma modu çubuğu: sepya/gece teması, 16-22px font ölçeği, odak modu (header/footer gizlenir, sadece metin + ilerleme çubuğu kalır).
-
Ruh hali + süre filtreleri: içerik meta verisine
readTimeMinutesvemoodeklendi; liste sayfaları istemci tarafında filtreleniyor. -
Kavram sözlüğü:
data-definitiontaşıyan terimlere hover/tık popover'ı. - MediaSession API'li sesli oynatıcı: kilit ekranından oynat/durdur, arka plan oynatma. Yanına podcast RSS beslemesi kuruldu ve Spotify'a bağlandı.
- Fısıltı Bulutu (Mind Cloud): makale başına 10 saniyelik ses kayıtları (MediaRecorder) veya 140 karakterlik notlar. Her gönderi yayınlanmadan önce LLM moderasyonundan geçiyor; ses önce transkribe edilip aynı süzgece giriyor.
- Daha sessiz deneyler: paragraf altı "görünmez mürekkep" şerhleri, okurların nerede durakladığını gösteren anonim odak haritası, cümle kenarına 140 karakterlik itiraz bırakılan marjin notları, scrollytelling şablonu, üretken sanat tuvali ve "şimdi ne okumalıyım?" karar ağacı.
Bunların onboarding'i de ayrı bir tasarım problemiydi: ekranı kaplayan tur yerine, ilk ziyarette 2-3 saniye görünüp kaybolan mikro ipuçları ve "özelliği tam kullanacağın anda öğreten" bağlamsal tetikleyiciler kullandık. Kullanıcı bir özelliği bir kez kullandığında ipucu bir daha çıkmıyor (LocalStorage bayrağı).
Revizyon notu: Bu setin tamamı ölçüme tabi. Odak haritası gibi "güzel ama belki kimsenin fark etmeyeceği" özellikler ilk budama adayları.
Park Bankı: iki yabancı, bir bank, 140 karakter
Aynı yazıyı okuyan iki anonim okur varsa, köşede bir davet beliriyor: "Parkta sizinle aynı makaleyi okuyan biri var. Bir bankta oturup iki cümle laflamak ister misiniz?"
Kabul edenler SVG ile çizilmiş bir park sahnesinde (gece/gündüz temasına duyarlı) karşılıklı iki banka oturuyor. Mesajlar karakterin kafasının üstünde konuşma balonu olarak beliriyor ve 6 saniyede sönüyor. Kalkan tarafın yerine "diğer okur banktan kalktı" notu düşüyor.
Teknik olarak en tartışmalı karar: spesifikasyon Socket.io diyordu, biz kısa yoklamayla yazdık. İki kişilik, 140 karakterlik, saniye hassasiyeti gerektirmeyen bir sohbet için WS altyapısı taşımak istemedik. Doğru karar mıydı? Kulüp tarafında göreceğiz; oradaki yük profili farklı.
Caz Kulübü: günün en büyük parçası
10 masa (5'i dört, 5'i iki kişilik), caz efsanelerinin adlarını taşıyor: Ella, Coltrane, Nina, Miles... Kuşbakışı SVG salon planında dolu koltuklar kehribar yanıyor. Masalar dolarsa bar alanında kuyruk; koltuk boşalınca 30 saniyelik rezervasyonla çağrı.
Masa içinde:
- Atmosfer: ışık (spot/loş/gece) ve ikram (kahve/meze/mum) masadaki herkese canlı yansıyor. Mum alevi ve kahve buharı CSS animasyonu.
- Medya ekranı: yalnızca YouTube/Spotify. YouTube linkleri sunucuda oEmbed ile doğrulanıyor (video gerçekten var mı, gömülebilir mi) ve başlık NSFW/şiddet kelime süzgecinden geçiyor.
- Sesli sohbet: masadaki HERKES onaylarsa açılıyor (oy birliği). Ses P2P WebRTC mesh; SDP/ICE sinyalleşmesi ayrı bir kanal yerine mevcut yoklama döngüsünün içinde taşınıyor. Sunucuya ses akışı hiç uğramıyor. Bilinen sınır: TURN sunucumuz yok, simetrik NAT arkasındaki azınlık ses kuramayabilir. Kabul edilmiş bir ödün.
Gece yarısına doğru altı "kült mekân" özelliği daha eklendi:
- İstek peçetesi (jukebox kuyruğu): link anında çalmıyor; sıraya giriyor, kim istedi görünüyor. "🍷 İkram Et" oyu şarkıyı öne alıyor. Otomatik parça geçişi bilerek yok: YouTube oEmbed süre bilgisi vermiyor, Data API'ye anahtar bağlamak istemedik. Geçiş masadakilerin elinde ("⏭").
- Ortak peçete: masanın ortasında herkesin aynı anda çizebildiği kanvas + kısa notlar. Çizgiler nokta dizisi olarak sunucuya gidiyor, diğer istemciler artımlı indeksle çekiyor. Masa dağılınca peçete siliniyor.
- Soru kartı: sohbet tıkanınca "🃏 Masaya Soru At" arşiv tonunda ~30 felsefi sorudan birini masaya düşürüyor. Aynı masada son 10 soru tekrarlanmıyor.
- Adisyon: 5 dakika etkileşimsiz kalan misafirin önüne adisyon geliyor; 60 saniyede "buradayım" demezse koltuk kuyruktakine devrediliyor. Tamamen istemci tarafında; sunucunun 25 saniyelik yoklama düşmesi zaten güvenlik ağı.
- Kişisel ambiyans mikseri: plak cızırtısı / yağmur / orman / kütüphane / sessiz + ses kaydırıcısı. Bilinçli karar: ortam sesi masaya değil, kişiye ait. Kimseye atmosfer dayatılmıyor; sessizlik her zaman bir tık uzakta.
- Yavaş sohbet protokolü: her mesajdan sonra 8 saniyelik "yudum molası". Sunucu 429 dönüyor, istemci girdiyi kilitleyip sayaç gösteriyor. Amaç, bar temposunu klavye yarışına kurban etmemek.
Ve günün son kararı: kapıya kilit
Gün biterken ürün kararı değişti: kulüp üyelik zorunlu olacak ve sistem açılmadan önce daha da geliştirilecek. Bu yüzden şu an canlıda kapı kapalı:
- Backend'de tek satırlık bir bayrak (
KULUP_ACIK = False) oturma ve bekleme uçlarını 403 ile kesiyor. - "Kapıdan Gir" düğmesi "🪑 Yerini Rezerve Et" oldu. Popup yalnızca e-posta + isteğe bağlı "hangi gün/saatlerde gelmek istersin?" alıyor. Kayıtlar diske yazılıyor (kulübün geri kalanının aksine, çünkü bunlar açılış davetiyesi listesi).
- Salon, masalar, ses, peçete: kodun tamamı yerinde duruyor. Bayrak
Trueyapıldığında mekân olduğu gibi geri gelecek, muhtemelen üyelik katmanıyla sarılmış olarak.
Bir günde inşa edip aynı gün kapısına "yakında" tabelası asmak tuhaf görünebilir. Ama bence sıralama doğru: önce mekânın çalıştığını uçtan uca kanıtla (iki sekmeli WebRTC testleri dahil), sonra kimlerin gireceğine karar ver. Tersi, üyelik sistemini boş bir mekân için kurmak olurdu.
Bir günün dürüst bilançosu
İyi çalışan şeyler: yoklama tabanlı mimari beklediğimden sağlam çıktı; WebRTC sinyalini aynı kanaldan taşımak ayrı bir sinyal sunucusunu tamamen ortadan kaldırdı; bellek içi durum + "her şey masada kalır" ilkesi hem gizlilik hem operasyon yükü açısından ucuz.
Bilinen borçlar: TURN yok; YouTube süre bilgisi yok (manuel geçiş); adisyon istemci tarafında (sekme açık ama kullanıcı yoksa 5+1 dakika koltuk işgali mümkün); yoklama aralıkları 30 kullanıcı üstü için yeniden düşünülmeli.
Akıbet: Bu revizyondaki her özellik gözlem altında. Kullanılmayanlar kaldırılacak, tutunanlar üyelik sistemiyle birlikte v2'ye taşınacak. Bir sonraki bölümde muhtemelen ya üyelik mimarisini ya da bu deneylerden hangilerinin hayatta kaldığını yazacağım.
Soruları yorumlara bırakabilirsiniz; özellikle "polling yerine WS kullansaydınız" itirazlarını memnuniyetle tartışırım.
Top comments (0)