Skip to content

GrydNotifications Module

GrydNotifications is a multi-channel notification module for .NET applications. It provides a unified pipeline for sending Email, Push (FCM), and In-App (SignalR) notifications with Scriban templates, retry policies, dead letter queue, scheduling, multi-tenancy, and observability — all following Clean Architecture.

✨ Features

FeatureDescription
📧 Email (SMTP + SendGrid)MailKit-based SMTP with SendGrid as alternative provider
🔔 Push NotificationsFirebase Cloud Messaging (FCM) with device token management
🔔 In-App NotificationsReal-time delivery via SignalR with read/unread, categories, and expiration
📝 Scriban TemplatesDatabase-stored templates with locale and tenant fallback, variable detection
🔁 Retry + Dead LetterConfigurable per-channel retry with exponential backoff and jitter
SchedulingSchedule notifications for future delivery, with cancel support
🏢 Multi-TenancyAutomatic tenant isolation across all channels and templates
📊 ObservabilityOpenTelemetry metrics, activity tracing, and health checks
🔌 Provider-AgnosticSwap email/push providers without changing application code
465 TestsComprehensive test coverage across all 5 layers

📦 Packages

GrydNotifications is modular — use only what you need:

📦 GrydNotifications                     # Meta-package (includes all)
├── GrydNotifications.Core               # Abstractions, entities, DTOs, enums
├── GrydNotifications.Application        # CQRS handlers, validators, MediatR
├── GrydNotifications.Infrastructure     # EF Core, MailKit, Scriban, SignalR sender
├── GrydNotifications.Scheduling         # GrydJobs integration (optional)
└── GrydNotifications.API                # REST controllers, SignalR hub, health checks

🚀 Quick Start

1. Install the meta-package

bash
dotnet add package GrydNotifications

2. Register services

csharp
builder.Services.AddGrydNotifications(options =>
{
    options.UsePostgreSqlStorage(
        builder.Configuration.GetConnectionString("Notifications")!);

    // Email (SMTP via MailKit)
    options.Email.DefaultFrom = "noreply@myapp.com";
    options.Email.SmtpHost = "smtp.myapp.com";
    options.Email.SmtpPort = 587;
    options.Email.SmtpUseSsl = true;
    options.Email.SmtpUsername = "apikey";
    options.Email.SmtpPassword = builder.Configuration["Smtp:Password"]!;

    // In-App (SignalR)
    options.InApp.Enabled = true;
    options.InApp.EnableSignalR = true;
});

// Optional: health checks
builder.Services.AddGrydNotificationsHealthChecks();

3. Configure middleware

csharp
app.UseGrydNotifications(); // Maps SignalR hub at /hubs/notifications

// Apply migrations (Development only)
if (app.Environment.IsDevelopment())
    await app.ApplyGrydNotificationsMigrationsAsync();

4. Send your first notification

csharp
public class OrderService
{
    private readonly IMediator _mediator;

    public OrderService(IMediator mediator) => _mediator = mediator;

    public async Task PlaceOrderAsync(Order order, CancellationToken ct)
    {
        // Send via unified pipeline
        await _mediator.Send(new SendNotificationCommand
        {
            Channel = NotificationChannel.Email,
            Recipients = [new RecipientDto { Address = order.Email }],
            Subject = "Order Confirmed",
            HtmlBody = $"<h1>Order #{order.Id} confirmed!</h1>"
        }, ct);

        // Or send directly via the email shortcut
        await _mediator.Send(new SendEmailCommand
        {
            To = [order.Email],
            Subject = "Order Confirmed",
            HtmlBody = $"<h1>Order #{order.Id} confirmed!</h1>"
        }, ct);
    }
}

5. Use templates

csharp
// Send using a Scriban template stored in the database
await _mediator.Send(new SendNotificationCommand
{
    Channel = NotificationChannel.Email,
    Recipients = [new RecipientDto { Address = "user@example.com" }],
    TemplateSlug = "order-confirmation",
    TemplateData = new Dictionary<string, object>
    {
        ["order_id"] = order.Id,
        ["customer_name"] = order.CustomerName,
        ["total"] = order.Total
    }
}, ct);

🏗️ Architecture

┌─────────────────────────────────────────────────────────────────┐
│                    GrydNotifications.API                         │
│  NotificationsController | TemplatesController | UserNotifs      │
│  NotificationHub (SignalR) | HealthCheck                         │
├─────────────────────────────────────────────────────────────────┤
│                 GrydNotifications.Application                    │
│  Commands → Handlers → INotificationSender/ITemplateRenderer     │
│  Queries → Handlers → INotificationRepository/ITemplateStore     │
│  Validators (FluentValidation) | MediatR Pipeline                │
├─────────────────────────────────────────────────────────────────┤
│                GrydNotifications.Infrastructure                  │
│  MailKit SMTP │ SendGrid │ FCM │ SignalR InApp │ Scriban Engine  │
│  EF Core (PostgreSQL) │ Queue (Channel<T>) │ Polly Retry        │
├─────────────────────────────────────────────────────────────────┤
│                   GrydNotifications.Core                         │
│  Entities │ Abstractions │ DTOs │ Enums │ Configuration          │
└─────────────────────────────────────────────────────────────────┘

📖 Documentation

Released under the MIT License.