Sarfiyum: Geliştirme Süreci, Mimari ve Saniyelik Veri Akışı

Kuyumculuk sektörüne özel geliştirdiğim finansal SaaS çözümü Sarfiyum'un Multi-Tenancy mimarisini, SignalR altyapısını ve Nginx ile optimize ettiğim Linux sunucu süreçlerini paylaşıyorum.

Yavuz Soylu

Sarfiyum: Geliştirme Süreci, Mimari ve Saniyelik Veri Akışı blog image

Sarfiyum, basit bir finansal takip uygulamasından ziyade, kuyumculuk sektörünün spesifik ve dinamik ihtiyaçlarına yanıt vermek üzere tasarladığım kapsamlı bir SaaS (Software as a Service) çözümüdür. Altın, döviz ve diğer değerli maden piyasalarının saniyelik değişimlerini takip etme ve portföy yönetimi sunma fikriyle yola çıktığım bu projede, teknik anlamda en büyük önceliğim ölçeklenebilirlik, anlık veri iletimi ve veri izolasyonuydu.

Bu yazıda, Sarfiyum'u hayata geçirirken aldığım mimari kararları, kullandığım teknoloji yığınını ve karşılaştığım mühendislik zorluklarını nasıl aştığımı detaylandıracağım.

1. Temel Mimari: Multi-Tenancy ve Clean Architecture

Sarfiyum, farklı kuyumcu firmalarına (kiracılara) kendi müşterilerine özel "White Label" hizmet sunma imkanı tanıdığı için mimarinin kalbine Multi-Tenancy (Çoklu Kiracı) yapısını yerleştirdim.

Arka planda yönetimi kolaylaştırmak ve kodun sürdürülebilirliğini sağlamak için Clean Architecture (Core, Data, Service ve API katmanları) prensiplerini benimsedim.

  • Veri İzolasyonu (ITenantEntity): Farklı firmaların verilerinin birbirine karışmasını engellemek en kritik konuydu. Bunun için veritabanı seviyesinde ITenantEntity arayüzünü kurguladım. Bu sayede yazdığım her sorguyu, otomatik olarak sadece ilgili kiracının verisini getirecek şekilde izole ettim.
  • Soft Delete ve ServiceResult: Veri kaybını önlemek adına tüm sistemde Soft Delete (veriyi silmek yerine pasife alma) mantığını uyguladım. Ayrıca, API katmanı ile servis katmanı arasındaki iletişimi standartlaştırmak için ServiceResult Pattern kullanarak hata yönetimini çok daha öngörülebilir bir hale getirdim.

2. Saniyelik Veri Akışı, SignalR ve Backend Performansı

Sistemin kalbinde .NET 8 Web API ve ORM olarak Entity Framework Core bulunuyor. Veritabanı tercihim ise sağlamlığı sebebiyle SQL Server oldu. Ancak uygulamanın asıl zorlayıcı kısmı veritabanı değil, gerçek zamanlı veri akışıydı.

Yurtdışı Socket Bağlantısı ve SignalR Mimarisi Sistemin can damarı olan finansal kurları, yurtdışı bazlı saniyelik bir socket sunucusundan canlı olarak alıyorum. Bu devasa ve kesintisiz ham veri akışını yakalayıp, kullanıcılara milisaniyeler içinde dağıtabilmek için kendi SignalR servisimi kurdum. Böylece saniyelik kur değişimlerini, hiçbir gecikme (latency) yaşamadan tüm istemcilere (hem mobil uygulamaya hem de web paneline) anında iletiyorum.

Kuyumculuğa Özel Çözüm: TenantMultiplier Kuyumculuk sektörünün en büyük zorluklarından biri, her firmanın (tenant) kurları kendi belirlediği marjlarla (çarpanlarla) müşterilerine yansıtmasıdır. Bunu çözmek için TenantProduct adında her tenant'a özel bir çarpan algoritması barındıran model geliştirdim. SignalR üzerinden akan saniyelik ham kurları, bu algoritmadan geçirerek anında her firmanın kendi özel kuruna dönüştürüyor ve istemciye o şekilde basıyorum.

public class TenantProduct : EntityBase
{
    [Required]
    [StringLength(EntityConstants.KeyLength)]
    public string TenantId { get; set; } = string.Empty;
    [Required]
    [StringLength(EntityConstants.KeyLength)]
    public string TenantProductCategoryId { get; set; } = string.Empty;
    [ForeignKey("TenantProductCategoryId")]
    public virtual TenantProductCategory? TenantProductCategory { get; set; }
    [Required]
    public string Name { get; set; } = default!; 
    [Required]
    public string SourceKey { get; set; } = default!; 
    // --- ÇARPANLAR ---
    [Column(TypeName = "decimal(18, 10)")]
    public decimal BuyMultiplier { get; set; } = 1.0000000000m;
    [Column(TypeName = "decimal(18, 10)")]
    public decimal SellMultiplier { get; set; } = 1.0000000000m;
    [Column(TypeName = "decimal(18, 10)")]
    public decimal AddonAmount { get; set; } = 0m;
    public int OrderIndex { get; set; } 
    public bool IsActive { get; set; } = true;
    public bool ShowOnWeb { get; set; } = true;    
    public bool ShowOnMobile { get; set; } = true; 
}

Memory Cache ile Milisaniyelik Yanıtlar Anlık finansal verilerin sürekli veritabanından sorgulanması büyük bir darboğaz (bottleneck) yaratabilirdi. Bu yüzden, sık okunan ama nadir değişen veriler ve saniyelik kur akışları için güçlü bir Memory Cache mekanizması kurdum. Bu sayede API yanıt sürelerini minimize ederek mobil tarafa gerçek zamanlıya yakın bir deneyim sundum.

3. Frontend ve Yönetim Paneli

Sistemin admin ve müşteri yönetimi tarafında, modern ve modüler bir yapı kurmak adına Angular 18+ tercih ettim.

Uygulamanın frontend mimarisinde Standalone Components yapısını kullanarak modül (NgModule) karmaşasından kurtuldum. Finansal verilerin ve uygulama içi durumların (state) karmaşıklaştığı noktalarda ise NgRx kullanarak State Management süreçlerini merkezi ve güvenli bir şekilde yönettim.

4. Mobil Tarafta Flutter ve White Label Stratejisi

Son kullanıcıların cebine giren uygulama için Flutter kullandım. Flutter'ın tek bir kod tabanıyla hem iOS hem de Android'de native performansa yakın çalışması, projenin hızını büyük ölçüde artırdı.

Mimarideki White Label vizyonum sayesinde, Flutter projesinde küçük konfigürasyon değişiklikleriyle aynı uygulamayı farklı logolar, renk paletleri ve isimlerle farklı kuyumcular için anında derleyip marketlere sunabiliyorum.

5. Sunucu, Nginx Optimizasyonu ve Operasyon Süreçleri

Bulut tabanlı hazır DevOps servislerine veya hantal yapılara bağımlı kalmak yerine, tüm sistemi kendi konfigüre ettiğim Linux tabanlı sunucularda barındırmayı tercih ettim. Bunun en büyük sebebi; Linux'un çok daha az kaynak tüketerek maliyet açısından inanılmaz hesaplı (cost-effective) olmasıydı.

Ayrıca, sunucu mimarisine entegre ettiğim Nginx optimizasyonlarıyla, Linux tabanlı servislerin performansını ve istek karşılama kapasitesini maksimum seviyeye çıkardım. Dağıtım ve yayınlama süreçlerinde Docker konteynerizasyon teknolojilerini kullandım. Bu sayede uygulamanın bağımlılıklarını izole ediyor, hem yönetim panelini hem de backend servislerini saniyeler içinde yeni versiyonlarına güncelleyebiliyorum.

Sonuç

Sarfiyum, sıfırdan bir ürün tasarlamanın, yüksek trafikli anlık socket verilerini SignalR ile başarıyla dağıtmanın ve domain spesifik sorunları mimari seviyede çözmenin benim için harika bir kanıtı oldu. Bir developer olarak sadece kod yazmanın değil; performans, maliyet, güvenlik ve son kullanıcı deneyimini aynı anda düşünmenin ne kadar önemli olduğunu bu projeyle bir kez daha deneyimledim.

Etiketler

  • Mimari
  • SaaS
  • SignalR
  • .NET
  • Angular
  • Flutter
  • Linux
  • Nginx
  • Docker

İletişim

Sorularınız veya daha fazla ayrıntı için sosyal medya bağlantılarımdan bana ulaşabilirsiniz.

Bülten

Teknoloji, tasarım, üretkenlik, programlama ve daha fazlası gibi konularda kişisel güncellemeler ve içerikler için katılın!

Diğer 0 okuyucuya katılın.