Tapis.Core.Reminders
1.0.5
dotnet add package Tapis.Core.Reminders --version 1.0.5
NuGet\Install-Package Tapis.Core.Reminders -Version 1.0.5
<PackageReference Include="Tapis.Core.Reminders" Version="1.0.5" />
<PackageVersion Include="Tapis.Core.Reminders" Version="1.0.5" />
<PackageReference Include="Tapis.Core.Reminders" />
paket add Tapis.Core.Reminders --version 1.0.5
#r "nuget: Tapis.Core.Reminders, 1.0.5"
#:package Tapis.Core.Reminders@1.0.5
#addin nuget:?package=Tapis.Core.Reminders&version=1.0.5
#tool nuget:?package=Tapis.Core.Reminders&version=1.0.5
Tapis.Core.Reminders
Notlar ve hatırlatıcılar modülünün sözleşme paketi. Her ürün (ServiceManagement, HostelManagement) bu paketi kendi API'sinde barındırır ve kendi tenant veritabanında kendi tablolarını tutar. Paket tenant çözümlemesi, kimlik doğrulama ya da ürün varlıkları bilmez; ihtiyaç duyduğu her şeyi port üzerinden alır.
1.0.2'den beri uygulama servisleri ürünün içindedir (kullanıcı kararı S1, 2026-10-13). Paket not, hatırlatıcı,
bildirim ve ek servislerinin yalnız arayüzünü verir; implementasyon ürünün kendi repository/UnitOfWork
katmanını kullandığı için ürün projesinde yaşar. Paket container'dan DbContext çözmez.
İçerik
| Alan | Ne yapar |
|---|---|
Entities/ |
Note, Reminder, ReminderChecklistItem, ReminderAlarm, Notification, Attachment — hepsi OwnerUserId taşır |
Persistence/ |
ApplyRemindersModel(ModelBuilder) ile tablolar ürünün kendi DbContext'ine katılır (xmin damgası ve denetim interceptor'ı böylece otomatik gelir) |
Services/ |
servis arayüzleri (INoteService, IReminderService, INotificationService, IAttachmentService), tekrar kuralı (RecurrenceService), alarm işleyici (ReminderDispatchService) ve ek eşlemesi (AttachmentMap) |
RemindersLocalizationConsts |
ileti ve işlem anahtarları (İngilizce); metinler ürünün kaynak dosyalarında, ISharedLocalizer ile çözülür |
Scheduling/ |
sonraki alarma kadar uyuyan zamanlayıcı döngüsü ve sinyal |
Hubs/ |
RemindersHub — kullanıcı bazlı grup, NotificationCreated / UnreadCount olayları |
Controllers/ |
api/Notes, api/Reminders, api/ReminderAttachments, api/ReminderNotifications |
Ports/ |
IFileStorage, IReminderDbContextFactory, IReminderSchedulerSignal, IReminderRealtimeNotifier, IReminderClock, IReminderRecipientResolver |
Services/RecordAccess |
erişim kuralının tek kaynağı (aşağıda "İşletme görünürlüğü") |
Ürüne bağlama
// Program.cs
builder.Services.AddRemindersModule(builder.Configuration);
builder.Services.AddScoped<IReminderDbContextFactory, ServiceManagementReminderDbContextFactory>();
// Uygulama servisleri ürünün kendisindedir (S1): paket yalnız arayüzü tanımlar.
builder.Services.AddScoped<INoteService, NotService>();
builder.Services.AddScoped<IReminderService, HatirlaticiService>();
builder.Services.AddScoped<INotificationService, HatirlaticiBildirimService>();
builder.Services.AddScoped<IAttachmentService, HatirlaticiEkService>();
builder.Services.AddControllers().AddRemindersControllers();
...
app.MapRemindersModule(); // hub
// DbContext.OnModelCreating
builder.ApplyRemindersModel();
Yapılandırma Reminders bölümünden okunur (MaxSleepMinutes, MaxAttempts, RetryDelayMinutes, BatchSize,
IdleShutdownMinutes, Attachments:MaxSizeMb, Attachments:AllowedExtensions, Attachments:MaxFilesPerRecord,
Attachments:LocalRootPath).
Kurallar
- Uygulama servisi yazan ürün kendi
IUnitOfWork/repository'lerini kullanır,DbContext'i doğrudan açmaz; doğrulama FluentValidation validator'ıyla ürün tarafında yapılır (paket DTO'ları ürünün globalValidationFilter'ından geçer); kullanıcıya dönen her iletiISharedLocalizerileRemindersLocalizationConstsanahtarından çözülür. - Kayıtlar varsayılan olarak kişiseldir (
Visibility = Personal); işletme kayıtları için aşağıdaki bölüme bakın. Her not/hatırlatıcı sorgusuRecordAccesskuralından geçer, erişilemeyen kayıt olmayan kayıtla aynı 404'ü alır. Bildirimler her zamanOwnerUserId == benile süzülür. - Bildirim yalnız uygulama içidir: e-posta, SMS, WhatsApp gönderilmez ve bunlar için soyutlama yoktur.
- Ek dosyalar yalnız yetki denetimi yapan indirme ucundan akar; depolama anahtarı istemciye hiç verilmez.
- Tüm tarihler yerel saat (Europe/Istanbul) yazılır; modülde UTC kullanılmaz.
- Elle transaction yalnız ürünün yürütme stratejisinin içinde açılır. Ürünler PostgreSQL context'ini
EnableRetryOnFailure(3)ile kuruyor; EF, yeniden deneyen bir strateji altındaBeginTransaction'ıInvalidOperationExceptionile reddeder. Yeni bir transaction gerekiyorsa gövdedb.Database.CreateExecutionStrategy().ExecuteAsync(...)içine konur ve yeniden denenebilir yazılır (her denemedeChangeTracker.Clear()+ veriyi sıfırdan oku). 1.0.0'da alarm turu bu kuralı ihlal ettiği için zamanlayıcı PostgreSQL'de hiç çalışmadı; SQLite testleri yeniden denemediği için göstermedi (regresyon testi:AlarmYenidenDenemeStratejisiTests).
Bildirim listesi: görünürlük, arama, süzgeç (1.0.5)
Migration gerekmez (şema aynı). Bildirimler hâlâ yalnız alıcısınındır: OwnerUserId == ben tek erişim kuralıdır,
RecordAccess'in işletme kuralı bildirimlere uygulanmaz; hatırlatıcıyla ilişki satır eklemez, yalnız görünürlüğü
taşır ve (süzgeçte) eler.
NotificationDTO.Visibility(RecordVisibility?): kaynak hatırlatıcının şu anki görünürlüğü; hatırlatıcı silinmişse ya daReminderIdboşsanull(arayüz rozet göstermez). Alarmın anlık push DTO'sunda da dolu gelir.NotificationQueryDTO: mevcutSkip,Take,SadeceOkunmamisyanındaArama(string?, kırpılır, en çokNotificationQuery.MaxSearchLength= 100, başlık + metinde büyük/küçük harfe duyarsız) veGorunurluk(NotificationVisibilityFilter:All0,Personal1,Business2; hatırlatıcısı silinmiş bildirimler yalnızAll'da).NotificationQuery(Tapis.Core.Reminders.Services):ApplyFilter(hatirlaticilar, ownerUserId, sorgu)(owner + okunmamış + arama + görünürlük),Project(hatirlaticilar)(DTO +Visibility),NormalizeSearch,IsSearchValid,IsValidVisibilityFilter.
Ürün kontrol listesi (HostelManagement / ServiceManagement)
BildirimRepository.SayfaAsync(veINotificationService.ListAsync) kendiOwnerUserId == ben/SadeceOkunmamissüzgecini bırakıpbildirimler.ApplyFilter(hatirlaticilar, kullaniciId, sorgu)çağırır; toplam sayı bu süzülmüş sorgudan, sırala (okunmamışlar önce, sonraOlusturmaTarihiazalan) +Skip/TakesonraProject(hatirlaticilar)ile DTO'ya.hatirlaticilar= ürününSet<Reminder>()'ı (AsNoTracking).UnreadCountsayacı süzgeçsiz kalır (zil rozeti).- Validator:
AramaiçinNotificationQuery.IsSearchValid(ya daMaximumLength(100)),GorunurlukiçinIsInEnum; mesaj Türkçe,WithMessageile. Paketin FluentValidation bağımlılığı yoktur. /api-regen, Angular Bildirimler sayfası:visibilityrozeti (Kişisel/İşletme;null= rozet yok), arama kutusu, görünürlük süzgeci. Başka kullanıcının satırı hiçbir süzgeçle dönmez.- Ürün
CLAUDE.md'sindeki bildirim bölümü güncellenir.
İşletme görünürlüğü (1.0.4)
Note ve Reminder bir Visibility taşır: RecordVisibility.Personal (0, varsayılan, mevcut satırlar) ya da
Business (1). İşletme kaydını tenant'ın kimliği doğrulanmış her kullanıcı oturumu okur ve yazar (düzenleme,
silme, tamamlama, erteleme, alarm, alt madde, etiket, ek). İşletme hatırlatıcısının alarmı tenant'ın her aktif
kullanıcısına ayrı bildirim üretir. Kişisele geri almayı yalnız oluşturan (OwnerUserId) yapar; işletmeye alma
her yazarın hakkıdır. OwnerUserId yalnız oluşturmada yazılır, hiçbir güncelleme DTO'su onu taşımaz ve görünürlük
değişimi onu değiştirmez.
Pakette olanlar
RecordAccess(Tapis.Core.Reminders.Services):NoteReadable/NoteWritable,ReminderReadable/ReminderWritable,ChecklistItemAccessible,AlarmAccessible,NoteTagAccessible,AttachmentAccessible(ek, üst kaydı okunabiliyorsa okunur; ek + üst kayıt + kural tek sorguda),NoteFilter/ReminderFilter(Gorunurluksüzgeci),CanChangeVisibility,IsValidVisibility,IsOwner,RemoveNonOwnerNotificationsAsync. Boş/boşluk kullanıcı kimliği hiçbir satırla eşleşmez (işletme satırıyla da).IReminderRecipientResolver:ActiveUserIdsAsync(DbContext, ct)veDisplayNamesAsync(DbContext, ids, ct).ReminderDispatchServiceişletme hatırlatıcısında alıcıları tur başına bir kez, alarmıFiredyapan transaction'ın içinde çözer; her alıcıya birNotificationsatırı yazar, commit'ten sonra alıcı başına tek push yollar (mevcutt:{tenant}:u:{user}grubu; yeni grup,Clients.All/User/Othersyok; okunmamış sayaçları alıcı başına sorgu değil parça başına gruplu sorguyla). Çözümleyici kayıtsızsa ya da boş dönerse bildirim üretilmez (sahibe ya da başka birine düşülmez). ÇözümleyiciReminderDispatchService'e isteğe bağlı enjekte edilir.Notificationtekil indeksi(AlarmId, OwnerUserId);(ReminderId, FireAt)değişmedi.- Entity/EF:
Visibility(zorunlu, varsayılan 0), indekslerNotlar (Visibility, IsPinned)veHatirlaticilar (Visibility, IsCompleted, DueAt). - DTO: create/update/list/detail'de
Visibility; list/detail'deCreatedByName,IsMine; filtre DTO'larındaGorunurluk.
Faz 2 ürün kontrol listesi (HostelManagement / ServiceManagement)
- Migration:
Notlar.Visibility,Hatirlaticilar.Visibility(int, NOT NULL, default 0), iki yeni indeks veBildirimlertekil indeksininAlarmId→(AlarmId, OwnerUserId)olarak değişmesi (/add-migration). - Fail-closed kapı: servisler ClientToken çağıranlarını ve boş kullanıcı kimliğini kural değerlendirilmeden ÖNCE reddeder (mevcut FU1 denetimi); paket de boş kimlikte hiçbir şey eşleştirmez, ama bu ikinci savunmadır.
RecordAccessher yerde: not, hatırlatıcı, alt madde, alarm/erteleme/tamamlama, etiket, sayaç (Counts), arama, liste ve ek indirme/yükleme/silme sorguları. ElleOwnerUserId == userIdyazılmaz. Bildirim sorguları (liste, sayaç, okundu, silme)OwnerUserId == benolarak KALIR.- Çözümleyici:
IReminderRecipientResolver'ı ürünApplicationUser.Aktif == trueile, yalnız verilenDbContextüzerinde uygular (scopedDbContext/HttpContextenjekte etmez; arka plan yolunda ikisi de yoktur),DisplayNamesAsyncyalnız görünen adı döner. DI'a kaydedilir. - Görünen ad: list/detail DTO'larında
CreatedByName(çözümleyiciden, sayfa başına tek sorgu) veIsMine(OwnerUserId == ben) doldurulur. - Bildirim temizliği: işletme kaydı silinirken ya da
Personal'a çevrilirkenRecordAccess.RemoveNonOwnerNotificationsAsyncAYNISaveChanges'te çağrılır. - Görünürlük değişimi: güncelleme DTO'larında
VisibilityRecordVisibility?'dir;null= mevcut değer korunur (CanChangeVisibilityçağrılmaz, bildirim temizliği yapılmaz). Değer doluysa ve mevcuttan farklıysaRecordAccess.CanChangeVisibilityile denetlenir; işletmeden kişisele yalnız oluşturan.OwnerUserIdyalnız oluşturmada yazılır, update DTO/mapper onu hiç yazmaz.NoteCreateDTO/ReminderCreateDTOartıkNoteUpdateDTO/ReminderUpdateDTO'nun tabanı değildir (ortak taban*InputBaseDTO): mapper'lar buna göre güncellenir. - Validator:
VisibilityiçinIsInEnum(paketin FluentValidation bağımlılığı yoktur; validator'lar ürünündür). Oluşturmada eksik değerPersonalsayılır; güncellemedenullmevcut değeri korur (madde 7). - Denetim: ürünün denetim interceptor'ı
Visibilitydeğişimini zaten kapsar; ayrı kod gerekmez, doğrula. - Güvenlik dokümanları (
DevelopmentStandards):security/AUTHORIZATION.md, Object-level bölümüne Reminders istisnası: Personal = yalnızOwnerUserId; Business = tenant'ın kimliği doğrulanmış her kullanıcı oturumu okur+yazar; Personal'a geri alma yalnız oluşturan; sahip asla yeniden atanmaz; bildirimler yalnız sahibinindir; erişimin dışı 404; ClientToken reddedilir.security/TENANT-SECURITY.md, Background work bölümüne: işletme alarm dağıtımı yalnız turun tenantDbContext'ini ve döngününtenantId'sini kullanır, yedek alıcı yoktur, push yalnız mevcutt:{tenant}:u:{user}gruplarına gider.
- Docs / istemci: ürün
CLAUDE.md'si (Notlar & Hatırlatıcılar bölümü),/api-regen, Angular tarafı.
Bilinen sınırlama
Bir alarm turu çalışırken kayıt kişisele çevrilirse (ya da silinirse), o turun yazdığı sahip-dışı bildirim satırları temizlikten sonra kalabilir (yarış). Bu durumda sahip-dışı alıcılar o alarmın başlığını ve metnini bildirim listelerinde görmeye devam edebilir (kayıt az önceye kadar onlara zaten açıktı); satırı kullanıcı silebilir. Alıcı kimlikleri çözümleyiciden olduğu gibi alınır: kenarında boşluk olan kimlik atılır.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.EntityFrameworkCore (>= 10.0.10)
- Microsoft.EntityFrameworkCore.Relational (>= 10.0.10)
- Npgsql.EntityFrameworkCore.PostgreSQL (>= 10.0.0)
- Tapis.Core.Shared (>= 2.0.19)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
1.0.5 (migration gerekmez): bildirim listesi - NotificationDTO.Visibility (kaynak hatirlaticinin simdiki gorunurlugu, hatirlatici yoksa null), NotificationQueryDTO.Arama ve Gorunurluk (NotificationVisibilityFilter), NotificationQuery yardimcisi (Normalize/Validate/ApplyFilter/Project); bildirim erisimi yine yalniz OwnerUserId == ben. 1.0.4: Isletme notlari/hatirlatici (kirici, urun migration ister): RecordVisibility (Personal=0, Business=1) ve RecordVisibilityFilter; Note.Visibility, Reminder.Visibility (varsayilan 0) ve indeksler (Visibility, IsPinned) / (Visibility, IsCompleted, DueAt); Notification tekil indeksi AlarmId yerine (AlarmId, OwnerUserId). RecordAccess: erisim kuralinin tek kaynagi (NoteReadable/NoteWritable, ReminderReadable/ReminderWritable, alt madde/alarm/etiket/ek ifadeleri, liste suzgecleri, CanChangeVisibility, RemoveNonOwnerNotificationsAsync); bos kullanici kimligi hicbir satirla eslesmez. Yeni IReminderRecipientResolver (ActiveUserIdsAsync, DisplayNamesAsync): ReminderDispatchService isletme hatirlaticisinda her aktif kullaniciya ayri bildirim uretir (ayni transaction), commit sonrasi alici basina tek push; cozumleyici yoksa ya da bos donerse bildirim uretilmez. DTO'lara Visibility, CreatedByName, IsMine ve Gorunurluk suzgeci eklendi.