Skip to main content
Bildirim servisi src/DiyanetCleanArchitecture.Infrastructure.Services.Notification projesindedir. Admin panelindeki kullanıcılara gerçek-zamanlı bildirim push etmek için Server-Sent Events (SSE) kullanır. Transport-agnostic bir broadcaster arayüzü etrafında kuruludur.

Broadcaster arayüzü

Default implementasyon InMemoryAdminNotificationBroadcaster’dır (singleton, tek API instance için). Her SSE bağlantısı bir Channel<NotificationEnvelope> tutar.

Rol-hedefli yayın

PublishAsync, NotificationEnvelope.TargetRoleId alanına göre filtre uygular: null ise tüm personele, dolu ise yalnızca o role sahip abonelere yazar. Yazım bekletmezDropOldest ile en eski mesaj düşürülür:
Abonelik kanalı kapasite 50 ve DropOldest ile sınırlıdır — yavaş okuyan client backpressure yaratmasın diye:
Kapasite 50 yeterlidir: sayfa açılışında REST list endpoint’i tam state’i tazelediği için, SSE yalnızca “canlı” delta’ları taşır.

NotificationEnvelope — transport modeli

Broadcaster, Domain entity’si yerine ince bir transport tipi taşır (Infrastructure’ın Application/Domain’e bağımlı kalmaması için):

HMAC stream-token

EventSource (tarayıcı SSE API’si) Authorization: Bearer header gönderemez. Bu nedenle frontend, mevcut Keycloak token’ı ile kısa-ömürlü bir capability token alır ve SSE bağlantısını query param ile açar. Token üretici HmacStreamTokenService’tir:
Token formatı base64url(payload).base64url(hmac) — JWT’ye benzer ama header yok (tek algoritma, HMAC-SHA256). Payload {"sub":"...","roles":[1,2],"exp":...} taşır. Doğrulamada imza FixedTimeEquals ile sabit-zamanlı karşılaştırılır ve exp kontrol edilir.
StreamTokenSecret boş ya da 32 karakterden kısa ise servis runtime’da rastgele 64 byte anahtar üretir ve uyarı loglar. Bu yalnızca geliştirme/test için kabul edilebilir; multi-instance prod’da paylaşılan secret zorunludur (aksi halde her instance farklı anahtarla token üretir/doğrular).
Bu token yalnızca SSE stream’ini açar; REST endpoint’lerini açamaz — sızıntı riskini azaltır (Keycloak access token kullanılmaz).

Application tarafı — AdminNotification aggregate

Bildirim oluşturmanın tek giriş noktası Application katmanındaki IAdminNotificationService.DispatchAsync’tir. Domain event handler’lar (MediatR INotificationHandler) bunu inject eder:
İmplementasyon, AdminNotification aggregate’ini aynı UnitOfWork ile DB’ye yazar; SaveEntitiesAsync sonrası NotificationEnvelope üretip broadcaster’a push eder (bağlı client’lar anında alır). Örnek tetikleyiciler: NotifyAdminsUserInvitedDomainEventHandler, NotifyAdminsEtkinlikKontenjanDolduDomainEventHandler, NotifyAdminsCitizenAccountDeactivatedDomainEventHandler.

Heartbeat

SSE bağlantısının canlı kalması için periyodik comment-line gönderilir. Frekans StreamHeartbeatSeconds (default 25 sn) ile ayarlanır ve nginx proxy_read_timeout (default 60 sn) altında kalmalıdır. Controller bunu dar bir INotificationStreamOptions abstraction’ı üzerinden okur.

Multi-instance — henüz desteklenmiyor

InMemoryBroadcaster: false ayarı multi-instance (Redis backplane) senaryosu içindir ama Redis impl’i henüz yoktur. Startup’ta bilinçli olarak NotSupportedException fırlatılır (fail-fast):

Config — Services:Notification

bool
default:"true"
true → in-memory; false → (NYI) Redis backplane, startup’ta exception.
int
default:"25"
SSE heartbeat frekansı (proxy timeout altında kalmalı).
string
HMAC anahtarı, min 32 karakter. Boş → runtime rastgele (sadece dev).
int
default:"300"
Stream-token ömrü (saniye).

DI kaydı

Domain Events

Bildirimleri tetikleyen domain event’ler ve handler’lar.

Caching

Multi-instance senaryosunda kullanılan Redis backplane deseni.