Skip to main content
Aggregate’in internal constructor’ı, oluşturmanın kontrollü olmasını sağlar (bkz. Aggregate’ler). Ama bir kullanıcı oluşturmadan önce “bu e-posta zaten var mı?” gibi kontroller yapmak gerekir — bu kontroller tek bir aggregate örneğinin sorumluluğu değildir. İşte burada factory ve domain service devreye girer.

Factory

Karmaşık oluşturma mantığını kapsüller: uniqueness kontrolü, dış IdP eşleştirme, doğru ctor seçimi. Sonuç: geçerli bir aggregate.

Domain Service

Tek bir aggregate’e doğal olarak ait olmayan iş kurallarını barındırır (genelde birden fazla aggregate’i ya da repository’yi ilgilendirir).

IUserFactory — kullanıcı oluşturma fabrikası

User’ın ctor’u internal olduğu için, dışarıdan oluşturmanın tek meşru yolu factory’dir. Arayüz, tüm kayıt senaryolarını kapsar:
İki tür metot vardır:
  • CreateWith... — sıfırdan kayıt (telefon veya e-posta ile). Uniqueness başarısızsa DomainException fırlatır.
  • GetOrCreateFrom... — dış IdP (Google/Meta/Keycloak) login akışı. Mevcut kullanıcı varsa bağlar, yoksa oluşturur.

Uniqueness kontrolü ile oluşturma

Factory, User’ı oluşturmadan önce IUserUniquenessChecker’a danışır. internal ctor sayesinde kimse bu kontrolü atlayarak User oluşturamaz — geçersiz durum domain dışına çıkamaz.

Dış IdP akışı — GetOrCreateFromExternalAsync

Google ve Meta ortak bir özel yardımcıyı kullanır. Eşleştirme önceliği üç adımdır:
1

Provider + sub eşleşmesi

(provider, externalId) ikilisi daha önce bağlanmışsa, o kullanıcı bulunur ve linkLogin ile display name tazelenir.
2

E-posta eşleşmesi

Aynı e-posta başka bir IdP’den gelmiş olabilir. Varsa mevcut kullanıcıya bu provider da eklenir (multi-provider) ve e-posta doğrulanmış sayılır.
3

Yeni kullanıcı

Hiçbir eşleşme yoksa yeni User oluşturulur, IdP bağlanır, e-posta varsa VerifyEmail() çağrılır.
linkLogin, provider’a göre değişen bağlama davranışını parametre olarak alır:
ICitizenFactory, IUserFactory ile birebir aynı arayüze sahiptir (vatandaş portalı için). Aynı oluşturma deseni iki ayrı aggregate’e tutarlı şekilde uygulanır.

Domain Service: IUserUniquenessChecker

Bir kullanıcının e-posta/telefon/dış kimlik açısından benzersiz olup olmadığı, tek bir User örneğinin bilemeyeceği bir kuraldır — tüm kullanıcı kümesine bakmak gerekir. Bu yüzden bir domain service’tir.
Üç-durumlu UniquenessResult, factory’nin kullanıcıya anlamlı mesaj verebilmesini sağlar: “zaten var, giriş yap” ile “var ama doğrulanmamış, doğrulamayı tamamla” farklı yönlendirmeler gerektirir.

Domain Service: UserRegistrationService

Daha basit bir kayıt yolu sunan, repository üzerinden doğrudan uniqueness kontrolü yapıp User döndüren bir domain service:

Ne zaman factory, ne zaman domain service?

Bir aggregate’i oluşturmak ek mantık gerektiriyorsa (uniqueness, dış IdP eşleştirme, hangi ctor/overload seçileceği, başlangıç event’leri) factory uygundur. Çıktısı her zaman geçerli bir aggregate’tir.
İş kuralı birden fazla aggregate’i, tüm bir koleksiyonu (uniqueness) veya repository sorgusunu ilgilendiriyorsa domain service’e koyun. Stateless’tır; durumu aggregate’lerde bırakır.
Pratikte UserFactory, oluşturma orkestrasyonunu yapar ve kural değerlendirmesi için IUserUniquenessChecker domain service’ine delege eder. Sorumluluklar net ayrılır: factory “nasıl oluşturulur”, service “izin var mı”.
Ne factory ne de domain service, kaydı persist etmez. Onlar yalnızca geçerli aggregate’i döndürür; repository’ye ekleme ve UnitOfWork.SaveEntitiesAsync çağrısı Application katmanındaki command handler’ın işidir. Böylece domain, transaction sınırından habersiz kalır.

Sonraki adımlar

Aggregate'ler

internal ctor ve User davranış metotları.

Domain Event'ler

Oluşturmada yayılan UserCreatedDomainEvent.

SharedKernel

IRepository, IReadRepository ve specification altyapısı.

Domain'e genel bakış

Katmanın rolü ve klasör yapısı.