
E-Ticaret API
Backend Servisi
Arayüzü olmayan bir e-ticaret backend'i: 15 rota grubu, 18 Prisma modeli, JWT ve yenileme token'ı ile kimlik, sağlayıcı girişi, oran sınırlama, denetim kaydı ve metrik ucu. Sözleşme Swagger'dan üretiliyor, servis Docker ile paketleniyor.
Kullanılan Teknolojiler
Öne Çıkan Özellikler
- 15 rota grubu — katalog, sepet, sipariş, kupon, yorum, istek listesi, webhook, denetim
- JWT erişim token'ı + ayrı tabloda yenileme token'ı + sağlayıcı girişi
- Sipariş durumu ayrı bir durum makinesinde tanımlı, controller'ın içinde değil
- Tekrarlanan isteklere karşı koruma — aynı istek iki kez işlenmiyor
- Yapılandırılmış log, istek kimliği ve maskeleme; token ve parola log'a girmiyor
- Prometheus uyumlu metrik ucu, kimlik doğrulama arkasında
Geliştirme Süresi
Problem
Arayüzü olan bir uygulamada "çalışıyor mu" sorusunun cevabı ekrandır. Arayüzü olmayan bir serviste böyle bir cevap yok: servis ayakta ama yanlış davranıyor olabilir ve bunu ancak onu tüketen taraf fark eder — çoğu zaman geç. Bu yüzden buradaki asıl problem iş mantığı değil, sözleşme ve görünürlük. İkincisi, bir e-ticaret API'sinde tekrar eden istek sıradan bir durum: ağ kopuyor, istemci yeniden deniyor, ödeme sağlayıcısı aynı bildirimi ikinci kez gönderiyor. "İki kez işlenirse ne olur" sorusunun cevabı her uçta ayrı ayrı düşünülürse er geç bir uç unutuluyor.
Kullanıcılar
İki tüketici tipi. Doğrudan istemci — web veya mobil arayüz: katalog okuyor, sepet ve sipariş yazıyor, oturum yönetiyor. Sunucu tarafı tüketici — ödeme veya kargo sağlayıcısı: webhook gönderiyor, kimliğini paylaşılan bir sır ile kanıtlıyor ve aynı bildirimi tekrarlayabiliyor. Üçüncü bir taraf var: servisi işleten kişi; onun ihtiyacı ekran değil, log, metrik ve denetim kaydı.
Rolüm
Tek geliştirici. Veri modeli ve migration'lar, ara katman zinciri, kimlik ve yetki katmanı, sipariş durum makinesi, denetim ve gözlemlenebilirlik katmanı, Swagger sözleşmesi ve Docker paketi.
Mimari
Express üzerinde tek servis; istek sabit bir ara katman zincirinden geçiyor: güvenlik başlıkları, kaynak paylaşımı politikası, istek kimliği, oran sınırlama, JWT doğrulama, rol kontrolü, sahiplik kontrolü ve Zod şema doğrulaması. Zincirin sonunda controller yalnız iş mantığını çalıştırıyor; hata yakalama ve hata gövdesinin biçimi tek bir hata ara katmanında toplanıyor, yani her uç aynı hata zarfını üretiyor. Sipariş durumu controller'ın içinde değil, ayrı bir durum makinesi modülünde tanımlı — hangi durumdan hangisine geçilebileceği tek yerde duruyor. Tekrar eden istekler ayrı bir idempotency ara katmanıyla ele alınıyor, yani her uç kendi çözümünü icat etmiyor. Veri tarafında Prisma ve PostgreSQL; ürün araması için şemada ayrı bir arama vektörü kolonu var ve listeleme uçları sayfa numarası yerine imleç tabanlı sayfalama kullanıyor. Gözlemlenebilirlik üç parçalı: yapılandırılmış log, istek kaydı ve metrik ucu.
Kritik Kararlar
Idempotency ara katmanda, uçların içinde değil
Tekrar eden istek bir uca özgü değil; sepete ekleme, sipariş oluşturma ve webhook işleme aynı sorunu paylaşıyor. Çözüm ara katmana alındığında bir uç bunu unutamıyor — koruma rotanın tanımına iliştiriliyor, controller'ın disiplinine değil.
Ödünleşimİstemcinin idempotency anahtarını üretmesi ve tekrar denemede aynı anahtarı göndermesi gerekiyor; bunu yapmayan bir istemci korumadan yararlanamıyor. Ayrıca işlenmiş anahtarların saklandığı yer sürekli büyüyor ve temizlenmesi gerekiyor.
Sipariş durumu ayrı bir modülde, controller'ın içinde değil
Sipariş yaşam döngüsü sistemin en çok dallanan yeri: ödeme, hazırlık, kargo, teslim, iptal ve iade. Geçiş kuralları controller'lara dağılırsa aynı kural birkaç yerde farklı yazılıyor ve zamanla ayrışıyor. Kuralları tek modülde toplamak, geçerli geçişlerin tek bir yerde okunmasını sağlıyor.
ÖdünleşimKural uygulamada duruyor, veritabanında değil: doğrudan SQL ile yapılan bir güncelleme durum makinesini atlayabiliyor. Ustura'da randevu çakışmasını veritabanı kısıtına indirdiğim gibi burada da geçişleri veri seviyesinde zorlamak mümkündü; yapılmadı.
Yenileme token'ı ayrı bir tabloda tutuluyor
Erişim token'ı kısa ömürlü ve durumsuz; yenileme token'ı ise veritabanında bir kayıt olarak duruyor. Bunun sebebi iptal edilebilirlik: durumsuz bir yenileme token'ı süresi dolana kadar geçerli kalıyor ve çalınmış bir oturumu kapatmanın yolu olmuyor. Sağlayıcı girişleri de ayrı bir hesap modeliyle ilişkilendiriliyor, yani aynı kullanıcı birden fazla giriş yöntemi taşıyabiliyor.
ÖdünleşimHer yenileme isteği bir veritabanı okuması demek — durumsuz bir tasarımın ölçekleme avantajı burada bilerek bırakılıyor. Tablo da zamanla büyüyor ve süresi geçmiş kayıtların temizlenmesi gerekiyor.
Metrik ve dokümantasyon uçları açık bırakılmadı
Metrik ucu sistemin iç durumunu, Swagger arayüzü ise tüm sözleşmeyi anlatıyor. İkisi de bir saldırgan için keşif materyali. Her ikisi de kimlik doğrulama arkasına alındı; webhook ucu ayrıca paylaşılan bir sır ile doğrulanıyor.
ÖdünleşimDokümantasyonun kapalı olması, API'yi tüketecek bir geliştirici için ek bir erişim adımı demek. Metrik ucunun korunması da toplayıcı tarafında ayrı yapılandırma gerektiriyor — kimlik doğrulamayı desteklemeyen bir toplayıcıyla doğrudan çalışmıyor.
Log alanları maskeleniyor
Bir isteğin gövdesini log'a yazmak hata ayıklamayı kolaylaştırıyor, ama aynı gövdede parola, token ve adres olabiliyor. Maskeleme, log yazma anında ve alan bazlı yapılıyor; hassas alan log'a hiç girmiyor, sonradan temizlenmiyor.
ÖdünleşimMaskelenecek alanların listesi elle tutuluyor; yeni bir hassas alan eklendiğinde listeye yazılması gerekiyor ve bunu hatırlatan bir mekanizma yok. Maskelenen bir alan hata ayıklamada da görünmüyor, yani bazı hatalar log'dan izlenemiyor.
Teknoloji Seçimi
Express, ara katman zincirinin okunabilir olması için seçildi: isteğin hangi sırayla neyden geçtiği kod okunarak takip edilebiliyor ve bu, güvenlik kararlarının görünür kalması demek. Prisma, 18 modelli bir şemada ilişkileri ve migration geçmişini takip edilebilir tutuyor; şema dosyası aynı zamanda veri modelinin dokümantasyonu. Zod, istek gövdesinin doğrulanmasını tek bir ara katmanda toplarken tipleri de aynı şemadan veriyor. Swagger sözleşmesi kodun yanında, yorum olarak yazılıyor — ayrı bir dokümanın koddan ayrışması bu şekilde zorlaşıyor. Docker, servisin bağımlılıklarıyla birlikte tek bir çalıştırılabilir birim olmasını sağlıyor; arayüzü olmayan bir serviste "benim makinemde çalışıyor" cümlesinin karşılığı yok.
Güvenlik
Ara katman zinciri güvenlik başlıklarıyla başlıyor ve kaynak paylaşımı politikası açıkça tanımlı. Oran sınırlama uç bazında yapılandırılmış; kimlik uçlarında daha dar. Parolalar bcrypt ile saklanıyor, erişim token'ı kısa ömürlü, yenileme token'ı veritabanında tutulduğu için iptal edilebiliyor. Yetki üç kademeli: kimlik doğrulama, rol kontrolü ve kaynak sahipliği kontrolü — yani doğru rolde olan bir kullanıcı bile başkasının kaydını düzenleyemiyor. Webhook ucu paylaşılan sır ile doğrulanıyor. Dosya yüklemeleri ayrı bir ara katmandan geçiyor. Metrik ve Swagger uçları kimlik doğrulama arkasında. Değişiklikler ayrı bir denetim kaydı modeline yazılıyor; log alanları yazma anında maskeleniyor.
Performans
Bu bir backend servisi; sayfa hızı ölçümü anlamlı değil ve saklanmış bir yük testi çıktısı da bulunmadığı için buraya bir sayı yazılmadı. Yapısal tarafta üç karar var: listeleme uçları imleç tabanlı sayfalama kullanıyor, böylece derin sayfalarda sorgu maliyeti sabit kalıyor; ürün araması için şemada ayrı bir arama vektörü kolonu tutuluyor, yani arama her istekte metin taraması yapmıyor; metrik ucu istek sayısı ve süresi gibi değerleri dışarı verdiği için servisin davranışı tahminle değil ölçümle izlenebiliyor.
Sonuçlar
- 15 rota grubu — kimlik, katalog, sepet, sipariş, kupon, yorum, adres, istek listesi, webhook, denetim, sağlık, metrik
- 18 Prisma modeli · 11 migration
- 99
- 15 ara katman modülü — kimlik, yetki, sahiplik, oran sınırlama, idempotency, doğrulama, maskeleme, hata
- Migration tarihleri 2026-04 → 2026-06; repo tek bir içe aktarma commit'i taşıyor
- Idempotency ara katmanda tanımlı; bir uç bu korumayı atlayamaz
- Metrik ve dokümantasyon uçları kimlik doğrulama olmadan erişilemez
Bugün Ne Farklı Yapardım
Bu repoda otomatik test yok ve bir backend servisinde bu, en pahalı eksik. Test edilecek en kolay ve en değerli yer belli: sipariş durum makinesi zaten saf bir modül, girdi-çıktı olarak test edilebilir ve sistemin en çok dallanan kuralını taşıyor. Bugün oradan başlar, ardından idempotency ara katmanını iki kez gönderilen aynı istekle doğrulardım. İkinci nokta durum kuralının yeri: geçişleri uygulamada tuttum, oysa Ustura'da çakışma kuralını veritabanı kısıtına indirdiğimde koruma her yazma yoluna aynı anda uygulanmıştı. Burada doğrudan SQL ile yapılan bir güncelleme durum makinesini atlayabilir; bugün en azından geçersiz duruma düşmeyi engelleyen bir kontrol kısıtı eklerdim.
Nereden başlayacağınızı birlikte bulalım
Ne yapmak istediğinizi anlatın; ne kadar süreceğini ve en mantıklı ilk adımı baştan söylerim.