Kod Havuzu Veri Modeli: Aynı Kodu 2 Kere Satmamak İçin Altın Kurallar

Kod Havuzu Veri Modeli: Aynı Kodu 2 Kere Satmamak İçin Altın Kurallar

12 Şubat 2026 8 dk okuma 241 görüntülenme

Kod havuzu veri modeli neden kritik? Çünkü dijitalde “geri alma” yok

E-pin/dijital kod satışında en pahalı iki hata şunlardır: (1) aynı kodun iki kez satılması ve (2) stok var görünüp teslim edilememesi. Bu hatalar sadece para kaybettirmez; destek yükünü artırır, chargeback riskini büyütür ve markaya “güvenilmez” etiketi yapıştırır.

Bu yazıda tek bir hedef var: veri modeli seviyesinde çift satış riskini sistematik olarak bitirmek. Yani “kod seçimini dikkatli yapalım” değil; hata yapmayı imkânsızlaştıran bir model kurmak.

1) Kod stoğu “var/yok” değildir: 3 durum + net geçişler

Sağlam bir kod havuzunda kodlar en az şu 3 durumdan birindedir:

  • Available (Müsait): Satışa hazır, kimseye ayrılmamış.
  • Reserved (Rezerve): Bir sipariş için ayrılmış, ödeme kesinleşmemiş.
  • Delivered (Teslim edildi): Müşteriye verilmiş, artık geri dönülmez.

Bu durumlar arasındaki geçişler de net olmalı:

  • Available → Reserved (rezervasyon)
  • Reserved → Delivered (ödeme doğrulandı)
  • Reserved → Available (timeout / ödeme başarısız)

“Delivered → Available” gibi bir geri dönüşü genelde istemezsin; dijitalde bu riskli bir kapıdır.

2) Minimum tablolar: Kod, Sipariş, Kod Teslimatı

Tek tabloyla her şeyi tutmaya çalışmak büyüdükçe karmaşa çıkarır. Basit ama sağlam yapı şöyle ilerler:

A) CodePool (kodların kendisi)

  • CodePoolId (PK)
  • ProductId (hangi dijital ürün)
  • CodeValue (şifreli/korumalı saklama önerilir)
  • Status (Available/Reserved/Delivered)
  • ReservedAt (ne zaman rezerve edildi)
  • DeliveredAt (ne zaman teslim edildi)
  • BatchId (tedarikçi yükleme partisi)

B) Order / OrderItem (sipariş tarafı)

  • OrderId (PK)
  • CustomerId
  • PaymentStatus (Pending/Paid/Failed/Cancelled)
  • CreatedAt

C) CodeDelivery (sipariş-kod eşleşmesi)

Bu tablo, “hangi sipariş hangi kodu aldı?” sorusunun tek kaynağı olur.

  • CodeDeliveryId (PK)
  • OrderId
  • OrderItemId (adetli siparişlerde önemli)
  • CodePoolId
  • Status (Reserved/Delivered/Released gibi)
  • CreatedAt, UpdatedAt

3) Altın Kural #1: Tekillik (uniqueness) veri tabanında zorunlu olmalı

“Uygulama kodunda kontrol ediyoruz” yeterli değildir. Eşzamanlılıkta (concurrency) iki istek aynı anda geçebilir. O yüzden tekillik DB seviyesinde garanti edilmelidir.

Uygulanabilir tekillik kısıtları

  • Bir kod sadece bir kez Delivered olabilir: CodePool.Status zaten bunu ifade eder ama ek güvenlik gerekir.
  • Bir CodePoolId sadece bir aktif teslimata bağlanabilsin: CodeDelivery üzerinde “aktif kayıt” tekil olmalı.
  • Bir ödeme transaction’ı bir kez işlenebilsin: ayrı bir PaymentTransactions tablosunda Unique(transactionId) gibi.

Özellikle şu mantık çok işe yarar: CodeDelivery tablosunda “Delivered kayıt” için CodePoolId tekil olsun. Böylece aynı kodun iki farklı siparişe Delivered yazılması DB tarafından engellenir.

4) Altın Kural #2: Rezervasyon atomik olmalı (SELECT + UPDATE birlikte)

Çift satışın en sık nedeni, “kodu seçtim” ile “kodu rezerve yaptım” işlemlerinin ayrı ayrı yapılmasıdır. İki istek aynı anda aynı kodu seçebilir.

Doğru yaklaşım: DB’de tek hamlede “müsait bir kodu bul ve rezerve et”.

  • Available kodlardan birini seç
  • Aynı işlem içinde Status=Reserved yap
  • Bu işlem başarısızsa başka kod dene (veya stok yok de)

Bu kural uygulanırsa “eşzamanlı iki satış” senaryosu büyük ölçüde çözülür.

5) Altın Kural #3: Reservation timeout olmadan stok yönetemezsin

Ödeme her zaman başarıyla bitmez. Kullanıcı sayfayı kapatır, banka reddeder, 3DS yarıda kalır. Eğer Reserved kodları serbest bırakmazsan, stok “kilitlenir”.

  • Rezervasyona bir TTL ver (örn. 15–30 dk)
  • TTL aşınca: CodeDelivery = Released, CodePool.Status = Available
  • Order = TimedOut/Cancelled (kuralına göre)

Bu işlem bir job/worker ile periyodik çalışabilir.

6) Altın Kural #4: Ödeme callback’i idempotent olmalı

Ödeme sağlayıcı aynı “success” callback’ini iki kez gönderebilir. Eğer sistem her callback’te teslimat yapıyorsa, çift satış/çift teslimat kaçınılmaz olur.

  • Callback geldiğinde önce “bu transaction işlendi mi?” kontrol et
  • İşlendiyse hiçbir şey yapma
  • İşlenmediyse: siparişi Paid yap, Reserved kodu Delivered yap

Burada DB’de Unique(transactionId) gibi bir kısıt, idempotency’nin sigortasıdır.

7) Altın Kural #5: “Tek kaynak” prensibi (source of truth) belirle

Çoğu sistemde sorun şu yüzden çıkar: kodun durumu bir yerde, siparişin durumu başka yerde, teslimat durumu başka yerde ve birbirini tutmaz.

  • “Sipariş hangi kodu aldı?” sorusunun cevabı CodeDelivery tablosunda olmalı.
  • CodePool.Status gerçek stoğu göstermeli.
  • Order.PaymentStatus ödeme gerçeğini temsil etmeli.

Bu üçlü tutarlı olursa, destek ve muhasebe tarafı da rahatlar.

8) Audit log: Krizde 2 dakikada teşhis için şart

Dijital ürün işinde kriz anı hızlı gelir: “Kod gelmedi”, “Kod çalışmıyor”, “Aynı kod satılmış”. Audit log olmadan her şey “tahmin” olur.

  • Kod rezerve edildi (kim, ne zaman, hangi sipariş)
  • Ödeme başarı/başarısız callback’i geldi
  • Kod teslim edildi (gösterildi/gönderildi)
  • Rezerv timeout ile serbest bırakıldı

Bu loglar; hem destek süreçlerini hızlandırır hem de chargeback itirazlarında delil üretir.

9) Dijital ürünlerde ekstra dikkat: Kodun saklanması ve gösterimi

Veri modeli kadar önemli bir konu da kodun “açığa çıkma” yüzeyidir.

  • Kodu düz metin tutmak yerine şifreli saklama düşün
  • Admin panelde kodu rol bazlı maskele (son 4 karakter gibi)
  • Kodun kaç kez görüntülendiğini (gerekliyse) logla

Burada hedef “paranoya” değil; sızıntı riskini makul seviyeye çekmek.

10) Hızlı kontrol listesi: Modelin çift satışa dayanıklı mı?

  • 3 durum modeli (Available/Reserved/Delivered) var mı?
  • Rezervasyon atomik mi?
  • Reserved timeout + otomatik serbest bırakma var mı?
  • CodeDelivery üzerinden “Delivered tekilliği” DB ile garanti mi?
  • Payment transaction idempotency DB ile garanti mi?
  • Audit loglar kriz teşhisine yeterli mi?

Kapanış

Aynı kodu iki kez satmamak, “dikkatli olmakla” değil; veri modeli ve kısıtlarla hatayı imkânsız kılmakla çözülür. Durum yönetimi, atomik rezervasyon, timeout, idempotent callback ve sağlam loglama birleştiğinde, dijital ürün işinde en kritik riskleri daha baştan kapatmış olursun.