Appearance
๐ค Architecture โ
This architecture follows the Onion Architecture principle, with the Core domain logic at the center.
- Core โ Contains the Domain rules and models, the Application layer for use cases, and Contracts for abstractions.
- Infrastructure โ Implements persistence, messaging, and storage (e.g. Database, Azure Service Bus, Azure Blob Storage).
- Connectors โ Integrations with external systems like KatanaPIM, Google Sheets, and Exact Online.
- UI โ Entry points such as API, Admin, Functions, and Jobs, all delegating to the Application layer.
- App โ Frontend client consuming the API.
Dependencies always point inward: outer layers depend on the Core, but the Core remains independent, ensuring separation of concerns and maintainability.
System Topology โ
All runtime components deployed to Azure and their primary communication paths.
| Component | Deployment | Key detail |
|---|---|---|
| App | Container App (port 3000) | Nuxt.js frontend, calls PublicApi via nuxt-api-party |
| Public API | Container App (port 8080) | ASP.NET, JWT/Auth0, Service Bus Data Sender role only |
| Admin | Container App (port 8080) | Blazor, Service Bus Data Owner (DLQ management), can start jobs |
| Functions | Flex Consumption plan | 5 timer, 2 ServiceBus, 2 HTTP triggers |
| Jobs | Container App Job | Event-triggered by queued-jobs, one message per instance, exits after completion |
| Tenant DBs | SQL Server elastic pool | Database-per-tenant; connector schemas (ExactOnline, KatanaPim, Wolfpack, GoogleSheet) live in the tenant DB |
| Admin DB | SQL Server | Shared across all tenants (administrations, identities, job definitions) |
Event Processing Flow โ
Domain changes propagate asynchronously through two chains where Service Bus queues and Azure Functions are the links. Both chains originate from synchronous API writes but continue independently in the background.
Part 1 โ Notification chain โ
A command handler writes to the database and the EventOutbox in a single transaction. A timer function publishes outbox entries to the events queue, where a ServiceBus function dispatches them to MediatR handlers. Handlers that produce webhooks push work to the webhooks queue for a second function to execute.
| Step | Detail |
|---|---|
| Outbox write | CustomMediator.PublishToOutbox writes notification + metadata in the same DB transaction as the command |
| Deduplication | DeduplicationKeyVisitor collapses multiple updates to the same entity within a batch |
| Event function | Sets IAdministrationContext, then runs all INotificationHandler<T> implementations |
| Webhook retries | Exponential backoff (1, 5, 15, 30 โฆ min), up to 16 attempts, then dead-lettered |
| Dead letters | Visible in Admin portal (DLQ page) for events, webhooks, and queued-jobs |
Part 2 โ Job execution chain โ
A timer function evaluates cron schedules and publishes JobExecuteCommand messages to the queued-jobs queue. Each message triggers a Container App Job instance that scales from zero, runs the sync/export, and exits.
| Job type | Purpose |
|---|---|
ItemSync / ItemSelectiveSync | Import items from connectors |
CustomerSync / CustomerSelectiveSync | Import customers from connectors |
PriceListSync | Import price lists from connectors |
OrderExport | Export orders to connectors |
AuditTrailPublish | Publish audit trail entries to Blob Storage |
Jobs can also be started manually from the Admin portal, which publishes directly to the queued-jobs queue via JobStartCommandHandler.
Notification types flowing through the chain โ
| Domain | Notifications |
|---|---|
| Items | ItemCreatedNotification ยท ItemUpdatedNotification ยท ItemDeletedNotification |
| Customers | CustomerCreatedNotification ยท CustomerUpdatedNotification ยท CustomerDeletedNotification |
| Customer addresses | CustomerAddressCreatedNotification ยท CustomerAddressUpdatedNotification ยท CustomerAddressDeletedNotification |
| Customer contacts | CustomerContactPersonCreatedNotification ยท CustomerContactPersonUpdatedNotification ยท CustomerContactPersonDeletedNotification |
| Price lists | PriceListCreatedNotification ยท PriceListUpdatedNotification ยท PriceListDeletedNotification |
| Entity lists | EntityListCreatedNotification ยท EntityListUpdatedNotification |
| Orders | OrderCreatedNotification |
| Administration | AdministrationNotificationSendEmailNotification |