Skip to content

Service Architecture

The Notification service follows the existing Clean Architecture style used across InfrastructureServices:

text
Notifications/
|-- Notification.Apis
|-- Notification.Application
|-- Notification.Domain
`-- Notification.Infrastructure

Layer Responsibilities

LayerResponsibility
Notification.ApisASP.NET Core entry point, controllers, middleware setup, appsettings, templates, WhatsApp assets.
Notification.ApplicationCQRS handlers, consumers, orchestration, channels, providers abstractions, rendering, retry, device token logic.
Notification.DomainEntities, enums, value objects, unit-of-work abstractions.
Notification.InfrastructureEF Core DbContext, mappings, migrations, interceptors, context middleware, provider infrastructure, WhatsApp T2 clients.

Startup Flow

Notification.Apis/Program.cs composes the service:

  1. Loads custom JSON config.
  2. Adds shared web services.
  3. Adds AddNotificationApplication(...).
  4. Adds AddNotificationInfrastructure(...).
  5. Adds Redis cache.
  6. Configures Hangfire and background job services.
  7. Registers localization, health checks, logging, and API key middleware.
  8. Builds the app.
  9. Configures web middleware through ConfigureNotificationWeb(...).
  10. Seeds database defaults.
  11. Applies pending EF Core migrations through EnsureCreated().
  12. 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
  • FirebaseAppManager
  • AdminNotificationReader
  • NotificationExecutionPipeline
  • NotificationOrchestrator

AddNotificationInfrastructure(...) registers:

  • NotificationDbContext
  • INotificationUnitOfWork
  • 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:

  1. Mark request as Processing.
  2. Add NotificationRequest.
  3. Add initial NotificationDelivery rows provided by the channel.
  4. Save changes.
  5. Run channel-specific sendAction.
  6. On success:
    • store provider request/response payloads on deliveries
    • mark deliveries as Sent
    • mark request as Sent
  7. 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 classPayloadProvider path
EmailChannelEmailPayloadConfig lookup, template rendering, IEmailProviderFactory, SMTP or Azure Graph.
SmsChannelSmsPayloadPhone normalization, config lookup, ISmsProviderFactory, Generic HTTP SMS.
PushChannelPushPayloadRequest per user, device resolution, FCM provider.
WhatsAppChannelWhatsAppPayloadTemplate 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:

  1. Add a contract payload in Microtec.Notifications.Contracts.
  2. Add a JsonDerivedType mapping on NotificationPayload.
  3. Add a NotificationChannelType value if needed.
  4. Implement INotificationChannel.
  5. Register provider factory/config support.
  6. Add persistence metadata extraction.
  7. Add API endpoint and client endpoint mapping.
  8. Add retry payload deserializer.
  9. Add integration and serialization tests.

To add a provider for an existing channel:

  1. Add provider enum value.
  2. Add credential DTO and value object.
  3. Add credential command/query support.
  4. Extend the provider factory.
  5. Keep channel behavior unchanged unless the channel needs a new capability.

Internal Documentation — Microtec