Appearance
Service Architecture
The Notification service follows the existing Clean Architecture style used across InfrastructureServices:
text
Notifications/
|-- Notification.Apis
|-- Notification.Application
|-- Notification.Domain
`-- Notification.InfrastructureLayer Responsibilities
| Layer | Responsibility |
|---|---|
Notification.Apis | ASP.NET Core entry point, controllers, middleware setup, appsettings, templates, WhatsApp assets. |
Notification.Application | CQRS handlers, consumers, orchestration, channels, providers abstractions, rendering, retry, device token logic. |
Notification.Domain | Entities, enums, value objects, unit-of-work abstractions. |
Notification.Infrastructure | EF Core DbContext, mappings, migrations, interceptors, context middleware, provider infrastructure, WhatsApp T2 clients. |
Startup Flow
Notification.Apis/Program.cs composes the service:
- Loads custom JSON config.
- Adds shared web services.
- Adds
AddNotificationApplication(...). - Adds
AddNotificationInfrastructure(...). - Adds Redis cache.
- Configures Hangfire and background job services.
- Registers localization, health checks, logging, and API key middleware.
- Builds the app.
- Configures web middleware through
ConfigureNotificationWeb(...). - Seeds database defaults.
- Applies pending EF Core migrations through
EnsureCreated(). - Runs the app.
Current service bootstrapping disables shared API middleware and authorization in the explicit options passed to shared web setup. Do not assume endpoint-level auth is active unless deployment or future code changes enable it.
Request Context Middleware
UseNotificationContext() reads notification headers and stores:
- subdomain
- user id
- source system
The context is consumed later by:
- channel configuration lookup
- device token commands and queries
- notification center queries
- WhatsApp provisioning
Application Dependency Injection
AddNotificationApplication(...) registers:
- AutoMapper profiles
- auto-registered services
- FluentValidation validators
- WhatsApp provisioning options
- MassTransit service bus consumers
- mediator handlers
FirebaseAppManagerAdminNotificationReaderNotificationExecutionPipelineNotificationOrchestrator
AddNotificationInfrastructure(...) registers:
NotificationDbContextINotificationUnitOfWork- notification metadata and audit interceptors
- notification context holder and middleware
- default seeder
- webhook configuration service
- T2 WhatsApp client and credential services
- WhatsApp template provisioning/sync services
- Hangfire job classes
Orchestration
NotificationOrchestrator receives a NotificationPayload, determines the channel by concrete payload type, finds the registered INotificationChannel, and calls SendAsync.
Execution Pipeline
NotificationExecutionPipeline standardizes persistence and result handling:
- Mark request as
Processing. - Add
NotificationRequest. - Add initial
NotificationDeliveryrows provided by the channel. - Save changes.
- Run channel-specific
sendAction. - On success:
- store provider request/response payloads on deliveries
- mark deliveries as
Sent - mark request as
Sent
- On failure:
- store provider request/response payloads when available
- mark deliveries as
Failed - mark request as
Failed - increment request retry count
Push is a special case: the channel creates a request per user and the push messaging service creates device-token deliveries after resolving devices.
Channels
| Channel class | Payload | Provider path |
|---|---|---|
EmailChannel | EmailPayload | Config lookup, template rendering, IEmailProviderFactory, SMTP or Azure Graph. |
SmsChannel | SmsPayload | Phone normalization, config lookup, ISmsProviderFactory, Generic HTTP SMS. |
PushChannel | PushPayload | Request per user, device resolution, FCM provider. |
WhatsAppChannel | WhatsAppPayload | Template lookup, approved T2 template id, Msegat/T2 provider, status-check job. |
Configuration Lookup
NotificationConfigProvider resolves active NotificationChannelConfig rows by:
- channel type
- provider type when requested
- application target when requested
- tenant subdomain or source system
The provider caches materialized configs for one hour using a versioned cache key.
Metadata Extraction
NotificationMetadataInterceptor runs during EF Core SaveChanges for added NotificationRequest rows. It extracts searchable metadata from the persisted payload and stores it in NotificationRequest.MetadataJson.
This supports Notification Center filtering and display without each channel duplicating metadata persistence logic.
Extension Points
To add a new channel:
- Add a contract payload in
Microtec.Notifications.Contracts. - Add a
JsonDerivedTypemapping onNotificationPayload. - Add a
NotificationChannelTypevalue if needed. - Implement
INotificationChannel. - Register provider factory/config support.
- Add persistence metadata extraction.
- Add API endpoint and client endpoint mapping.
- Add retry payload deserializer.
- Add integration and serialization tests.
To add a provider for an existing channel:
- Add provider enum value.
- Add credential DTO and value object.
- Add credential command/query support.
- Extend the provider factory.
- Keep channel behavior unchanged unless the channel needs a new capability.