Ana içeriğe geç
Projelere Dön
E-Ticaret API logo

E-Ticaret API

Backend Servisi

E-Ticaret API mimari şeması E-Ticaret API Arayüzü olmayan bir servis — sözleşme, kimlik ve gözlemlenebilirlik Express + Prisma · Docker ile paketlenir Swagger dokümanı kodun yanında üretilir İstemci web · mobil · üçüncü taraf tek sözleşme, tek doküman Ara katman zinciri helmet → cors → rate limit → JWT doğrulama → rol kontrolü → Zod şema doğrulama Hata gövdesi tek biçimde; log alanları fast-redact ile maskelenir, token ve parola log'a girmez. 15 ROTA GRUBU auth product category producer tag cart order coupon address wishlist review webhook auditLog health /metrics Prisma · PostgreSQL 18 model · 12 migration ürün, varyant görseli, kategori, üretici, etiket, kullanıcı, sipariş, kupon, yorum, denetim kaydı Kimlik: JWT + refresh + OAuth kısa ömürlü erişim token'ı, ayrı tabloda refresh token arctic ile sağlayıcı akışı · OAuthAccount modeli parolalar bcrypt ile saklanır Gözlemlenebilirlik: winston ile yapılandırılmış log, morgan ile istek kaydı, prom-client ile metrik ucu. Arayüzü olmayan bir serviste "çalışıyor mu" sorusunun tek cevabı bunlar.
Arayüzü olmayan bir Express + Prisma servisi. Her istek aynı ara katman zincirinden geçer: helmet, cors, sıklık sınırı, JWT doğrulama, rol kontrolü ve Zod şema doğrulaması. 15 rota grubu 18 Prisma modeline bağlanır; kimlik JWT + refresh + OAuth ile kurulur, gözlemlenebilirlik winston, morgan ve prom-client ile sağlanır. Hata gövdesi tek biçimdedir ve log alanları maskelenir.

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

  • Node.js
  • Express
  • TypeScript
  • Prisma
  • PostgreSQL
  • Zod
  • JWT
  • Swagger
  • Docker

Ö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

2 ay

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

  1. 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.

  2. 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ı.

  3. 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.

  4. 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.

  5. 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

Rota
15 rota grubu — kimlik, katalog, sepet, sipariş, kupon, yorum, adres, istek listesi, webhook, denetim, sağlık, metrik
Şema
18 Prisma modeli · 11 migration
TypeScript kaynak dosyası
99
Ara katman
15 ara katman modülü — kimlik, yetki, sahiplik, oran sınırlama, idempotency, doğrulama, maskeleme, hata
Şema geçmişi
Migration tarihleri 2026-04 → 2026-06; repo tek bir içe aktarma commit'i taşıyor
Mimari garanti
Idempotency ara katmanda tanımlı; bir uç bu korumayı atlayamaz
Mimari garanti
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.

Backend servisi

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.