Sağlık Turizmi

Esthetic Hair: çok dilli klinik sitesi ve kendi CMS'i

Saç ekimi kliniği için headless CMS, çok dilli site ağı ve Bitrix24 ile kuyruklu çalışan bir başvuru hattı.

Şirket
Esthetic Hair · esthetichair.com
Rol
Kendi şirketimiz · uçtan uca
Sektör
Sağlık Turizmi
Tarih
Esthetic Hair vaka çalışması kapak görseli

Problem

Klinik birden fazla dilde hasta topluyordu; her dil ayrı bir siteydi ve ayrı ayrı güncelleniyordu. Tek bir fiyat değişikliği, aynı işin dil sayısı kadar tekrarlanması demekti. Formdan gelen başvurular Bitrix24 tarafına elle giriliyor, bu sırada hem kaynak bilgisi (hangi reklam, hangi dil, hangi sayfa) hem de başvuruların bir kısmı kayboluyordu.

Yaklaşım

İçeriği tek yerde toplayıp sunumdan ayırdık: Django REST Framework üzerinde, editörün bloklarla sayfa kurduğu bir CMS yazdık; Next.js tarafı bu API'den beslenen çok dilli siteyi üretti. Başvuru hattını "gönder ve unut" olmaktan çıkarıp outbox desenine taşıdık — form önce kendi veritabanımıza düşüyor, Bitrix24'e Celery kuyruğundan idempotent biçimde yazılıyor.

Başlangıç durumu

Esthetic Hair, yurt dışından hasta kabul eden bir saç ekimi kliniği. Bu iş modelinde site bir vitrin değil, satış hattının ilk adımı: ziyaretçi bir arama sonucundan ya da reklamdan geliyor, tedavi sayfasını okuyor, fotoğraf gönderiyor ve bir danışmana bağlanıyor. Sürecin geri kalanı Bitrix24 üzerinde yürüyor.

Devraldığımızda üç problem iç içe geçmişti:

  • Dil başına bir site. Her dil kendi kurulumunda, kendi temasında yaşıyordu. Ortak olan tek şey markaydı; içerik, bileşenler, hatta form alanları zamanla birbirinden ayrışmıştı.
  • İçerik değişikliğinin maliyeti dil sayısına bağlıydı. Bir fiyat güncellemesi, dil sayısı kadar ayrı işti. Bu yüzden pratikte yapılmıyordu ve siteler birbirinden farklı gerçekleri anlatıyordu.
  • Başvuru ile CRM arasında insan vardı. Form bir e-posta kutusuna düşüyor, oradan Bitrix24’e elle giriliyordu. Aktarım sırasında kampanya, dil ve açılış sayfası bilgisi kayboluyordu — yani hangi reklamın hasta getirdiği ölçülemiyordu.

Kararlar

Neden hazır bir CMS değil

İlk değerlendirdiğimiz seçenek WordPress’ti: kurulu, ucuz, ekibin tanıdığı bir zemin. İki nedenle reddettik.

Birincisi çok dillilik. Sağlık turizminde diller birbirinin çevirisi değildir; aynı tedavi sayfası bir dilde fiyat tablosuyla, başka bir dilde hasta hikâyeleriyle satar. Eklenti tabanlı çeviri katmanları bu ayrımı “eksik çeviri” sayar ve sizi tek bir yapıya zorlar.

İkincisi entegrasyon. Bitrix24 tarafında ihtiyacımız olan şey basit bir webhook değil, kuyruklu ve tekrar denemeli bir aktarım hattıydı. Bunu bir eklenti ekosisteminin içinde kurmak, kritik yolu bizim kontrol etmediğimiz koda bağlamak demekti.

Neden Django REST Framework

Yazdığımız şey bir API’den çok bir yönetim sistemi: rol bazlı yetki, taslak/yayın akışı, medya kütüphanesi, sürüm geçmişi. Django’nun ORM’i, göç disiplini ve admin altyapısı bu işin önemli bir kısmını hazır getiriyor. FastAPI’yi ölçek gerekçesiyle düşünmedik bile — buradaki darboğaz istek başına framework süresi değil, editörün bir sayfayı kaç dakikada kurabildiği.

DRF’in serializer katmanı çok dilli modelde ayrıca işe yaradı: aynı içerik nesnesi, dil parametresine göre farklı alan setiyle serileşiyor; Next.js tarafı dil mantığını taşımak zorunda kalmıyor.

Neden Next.js, neden tamamen statik değil

Site yüzlerce sayfa taşıyor ve içerik ekibi bunları gün içinde düzenliyor. Tam statik üretimde her küçük düzeltme bütün siteyi yeniden derletir. Next.js’in artımlı yeniden üretimi ortadaki dengeyi kuruyor: ziyaretçi her zaman önceden üretilmiş HTML alıyor, düzenlenen sayfa arka planda tazeleniyor.

Arama motoru tarafı bu kararın asıl gerekçesi. Sayfalar sunucuda üretildiği için Googlebot içeriği JavaScript çalıştırmadan görüyor; hreflang etiketleri CMS’teki dil eşleşmesinden üretiliyor, elle yazılmıyor.

İçerik modeli: blok tabanlı

Sayfalar serbest HTML değil, tiplenmiş bloklardan oluşuyor: kahraman bölümü, fiyat tablosu, öncesi/sonrası galerisi, SSS, doktor kartı, hasta yorumu. Her blok Next.js tarafında bir bileşene karşılık geliyor.

Bunun bir bedeli var: editör istediği her düzeni kuramıyor. Karşılığında site yıllar sonra da tutarlı görünüyor ve bir bloğun tasarımını değiştirdiğimizde bütün dillerdeki sayfalar aynı anda düzeliyor. Bu ödünü bilerek verdik.

Uygulama

Bitrix24 hattı

Entegrasyonun tamamı tek bir varsayım üzerine kurulu: dış sistem er ya da geç cevap vermeyecek.

  1. Form gönderildiğinde başvuru önce kendi PostgreSQL tablomuza yazılır. Kullanıcı bu noktada teşekkür sayfasını görür; Bitrix’in o anki durumu ziyaretçiyi ilgilendirmez.
  2. Aynı işlemde bir outbox kaydı oluşur. Celery işçisi bu kayıtları sırayla alıp Bitrix24 REST API’sine yazar.
  3. Her kayıt bir idempotency anahtarı taşır. Aynı başvuru iki kez denenirse Bitrix tarafında ikinci bir lead açılmaz.
  4. Hata durumunda üstel bekleme ile yeniden denenir; belirli bir denemeden sonra kayıt ölü mektup kuyruğuna düşer ve panelde görünür. Sessizce kaybolan başvuru yoktur.
  5. Bitrix tarafındaki aşama değişiklikleri webhook ile geri gelir; lead’in hangi aşamada olduğu sitede de bilinir.

UTM parametreleri, gclid, dil, açılış sayfası ve cihaz bilgisi başvuruyla birlikte taşınıp Bitrix’te özel alanlara yazılır. “Hangi reklam hasta getirdi” sorusunun cevabı bu alanlarda duruyor.

Redis’in dört işi

Tek bir Redis kurulumu dört role birden hizmet ediyor: Celery’nin mesaj aracısı, API okuma yanıtlarının önbelleği, form uçları için hız sınırı sayacı, ve senkron işlerinin aynı anda iki kez başlamasını engelleyen kilit. Ayrı ayrı kurulmuş dört bileşen yerine tek bağımlılık — operasyon yükü buradan düşüyor.

Medya

Öncesi/sonrası galerileri bu sektörün en ağır varlığı. Yükleme anında türevler üretiliyor (AVIF ve WebP, üç genişlik), orijinal nesne depolamada kalıyor, dağıtım Cloudflare üzerinden yapılıyor. Editör tek bir dosya yüklüyor ve boyutlandırmayı hiç düşünmüyor.

Dağıtım

Docker imajı GitHub Actions üzerinde derlenip test edildikten sonra yayına çıkıyor. Veritabanı göçleri dağıtımdan ayrı, geri alınabilir bir adımda çalışıyor. Hata takibi Sentry’de; başvuru hattındaki her hata ayrı bir uyarı üretiyor, çünkü orada bir hata doğrudan kaybedilmiş bir hasta demek.

Ölçüm

Bu vaka çalışmasına sayı yazmadık; ölçüm dönemi henüz kapanmadı. Kapandığında buraya girecek metrikler:

  • Form gönderiminden Bitrix24’te lead oluşana kadar geçen süre.
  • Kaynağı belirlenebilen başvuru oranı — entegrasyon öncesi ve sonrası.
  • Yeni bir tedavi sayfasının bütün dillerde yayına çıkma süresi.
  • Çekirdek Web Verileri (LCP, INP, CLS) — alan verisiyle, laboratuvar skoruyla değil.

Sonuç

İçerik ekibi bütün dillerde tek panelden çalışıyor; yeni bir tedavi sayfası bir kez kuruluyor, çeviri katmanı üzerinden diğer dillere açılıyor. Formdan Bitrix24'e giden her başvuru kaynak bilgisiyle birlikte ve tekrarsız düşüyor; kuyruk sayesinde entegrasyon kesintisi başvuru kaybına dönüşmüyor. Sayısal karşılaştırma için ölçüm dönemi sürüyor.

Bir fikriniz mi var, yoksa duran bir ürün mü?

Kısa bir görüşmede kapsamı netleştirelim. İlk konuşmada teknik yaklaşımı ve tahmini bütçe aralığını konuşuruz.