diff --git a/docs/quality/evidence/qa-browser-acceptance-runtime.json b/docs/quality/evidence/qa-browser-acceptance-runtime.json
index 17d0d25..43689ca 100644
--- a/docs/quality/evidence/qa-browser-acceptance-runtime.json
+++ b/docs/quality/evidence/qa-browser-acceptance-runtime.json
@@ -33,6 +33,11 @@
"outlookStart": "2026-09-10T07:00:00Z",
"outlookEnd": "2026-09-10T07:00:00Z"
},
+ "calendarMissingTimeGuard": {
+ "googleDisabled": true,
+ "outlookDisabled": true,
+ "providerLinks": 0
+ },
"analyticsTargetLabel": true,
"accountScopedAnalyticsTarget": true,
"primaryAnalyticsTargetRestored": true,
diff --git a/docs/quality/uygulama-durumu.md b/docs/quality/uygulama-durumu.md
index f92169c..0fb67b5 100644
--- a/docs/quality/uygulama-durumu.md
+++ b/docs/quality/uygulama-durumu.md
@@ -2332,3 +2332,9 @@ Doğrulama: `npm test` 301/301, `npm run build` başarılı ve `npm run qa:brows
Takvim bağlantıları artık yalnız servis birim testlerinde değil, ihale detay modalının gerçek DOM akışında da kontrol ediliyor. Yerel QA fikstürü kaynak tarihi 10.09.2026 10:00 İstanbul olan bir ihale açıyor; Google bağlantısında `20260910T070000Z`, Outlook bağlantısında `2026-09-10T07:00:00Z` başlangıç/bitiş değerleri ve doğru provider hostları doğrulanıyor.
Doğrulama: `npm run qa:browser` başarılı; kanıt [`qa-browser-acceptance-runtime.json`](evidence/qa-browser-acceptance-runtime.json) içindeki `calendarProviderLinks` alanında. Bu kabul sentetik ve salt okunur; OAuth hesabına kaydetme ve zeyilname sonrası gerçek senkronizasyon açık iş olarak kalıyor.
+
+### 2026-09-06 · Eksik saat için takvim bağlantısı güvenliği
+
+Kaynakta son teklif saati bulunmadığında Google/Outlook bağlantıları artık `#` gibi sahte bir hedefe gitmiyor; pasif seçenek ve açık “saat gerekli” açıklaması gösteriliyor. Geçerli tarih/saat akışı ile eksik saat akışı ayrı browser kontrollerine ayrıldı.
+
+Doğrulama: `calendarMissingTimeGuard` içinde iki provider seçeneği pasif ve gerçek provider bağlantısı sayısı 0; `npm run qa:browser` ve `npm test` (301/301) başarılı.
diff --git a/src/components/TenderDetailModal.jsx b/src/components/TenderDetailModal.jsx
index af46669..d4c8585 100644
--- a/src/components/TenderDetailModal.jsx
+++ b/src/components/TenderDetailModal.jsx
@@ -440,17 +440,26 @@ export const TenderDetailModal = () => {
Takvim taslağı için kaynak tarih ve saat birlikte gerekli.
}Google ve Outlook bağlantıları doğrulanmış tarih/saatle ön-doldurulmuş taslak açar; kaydetme ve değişiklik sonrası yeniden senkronizasyon kullanıcıya aittir. Otomatik OAuth senkronu yapılmaz.
diff --git a/tests/browser-acceptance.mjs b/tests/browser-acceptance.mjs index 7687662..4772ee1 100644 --- a/tests/browser-acceptance.mjs +++ b/tests/browser-acceptance.mjs @@ -55,6 +55,18 @@ try { outlookUrl.searchParams.get('enddt') !== '2026-09-10T07:00:00Z') { throw new Error(`Takvim provider bağlantısı kaynak son tarihi korumuyor: ${JSON.stringify(evidence.checks.calendarProviderLinks)}`); } + const missingCalendarPage = await context.newPage(); + try { + await missingCalendarPage.goto(`${url.replace(/\/qa-signin$/, '')}/qa-calendar-links?missing=1`, { waitUntil: 'networkidle' }); + evidence.checks.calendarMissingTimeGuard = { + googleDisabled: await missingCalendarPage.getByText('Google Takvim (saat gerekli)', { exact: true }).count() === 1, + outlookDisabled: await missingCalendarPage.getByText('Outlook (saat gerekli)', { exact: true }).count() === 1, + providerLinks: await missingCalendarPage.locator('a').filter({ hasText: /Google Takvim taslağı|Outlook taslağı/ }).count(), + }; + if (!evidence.checks.calendarMissingTimeGuard.googleDisabled || !evidence.checks.calendarMissingTimeGuard.outlookDisabled || evidence.checks.calendarMissingTimeGuard.providerLinks !== 0) { + throw new Error(`Saat bilinmiyorken takvim bağlantısı pasifleşmedi: ${JSON.stringify(evidence.checks.calendarMissingTimeGuard)}`); + } + } finally { await missingCalendarPage.close(); } } finally { await calendarPage.close(); } await page.getByRole('button', { name: 'Ana İhale Listesi', exact: true }).click(); await page.getByRole('button', { name: 'Pazar', exact: true }).click(); diff --git a/tests/browser-qa.mjs b/tests/browser-qa.mjs index 7a4844c..dc40151 100644 --- a/tests/browser-qa.mjs +++ b/tests/browser-qa.mjs @@ -140,8 +140,9 @@ const ui=await createServer({server:{host:'127.0.0.1',port:0,proxy:{'/api':{targ