A production-style backend system built using ASP.NET Core Clean Architecture + CQRS + Domain Events.
This project demonstrates how to build a multi-tenant SaaS backend with invoice management, payment processing simulation, webhook handling, and activity timelines.
- Multi-Tenant SaaS Architecture
- Invoice Management
- Payment Processing Simulation
- Payment Webhook Handling
- Activity Timeline
- CQRS with MediatR
- Domain Events
- Pagination & Filtering
- Global Exception Handling
- Clean Architecture
- ASP.NET Core Web API
- Entity Framework Core
- MediatR (CQRS)
- SQL Server
- Swagger / OpenAPI
This project follows Clean Architecture + CQRS + Domain Events.
flowchart TD
Client[Client / Frontend]
API[API Layer\nControllers]
App[Application Layer\nCQRS Commands & Queries]
Domain[Domain Layer\nEntities & Domain Events]
Infra[Infrastructure Layer\nEF Core / Database]
Client --> API
API --> App
App --> Domain
App --> Infra
Infra --> App
Domain --> App
Payment processing uses Domain Events + Event Handlers.
sequenceDiagram
participant Client
participant API
participant Command
participant Domain
participant DB
participant EventHandler
Client->>API: POST /api/payments
API->>Command: AttemptPaymentCommand
Command->>Domain: Create Payment
Domain->>DB: Save Payment
Domain->>EventHandler: Raise PaymentAttemptedEvent
EventHandler->>DB: Insert AuditLog
Client->>API: POST /api/webhooks/payments
API->>Command: HandlePaymentWebhookCommand
Command->>Domain: Update Payment Status
Domain->>EventHandler: Raise PaymentSucceededEvent
EventHandler->>DB: Insert Timeline Event
This system uses shared database + tenant isolation.
Each entity implements:
- TenantId
- Global Query Filters
- Tenant Middleware
Flow:
TenantMiddleware
↓
TenantProvider
↓
DbContext Global Filter
↓
Tenant Data Isolation
This ensures each tenant only accesses its own data.
Client
↓
AttemptPaymentCommand
↓
Payment Entity Created
↓
Domain Event Raised
↓
Event Handler
↓
AuditLog Timeline
Webhook flow:
Payment Gateway
↓
POST /api/webhooks/payments
↓
HandlePaymentWebhookCommand
↓
Update Payment Status
↓
Raise Domain Event
↓
Update Timeline
All important events are recorded in AuditLogs.
Examples:
- invoice.created
- payment.attempted
- payment.succeeded
- payment.failed
Timeline API:
GET /api/invoices/{id}/timeline
Example response:
[
{ "eventType": "invoice.created" },
{ "eventType": "payment.succeeded" }
]Invoice listing uses offset pagination.
GET /api/invoices?page=1&pageSize=10
Implementation:
Skip((Page - 1) * PageSize)
Take(PageSize)
| Method | Endpoint |
|---|---|
| GET | /api/invoices |
| GET | /api/invoices/{id}/timeline |
| Method | Endpoint |
|---|---|
| POST | /api/payments |
| GET | /api/payments/{id} |
| Method | Endpoint |
|---|---|
| POST | /api/webhooks/payments |
Create Invoice
↓
Attempt Payment
↓
Payment Webhook
↓
Invoice Paid
↓
Timeline Updated
Unit tests can be implemented for core business logic such as:
- Invoice total calculation
- Payment command handlers
- Domain event behavior
Example:
dotnet test
Possible production improvements:
- Redis caching
- Background job processing (Hangfire)
- Idempotency key for webhook processing
- Distributed tracing
- Integration tests
- Rate limiting for public APIs
This project is built as a backend architecture showcase demonstrating how to design scalable SaaS backend systems using modern .NET architecture patterns.