User aggregate’ı Draft durumunda oluşturur, bir OTP üretir ve SMS ile gönderir; kullanıcı kodu doğrulayınca telefon “verified” işaretlenir. Bu akış tamamen lokal (User aggregate) çalışır — Keycloak’a gerek yoktur.
İlgili dosyalar:
src/DiyanetCleanArchitecture.API/Controllers/AuthController.cs ·
Application/Features/Authentication/Website/Commands/SignUpUser/* ·
Domain/Services/UserRegistrationService.cs ·
Domain/AggregatesModel/UserAggregate/User.cs ·
Application/DomainEventHandlers/UserOtpGenerated/SendOtpSmsDomainEventHandler.csSequence — kayıt (sign-up)
Adım adım
Controller — ince giriş noktası
AuthController.SignUp yalnızca komutu MediatR’a iletir. Başarıda 201 Created döner.SignUpUserCommand): Phone (zorunlu), FullName?, Consents?. Validator Phone için MustBeValidMobilePhone(), FullName için boş olamaz + max 100 karakter kuralını uygular.Domain service — uniqueness + factory
Handler önce
UserRegistrationService.RegisterNewUserAsync çağırır. Bu servis telefon/e-posta global benzersizliğini spec ile kontrol eder ve geçerse new User(...) döner:“Doğrulanmamış ama var olan” telefon ayrı mesajla ele alınır: kullanıcı kayıt yerine giriş akışına yönlendirilir.
DomainException global exception handler tarafından 400’e çevrilir.Aggregate — Draft kullanıcı + OTP challenge
User’ın internal ctor’u durumu Draft yapar ve UserCreatedDomainEvent biriktirir. Handler ardından OTP üretip aggregate’e ekler:User.AddOtpChallenge içeride bir UserOtpChallenge (SMS için 1 dk geçerli) oluşturur ve UserOtpGeneratedDomainEvent biriktirir:CanRequestOtp, Draft veya Active durumlar için true’dur — yeni kayıt Draft olduğundan geçer.Kaydet — event dispatch + SMS
SaveEntitiesAsync, SaveChanges’ten sonra biriken domain event’leri dispatch eder. UserOtpGeneratedDomainEvent’i SendOtpSmsDomainEventHandler dinler:IOtpSmsService implementasyonu (OtpSmsService) NetGSM OTP endpoint’ine Phone.ToNetGsmFormat() ile gönderir. Bkz. SMS Servisi.Challenge token üret + dön
Handler aktif challenge’ı bulur ve sonraki adımda kullanılacak kısa ömürlü challenge token’ı üretir:
ChallengeToken, OTPChallenge JWT şemasıyla imzalanır ve userId + challengeId’yi taşır. SPA bunu saklar; SMS kodu girilince verify-otp çağrısında Authorization header’ında gönderir.Aktivasyon — VerifyOtp
Kullanıcı SMS kodunu girer. SPA, challenge token’ı bearer olarak taşıyan
verify-otp çağrısı yapar:VerifyOtpCommandHandler, userId/challengeId’yi IOtpChallengeContext üzerinden (challenge token’dan) okur, kodu doğrular, telefonu “verified” işaretler ve oturum başlatır:User.VerifyChallenge başarılıysa IsPhoneNumberVerified = true yapar ve UserPhoneNumberVerifiedDomainEvent yayar. Doğrulama detayları için OTP / TOTP Akışı.Hata senaryoları
| Durum | Nerede | Sonuç |
|---|---|---|
| Telefon zaten kayıtlı (doğrulanmış) | UserRegistrationService | DomainException → 400 |
| Telefon var ama doğrulanmamış | UserRegistrationService | DomainException (“giriş yapınız”) → 400 |
| Geçersiz telefon formatı | SignUpUserCommandValidator | ValidationException → 422 + errors |
| SMS gönderilemedi (NetGSM) | OtpSmsService | SmsServiceException → 503 (kayıt yine de oluşmuştur; ResendOtp ile tekrar denenebilir) |
| Yanlış / süresi dolmuş OTP kodu | VerifyOtpCommandHandler | ApplicationException → 400 |
İlgili
OTP / TOTP Akışı
VerifyOtp, ResendOtp ve TOTP detayları.
SMS Servisi
NetGSM entegrasyonu, test numaraları, encoding.
User Aggregate
Durumlar, çocuk entity’ler, metodlar.
Domain Event'ler
AddDomainEvent → dispatch mekaniği.