Appearance
Architecture Overview
This section documents the core architectural decisions and patterns that shape the Microtec ERP platform. The architecture is designed for cloud-native multi-tenancy, developer velocity, and operational independence between services.
Four Architectural Pillars
| Pillar | Pattern | Technology | Details |
|---|---|---|---|
| Separation of Concerns | Clean Architecture | .NET 8 | Four strict layers per service; no cross-layer shortcuts |
| Command/Query Separation | CQRS | MediatR | Read and write models are independent |
| Tenant Isolation | Database-per-Tenant | EF Core + SQL Server | Complete data isolation per customer |
| Async Decoupling | Event-Driven | MassTransit + Azure Service Bus | Services communicate via messages, not direct calls |
C4 Level-1: Platform Architecture
Container Apps Environment Split
Public vs Private CAE
The two-CAE model is a deliberate security boundary. The public CAE has an internet-facing IP and handles only two workloads: the API Gateway (Ocelot/YARP) and Keycloak. All business microservices live in the private CAE with no public IP — they are reachable only through the gateway.
Architectural Layers per Service
Each of the 13 backend microservices follows the same four-layer Clean Architecture structure:
{ServiceName}/
├── {ServiceName}.Apis/ # Presentation: REST controllers, Swagger, middleware
├── {ServiceName}.Application/ # Application: CQRS handlers, validators, DTOs
├── {ServiceName}.Domain/ # Domain: Entities, value objects, domain events
└── {ServiceName}.Infrastructure/ # Infrastructure: EF Core, repos, external servicesDependency Rule
Dependencies only point inward. Infrastructure depends on Application; Application depends on Domain. The Domain layer has zero external dependencies.
Key Architectural Decisions
The following Architecture Decision Records capture the most significant choices made during platform design. Refer to the linked ADRs for full context, alternatives considered, and consequences.
| ADR | Decision | Status |
|---|---|---|
| ADR-001 | Adopt microservices architecture | Accepted |
| ADR-002 | Use Azure Container Apps over AKS | Accepted |
| ADR-003 | Webpack Module Federation for MFE | Accepted |
| ADR-004 | Self-hosted Keycloak for SSO | Accepted |
| ADR-005 | Migrate from RabbitMQ to Azure Service Bus | Accepted |
| ADR-006 | Clean Architecture with CQRS/MediatR | Accepted |
| ADR-007 | Centralized DevSecOps pipeline templates | Accepted |
| ADR-008 | Database-per-tenant multi-tenancy | Accepted |
| ADR-009 | Shared code as private NuGet packages | Accepted |
Architecture Deep Dives
| Topic | Page | Audience |
|---|---|---|
| Clean Architecture + CQRS | clean-architecture.md | BE-DEV, ARCH |
| Multi-Tenancy Strategy | multi-tenancy.md | BE-DEV, ARCH, SRE |
| Service Communication | service-communication.md | BE-DEV, DEVOPS, SRE |
| Event-Driven Design | event-driven.md | BE-DEV, ARCH |
| Micro-Frontend Architecture | micro-frontend.md | FE-DEV, ARCH |
Non-Functional Requirements
| Concern | Approach |
|---|---|
| Scalability | KEDA autoscaling on Container Apps (min/max replicas per service in services-config.json) |
| Availability | Multiple replicas in prod; AFD health probes; CAE restart policies |
| Security | mTLS in private CAE; WAF on AFD; Keycloak OIDC; Key Vault for all secrets |
| Observability | OpenTelemetry traces + Serilog structured logs → Seq + Application Insights |
| Resilience | Polly retry/circuit-breaker on HTTP clients; MassTransit dead-letter queues |
| Portability | Docker containers; Bicep IaC; environment parity across 5 environments |
| Compliance | ZATCA Phase 2 (Saudi), ETA (Egypt); SBOM per image; audit logs |