Problem
Estetik operasyon randevusu, takvimden bir saat seçmekten ibaret değil. Hasta hangi operasyonlarla ilgilendiğini söylüyor, o operasyonları yapan doktorlar arasından biri seçiliyor, doktorun o gün gerçekten müsait olup olmadığı kontrol ediliyor, ön görüşme için ücret tahsil ediliyor ve görüşme bağlantısı ile bilgilendirme her iki tarafa ulaştırılıyor.
Bu adımlar birbirinden ayrı yönetildiğinde iki taraf da aynı anda kör kalıyor: hasta randevusunun gerçekten oluşup oluşmadığını bilemiyor, klinik tarafı ise elindeki listenin hangi kayıtlarının ödenmiş randevu, hangilerinin yarım kalmış talep olduğunu ayırt edemiyor. Uluslararası hasta trafiği eklendiğinde dil, saat dilimi ve ödeme sağlayıcısı farkları da aynı akışın üzerine biniyor.
Yaklaşım
Vanity Appointment'ı iki ayrı ürün — bir randevu formu ve bir yönetim paneli — olarak değil, talep → doktor eşleştirme → müsaitlik doğrulama → ödeme → randevu kaydı → bilgilendirme zincirinin tamamı olarak ele aldım. Ziyaretçiye açık akış ile admin paneli tek Laravel uygulamasında, ortak veri modeli üzerinde çalışıyor.
Belirleyici tasarım kararı şu oldu: randevu, form gönderildiğinde değil, ödeme doğrulandığında kesinleşiyor. Aradaki her şey geçici bir booking session kaydı olarak tutuluyor.
Randevu Akışı
Ziyaretçi tarafı, hangi adımda olduğunu her ekranda gösteren üç aşamalı bir akış olarak kurgulandı:
- Hasta bilgileri. Ad, soyad, uluslararası formatta telefon ve e-posta alınıyor; ardından ilgilenilen operasyonlar seçiliyor. Tek operasyon zorunluluğu yok — hasta birden fazla işlem için aynı ön görüşmeyi talep edebiliyor.
- Doktor ve randevu. Seçilen operasyonları yapan doktorlar listeleniyor; doktorun uygunluk takvimi, tanımlı izinleri ve mevcut randevuları birlikte değerlendirilerek yalnızca gerçekten seçilebilir saatler gösteriliyor.
- Önizleme ve ödeme. Hasta seçimlerini son kez görüyor ve ön görüşme ödemesini yapıyor. Sağlayıcıdan dönen sonuç doğrulandıktan sonra randevu kesinleşiyor, görüşme bağlantısı üretiliyor ve bilgilendirme e-postaları gönderiliyor.
Çok Dilli Randevu Deneyimi
Randevu akışı locale'e göre ayrı route üzerinden sunuluyor; dil seçimi akışın başında değiştirilebiliyor ve ödeme dönüşü dâhil bütün adımlarda korunuyor. Operasyon adları ve açıklamaları panelden dile göre yönetiliyor, koda gömülü metin olarak taşınmıyor.
Uluslararası hasta trafiğinin görünmeyen tarafı ise saat dilimi. Hastanın gördüğü saat ile doktorun takviminde açılan saat aynı anı işaret etmek zorunda; bu yüzden doktor tarafı için referans saat dilimi uygulama ayarı olarak tutuluyor ve müsaitlik hesabı bu referans üzerinden yapılıyor.
Doktor Planlaması ve Müsaitlik
Panelde doktor kaydı, doktorun hangi operasyonları yaptığı, uygunluk takvimi, izin dönemleri ve konsültasyon bilgileri ayrı ayrı yönetiliyor. Ziyaretçiye gösterilen saat listesi bu kaynakların kesişiminden üretiliyor:
- Doktor ↔ operasyon eşleşmesi, seçilen işlemi yapmayan doktorun listede görünmesini engelliyor.
- Uygunluk takvimi, doktorun çalışma düzenini tanımlıyor.
- İzin kayıtları, tanımlı çalışma düzenini geçici olarak kapatıyor.
- Mevcut randevular, dolmuş saatleri listeden düşüyor.
İzni ayrı bir kavram olarak tutmak bilinçli bir tercihti: doktorun çalışma düzenini bir haftalığına silip sonra geri yazmak, hem düzenin kendisini bozuyor hem de o aralığın neden kapatıldığı bilgisini kaybettiriyor.
Ödeme ve Randevunun Kesinleşmesi
Ön görüşme tahsilatı, birden fazla ödeme sağlayıcısıyla çalışacak şekilde kurgulandı; hangi sağlayıcının kullanılacağı ve test/canlı ayrımı panelden yönetiliyor. Sağlayıcıdan dönüş için her sağlayıcının kendi callback route'u var; bu route'lar sağlayıcı doğrulaması ve istek sınırlandırmasıyla korunuyor.
Kullanıcının tarayıcısına dönen yönlendirme, ödemenin gerçekleştiğinin kanıtı olarak kabul edilmiyor. Randevu, dönen sonucun doğrulanıp booking session'ın kesin kayda dönüştürüldüğü anda oluşuyor. Ekranda "randevunuz oluşturuldu" yazması ile veritabanında randevunun bulunması aynı anlama gelmeli.
Yönetim Paneli
Panel, randevu taleplerinin listelendiği bir tablodan ibaret değil; operasyon ekibinin günlük takibi ile klinik tarafının planlama işini aynı yerde yapabildiği bir çalışma alanı olarak tasarlandı.
Randevu talebi sayısı, aktif doktor ve operasyon sayısı ile bekleyen/ödenmemiş kayıtlar bir arada gösteriliyor; randevular hem durumlarına (bekleyen, onaylanan, tamamlanan, iptal edilen) hem de günlere göre dağılımlarıyla izleniyor. Tarih aralığı filtresi bu görünümlerin tamamına aynı anda uygulanıyor, yaklaşan randevular ayrı bir listede aranabiliyor.
Erişim rol bazlı: randevu operasyonunu yürüten kullanıcı ile ödeme ayarlarını veya entegrasyon anahtarlarını görebilen kullanıcı aynı yetki seviyesinde değil.
Entegrasyonlar
- Satış süreci (Pipedrive): Randevu talebi oluşturan hasta, ilgili CRM kaydına kişi ve fırsat olarak yansıtılıyor; satış ekibi randevuyu kendi akışı içinde takip edebiliyor.
- Finans platformu: Tahsil edilen ön görüşme ödemeleri, ödeme aracı bilgisiyle birlikte VPM tarafına aktarılıyor. Böylece randevu tahsilatı, kliniğin diğer ödeme kanallarıyla aynı finansal tabloda değerlendirilebiliyor.
- Hastane bilgi sistemi: Hasta ve randevu bilgisi, kurumun kendi bilgi sistemiyle birlikte ele alınıyor.
- Görüşme bağlantısı: Onaylanan randevu için çevrimiçi görüşme bağlantısı üretiliyor ve bilgilendirme e-postalarıyla hastaya ve doktora ulaştırılıyor.
- Senkronizasyon callback'i: Dış sistemden gelen bildirimler imza doğrulamasından geçtikten sonra işleniyor; gönderilen bilgilendirme mailleri panelde ayrı bir log ekranından izlenebiliyor.
Entegrasyonların hepsi aynı prensiple çalışıyor: dış sistemin cevabı gecikebilir veya hiç gelmeyebilir; bu durum randevunun oluşmasını engellememeli, ama sessizce de kaybolmamalı.
Ayar Yönetimi ve Güvenlik
Sağlayıcı anahtarları, entegrasyon token'ları ve akışa ait eşik değerleri koda ya da deploy dosyalarına gömülmek yerine veritabanı tabanlı bir ayar katmanında tutuluyor. Secret niteliğindeki değerler şifreli saklanıyor ve panelde açık metin olarak geri gösterilmiyor.
Birkaç güvenlik kararı doğrudan bu yapının parçası:
- Randevu bağlantıları imzalı üretiliyor; bağlantıdaki parametrelerin sonradan değiştirilmesi kaydı ele geçirmeye yetmiyor.
- Ödeme callback route'ları sağlayıcı doğrulaması ve throttle ile korunuyor.
- Dış sistem callback'i HMAC imza doğrulaması gerektiriyor.
- İlk yönetici hesabı repoda default parolayla gelmiyor; kurulumda bilinçli olarak, yalnızca hiç yönetici yokken çalışan bir seeder ile oluşturuluyor.
Kullandığım Teknolojiler
Laravel, PHP, MySQL, Blade, JavaScript, Bootstrap, SCSS ve Vite. Randevu akışında tarih/saat seçimi ve uluslararası telefon girişi için arayüz bileşenleri kullanılıyor. Bilgilendirme e-postaları ve entegrasyon bildirimleri kuyruk üzerinden işleniyor; oturum temizliği zamanlanmış komutla yürütülüyor.
Teknik Odak
- Çok dilli, adım adım ilerleyen ve durumunu koruyan randevu akışı.
- Ödeme doğrulanana kadar geçici tutulan booking session modeli.
- Operasyon, uygunluk takvimi, izin ve mevcut randevunun kesişiminden müsaitlik hesabı.
- Saat dilimi farkının hasta ve doktor tarafında tutarlı ele alınması.
- Sağlayıcı doğrulamalı ve sınırlandırılmış ödeme callback akışları.
- İmzalı randevu bağlantıları ve HMAC doğrulamalı dış sistem callback'i.
- Şifreli saklanan, panelden yönetilen çalışma zamanı ayarları.
- Kuyruk tabanlı bildirim ve zamanlanmış oturum temizliği.
Karşılaştığım Problemler
Zorluk randevu kaydetmekte değil, akışın yarım kaldığı durumları tanımlamaktaydı:
- Ödeme sayfasına gidip geri dönmeyen ziyaretçilerin bıraktığı yarım oturumlar.
- Sağlayıcı dönüşü ile gerçek ödeme sonucunun aynı anlama gelmediği durumlar.
- Aynı saat için iki ziyaretçinin neredeyse eş zamanlı ilerlemesi.
- Doktorun izne çıkması veya takviminin akış sürerken değişmesi.
- Hastanın gördüğü saat ile doktorun takvimindeki saatin farklı dilim üzerinden hesaplanma riski.
- Dış sistem bildiriminin gecikmesi ya da aynı bildirimin tekrar gelmesi.
Çözümler
Booking session, yarım kalan akışın randevu tablosuna sızmasını engelliyor; ödenmemiş ve başarısız oturumlar zamanlanmış temizlikle düşürülüyor. Ödeme sonucunun doğrulanması randevunun oluşma koşulu olduğu için, sağlayıcıdan dönen yönlendirme tek başına bir sonuç kabul edilmiyor.
Müsaitlik, akışın başında hesaplanıp saklanan bir liste değil; seçim anında yeniden değerlendirilen bir sonuç. Doktor tarafı için referans saat dilimini ayar olarak tutmak da hasta ve doktor takvimindeki saatin ortak bir eksende hesaplanmasını sağlıyor.
Entegrasyon tarafında ise bildirimin randevu akışından ayrı ele alınması belirleyici oldu: dış sistem cevap vermediğinde randevu yine oluşuyor, bildirim ise tekrar denenebilir bir iş olarak kalıyor. Aynı bildirimin ikinci kez gelmesi de sonucu değiştirmiyor.
Tasarım Notu
Randevu ekranının basit görünmesi, arkadaki akışın tek adımdan oluştuğu anlamına gelmiyor. Ziyaretçi için "randevu al" tek bir düğme; arkasında operasyon eşleştirme, müsaitlik kontrolü, ödeme doğrulaması, kayıt oluşturma ve iki tarafın bilgilendirilmesi var.
Bu zincirin herhangi bir halkasında kalan kayıt, iki taraf için de belirsizlik üretiyor: hasta randevusunun var olduğunu sanıyor, klinik ise olmayan bir randevu için saat ayırıyor. Bu yüzden projede en çok uğraştığım şey mutlu senaryo değil, akışın ortasında kesildiği anlar oldu.
