Proje: Okul Platform · Hub: Okul Platform — Incidents
tesekkurler/{id} multiple-form 24h dedupe eksikti
Semptom
/tesekkurler/{offer_id} sayfasında bottom sheet üzerinden önerilen okullara form gönderildikten sonra başarı popup’ı kapatıldığında, kullanıcı aynı butona tekrar tıklayıp aynı okullara birden fazla offer yaratabiliyordu. Aynı okula 24 saat içinde duplicate SchoolOffer kayıtları oluşuyordu.
Root Cause
İki katmanda da koruma yoktu:
- Backend:
app/Http/Controllers/Ajax/FormController.php::submitMultipleFormherschool_idiçin körü körüneSchoolOfferService::create()çağırıyordu. Service’incheckOfferCountkontrolü sadece 24 saatte toplam 10 form sınırına bakıyor, aynı okula tekrar göndermeyi engellemiyor. - Frontend:
sendForm()(desktop,frontend/offer/success.blade.php) vesendPlusLeadForm()(mobile,mobile/app.js:6913) AJAX başarı sonrası okul card’larını DOM’dan kaldırmıyor, butonu disable etmiyor, çift tıklama koruması yok.
İlginç: SchoolSuggestService ilk render’da userOfferSchoolIds() ile son 1 ayda gönderilen okulları zaten hariç tutuyor. Yani sayfa yenilense problem çıkmaz; sorun yalnızca aynı sayfa açıkken tekrar submit’e izin verilmesinden geliyordu.
Çözüm
BE (Ajax/FormController::submitMultipleForm): Çağrı başında SchoolOffer::where(user_id, school_id, created_at >= now-24h) ile mevcut offer’ları çek, gelen school_ids’i bunlardan filtrele. Tamamı duplicate ise status: false + bilgi mesajı dön; aksi halde sadece kalan okullar için create(). Yanıta submittedSchoolIds ve skippedSchoolIds eklendi.
FE:
- Çift tıklama guard’ı (
_isSendingForm/_isSendingPlusLeadForm). - Başarı sonrası
removeSubmittedSchoolCards(submittedIds)ile gönderilen card’lar DOM’dan silinir;schoolsarray sıfırlanır. - Hiç okul kalmadıysa send butonları “Tüm okullara gönderildi” yazısıyla kilitlenir.
- Tamamı duplicate döndüğünde de aynı kilit + bilgilendirme popup’ı.
Önemli Notlar
submitMultipleOffers(profiling flow) zaten dedupe yapıyordu — bkz[[2026-04-27-school-offer-business-rules]]. Bu bug onun kuzenisubmitMultipleFormendpoint’inin aynı kuralı atladığını gösterdi.- Dedupe
user_id’ye göre yapıldı, e-mail’e değil — çünkütesekkurler/{id}her zaman kayıtlı birSchoolOffer.user_idüzerinden çalışır (offer ya auth kullanıcının ya da form sırasındacreateUserile oluşturulmuş kullanıcı).
Related
- 2026-04-27-school-offer-business-rules — 24h dedupe kuralı (genel)
- Okul Platform — Incidents