Teknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor HaberleriTeknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor HaberleriTeknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor Haberleri
Yazı Tipi BoyutlandırıcıAa
  • Anasayfa
  • Teknoloji
    • Siber Güvenlik
    • Yapay Zeka
    • Donanım
    • Bilim
  • Yazılım
  • Savunma & İstihbarat
  • Oyun
  • Yaşam
    • Finans
    • Sinema
    • Dünyadan Haberler
  • İş Birliği
Okuma: Laravel ile Çok Kiracılı Bir Bordro Motoru Geliştirirken Öğrendiklerimiz
Paylaş
Yazı Tipi BoyutlandırıcıAa
Teknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor HaberleriTeknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor Haberleri
Ara
Bizi Takip Et
  • Hakkımızda
  • Gizlilik politikası
  • Tanıtım Yazısı ve Backlink Hizmeti
© 2026 Teknomers. All Rights Reserved.

Anasayfa » Laravel ile Çok Kiracılı Bir Bordro Motoru Geliştirirken Öğrendiklerimiz

Yazılım

Laravel ile Çok Kiracılı Bir Bordro Motoru Geliştirirken Öğrendiklerimiz

teknomers
Son güncelleme: 7 Haziran 2026 03:52
teknomers
Paylaş
Paylaş

Ödeme yazılımları dışarıdan basit görünse de, aslında oldukça karmaşık yapılar olabilir. Temel hesaplama, saatleri oranla çarpıp, vergileri çıkararak bir sonucu bankaya göndermeye kadar giden basit bir süreç. Ama when you start building it, everything changes.

Uzun bir süredir Laravel tabanlı bir İK ve ödeme platformu geliştiriyoruz — 14 entegre modül, çok kiracılı (multi-tenant), modüler bir yapı. Bu süreçte alınan bazı kararlar, beklenenden daha zorlu hale geldi ve farklı yapabileceğimiz noktalar oldu.




Çok Kiracılılık Kararı

İlk büyük karar, çok kiracılılığı nasıl yöneteceğimizdi. Laravel’de üç yaygın yaklaşım mevcuttur:

  1. Kiracı başına ayrı veritabanları — en temiz izolasyon, yönetimi daha masraflı
  2. Ayrı şemalar (PostgreSQL) — iyi bir orta yol
  3. Kiracı ID sütunu olan paylaşılan veritabanı — en yaygın, yanlış yaparsanız en tehlikeli olanı

Biz 3. seçeneği tercih ettik. Her tablodaki tenant_id ile global sorgu kapsamlarının yönetimi mantıklı görünüyordu. Ancak hemen herkesin dikkate aldığı sorunla karşılaştık.

Bir yönetici işlemi sırasında eksik bir kapsam, kayıtların kiracılar arasında sızmasına neden oldu. Bir görev uygulamasında hayal kırıklığı olsa da, ödeme yazılımında verilerin maaş miktarları ve banka hesap numaraları olması sebepleriyle bu hata katı bir engel oluşturdu.

Bunun sonucunda her kiracı için ayrı veritabanlarına geçtik. Her kiracı, kendi veritabanını alıyor. Bağlantı, her istekte değil, kimlik doğrulama sırasında çözülüyor. Bir kullanıcı oturum açtığında, bu kiracının veritabanı adı oturuma kaydediliyor, sonraki her istekte bu kullanılmakta:

class AuthenticatedSessionController extends Controller
{
    public function store(LoginRequest $request): RedirectResponse
    {
        $request->authenticate();

        $user   = $request->user();
        $tenant = $user->tenant;

        // Oturum açıldığında saklayın — bir kez çözülmeli, istek başına değil
        session(['tenant_db' => $tenant->database_name]);

        config(['database.connections.tenant.database' => $tenant->database_name]);
        DB::purge();

        $request->session()->regenerate();

        return redirect()->intended(RouteServiceProvider::HOME);
    }
}
Geniş ekran moduna geç

Geniş ekran modundan çık

Her istekte çözümleme masrafı yok. Bağlantı, oturum açılırken ayarlanıyor ve ömrü boyunca kalıyor.

Kiracılar arası sızma şimdi yapısal olarak imkansız — bu bir disiplin problemi değil, bir yapısal sorun. Gerçek bir takas var: veritabanı geçişleri her kiracı için çalıştırılıyor, bir kez değil. Bununla, tüm kiracı veritabanlarında Artisan::call() kullanarak kuyruklu bir geçiş çalıştırıcısı ile başa çıktık.

Bu ek yük, kesinlikle buna değerdi. Çünkü ödeme verilerini yönetirken, izolasyona güvenmek değil, garantilemek zorundasınız.




Modüler Mimari — Doğru Yaptığımız Kısım

İK yazılımlarında kullanılmayan modüller sıkça görülmektedir. Eğer 30 kişilik bir ekip, işe alım sürecini, performans değerlendirme motorunu ve eğitim katalogunu ilk günden açar ve bunların hepsinden masraf ederse, gereksiz bir karmaşaya dabakat alırlar.

Her bir modülü, kendi rotalarını, politikalarını ve birleştirmelerini kaydeden bir Laravel hizmet sağlayıcısı yaptık:

class PayrollServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        if (!Module::isEnabled()) {
            return; // Rotalar, politikalar ve kaynaklar yüklenmez
        }

        $this->app->bind(PayrollEngine::class, StandardPayrollEngine::class);
    }

    public function boot(): void
    {
        if (!Module::isEnabled()) {
            return;
        }

        $this->loadRoutesFrom(__DIR__.);
        $this->loadPoliciesFrom(__DIR__.);
    }
}
Geniş ekran moduna geç

Geniş ekran modundan çık

Bir modül devre dışı bırakıldığında, rotaları var olmaz. Politika kayıtları gerçekleştirilmez. Sorgular çalıştırılmaz. Kontrolörlerde parçalı mantık yoktur — modül basitçe yoktur.

Bu durum, testleri de önemli ölçüde temizlemiştir. Her modülün test seti, yalnızca bağımlılıkları yüklenerek izole bir biçimde çalışır.




Ödeme Hesaplama Problemi

Ödeme yazılımının zorluğu burada başlar.

500 çalışan için bir ödeme dönemi tek bir hesaplama değil — aslında 500 bağımsız hesaplama yapmaktır, her biri şu bilgileri içerir:

  • Dönem için temel ücret (ay içinde işe başlayan ve ayrılanlar dahil)
  • Devam verileri ve onaylı fazla mesai
  • Kullanılan izinler (ücretli, ücretsiz, kısmi ücretli)
  • Aktif kesintiler (kredi taksitleri, avanslar)
  • Yasal rakamlar (Ulusal Sigorta, Sağlık Sigortası, gelir vergisi kesintisi)
  • Maaş yapısına göre yapılandırılan özel kazanç ve kesinti bileşenleri

Bunu tek seferde bir web isteği içinde çalıştırmak pek mümkün değil. Yavaş bir bağlantıda 500 çalışan için bir çalışma süresi, iki dakikadan kısa sürede zaman aşımına uğrayacaktır.

Bu nedenle, tüm ödeme hesaplamalarını Laravel kuyruklarına taşıdık ve Horizon, çalışanların yönetimini sağladı:

class ProcessPayrollRun implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public int $timeout = 3600; // Büyük kiracılar için maksimum 1 saat

    public function handle(PayrollEngine $engine): void
    {
        $this->run->employees->each(function (Employee $employee) use ($engine) {
            ProcessEmployeePayslip::dispatch($employee, $this->run);
        });
    }
}
Geniş ekran moduna geç

Geniş ekran modundan çık

Her çalışanın maaş bordrosu, ayrı bir iş olarak hesaplanır. Eğer biri başarısız olursa (kötü veri, fazla mesai hesaplamasındaki bir uç durum), geri kalan işler devam eder. Başarısız olan işler otomatik olarak tekrar denenir ve bordro memuru için bir inceleme kuyruğuna çıkar.

Arayüz, canlı bir ilerleme çubuğu gösterir. Bordro memuru anormallikleri inceleyebilir — fazla mesai dalgalanmaları, kısmi ay işe girişler, ortada kalan istifalar — ödemeyi onaylamadan önce gözden geçirebilir.




Yasal Uyum Rapor Değildir

Yaptığımız neredeyse bir hata: yasal uyumu sonradan eklenen bir raporlama özelliği olarak düşünmek.

Ulusal sigorta katkıları, sağlık sigortası üzerinde çalışan ve işveren payları, gelir vergisi kesintileri — bunlar yıl sonu hesaplayıp umduğunuz rakamların üzerinden geçmekle olmuyor. Her hesaplama döngüsünde, o dönemde geçerli olan oranlar ve ücret tavanlarına karşı göz önünde bulundurulmalıdır.

Yasal oranları, versiyonlanmış yapılandırma olarak modelledik:

// config/statutory/national_insurance.php
return [
    => [
        => 0.12,
        => 0.138,
        => 967, // haftalık
        => 123,
    ],
    ];
Geniş ekran moduna geç

Geniş ekran modundan çık

Oranlar değiştiğinde, yeni bir giriş ekliyoruz. Geçmişteki bordro işlemleri, o dönemde geçerli olan oranları kullanıyor — hesaplama, yıllar sonra tekrarlanabilir ve veritabanı bugünün oranlarını bilmek zorunda değil.




Denetim İzleme Problemi

İK verisi değişiklikleri kalıcı ve değiştirilemez olmalıdır. Bir çalışanın maaş değişikliği, bir izin onayı, bir ödeme yapıldığında — bunlardan herhangi biri daha sonra sorgulanırsa, düzenlenemez bir kaydınız olmalıdır.

Standart Laravel model olayları bir günlük tabloya yazar, ancak bu tablo, veritabanına erişimi olan herkes tarafından düzenlenebilir.

Bunu yalnızca ekleme ile çözmek için ve bir hash zinciri kullanarak:

class AuditEntry extends Model
{
    public $timestamps = false;

    // update() veya delete() yöntemleri yok
    protected static function booted(): void
    {
        static::updating(fn() => throw new \Exception());
        static::deleting(fn() => throw new \Exception());
    }
}
Geniş ekran moduna geç

Geniş ekran modundan çık

Her giriş, bir öncekinin hash’ini içerir. Herhangi bir kaydı bozmak, zinciri kırar — ayrı bir bütünlük hizmetine ihtiyaç duymadan tespit edilebilir olur.




Nasıl Farklı Yapardık

İzin modeliyle başlamak. Özellikleri önce tasarladık ve erişim denetimini sonradan ekledik. Alan düzeyinde izinleri mevcut bir kod tabanına geriye dönük olarak eklemek zor bir süreçtir. Erişim kontrol matrisinizi ilk geçişinizden önce tanımlayın.

Bildirim sistemini sıfırdan inşa etmeyin. In-app bir bildirim sistemi geliştirmek için haftalar harcadık, bu da aslında Laravel Bildirimları’nın basit bir versiyonuydu ancak özel bir arayüz ile. Laravel Bildirimları ile bir veritabanı kanalını ve ince bir frontend’i çoğu şey için yeterlidir.

API’nizi başından itibaren versiyonlayın. REST API’ye versiyonlama eklemesi, iki dış entegrasyon zaten üretimdeyken gerçekleştirdik. Geçiş yönetilebilir fakat gereksizdi.


Ürün canlı. Benzer bir şey üzerinde çalışıyorsanız veya bu kararlarla ilgili sorularınız varsa, yorumlar açık.


Laravel tabanlı ürünler geliştiriyoruz Syftnex. İK & Ödeme platformumuz, mimarinin işleyişini görmek isterseniz, demo için hazır.

Kaynak: Orijinal Makale

Contents
  • Çok Kiracılılık Kararı
  • Modüler Mimari — Doğru Yaptığımız Kısım
  • Ödeme Hesaplama Problemi
  • Yasal Uyum Rapor Değildir
  • Denetim İzleme Problemi
  • Nasıl Farklı Yapardık
Laravel 13 Derinlemesine İnceleme: Her Yeni Özellik ve Değişiklik ile Kodu Örnekleme
Amazon TV’ler artık Zoom aramaları yapacak – ancak çok önemli bir kit parçasına ihtiyacınız olacak
Etkili Bir Kahraman Bölümü Oluşturma: UX, SEO ve Dönüşümü Artırma Yöntemleri
İngiltere’deki En İyi Laravel Geliştirme Şirketleri
En Yaygın 3 .env Sızıntısı ve Bunlardan Nasıl Korunulur
Bu Makaleyi Paylaş
Facebook Bağlantıyı Kopyala Yazdır
Paylaş
Önceki Makale Final Fantasy 7 Dünyasında Keşfedilecek 22 Yeni Ekran Görüntüsü
Sonraki Makale Kripto Para Piyasasında Sert Düşüş: Bitcoin ve Ether FTX Krizinden Beri En Kötü Haftayı Geçirdi

Sanal Medya

FacebookBeğen
452Takip Et
PinterestSabitle
237Takip Et

Son Eklenenler

Anthropic Yeni Modellerine Erişimi Durdururken Hindistan’ın AI Geleceği Tartışılıyor
Genel
Meta’nın Beijing’e tepki olarak 2 milyar dolarlık anlaşmayı geri çektiği iddia edildi
Yapay Zeka
Mumbai’de Web Geliştirme Hizmetleri: HTML, CSS, PHP, Laravel, React ve Next.js
Yazılım
SteelSeries’ten Beklenen Eğlenceli South Park Oyun Aksesuarı
Oyun
Amazon güvenlik araştırması Beyaz Saray’ın Anthropic Fable yasağına neden oldu
Liste
Eski çalışan, eski işvereni hedef alan siber saldırılarla hapse girdi!
Siber Güvenlik
//

Siber güvenlik, yapay zeka ve savunma sanayiinden; finans ve sinema dünyasına uzanan geniş bir yelpaze. Teknomers; teknoloji, strateji ve yazılım dünyasını sade bir dille sizlerle buluşturuyor.

Kurumsal

  • Hakkımızda
  • Gizlilik politikası
  • Tanıtım Yazısı ve Backlink Hizmeti

Kategoriler

  • Teknoloji
  • Oyun
  • Sinema
  • Siber Güvenlik
  • Bilim
  • Finans
  • Dünyadan Güncel Haberler

Populer

  • TV'de Ücretsiz İzlenebilen Şifresiz Erotik Kanallar (2025 Güncel Frekans Listesi)

  • The Last of Us PC Kontrolleri: Hızlı Silah Değiştirme ve Tüm Tuşlar (2025)

  • Hogwarts Legacy'de Odaklanma İksiri Nasıl Yapılır?

Teknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor HaberleriTeknomers | Dünyadan Güncel Teknoloji | Oyun | Müzik | Film | Spor Haberleri
Bizi Takip Et
© 2026 Teknomers. All Rights Reserved.
Welcome Back!

Sign in to your account

Kullanıcı Adı veya E-posta Adresi
Şifre

Şifrenizi mi unuttunuz?