[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"\u002Fblog\u002Fsocket-io-canli-sohbet":3,"\u002Fblog\u002Fsocket-io-canli-sohbet-surround":92},{"id":4,"title":5,"author":6,"body":11,"date":81,"description":82,"extension":83,"image":84,"meta":85,"minRead":86,"navigation":87,"path":88,"seo":89,"stem":90,"__hash__":91},"blog\u002Fblog\u002Fsocket-io-canli-sohbet.md","Support.io'da Socket.IO ile canlı sohbet altyapısı",{"name":7,"description":8,"avatar":9},"Uhut Sancar","Frontend Developer",{"src":10,"alt":7},"\u002Fprofile.jpg",{"type":12,"value":13,"toc":72},"minimark",[14,18,21,26,29,32,36,39,42,46,49,52,55,59,62,65,69],[15,16,17],"p",{},"Support.io, bir web sitesine tek satır kodla eklenen SaaS bir canlı destek sistemi. Ziyaretçi widget üzerinden yazıyor, destek ekibi yönetici panelinden yanıtlıyor, aynı panelden birden fazla site yönetilebiliyor.",[15,19,20],{},"Gerçek zamanlı tarafı Socket.IO ile kurdum. Geliştirirken en çok uğraştığım şey mesajın iletilmesi değil; bağlantı koptuğunda, sekme arka plana atıldığında ya da aynı kullanıcı iki cihazdan bağlandığında sistemin tutarlı kalmasıydı.",[22,23,25],"h2",{"id":24},"oda-yapısı","Oda yapısı",[15,27,28],{},"Her konuşma için ayrı bir oda kullandım. Ziyaretçi bağlandığında kendi konuşma odasına katılıyor; destek ekibindeki kullanıcı ise ait olduğu sitenin tüm konuşmalarını dinleyebilecek şekilde ek bir odaya alınıyor.",[15,30,31],{},"Bu ayrım önemliydi çünkü bir ziyaretçinin başka bir ziyaretçinin mesajını görmemesi gerekiyor. Yayını \"herkese gönder, istemcide filtrele\" mantığıyla yapmak kolay görünüyor ama güvenlik açısından kabul edilebilir değil.",[22,33,35],{"id":34},"kimlik-doğrulama","Kimlik doğrulama",[15,37,38],{},"Socket bağlantısını kurarken JWT'yi handshake aşamasında doğruluyorum. Token geçersizse bağlantı hiç kurulmuyor.",[15,40,41],{},"Destek ekibi tarafında ek bir kontrol daha var: kullanıcının katılmak istediği odanın, gerçekten yetkili olduğu siteye ait olup olmadığını sunucuda kontrol ediyorum. İstemciden gelen oda bilgisine güvenmek, panelin tamamını açık hale getirirdi.",[22,43,45],{"id":44},"mesaj-sırası-ve-yeniden-bağlanma","Mesaj sırası ve yeniden bağlanma",[15,47,48],{},"Socket bağlantısı kopup yeniden kurulduğunda, kopma süresince gönderilen mesajlar istemciye ulaşmıyor. Bunu çözmek için mesajları yalnızca socket üzerinden akıtmak yerine kalıcı olarak veritabanına yazıyorum; istemci yeniden bağlandığında elindeki son mesajın zaman damgasından sonrasını REST üzerinden çekiyor.",[15,50,51],{},"Yani socket \"anlık iletim\" için, veritabanı ise \"gerçeğin kaynağı\" olarak çalışıyor. Bu ayrımı baştan kurmak, sonradan ortaya çıkan pek çok tutarsızlığı engelledi.",[15,53,54],{},"Kullanıcı deneyimi tarafında ise mesajı gönderirken hemen ekranda gösterip, sunucudan onay geldiğinde durumunu güncelliyorum. Onay gelmezse mesaj \"gönderilemedi\" durumunda kalıyor ve tekrar denenebiliyor.",[22,56,58],{"id":57},"widget-tarafındaki-kısıtlar","Widget tarafındaki kısıtlar",[15,60,61],{},"Widget başka birinin sitesinde çalıştığı için sayfanın stillerinden etkilenmemesi gerekiyordu. Stil izolasyonu ve z-index yönetimi, gerçek zamanlı taraftan daha fazla vaktimi aldı.",[15,63,64],{},"Mobil tarafta klavye açıldığında sohbet alanının kayması, safe area ve viewport yüksekliği gibi konular da ayrı bir başlıktı. Bir widget'ın masaüstünde düzgün görünmesi, mobilde çalıştığı anlamına gelmiyor.",[22,66,68],{"id":67},"çıkardığım-ders","Çıkardığım ders",[15,70,71],{},"Gerçek zamanlı bir özellik geliştirirken asıl iş, mesajı iletmek değil; bağlantının koptuğu, geciktiği ya da iki kez kurulduğu durumları planlamak. Bu senaryoları sonradan eklemeye çalışmak, baştan tasarlamaktan çok daha zor oluyor.",{"title":73,"searchDepth":74,"depth":74,"links":75},"",2,[76,77,78,79,80],{"id":24,"depth":74,"text":25},{"id":34,"depth":74,"text":35},{"id":44,"depth":74,"text":45},{"id":57,"depth":74,"text":58},{"id":67,"depth":74,"text":68},"2026-03-10","Tek satır kodla siteye gömülen bir canlı destek sistemini geliştirirken oda yönetimi, yeniden bağlanma ve mesaj sırası konusunda öğrendiklerim.","md","\u002Fimages\u002Fprojects-1.avif",{},6,true,"\u002Fblog\u002Fsocket-io-canli-sohbet",{"title":5,"description":82},"blog\u002Fsocket-io-canli-sohbet","qThLXTNZWAHPEV5NSWZ3kS2BV-nba05u9aR2baM8_NU",[93,98],{"title":94,"path":95,"stem":96,"description":97,"children":-1},"MongoDB'de embed mi reference mı?","\u002Fblog\u002Fmongodb-embed-reference","blog\u002Fmongodb-embed-reference","Veri modelini uygulamanın sorgu şekline göre kurmak, embed ve reference arasındaki seçim ve bu kararın pagination ile index performansına etkisi.",null]