NainNotify is an event-driven notification gateway and worker engine built with .NET 10, Clean Architecture, and MassTransit. It decouples high-throughput HTTP ingestion from background processing, email rendering (responsive HTML with VML Outlook bulletproofing), and delivery provider execution, while streaming end-to-end domain lifecycle events directly to a reactive Vue 3 + TypeScript telemetry client via Server-Sent Events (SSE).
graph TB
subgraph ClientLayer["Frontend Client Layer"]
VueClient["Vue 3 + TypeScript Client<br/><code>Port 5378 / notify.naindev.com</code><br/><i>Guided Studio & Live Pipeline</i>"]
end
subgraph GatewayLayer["API Gateway Layer (:8120)"]
ApiGateway["ASP.NET Core API Gateway<br/><code>Rate Limiter & Honeypot Anti-Spam</code>"]
PrivacyMasker["PrivacyMasker<br/><i>Zero-PII Masking at Edge</i>"]
SSEHub["SSE Hub & Channels<br/><i>Real-time Telemetry Broadcast</i>"]
end
subgraph BusLayer["Messaging & Event Bus Transport"]
MassTransit["MassTransit Bus<br/><i>Dual-Mode: In-Memory / RabbitMQ</i>"]
ExQueue[("NotificationEvent Exchange<br/>& Lifecycle Streams")]
end
subgraph WorkerLayer["Worker Execution Engine"]
WorkerEngine["Background Worker Engine<br/><i>MassTransit Consumers</i>"]
TemplateEngine["EmailTemplateEngine<br/><i>VML-Bulletproof HTML & RFC 2822</i>"]
SmtpRelay["SMTP Dispatcher &<br/>Delivery Simulation Adapter"]
end
VueClient -->|"HTTP POST (Ingest)"| ApiGateway
ApiGateway --> PrivacyMasker
PrivacyMasker -->|"Publish Event"| MassTransit
MassTransit --> ExQueue
ExQueue -->|"Consume Batch"| WorkerEngine
WorkerEngine --> TemplateEngine
TemplateEngine --> SmtpRelay
WorkerEngine -->|"Lifecycle State Transitions<br/>(Accepted → Dispatched)"| MassTransit
MassTransit -->|"Push Lifecycle"| SSEHub
SSEHub -->|"Server-Sent Events (SSE < 20ms)"| VueClient
classDef client fill:#0047AB,stroke:#38BDF8,stroke-width:2px,color:#FFFFFF;
classDef gateway fill:#002B66,stroke:#80FF00,stroke-width:2px,color:#FFFFFF;
classDef bus fill:#060D1A,stroke:#38BDF8,stroke-width:2px,color:#FFFFFF;
classDef worker fill:#0A1629,stroke:#94A3B8,stroke-width:2px,color:#FFFFFF;
class VueClient client;
class ApiGateway,PrivacyMasker,SSEHub gateway;
class MassTransit,ExQueue bus;
class WorkerEngine,TemplateEngine,SmtpRelay worker;
All listening ports are allocated deterministically in accordance with dev-ports.json:
| Service / Component | Protocol / Transport | Port | URL / Path |
|---|---|---|---|
| NainNotify Client (Vue 3) | HTTP (Vite Dev / Preview) | 5378 |
http://localhost:5378 |
| API Gateway | HTTP (ASP.NET Core) | 8120 |
http://localhost:8120 |
| Scalar Interactive API Docs | HTTP (OpenAPI 3.0) | 8120 |
http://localhost:8120/docs |
| Swagger UI | HTTP | 8120 |
http://localhost:8120/swagger |
| SSE Telemetry Stream | HTTP EventSource | 8120 |
http://localhost:8120/api/v1/Notifications/stream |
| Health Check & Diagnostics | HTTP | 8120 |
http://localhost:8120/api/v1/Notifications/health |
| RabbitMQ Management | HTTP (Docker Compose) | 15672 |
http://localhost:15672 |
By default, the gateway runs in zero-dependency in-memory mode, requiring no external databases or message brokers:
dotnet run --project src/Notificaciones.ApiThe gateway listens on http://localhost:8120.
In a separate terminal:
cd Notificaciones.Client
npm install
npm run devOpen http://localhost:5378 to launch the guided studio: pick a scenario, send it, watch it travel through the pipeline and see the rendered email. With the gateway stopped the client runs on its standalone in-browser engine (same experience as the GitHub Pages deployment).
To run the distributed multi-container topology (API Gateway, Worker, and RabbitMQ):
docker-compose up -d --buildRun the automated test suite across all architectural layers:
# Execute unit and integration tests (78 tests total)
dotnet test MicroservicioNotificaciones.sln
# Type-check and build the frontend client
cd Notificaciones.Client
npm run build| Test Layer | Framework | Count | Scope |
|---|---|---|---|
| Notificaciones.UnitTests | xUnit | 55 | PrivacyMasker, EmailTemplateEngine (HTML escaping, VML bulletproofing), and InMemoryNotificationTelemetryStore arithmetic. |
| Notificaciones.IntegrationTests | xUnit + WebApplicationFactory | 23 | In-memory MassTransit bus, end-to-end 5-stage lifecycle transitions, sandbox recipient redirection, rate limiter policies, honeypot anti-spam, and SSE streaming. |
| Notificaciones.Client | vue-tsc + Vite | 1 | TypeScript strict template verification, contract alignment, production bundle generation. |
- Zero-PII Telemetry Leakage (
PrivacyMasker): All recipient addresses entering public telemetry streams and event stores are masked at the edge (e.g.,e*******r@c*********p.com). - Honeypot Anti-Spam Gate: Automated bots completing hidden input fields are met with standard
202 Acceptedresponses to prevent detection, while their payloads are dropped before enqueuing. - Decoupled Server-Sent Events (SSE): The API Gateway maintains bounded broadcast channels with keepalive heartbeats, broadcasting state changes without poll overhead.
- VML Bulletproof Email Layouts: HTML email generation utilizes Vector Markup Language fallbacks, ensuring correct multi-column rendering across Microsoft Outlook desktop and web clients.
.
├── src/
│ ├── Notificaciones.Api/ # ASP.NET Core gateway, rate-limiting, SSE broadcast
│ ├── Notificaciones.Application/ # MassTransit consumers, email template rendering
│ ├── Notificaciones.Domain/ # Core events, NotificationLifecycleEvent contracts
│ ├── Notificaciones.Infrastructure/ # Smtp client, configuration loaders, serialization
│ └── Notificaciones.Worker/ # Standalone background worker entry point
├── Notificaciones.Client/ # Decoupled Vue 3 + TypeScript showcase client (port 5378)
├── tests/
│ ├── Notificaciones.UnitTests/ # 55 unit tests
│ └── Notificaciones.IntegrationTests/# 23 integration tests
├── docs/ # Architecture decisions (ADRs), changelog, traceability
└── specs/ # Spec-Driven Development specifications and task plans