Yürürlük 10.08.2026

Saklama ve İmha Politikası

Hangi kayıt ne kadar duruyor, sonra ne oluyor.

Kanun m.7 ve Kişisel Verilerin Silinmesi, Yok Edilmesi veya Anonim Hale Getirilmesi Hakkında Yönetmelik uyarınca hazırlanmıştır. 🔴 Bu politika CEO'nun iki isteğini uzlaştırır: "her şeyi loglayalım, cevapsız kalmayalım" ve "bizi hukuken koru". KVKK veri minimizasyonu ilkesi taşır — "her şeyi süresiz sakla" denetimde ceza sebebidir. Çözüm: katmanlı saklama.

1. Saklama süreleri

KatmanİçerikSüreDayanak
MaliTutar, KDV, servis bedeli, bahşiş, masa etiketi, tarih-saat, ödeme referansı, adisyon kalemi kopyası10 yılTTK m.82 / VUK m.253 saklama yükümlülüğü — KVKK'nın meşru istisnası
İşlemselKim onayladı, hangi bildirim gitti, mutabakat izi, ikram/indirim/iade kaydı2 yılUyuşmazlık/zamanaşımı süresi
İşlem güvenliğiHız sınırı kayıtları — IP ham hâliyle saklanmaz, salt+SHA-256 özeti tutulur (§4)90 gün (üst sınır; işlevsel ömrü 15 dk)Meşru menfaat (m.5/2-f) — güvenlik amacı sona erince silinir
Cihaz bildirim kimliğiPush token, platformKullanıcı bildirimleri kapatana / hesabı silene kadarSözleşmenin ifası
Kimlik bağıE-posta, görünen adHesap silinene kadarSözleşmenin ifası
Ödemedeki "kim ödedi" bağıpayments.user_idMasa kapandıktan 3 gün sonra otomatik kopar — kullanıcı hiçbir şey yapmasa bileVeri minimizasyonu (m.4/2-d)

2. Hesap silindiğinde ne olur

🔴 Mali kayıt silinmez — kanunen silinemez. Silinen şey kimlik bağıdır:

`` ÖNCE: ödeme #123 → user_id: <kullanıcı> → e-posta: ali@ornek.com SONRA: ödeme #123 → user_id: (bağ koparıldı) → kimlik yok ``

Ödeme tutarı, tarihi ve restoranın mutabakat kaydı yerinde kalır; kullanıcı ile bağı kalmaz. Bu, hem KVKK'nın silme hakkını hem TTK/VUK saklama yükümlülüğünü aynı anda karşılar.

Tam döküm — ne siliniyor, ne kalıyor

İşlemVeri
DELETEauth.users kaydı (e-posta, kimlik), session_participants, item_claims, user_push_tokens, receipt_visibility, session_tokens, payment_reminder_queue, staff_pins, restaurant_staff
Kimlik bağı NULLpayments.user_id, table_sessions.opened_by, audit_log.actor_user_id, shift_closures.closed_by
DokunulmazÖdeme tutarı/tarihi/yöntemi, adisyon kalemleri, denetim defterindeki işlemin kendisi

⚠️ Restoran sahibi hesabını doğrudan silemez. restaurants.owner_id yabancı anahtarı ON DELETE CASCADE'dir; sahip hesabını silmek restoranın tüm verisini (masalar, adisyonlar, personel, geçmiş ciro) birlikte götürürdü. Bu, sahibin kendi verisi değil başkalarının verisidir. Akış: önce devir ya da purge_restaurant (§2.1).

🔴 2026-08-10 — bu mekanizma canlıda ÖLÜ bulundu ve diriltildi

20260803190000_delete_account_preserve_payments fonksiyonu public şemasına yazılmıştı; istemci ise splittable şemasını kullanıyor ve taşımada yalnız o şema geldi. Sonuç: "Hesabı Sil" düğmesi canlıda çalışmıyordu — KVKK m.7 silme hakkı fiilen sağlanamıyordu (App Store Review Guideline 5.1.1(v) ihlali de aynı kapıya çıkıyordu).

✅ Düzeltme: 20260810110000_e11_hesap_silme_dirilt.sql — splittable.delete_my_account(), imha izi yazan ve sahip kapısı olan sürüm. Kanıt: scripts/guvenlik/e11_dogrula.py.

📌 Politikadan çıkan kural: bu belgede "mekanizma kurulu" yazan her satırın arkasında canlıdan alınmış bir kanıt olmalı. Migration dosyasının varlığı kanıt değildir.

2.1 Restoran silme talebi (veri sorumlusu restoran ise)

Bir restoran kendi verisinin silinmesini isterse purge_restaurant(restoran, gerekçe) çalıştırılır: restoran ve tüm bağlı kayıtları silinir, denetim defterindeki satırlar kimlikten arındırılıp purged=true işaretiyle anonim arşiv olarak kalır. Yalnız restoran sahibi çağırabilir ve gerekçe zorunludur.


3. Müşterinin "listemden kaldır" işlemi (silme değildir)

Uygulamadaki "Listemden Kaldır" seçeneği ödeme kaydını silmez, yalnız müşterinin kendi görünümünden gizler (receipt_visibility). Restoranın mutabakat raporunda kayıt durmaya devam eder ve olay defterine receipt_hidden_by_customer yazılır.

🟢 Bu davranış teknik olarak doğrulanıyor: scripts/guvenlik/d_dogrula.py T6 her koşumda "müşteri gizledi, restoranın raporunda duruyor" şartını ölçüyor. 🟢 Kullanıcıya da dürüstçe söyleniyor: "Ödeme kaydı silinmez; yalnız senin listenden kaldırılır. Restoranın muhasebe kayıtlarında durmaya devam eder."


4. ✅ TESPİT EDİLEN TEKNİK EKSİKLER — ÜÇÜ DE KAPATILDI (2026-08-08)

Bu politikanın tam uygulanmadığı üç nokta ölçülerek tespit edilmiş ve aynı gün kapatılmıştı. Migration: 20260808500000_s1_s2_s3_data_retention.sql · kanıt: scripts/guvenlik/s_dogrula.py → 10/10.

#EksiktiBugünkü hâliKanıt
S1~~IP adresi MASKELENMEMİŞ saklanıyor (92.44.118.223)~~✅ Anahtar artık salt + SHA-256 özeti (ipx_…), ham IP hiç yazılmıyors_dogrula T1–T4
S2~~IP kayıtları için otomatik silme YOK~~✅ splittable-purge-join-attempts cron işi, günlük 04:45 UTC, 90 güns_dogrula T6–T7
S3~~data_retention_purge olayı hiç yazılmamış~~✅ Hem IP temizliği hem ödeme anonimleştirmesi deftere yazıyors_dogrula T8–T9

🔴 S1'de neden maskeleme değil özet seçildi

Politikanın ilk hâli "maskelenmiş IP" diyordu (92.44.118.x). Uygulanmadı, çünkü attempt_key aynı zamanda kaba kuvvet hız sınırının anahtarıdır; /24'e indirmek aynı kovaya farklı kişileri düşürürdü:

Salt + SHA-256 ikisini de çözer: aynı IP → aynı anahtar (hız sınırı çalışır), farklı IP → farklı anahtar (çakışma yok), anahtardan IP geri elde edilemez. 🟢 Hız sınırının gerçekten sağlam kaldığı gerçek REST turunda ölçülüyor (g1_g2_g3_dogrula.py T6 — 10. denemede kilit geldi).

⚠️ Dürüst sınır: salt veritabanında (splittable.security_salts, RLS açık + politika yok + GRANT yok) durur. Veritabanına tam erişen biri salt'ı da görür. Özet, tabloyu okuyanın IP öğrenmesini engeller — DB'yi ele geçirene karşı değil. KVKK açısından belirleyici olan birincisidir (veri minimizasyonu).

🟢 Zaten çalışıyordu: splittable-anonymize-payments cron işi (30 4 *) günlük anonimleştirme yapıyor — mali kayıtla kimlik bağını koparan mekanizmanın bir parçası. Artık bu koşum da restoran bazında imha izi yazıyor, böylece restoran kendi verisinin imhasını payment_events üzerinden görebiliyor.


5. İmha yöntemleri

Veri tipiYöntem
Veritabanı kaydı (kimlik bağı)Silme (DELETE) veya anonim hale getirme (bağ koparma)
Mali kayıt🔴 Silinmez — 10 yıl sonunda anonim hâlde kalır veya imha edilir
Değiştirilemez defter (payment_events, audit_log)Append-only; silinemez. Kimlik alanları anonimleştirilir
Yedekler~/SplitTable-Yedekler/ — rotasyon: son 14 yedek, eskiler otomatik düşer

⚠️ Append-only defterlerin sınırı dürüstçe kayda geçiriliyor: payment_events ve audit_log tasarım gereği silinemez (mali denetim izinin değiştirilemez olması için). Bu tablolarda imha, kimlik alanlarının anonimleştirilmesi yoluyla yapılır.

📌 Ayrıca defterde, eski test sürümlerinden kalan ve append-only olduğu için silinemeyen teknik kayıtlar bulunmaktadır (5 b1_test + 36 yetim olay). Bunlar kişisel veri içermez; raporlarda ayıklanır.


6. Periyodik imha

Yönetmelik gereği periyodik imha 6 ayda birden fazla aralıklarla yapılamaz.

NeSıklıkDurum
Mali kayıt anonimleştirmeGünlük (30 4 *)🟢 kurulu
İşlem güvenliği (IP) temizliğiGünlük tarama, 90 gün eşiği (45 4 *)🟢 kuruldu (S2)
İşlemsel kayıt temizliği2 yıl⏳ süre henüz dolmadı
Politika gözden geçirmeYılda 1⏳ takvime bağlanacak