Verify subscription lifecycle in browser and clarify delivery status

This commit is contained in:
2026-09-06 12:58:34 +03:00
parent f50468e768
commit d2d66c8e9d
4 changed files with 24 additions and 2 deletions
File diff suppressed because one or more lines are too long
+6
View File
@@ -793,3 +793,9 @@ Taslak türü seçicisine erişilebilir ad eklendi. Üretim derlemesi geçti. Ö
- Legacy tablo tek transaction ile taşınır. Kimlikler, gönderim/görülen ihale alanları, aktiflik ve AUTOINCREMENT üst sınırı korunur. Normalleştirmeyle eşdeğer olan eski kayıtlar kayıpsız bırakılır; bozuk eski JSON'da geçiş rollback olur.
- 177 otomatik test geçti: farklı kümeler, eşdeğer kayıt tekrarları, gönderim geçmişi, legacy tekrarlar/id sırası, index yeniden kurulması ve hatada rollback/integrity doğrulandı. Sunucu kodu değişti; arayüz değişmediği için önceki derleme tekrarlanmadı.
- Eski koda geri dönüşün veritabanı yedeğiyle eşleştirilmesi runbook'a eklendi. Üretim migration uygulanmadı. Yeni abonelik formunun tarayıcı kayıt/sil/hata kabulü açık.
### Abonelik formu tarayıcı kabulü — 6 Eylül 2026
- Yerel 5181 ortamında gerçek API/notify.sqlite ile liste GET503→yeniden yükle, Laboratuvar sarfı ve Test cihazı için aynı daraltmayla iki ayrı kayıt, DELETE503→iki kaydın korunması, başarılı silme→yalnız hedefin kaldırılması ve sayfa yenilemede kalıcılık doğrulandı.
- `qa-subscription-lifecycle.json`: 6 kontrol doğru. Hata yanıtları yalnız QA middleware'de üretilir; gerçek kayıt/sil/liste endpointleri kullanıldı. E-posta teslimi yapılmadı.
- Ekrandaki koşulsuz gönderim ve yinelenmeme vaadi değiştirildi: e-posta hizmetinin etkin olması gerektiği ve abonelik kaydının teslim kanıtı olmadığı açıklandı. Derleme geçti; salt UI metni/test altyapısı değiştiği için önceki 177 test yeniden çalıştırılmadı.
- Dış e-posta/Telegram teslimi, provider hata sonrası yeniden deneme ve planın diğer kabul maddeleri açık.
+2 -2
View File
@@ -109,7 +109,7 @@ const SubscriptionForm = () => {
<p className="text-xs text-slate-600 leading-relaxed">
Hangi <strong>konularda</strong> ihale alabiliyorsanız onları seçin — <strong>tüm Türkiye</strong> taranır,
yalnızca size uyan yeni ihaleler <strong>{authUser.email}</strong> adresine gelir. Gereksiz ilan gönderilmez.
E-posta gönderim hizmeti etkin olduğunda, eşleşen yeni ihaleler <strong>{authUser.email}</strong> adresine gönderilir.
</p>
{/* Mevcut kayıtlar */}
@@ -251,7 +251,7 @@ const SubscriptionForm = () => {
<Info className="w-3.5 h-3.5 text-slate-500 shrink-0 mt-0.5" />
<p className="text-[11px] text-slate-600 leading-relaxed">
İlk kayıtta mevcut ihaleler <strong>bildirilmez</strong> — yalnızca temel alınır, sonrasında çıkan
yeni ihaleler gönderilir. Aynı ihale iki kez gönderilmez; sonuçlanmış arşiv kayıtları bildirime girmez.
yeni ihaleler gönderilir. Sonuçlanmış arşiv kayıtları bildirime girmez. Aboneliği kaydetmek, e-postanın teslim edildiği anlamına gelmez.
</p>
</div>
</div>
+4
View File
@@ -33,7 +33,11 @@ const qaNotifications=await import('../server/zeyilname.mjs');
qaNotifications.bildirimYaz({email:user.email,tur:'zeyilname',ikn:'2026/1582991',baslik:'QA tarih değişikliği',metin:'Sentetik bildirim: ihale tarihi güncellendi.'});
qaNotifications.bildirimYaz({email:user.email,tur:'sonuc',ikn:'2026/1534665',baslik:'QA sonuç bildirimi',metin:'Sentetik sonuç inceleme bildirimi.'});
let notificationFailure='read';
let subscriptionFailure='read';
const ui=await createServer({server:{host:'127.0.0.1',port:0,proxy:{'/api':{target:'http://127.0.0.1:'+port}}},plugins:[{name:'qa-fixtures',configureServer(server){server.middlewares.use(async(req,res,next)=>{
if(req.url==='/qa-subscription-controls'){res.setHeader('Content-Type','text/html; charset=utf-8');res.end(`<html lang="tr"><h1>Yerel abonelik testi</h1><button id="read">Abonelik liste hatası</button><button id="delete">Abonelik silme hatası</button><button id="none">Abonelik hatalarını kapat</button><p role="status"></p><script>for(const mode of ['read','delete','none'])document.getElementById(mode).onclick=async()=>{const r=await fetch('/qa-subscription-failure?mode='+mode,{method:'POST'});document.querySelector('[role=status]').textContent=await r.text();};</script></html>`);return;}
if(req.url?.startsWith('/qa-subscription-failure?')&&req.method==='POST'){subscriptionFailure=new URL(req.url,'http://localhost').searchParams.get('mode');res.end('Abonelik test durumu: '+subscriptionFailure);return;}
if(req.url?.startsWith('/api/notify/subscriptions')&&((subscriptionFailure==='read'&&req.method==='GET')||(subscriptionFailure==='delete'&&req.method==='DELETE'))){res.writeHead(503,{'Content-Type':'application/json'});res.end(JSON.stringify({success:false,error:'QA: Abonelik deposuna erişilemiyor.'}));return;}
if(req.url==='/qa-notification-controls') {res.setHeader('Content-Type','text/html; charset=utf-8');res.end(`<html lang="tr"><h1>Yerel bildirim testi</h1><button id="read">Liste hatası</button><button id="write">Okundu kayıt hatası</button><button id="none">Hataları kapat</button><p role="status"></p><script>for(const mode of ['read','write','none'])document.getElementById(mode).onclick=async()=>{const r=await fetch('/qa-notification-failure?mode='+mode,{method:'POST'});document.querySelector('[role=status]').textContent=await r.text();};</script></html>`);return;}
if(req.url?.startsWith('/qa-notification-failure?')&&req.method==='POST'){notificationFailure=new URL(req.url,'http://localhost').searchParams.get('mode');res.end('Bildirim test durumu: '+notificationFailure);return;}
if(req.url==='/api/me/bildirimler'&&((notificationFailure==='read'&&req.method==='GET')||(notificationFailure==='write'&&req.method==='POST'))){res.writeHead(503,{'Content-Type':'application/json'});res.end(JSON.stringify({success:false,error:'QA: Bildirim deposuna erişilemiyor.'}));return;}