Kişisel Veri İhlali İlk Değerlendirme Formu

Kurumlarda meydana gelen veya şüphe duyulan kişisel veri ihlallerinin hızlı, düzenli ve standart şekilde değerlendirilmesini sağlar. Olayın türünü, etkilenen verileri, riskleri ve alınan ilk önlemleri kayıt altına alarak ihlal yönetimini kolaylaştırır.

Formun temel hedefi, kişisel veri ihlallerine zamanında müdahale edilmesini ve KVKK kapsamındaki yükümlülüklerin takip edilmesini sağlamaktır. 72 saatlik bildirim sürecini, alınan kararları ve sorumlulukları izleyerek kurumsal veri güvenliğini, denetlenebilirliği ve hesap verebilirliği destekler

Bir Not defteri açarak, aşağıdaki (Mavi satırlar) html kodu içine kaydedin. Not defteri uzantısını .txt yerine ".html" olarak değiştirip kaydedin. Ör: "Kişisel Veri İhlali İlk Değerlendirme Formu.html" sayfayı kapatıp tekrar açtığınızda, web browser üzerinden sayfanız açılacaktır. 

Sol tarafta görünen logo için, html dosyanız nerede ise, masaüstü veya oluşturulan bir klasör. Logonuzda aynı yerde olursa forma yansır. Logo ismi "logo.jpg" olmalı. Çift tıklayarak açtığınızda, browser üzerinde form açılışı gerçekleşir. Veya alanına 5 kez peş peşe tıklayarak çalışma esnasında logo değişimi de yapılabilir.

Başlık, başlığın altındaki, başlığın sağındaki ve alttaki yazıları, not defteri içinde "Ctrl + F" tuşları ile kelime yazarak bulabilir, ilgili metinleri kendinize göre uyarlayarak kaydederek kullanabilirsiniz. Başlık alanındaki "OLGUN BAŞKANLIĞI" alanına 5 kez peş peşe tıklayarak; Departman, Müdürlük veya Başkanlığınıza ait bilgiyi manuel girebilirsiniz.

Formun boş hali;

Formun dolu hali:

PDF / Yazdır

Dışarı Aktarılan Excel Verisi:


HTML Kod:
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Kişisel Veri İhlali İlk Değerlendirme Formu</title>
<style>
:root{--outer:#e2eaf1;--page:#f8fafc;--white:#fff;--sky:#0284c7;--dark:#075985;--ink:#1e293b;--muted:#64748b;--line:#cbd5e1;--light:#e2e8f0;--frame:#8498aa}
*{box-sizing:border-box}
html,body{margin:0;min-height:100%;background:var(--outer);font:13px/1.4 "Segoe UI",Arial,sans-serif;color:var(--ink);overflow-x:hidden}
[hidden]{display:none!important}
button,input,select,textarea{font:inherit}
button{cursor:pointer}
:focus-visible{outline:2px solid var(--sky);outline-offset:2px}
/* OLGUN UI2 • tek geniş çerçeve */
.page{background:var(--page);border:3px solid var(--frame);width:100%;min-height:100vh;min-height:100dvh;padding:12px 14px 10px;display:flex;flex-direction:column;gap:10px;overflow-wrap:anywhere}
.head{display:grid;grid-template-columns:70px minmax(0,1fr) minmax(185px,26%);gap:14px;align-items:center;padding:12px 14px;min-height:91px;border:1px solid var(--line);border-left:4px solid var(--sky);border-radius:6px;background:var(--white);box-shadow:0 1px 3px #0f172a0c}
.logo{height:65px;width:66px;background:var(--page);border:1px solid var(--light);border-radius:5px;display:flex;align-items:center;justify-content:center;cursor:pointer;overflow:hidden}
.logo img{width:100%;height:100%;object-fit:contain}.logo span{color:var(--muted);font-size:10px}
.heading{min-width:0}.heading h1{margin:0 0 5px;color:var(--dark);font-size:clamp(17px,1.55vw,22px);font-weight:750;line-height:1.24;white-space:normal;overflow-wrap:anywhere}.heading p{margin:0;color:var(--muted);font-size:11px;overflow-wrap:anywhere}
.edit-five{cursor:pointer}.edit-five:not([contenteditable="true"]){user-select:none}.edit-five[contenteditable="true"]{outline:2px solid #7dd3fc;background:#f0f9ff;border-radius:4px}
.institution{width:100%;min-width:0;max-width:100%;justify-self:end;white-space:normal;overflow:visible;overflow-wrap:anywhere;text-align:right;color:var(--dark);font-size:14px;font-weight:750;padding:10px 11px;border:1px solid #dbeafe;border-radius:5px;background:var(--page)}
.action-row{display:flex;justify-content:flex-start}.actions{border:1px solid var(--line);border-radius:6px;background:#fff;padding:7px;display:inline-flex;align-items:center;flex-wrap:wrap;gap:8px;box-shadow:0 1px 3px #0f172a08}
.btn{min-height:35px;border:1px solid var(--line);border-radius:5px;padding:7px 13px;font-weight:700;white-space:nowrap}.btn:hover{filter:brightness(.98)}.import{background:#dbeafe;border-color:#93c5fd;color:#1e40af}.export{background:#dcfce7;border-color:#86efac;color:#166534}.print{background:#e5e7eb;border-color:#cbd5e1;color:#334155}
.main{background:#fff;border:1px solid var(--line);border-radius:6px;display:flex;flex-direction:column;flex:1;min-width:0;min-height:0;overflow:visible}
.main-heading{padding:9px 12px;background:#eff6ff;border-bottom:1px solid #bfdbfe;display:flex;justify-content:space-between;gap:10px;align-items:center;color:var(--dark);font-weight:750;font-size:13px;flex-wrap:wrap}.main-heading small{font-weight:400;color:var(--muted);font-size:10px;text-align:right;max-width:50%}
.breach-form{flex:1;min-width:0;display:flex;flex-direction:column;padding:11px 12px 12px}
.stats{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:9px;margin-bottom:10px}.stat{min-width:0;border:1px solid var(--light);border-radius:5px;background:var(--page);padding:9px 11px}.stat small{display:block;color:var(--muted);font-size:10.5px;margin-bottom:3px}.stat strong{display:block;color:var(--dark);font-size:14px;white-space:normal;overflow-wrap:anywhere}.stat em{display:block;color:var(--muted);font-size:10px;font-style:normal;min-height:13px;overflow-wrap:anywhere}.stat .warn{color:#a16207}.stat .danger{color:#b91c1c}.stat .good{color:#15803d}
/* İçerik büyüdükçe her kutunun yüksekliği kendiliğinden genişler. */
.sections{display:flex;flex-direction:column;flex:1;gap:9px;min-width:0}
.section{border:1px solid var(--light);border-radius:5px;min-width:0;display:flex;flex:1;flex-direction:column;overflow:visible}
.section-title{background:#f1f5f9;border-bottom:1px solid var(--light);padding:8px 10px;color:var(--dark);font-size:12px;font-weight:750;overflow-wrap:anywhere}
.fields{padding:9px 10px;flex:1;display:grid;grid-template-columns:repeat(4,minmax(0,1fr));align-content:center;align-items:start;gap:9px 11px;min-width:0}
.field{min-width:0;max-width:100%;break-inside:avoid}.field label{display:block;font-weight:650;font-size:11px;color:#475569;margin-bottom:4px;line-height:1.28;overflow-wrap:anywhere}
.field input,.field select,.field textarea{display:block;width:100%;max-width:100%;min-width:0;border:1px solid var(--line);background:#fff;color:var(--ink);border-radius:4px;min-height:35px;padding:7px 9px;font-size:12px;line-height:1.4}
.field input[type="date"],.field input[type="datetime-local"],.field input[type="number"],.field select{height:35px;white-space:nowrap;text-overflow:ellipsis}
.field textarea{height:35px;min-height:35px;resize:vertical;overflow:hidden;white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;field-sizing:content}
.field textarea:focus{overflow:hidden}
.field textarea[readonly]{background:var(--page)}
.field input[readonly]{background:var(--page)}
.span2{grid-column:span 2}
/* Yazdırmada her alana tam değerini taşıyan metin yansıması yerleştirilir. */
.print-value{display:none}
.screen-footer{margin-top:auto;min-height:25px;display:flex;justify-content:flex-end;align-items:end;padding:4px 3px 1px;color:#475569;font-size:11px;font-weight:700;text-align:right}
@media(min-width:1250px){.field label{font-size:11.2px}.fields{gap:10px 13px}}
@media(max-width:950px){.head{grid-template-columns:58px minmax(0,1fr) minmax(155px,30%);gap:10px}.logo{width:56px;height:55px}.fields{grid-template-columns:repeat(2,minmax(0,1fr))}.stats{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:580px){.page{padding:8px;gap:8px}.head{grid-template-columns:52px minmax(0,1fr);gap:8px;padding:9px}.logo{width:50px;height:50px}.heading h1{font-size:16px}.heading p{font-size:10px}.institution{grid-column:1/-1;justify-self:stretch;text-align:center}.actions{width:100%;gap:6px}.btn{flex:1;padding:6px}.fields{grid-template-columns:1fr}.span2{grid-column:span 1}.main-heading small{max-width:100%;text-align:left}.breach-form{padding:8px}.stat strong{font-size:12px}}
/* Chrome/Edge için sayfa altı gerçek sayfa sayacı; içerik taşarsa yeni sayfaya aktarılır. */
@page{
 size:A4 landscape;
 margin:6.5mm 8mm 11.5mm;
 @bottom-right{
  content:"Sayfa " counter(page) " / " counter(pages);
  color:#475569;
  font-family:"Segoe UI",Arial,sans-serif;
  font-size:9pt;
  font-weight:700;
  /* Sayfa sonunda istenmeyen boş çizgi yok. */
  border:0;
  padding-top:0;
 }
}
@media print{
 html,body{width:auto!important;min-height:0!important;height:auto!important;margin:0!important;padding:0!important;overflow:visible!important;background:#fff!important;font-size:9pt!important}
 .page{display:block!important;width:100%!important;min-height:0!important;height:auto!important;max-height:none!important;border:0!important;padding:1mm 2mm 0!important;overflow:visible!important;box-shadow:none!important}
 .head{min-height:0!important;grid-template-columns:13mm minmax(0,1fr) minmax(36mm,24%)!important;gap:2.2mm!important;padding:.8mm 2mm!important;break-inside:avoid!important;box-shadow:none!important}
 .logo{width:11mm!important;height:10mm!important}
 .heading h1{font-size:11pt!important;margin:0 0 .4mm!important;line-height:1.17!important}.heading p{font-size:7.1pt!important}
 .institution{font-size:8.5pt!important;padding:1.4mm!important;text-align:right!important;white-space:normal!important;overflow-wrap:anywhere!important}
 .action-row,.screen-footer{display:none!important}
 /* Başlık ile ana form arasında yaklaşık bir satır mesafe. */
 .main{display:block!important;overflow:visible!important;min-height:0!important;border:0!important;box-shadow:none!important;margin-top:4.5mm!important}
 .main-heading{padding:.75mm 2mm!important;font-size:8.7pt!important;break-inside:avoid!important}.main-heading small{font-size:7pt!important}
 .breach-form{display:block!important;padding:.55mm .8mm 0!important;min-height:0!important}
 .stats{grid-template-columns:repeat(4,minmax(0,1fr))!important;gap:.8mm!important;margin-bottom:.7mm!important;break-inside:avoid!important}
 .stat{padding:.45mm 1mm!important}.stat small{font-size:6.5pt!important;margin:0!important}.stat strong{font-size:8.3pt!important}.stat em{font-size:6.25pt!important;min-height:0!important}
 .sections{display:block!important;min-height:0!important;overflow:visible!important}
 .section{display:block!important;height:auto!important;min-height:0!important;max-height:none!important;break-inside:auto!important;page-break-inside:auto!important;margin:0 0 1.1mm!important;overflow:visible!important}
 .section-title{padding:.6mm 1.7mm!important;font-size:8pt!important;break-after:avoid!important}
 .fields{display:grid!important;grid-template-columns:repeat(4,minmax(0,1fr))!important;align-items:start!important;padding:1.1mm 1.2mm!important;gap:.9mm 1.8mm!important}
 .field{break-inside:avoid!important;min-width:0!important}
 .field label{font-size:7pt!important;line-height:1.14!important;margin:0 0 .35mm!important;white-space:normal!important}
 .field input,.field textarea,.field select{display:none!important}
 .field .print-value{display:block!important;min-height:5.2mm!important;height:auto!important;padding:.85mm 1mm!important;border:1px solid #bfcbd6!important;border-radius:2px!important;font-size:8.1pt!important;line-height:1.23!important;font-weight:450!important;color:#1e293b!important;background:#fff!important;white-space:pre-wrap!important;overflow-wrap:anywhere!important;word-break:break-word!important}
 .section:last-child{border-bottom:0!important;margin-bottom:0!important}
 .span2{grid-column:span 2!important}
 *{-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}
}
</style>
</head>
<body>
<div class="page">
 <header class="head">
   <div id="logoBox" class="logo edit-five" role="button" tabindex="0" title="Logoyu değiştirmek için beş kez tıklayın"><img id="logoImg" src="logo.jpg" alt="Kurum logosu"><span id="logoPlaceholder" hidden>LOGO</span></div>
   <div class="heading"><h1 id="formTitle" class="edit-five" tabindex="0" title="Başlığı değiştirmek için beş kez tıklayın">Kişisel Veri İhlali İlk Değerlendirme Formu</h1><p>Olay Kaydı · Etki ve Kapsam · KVKK Bildirimi · Müdahale Takibi</p></div>
   <div id="institution" class="institution edit-five" tabindex="0" title="Kurum adını değiştirmek için beş kez tıklayın">OLGUN BAŞKANLIĞI</div>
 </header>
 <div class="action-row"><div class="actions" aria-label="Form işlemleri">
  <button id="importBtn" type="button" class="btn import">Excel İçeri Aktar</button>
  <button id="exportBtn" type="button" class="btn export">Excel Dışarı Aktar</button>
  <button id="printBtn" type="button" class="btn print">PDF / Yazdır</button>
 </div></div>
 <input id="excelInput" type="file" accept=".xlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" hidden>
 <input id="logoInput" type="file" accept="image/*" hidden>
 <main class="main">
  <div class="main-heading"><span>Kişisel Veri İhlali — Ön Değerlendirme Kaydı</span><small>Veri ve dijital kanıt içeriklerini değil, güvenli referanslarını kaydedin.</small></div>
  <form id="breachForm" class="breach-form" autocomplete="off" novalidate>
   <div class="stats" aria-live="polite">
    <div class="stat"><small>İhlal Durumu</small><strong id="sIncident">Belirlenmedi</strong><em>Olay sınıflandırması</em></div>
    <div class="stat"><small>Ön Risk Seviyesi</small><strong id="sRisk">Belirlenmedi</strong><em id="sRiskInfo">Etki × hassasiyet</em></div>
    <div class="stat"><small>Kurula Bildirim</small><strong id="sNotify">İnceleniyor</strong><em id="sNotifyInfo">Karar kullanıcıya aittir</em></div>
    <div class="stat"><small>72 Saatlik Son Tarih</small><strong id="sDue">—</strong><em id="sDueInfo">İhlalin öğrenilme zamanı esas alınır</em></div>
   </div>
   <div class="sections">
    <section class="section">
     <div class="section-title">1. Olay Kaydı ve Öğrenilme Bilgileri</div>
     <div class="fields">
      <div class="field"><label for="recordNo">Olay / Kayıt No</label><textarea id="recordNo" placeholder="Dışa aktarımda otomatik" readonly rows="1"></textarea></div>
      <div class="field span2"><label for="incidentTitle">Olay Başlığı</label><textarea id="incidentTitle" maxlength="320" placeholder="Örn. yetkisiz erişim şüphesi" rows="1"></textarea></div>
      <div class="field"><label for="incidentStatus">İhlal Durumu</label><select id="incidentStatus"><option value="">Seçiniz</option><option>Şüpheli</option><option>Doğrulandı</option><option>Doğrulanmadı</option></select></div>
      <div class="field"><label for="detectedAt">Tespit Zamanı</label><input id="detectedAt" type="datetime-local"></div>
      <div class="field"><label for="knownAt">Veri Sorumlusunun Öğrenme Zamanı</label><input id="knownAt" type="datetime-local" title="72 saatlik hesaplama bu andan başlar"></div>
      <div class="field"><label for="incidentType">Olay / İhlal Türü</label><select id="incidentType"><option value="">Seçiniz</option><option>Yetkisiz erişim</option><option>Yanlış alıcıya gönderim</option><option>Veri sızıntısı</option><option>Kayıp / çalıntı cihaz</option><option>Zararlı yazılım</option><option>İç kaynaklı olay</option><option>Diğer</option></select></div>
      <div class="field"><label for="owner">Sorumlu Birim / Görevli</label><textarea id="owner" maxlength="100" placeholder="Birim / rol" rows="1"></textarea></div>
     </div>
    </section>
    <section class="section">
     <div class="section-title">2. Etkilenen Veri, Kişi ve Sistem Kapsamı</div>
     <div class="fields">
      <div class="field"><label for="systemName">Etkilenen Sistem / Hizmet</label><textarea id="systemName" maxlength="100" placeholder="Uygulama / hizmet" rows="1"></textarea></div>
      <div class="field"><label for="dataType">Kişisel Veri Kategorisi</label><select id="dataType"><option value="">Seçiniz</option><option>Kimlik / İletişim</option><option>Müşteri işlemleri</option><option>Finansal</option><option>Özlük</option><option>Özel nitelikli veri</option><option>Birden fazla kategori</option><option>Diğer</option></select></div>
      <div class="field span2"><label for="dataDetail">Etkilenen Veri Türleri / Açıklama</label><textarea id="dataDetail" maxlength="1400" placeholder="Örn. ad-soyad, e-posta, işlem tarihi (gerçek veri yazmayın)" rows="1"></textarea></div>
      <div class="field"><label for="personCount">Etkilenen Kişi Sayısı</label><input id="personCount" type="number" min="0" max="1000000000" step="1" placeholder="Sayı"></div>
      <div class="field"><label for="personCountType">Kişi Sayısı Niteliği</label><select id="personCountType"><option value="">Seçiniz</option><option>Tahmini</option><option>Kesin</option><option>Henüz bilinmiyor</option></select></div>
      <div class="field"><label for="affectedGroups">Etkilenen Kişi Grubu</label><select id="affectedGroups"><option value="">Seçiniz</option><option>Çalışanlar</option><option>Müşteriler / hizmet alanlar</option><option>Vatandaşlar</option><option>Tedarikçiler</option><option>Çocuklar / kırılgan gruplar</option><option>Birden fazla grup</option><option>Diğer</option></select></div>
      <div class="field"><label for="thirdPartyAccess">Yetkisiz Kişi Elde Etti mi?</label><select id="thirdPartyAccess"><option value="">Belirsiz</option><option>Evet</option><option>Hayır</option><option>İnceleniyor</option></select></div>
     </div>
    </section>
    <section class="section">
     <div class="section-title">3. İlk Risk Analizi ve Bildirim Değerlendirmesi</div>
     <div class="fields">
      <div class="field"><label for="impactDimensions">Etki Boyutu</label><select id="impactDimensions"><option value="">Seçiniz</option><option>Gizlilik</option><option>Bütünlük</option><option>Erişilebilirlik</option><option>Birden fazla boyut</option></select></div>
      <div class="field"><label for="sensitivity">Veri Hassasiyeti</label><select id="sensitivity"><option value="">Seçiniz</option><option value="1">Düşük</option><option value="2">Orta</option><option value="3">Yüksek</option><option value="4">Kritik</option></select></div>
      <div class="field"><label for="impact">İlgili Kişiye Olası Zarar</label><select id="impact"><option value="">Seçiniz</option><option value="1">Düşük</option><option value="2">Orta</option><option value="3">Yüksek</option><option value="4">Kritik</option></select></div>
      <div class="field"><label for="encryptionStatus">Verilerin Korunma Durumu</label><select id="encryptionStatus"><option value="">Seçiniz</option><option>Okunabilir</option><option>Şifreli / korumalı</option><option>Koruma aşılmış olabilir</option><option>Bilinmiyor</option></select></div>
      <div class="field"><label for="notification">KVKK Kuruluna Bildirim</label><select id="notification"><option>İnceleniyor</option><option>Gerekli</option><option>Gerekli değil</option><option>Bildirildi</option></select></div>
      <div class="field"><label for="personNotification">İlgili Kişilere Bildirim</label><select id="personNotification"><option>İnceleniyor</option><option>Gerekli</option><option>Gerekli değil</option><option>Bildirildi</option></select></div>
      <div class="field"><label for="reportedAt">Kurula Bildirim Zamanı</label><input type="datetime-local" id="reportedAt"></div>
      <div class="field"><label for="notifiedPersonsAt">İlgili Kişilere Bildirim Zamanı</label><input type="datetime-local" id="notifiedPersonsAt"></div>
      <div class="field span2"><label for="decisionReason">Bildirim Kararı ve Gerekçesi</label><textarea id="decisionReason" maxlength="1600" placeholder="İlgili olgu, dayanak ve karar özeti" rows="1"></textarea></div>
      <div class="field"><label for="reportRef">Kurul Bildirim Referansı</label><textarea id="reportRef" maxlength="90" placeholder="Varsa takip numarası" rows="1"></textarea></div>
      <div class="field"><label for="riskJustification">Ön Risk / Zarar Açıklaması</label><textarea id="riskJustification" maxlength="1600" placeholder="Örn. mahremiyet, dolandırıcılık" rows="1"></textarea></div>
     </div>
    </section>
    <section class="section">
     <div class="section-title">4. İlk Müdahale, Kanıt ve Sorumluluk Takibi</div>
     <div class="fields">
      <div class="field"><label for="response">Müdahale Durumu</label><select id="response"><option value="">Seçiniz</option><option>Başlamadı</option><option>Devam ediyor</option><option>Tamamlandı</option></select></div>
      <div class="field"><label for="occurrenceStatus">Olayın Güncel Durumu</label><select id="occurrenceStatus"><option value="">Seçiniz</option><option>Devam ediyor</option><option>Durduruldu</option><option>Kontrol altında</option><option>Bilinmiyor</option></select></div>
      <div class="field"><label for="actionOwner">Aksiyon Sorumlusu</label><textarea id="actionOwner" maxlength="100" placeholder="Birim / görevli" rows="1"></textarea></div>
      <div class="field"><label for="targetDate">Aksiyon Hedef Tarihi</label><input type="date" id="targetDate"></div>
      <div class="field span2"><label for="actions">İlk Tedbirler / Devam Eden Aksiyonlar</label><textarea id="actions" maxlength="3000" placeholder="Erişim kesme, izolasyon, alıcıdan silme teyidi, yeni önlemler..."></textarea></div>
      <div class="field"><label for="evidenceRef">Dijital Kanıt / Olay Referansı</label><textarea id="evidenceRef" maxlength="120" placeholder="Güvenli klasör / vaka no" rows="1"></textarea></div>
      <div class="field"><label for="result">Değerlendirme Sonucu</label><select id="result"><option value="">Seçiniz</option><option>İnceleme sürüyor</option><option>İhlal doğrulandı</option><option>İhlal doğrulanmadı</option><option>Takip sürüyor</option><option>Kapatıldı</option></select></div>
      <div class="field"><label for="approver">Değerlendiren / Onaylayan</label><textarea id="approver" maxlength="100" placeholder="Rol / yetkili" rows="1"></textarea></div>
      <div class="field"><label for="reviewDate">Değerlendirme Tarihi</label><input type="date" id="reviewDate"></div>
      <div class="field"><label for="nextReviewDate">Sonraki Kontrol Tarihi</label><input type="date" id="nextReviewDate"></div>
      <div class="field"><label for="closureNote">Kapanış / Takip Notu</label><textarea id="closureNote" maxlength="1600" placeholder="Kısa yönetim kararı / takip" rows="1"></textarea></div>
     </div>
    </section>
   </div>
  </form>
 </main>
 <footer class="screen-footer" aria-label="Ekran sayfa numarası">Sayfa 1 / 1</footer>
</div>
<script>
"use strict";
const $=id=>document.getElementById(id);
const fieldIds=["recordNo","incidentTitle","incidentStatus","detectedAt","knownAt","incidentType","owner","systemName","dataType","dataDetail","personCount","personCountType","affectedGroups","thirdPartyAccess","impactDimensions","sensitivity","impact","encryptionStatus","notification","personNotification","reportedAt","notifiedPersonsAt","decisionReason","reportRef","riskJustification","response","occurrenceStatus","actionOwner","targetDate","actions","evidenceRef","result","approver","reviewDate","nextReviewDate","closureNote"];

// Uzun metin alanlarını dikey olarak genişlet; yazı hiçbir zaman yatay kesilmez.
const textAreas=()=>Array.from(document.querySelectorAll('.field textarea'));
function autoGrow(area){
 if(!area||area.tagName!=='TEXTAREA')return;
 area.style.height='auto';
 area.style.height=Math.max(35,Math.ceil(area.scrollHeight)+2)+'px';
}
// Baskı yansımaları bütün metni satırlara bölerek gösterir; input/textarea kırpılması önlenir.
function updatePrintValues(){
 document.querySelectorAll('.field').forEach(field=>{
  const control=field.querySelector('input,select,textarea');
  if(!control)return;
  let mirror=field.querySelector('.print-value');
  if(!mirror){mirror=document.createElement('div');mirror.className='print-value';field.appendChild(mirror)}
  let value=(control.tagName==='SELECT')?(control.selectedOptions[0]?.textContent||''):control.value;
  // Baskıda tarihleri Türkçe, okunabilir biçimde göster; veri dosyasındaki orijinali değiştirme.
  if(value && control.type==='date' && /^\d{4}-\d{2}-\d{2}$/.test(value)){
   const [y,m,d]=value.split('-');value=`${d}.${m}.${y}`;
  }else if(value && control.type==='datetime-local' && /^\d{4}-\d{2}-\d{2}T/.test(value)){
   const [day,time]=value.split('T');const [y,m,d]=day.split('-');value=`${d}.${m}.${y} ${time}`;
  }
  mirror.textContent=value&&value.trim()?value:'\u00a0';
 });
}
function resizeAllAreas(){textAreas().forEach(autoGrow);updatePrintValues()}
document.querySelectorAll('.field input,.field select,.field textarea').forEach(control=>{
 control.addEventListener('input',()=>{if(control.tagName==='TEXTAREA')autoGrow(control);updatePrintValues()});
 control.addEventListener('change',()=>{if(control.tagName==='TEXTAREA')autoGrow(control);updatePrintValues()});
});
window.addEventListener('beforeprint',resizeAllAreas);
window.addEventListener('resize',resizeAllAreas);

const KEY="olgunui2_kvkk_header_v5";
const pad=n=>String(n).padStart(2,"0");
function newId(){const d=new Date();return `KV-${d.getFullYear()}${pad(d.getMonth()+1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}-${Math.random().toString(36).slice(2,7).toUpperCase()}`}
function getFormData(){return Object.fromEntries(fieldIds.map(id=>[id,$(id).value]));}
function putFormData(data){fieldIds.forEach(id=>{if(Object.hasOwn(data,id)){
 const el=$(id),val=String(data[id]??"");
 if(el.tagName==="SELECT" && val && !Array.from(el.options).some(opt=>opt.value===val)){
  // Eski Excel sürümlerinde veya kuruma özel listelerde kullanılan değeri koru.
  const opt=document.createElement("option");opt.value=val;opt.textContent=val;el.add(opt);
 }
 el.value=val;
 }});refresh();resizeAllAreas()}
function formatTR(d){return new Intl.DateTimeFormat("tr-TR",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit",hourCycle:"h23"}).format(d)}
function refresh(){
 const status=$("incidentStatus").value||"Belirlenmedi";$("sIncident").textContent=status;$("sIncident").className=status==="Doğrulandı"?"danger":status==="Doğrulanmadı"?"good":"";
 const s=Number($("sensitivity").value),i=Number($("impact").value),score=s*i;let risk="Belirlenmedi",cls="";
 if(s&&i){risk=score>=12?"Kritik":score>=8?"Yüksek":score>=4?"Orta":"Düşük";cls=score>=8?"danger":score>=4?"warn":"good";}
 $("sRisk").textContent=risk;$("sRisk").className=cls;$("sRiskInfo").textContent=s&&i?`Ön değerlendirme puanı: ${score}/16`:"Etki × hassasiyet";
 const decision=$("notification").value;$("sNotify").textContent=decision;$("sNotify").className=decision==="Gerekli"?"warn":decision==="Bildirildi"||decision==="Gerekli değil"?"good":"";
 $("sNotifyInfo").textContent=decision==="Bildirildi"&&!$("reportedAt").value?"Bildirim tarihi girilmeli":"Karar kullanıcıya aittir";
 const known=$("knownAt").value,dt=known?new Date(known):null,due=dt&&!isNaN(dt.getTime())?new Date(dt.getTime()+72*3600000):null;
 $("sDue").textContent=due?formatTR(due):"—";
 if(!due){$("sDueInfo").textContent="İhlalin öğrenilme zamanı esas alınır";$("sDue").className="";return;}
 const reported=$("reportedAt").value?new Date($("reportedAt").value):null;
 if(decision==="Bildirildi" && reported && !isNaN(reported.getTime())){
  const late=reported>due;$("sDueInfo").textContent=late?"Geç bildirim kayıtlı":"Süresi içinde bildirim kayıtlı";$("sDue").className=late?"warn":"good";
 }else if(decision==="Gerekli değil"){$("sDueInfo").textContent="Karar gerekçesi belgelenmeli";$("sDue").className="";}
 else{const hours=(due-new Date())/3600000;$("sDueInfo").textContent=hours<0?"Süre aşıldı":`${Math.ceil(hours)} saat kaldı`;$("sDue").className=hours<0?"danger":hours<24?"warn":"";}
}
fieldIds.forEach(id=>{$(id).addEventListener("input",refresh);$(id).addEventListener("change",refresh)});
$("breachForm").addEventListener("submit",e=>e.preventDefault());
function onFiveClicks(el,fn){let n=0,last=0;el.addEventListener("click",()=>{const now=Date.now();if(now-last>1400)n=0;last=now;if(++n===5){n=0;fn();}})}
function makeEditable(id,key){const el=$(id);try{el.textContent=localStorage.getItem(key)||el.textContent}catch(e){};
 el.dataset.fallback=el.textContent;
 const start=()=>{el.contentEditable="true";el.focus();const r=document.createRange();r.selectNodeContents(el);const sel=window.getSelection();sel.removeAllRanges();sel.addRange(r)};
 const finish=()=>{if(el.contentEditable!=="true")return;el.contentEditable="false";el.textContent=el.textContent.trim().slice(0,120)||el.dataset.fallback;try{localStorage.setItem(key,el.textContent)}catch(e){}};
 onFiveClicks(el,start);el.addEventListener("keydown",e=>{if(e.key==="Enter"){e.preventDefault();if(el.contentEditable==="true")el.blur();else start()}});el.addEventListener("blur",finish);
}
makeEditable("formTitle",KEY+"_title");makeEditable("institution",KEY+"_institution");
const logoImg=$("logoImg"),logoHolder=$("logoPlaceholder");
logoImg.addEventListener("error",()=>{logoImg.hidden=true;logoHolder.hidden=false});logoImg.addEventListener("load",()=>{logoImg.hidden=false;logoHolder.hidden=true});
try{const saved=localStorage.getItem(KEY+"_logo");if(saved)logoImg.src=saved}catch(e){}
onFiveClicks($("logoBox"),()=>$("logoInput").click());$("logoBox").addEventListener("keydown",e=>{if(e.key==="Enter")$("logoInput").click()});
$("logoInput").addEventListener("change",e=>{const file=e.target.files?.[0];if(!file)return;if(!file.type.startsWith("image/")||file.size>1500000){alert("Lütfen 1,5 MB altında bir resim seçin.");e.target.value="";return}
 const reader=new FileReader();reader.onload=()=>{logoImg.src=String(reader.result);try{localStorage.setItem(KEY+"_logo",String(reader.result))}catch(err){alert("Logo görüntülendi fakat tarayıcıda saklanamadı.")}};reader.readAsDataURL(file);e.target.value="";
});

// Gerçek .xlsx (Office Open XML) okuma/yazma: gömülü, çevrimdışı, kütüphanesiz.
// Yeni Chrome/Edge tarayıcılarında yerleşik deflate-raw açıcı kullanılır.
const enc=new TextEncoder();
const dec=new TextDecoder("utf-8");
function escXml(s){return String(s??"").replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g,"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}
function makeXmlCell(address,value,style=0){return `<c r="${address}" s="${style}" t="inlineStr"><is><t xml:space="preserve">${escXml(value)}</t></is></c>`}
function makeSheetXml(){
 const titles=["Alan Kodu","Alan Adı","Değer"];
 let rows=`<row r="1">${titles.map((v,i)=>makeXmlCell("ABC"[i]+"1",v,1)).join("")}</row>`;
 const data=getFormData();
 fieldIds.forEach((id,i)=>{
  const r=i+2;
  const label=$(id).closest(".field")?.querySelector("label")?.textContent?.trim()||id;
  rows+=`<row r="${r}">${makeXmlCell("A"+r,id)}${makeXmlCell("B"+r,label)}${makeXmlCell("C"+r,data[id])}</row>`;
 });
 return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>`+
 `<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><dimension ref="A1:C${fieldIds.length+1}"/>`+
 `<sheetViews><sheetView workbookViewId="0"><pane ySplit="1" topLeftCell="A2" activePane="bottomLeft" state="frozen"/></sheetView></sheetViews>`+
 `<cols><col min="1" max="1" width="24" customWidth="1"/><col min="2" max="2" width="35" customWidth="1"/><col min="3" max="3" width="75" customWidth="1"/></cols>`+
 `<sheetData>${rows}</sheetData></worksheet>`;
}
// ZIP oluşturma: sıkıştırılmamış (STORE) ZIP kayıtları, gerçek XLSX dosyası.
const crcTable=(()=>{const tab=[];for(let n=0;n<256;n++){let c=n;for(let k=0;k<8;k++)c=c&1?(0xedb88320^(c>>>1)):(c>>>1);tab.push(c>>>0);}return tab})();
function crc32(bytes){let c=0xffffffff;for(const b of bytes)c=crcTable[(c^b)&255]^(c>>>8);return (c^0xffffffff)>>>0;}
function makeZip(files){
 const chunks=[],directory=[];let position=0;
 for(const [name,content] of Object.entries(files)){
  const nameBytes=enc.encode(name),bytes=enc.encode(content),crc=crc32(bytes);
  const local=new Uint8Array(30+nameBytes.length);const v=new DataView(local.buffer);
  v.setUint32(0,0x04034b50,true);v.setUint16(4,20,true);v.setUint16(8,0,true);
  v.setUint32(14,crc,true);v.setUint32(18,bytes.length,true);v.setUint32(22,bytes.length,true);
  v.setUint16(26,nameBytes.length,true);local.set(nameBytes,30);
  chunks.push(local,bytes);
  const central=new Uint8Array(46+nameBytes.length);const cv=new DataView(central.buffer);
  cv.setUint32(0,0x02014b50,true);cv.setUint16(4,20,true);cv.setUint16(6,20,true);
  cv.setUint32(16,crc,true);cv.setUint32(20,bytes.length,true);cv.setUint32(24,bytes.length,true);
  cv.setUint16(28,nameBytes.length,true);cv.setUint32(42,position,true);
  central.set(nameBytes,46);directory.push(central);
  position+=local.length+bytes.length;
 }
 const directoryStart=position;
 directory.forEach(part=>{chunks.push(part);position+=part.length});
 const eocd=new Uint8Array(22);const e=new DataView(eocd.buffer);
 e.setUint32(0,0x06054b50,true);e.setUint16(8,directory.length,true);e.setUint16(10,directory.length,true);
 e.setUint32(12,position-directoryStart,true);e.setUint32(16,directoryStart,true);
 chunks.push(eocd);
 return new Blob(chunks,{type:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"});
}
function buildXlsx(){
 const main="http://schemas.openxmlformats.org/spreadsheetml/2006/main";
 const rel="http://schemas.openxmlformats.org/officeDocument/2006/relationships";
 return makeZip({
  "[Content_Types].xml":`<?xml version="1.0" encoding="UTF-8"?>`+
   `<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">`+
   `<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>`+
   `<Default Extension="xml" ContentType="application/xml"/>`+
   `<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>`+
   `<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>`+
   `<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>`+
   `</Types>`,
  "_rels/.rels":`<?xml version="1.0" encoding="UTF-8"?>`+
   `<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">`+
   `<Relationship Id="rId1" Type="${rel}/officeDocument" Target="xl/workbook.xml"/>`+
   `</Relationships>`,
  "xl/workbook.xml":`<?xml version="1.0" encoding="UTF-8"?>`+
   `<workbook xmlns="${main}" xmlns:r="${rel}">`+
   `<sheets><sheet name="Ilk Degerlendirme" sheetId="1" r:id="rId1"/></sheets></workbook>`,
  "xl/_rels/workbook.xml.rels":`<?xml version="1.0" encoding="UTF-8"?>`+
   `<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">`+
   `<Relationship Id="rId1" Type="${rel}/worksheet" Target="worksheets/sheet1.xml"/>`+
   `<Relationship Id="rId2" Type="${rel}/styles" Target="styles.xml"/>`+
   `</Relationships>`,
  "xl/styles.xml":`<?xml version="1.0" encoding="UTF-8"?>`+
   `<styleSheet xmlns="${main}"><fonts count="2"><font><sz val="11"/><name val="Calibri"/></font>`+
   `<font><b/><color rgb="FF075985"/><sz val="11"/><name val="Calibri"/></font></fonts>`+
   `<fills count="2"><fill><patternFill patternType="none"/></fill>`+
   `<fill><patternFill patternType="gray125"/></fill></fills>`+
   `<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>`+
   `<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>`+
   `<cellXfs count="2"><xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/>`+
   `<xf numFmtId="0" fontId="1" fillId="0" borderId="0" xfId="0"/></cellXfs><cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles></styleSheet>`,
  "xl/worksheets/sheet1.xml":makeSheetXml()
 });
}
function downloadBlob(blob,name){
 const url=URL.createObjectURL(blob);const a=document.createElement("a");a.href=url;a.download=name;
 document.body.append(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(url),2000);
}
$("exportBtn").addEventListener("click",()=>{
 try{if(!$("recordNo").value)$("recordNo").value=newId();
  downloadBlob(buildXlsx(),"Kisisel_Veri_Ihlali_Ilk_Degerlendirme.xlsx");
 }catch(err){alert("Excel dosyası oluşturulamadı: "+err.message);}
});
// ZIP dosyasının merkez dizininden XLSX parçalarını güvenli boyut sınırı ile oku.
async function readXlsxParts(buffer){
 if(buffer.byteLength>15*1024*1024)throw Error("Dosya 15 MB sınırını aşıyor.");
 const v=new DataView(buffer),bytes=new Uint8Array(buffer);let end=-1;
 for(let i=bytes.length-22;i>=Math.max(0,bytes.length-65557);i--){if(v.getUint32(i,true)===0x06054b50){end=i;break}}
 if(end<0)throw Error("Geçerli .xlsx ZIP içeriği bulunamadı.");
 const count=v.getUint16(end+10,true),dir=v.getUint32(end+16,true);
 if(count>1000)throw Error("Çalışma kitabında çok fazla parça var.");
 let off=dir;const entries=new Map();
 for(let n=0;n<count;n++){
  if(off+46>bytes.length||v.getUint32(off,true)!==0x02014b50)throw Error("ZIP dizini bozuk.");
  const flag=v.getUint16(off+8,true),method=v.getUint16(off+10,true);
  const size=v.getUint32(off+20,true),plain=v.getUint32(off+24,true);
  const nameLen=v.getUint16(off+28,true),extra=v.getUint16(off+30,true),comment=v.getUint16(off+32,true);
  const local=v.getUint32(off+42,true);
  if(flag&1)throw Error("Parola korumalı XLSX okunamaz.");
  if(plain>12*1024*1024)throw Error("XLSX parçası çok büyük.");
  const name=dec.decode(bytes.subarray(off+46,off+46+nameLen));
  entries.set(name,{method,size,plain,local});off+=46+nameLen+extra+comment;
 }
 async function part(path){
  const ent=entries.get(path);if(!ent)return null;
  if(ent.local+30>bytes.length||v.getUint32(ent.local,true)!==0x04034b50)throw Error("ZIP parçası bozuk.");
  const at=ent.local+30+v.getUint16(ent.local+26,true)+v.getUint16(ent.local+28,true);
  if(at+ent.size>bytes.length)throw Error("ZIP içerik sınırı geçersiz.");
  let uncompressed=bytes.slice(at,at+ent.size);
  if(ent.method===8){
   if(typeof DecompressionStream==="undefined")throw Error("Bu tarayıcı XLSX sıkıştırmasını desteklemiyor; güncel Chrome veya Edge kullanın.");
   try{const stream=new Blob([uncompressed]).stream().pipeThrough(new DecompressionStream("deflate-raw"));
    uncompressed=new Uint8Array(await new Response(stream).arrayBuffer());
   }catch(e){throw Error("Sıkıştırılmış XLSX dosyası açılamadı. Güncel Chrome/Edge kullanın.")}
  }else if(ent.method!==0){throw Error("Desteklenmeyen XLSX sıkıştırma biçimi.")}
  if(uncompressed.length!==ent.plain)throw Error("XLSX içerik boyutu uyuşmuyor.");
  return dec.decode(uncompressed);
 }
 return {part,entries};
}
function parseXml(xml){
 const doc=new DOMParser().parseFromString(xml,"application/xml");
 if(doc.querySelector("parsererror"))throw Error("Excel XML içeriği bozuk.");return doc;
}
function allLocal(node,name){return Array.from(node.getElementsByTagName("*")).filter(el=>el.localName===name)}
function directLocal(node,name){return Array.from(node.children).find(el=>el.localName===name)}
async function parseXlsx(buffer){
 const {part,entries}=await readXlsxParts(buffer);
 let path="xl/worksheets/sheet1.xml";
 // Kullanıcı ilk çalışma sayfasını yeniden adlandırsa da doğru dosyayı bul.
 const workbook=await part("xl/workbook.xml"),rels=await part("xl/_rels/workbook.xml.rels");
 if(workbook&&rels){
  const sheet=allLocal(parseXml(workbook),"sheet")[0];
  const relId=sheet?.getAttribute("r:id")||sheet?.getAttributeNS("http://schemas.openxmlformats.org/officeDocument/2006/relationships","id");
  const relNode=allLocal(parseXml(rels),"Relationship").find(r=>r.getAttribute("Id")===relId);
  if(relNode){let target=relNode.getAttribute("Target")||"";
   target=target.startsWith("/")?target.slice(1):target.startsWith("xl/")?target:"xl/"+target;
   const parts=[];for(const seg of target.split("/")){if(seg==="..")parts.pop();else if(seg&&seg!==".")parts.push(seg)}
   path=parts.join("/");
  }
 }
 if(!entries.has(path)){path=Array.from(entries.keys()).find(x=>/^xl\/worksheets\/[^/]+\.xml$/.test(x));}
 if(!path)throw Error("Çalışma sayfası bulunamadı.");
 const sheetText=await part(path);if(!sheetText)throw Error("İlk çalışma sayfası okunamadı.");
 const sharedText=await part("xl/sharedStrings.xml");
 const shared=sharedText?allLocal(parseXml(sharedText),"si").map(si=>allLocal(si,"t").map(n=>n.textContent).join("")):[];
 const sheet= parseXml(sheetText);
 const result={};let matches=0;
 const labels=new Map(fieldIds.map(id=>[$(id).closest(".field")?.querySelector("label")?.textContent?.trim().toLocaleLowerCase("tr-TR"),id]));
 const lookup=s=>fieldIds.includes(s)?s:labels.get(String(s||"").trim().toLocaleLowerCase("tr-TR"));
 for(const row of allLocal(sheet,"row")){
  const cells={};let next=0;
  for(const cell of Array.from(row.children).filter(n=>n.localName==="c")){
   const a=(cell.getAttribute("r")||"").match(/^([A-Z]+)/i);
   const index=a?a[1].toUpperCase().split("").reduce((v,c)=>v*26+c.charCodeAt(0)-64,0)-1:next;
   next=index+1;if(index>4)continue;
   const typ=cell.getAttribute("t")||"";
   let val="";if(typ==="inlineStr"){
    const inline=directLocal(cell,"is");val=inline?allLocal(inline,"t").map(n=>n.textContent).join(""):"";
   }else{
    const v=directLocal(cell,"v")?.textContent??"";
    val=typ==="s"?shared[Number(v)]??"":v;
   }
   cells[index]=val;
  }
  const key=lookup(cells[0]);
  if(key){let val=cells[2]??(cells[1]??"");
   // Excel'in gerçek tarih hücrelerini tarih inputlarına çevirebil.
   const el=$(key);
   if((el.type==="date"||el.type==="datetime-local")&& /^\d{2,6}(?:\.\d+)?$/.test(val)){
    const date=new Date(Date.UTC(1899,11,30)+Number(val)*86400000);
    if(!isNaN(date.getTime()))val=date.toISOString().slice(0,el.type==="date"?10:16);
   }else if((el.type==="date"||el.type==="datetime-local")&& /^\d{1,2}\.\d{1,2}\.\d{4}/.test(val)){
    const m=val.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})(?:\s+(\d{1,2}):(\d{2}))?/);
    if(m)val=`${m[3]}-${m[2].padStart(2,"0")}-${m[1].padStart(2,"0")}`+(el.type==="datetime-local"?`T${(m[4]||"00").padStart(2,"0")}:${m[5]||"00"}`:"");
   }
   result[key]=val;matches++;
  }
 }
 if(matches<3)throw Error("İlk sayfada form alanları bulunamadı. Bu formun dışa aktardığı dikey şablonu kullanın.");
 return result;
}
$("importBtn").addEventListener("click",()=>$("excelInput").click());
$("excelInput").addEventListener("change",async e=>{
 const file=e.target.files?.[0];e.target.value="";if(!file)return;
 try{
  if(!file.name.toLowerCase().endsWith(".xlsx"))throw Error("Lütfen .xlsx dosyası seçin.");
  const data=await parseXlsx(await file.arrayBuffer());
  if(confirm(`${Object.keys(data).length} alan Excel dosyasından okundu. Mevcut formun üzerine aktarılsın mı?`)){
   $("breachForm").reset();putFormData(data);
  }
 }catch(err){alert("Excel içeri aktarılamadı: "+err.message)}
});
$("printBtn").addEventListener("click",()=>{resizeAllAreas();window.print()});
// Olay verileri otomatik kaydedilmez. Sayfa ilk açıldığında boş kayıt gelir.
$("breachForm").reset();refresh();resizeAllAreas();

</script>
</body>
</html>