Skip to content

Infrastructure Technology Reference

Detailed reference for every Azure service and infrastructure component used in the Microtec ERP platform.


Infrastructure as Code

Azure Bicep

Role: Declarative IaC DSL — all Azure resources are defined and deployed via Bicep
Scope: Subscription-scoped (main.bicep) — creates resource groups and all child resources in a single deployment
Location: Devops/azure/infrastructure/

Module structure:

infrastructure/
├── main.bicep                     # Subscription entrypoint
├── modules/
│   ├── containerEnv.bicep         # Container Apps Environment
│   ├── containerApp.bicep         # Individual Container App
│   ├── keyVault.bicep             # Key Vault + RBAC assignments
│   ├── serviceBus.bicep           # Service Bus namespace + queues/topics
│   ├── redis.bicep                # Azure Managed Redis
│   ├── sql.bicep                  # Azure SQL Server + databases
│   ├── acr.bicep                  # Azure Container Registry
│   ├── staticWebApp.bicep         # Frontend SWA
│   ├── frontDoor.bicep            # AFD profile + origins
│   └── vnet.bicep                 # VNet + subnets + NSGs
└── parameters/
    ├── dev.bicepparam
    ├── stage.bicepparam
    ├── preprod.bicepparam
    ├── uat.bicepparam
    └── prod.bicepparam

Deploy command:

bash
# Full infrastructure deploy for dev
az deployment sub create \
  --location "uksouth" \
  --template-file Devops/azure/infrastructure/main.bicep \
  --parameters @Devops/azure/infrastructure/parameters/dev.bicepparam

Parameter generation: Build-BicepParams.ps1 reads services-config.json and outputs .bicepparam files — no hand-editing of parameter files.


Container Runtime

Azure Container Apps (ACA)

SKU: Consumption tier (pay-per-use serverless)
Role: Managed Kubernetes-based container runtime — all backend microservices
Region: UK South (uksouth) for all environments

Two-CAE pattern per environment:

CAEInternet-facingServicesmTLS
Public CAEYes (via AFD)Gateway.API, KeycloakNo
Private CAENo — VNet-internalAll other 12+ servicesYes (enforced)

Key ACA features used:

FeatureConfiguration
Managed identitySystem-assigned — ACR pull, Key Vault read
VNet integrationPrivate CAE is subnet-joined (no public IP)
KEDA autoscalingHTTP, CPU, memory, and cron triggers
Revision managementTraffic splitting for zero-downtime deploy
Health probesLiveness (/health/live) + readiness (/health/ready)
Secret referencesKV references via keyvaultref: syntax
DaprNot used

KEDA scaling configuration (from services-config.json):

Trigger typeMetricDefault config
httpConcurrent requests per replica100
cpuCPU utilisation %70
memoryMemory utilisation %75
cronTime scheduleBusiness-hours pre-warm

Resource allocation:

Service tierCPUMemoryMin replicasMax replicas
Gateway (prod)1.02Gi210
Keycloak (prod)2.04Gi26
AppsPortal (prod)0.51Gi18
Other services (prod)0.250.5Gi15
All services (dev)0.250.5Gi03

Scale-to-zero in dev

Dev environment Container Apps scale to 0 replicas after 5 minutes of inactivity, eliminating idle costs. Cold start latency is ~3–5 seconds.


Container Registry

Azure Container Registry (ACR)

SKU: Basic (dev/stage) / Standard (preprod/uat/prod)
Role: Private Docker image registry for all backend service images
Authentication: Pipeline uses $(System.AccessToken) built-in identity; Container Apps use managed identity for pull

ACR names per environment:

EnvironmentBackend ACRFrontend ACR
devmicerpbedevacrmicerpfrdevacr
stagemicerpbestageacrmicerpfrstageacr
preprodmicerpbepreprodacrmicerpfrpreprodacr
uatmicerpbeuatacrmicerpfruatacr
productionmicerpbeproductionacrmicerpfrproductionacr

Naming formula: replace('mic-erp-be-{env}acr', '-', '') (all alphanumeric — Azure Storage naming rules)

Image tag strategy:

TagLifecycle
$(Build.BuildId)Created on every pipeline run — permanent
latestOverwritten on every successful dev build
stableSet manually post production validation

Geo-replication: Production ACR is geo-replicated to West Europe for disaster recovery.


Relational Database

Azure SQL (SQL Server 2022 compatible)

SKU: General Purpose, 4 vCores (prod) / Basic, 5 DTU (dev/stage)
Role: Primary relational database for all tenant and admin data
Server naming: mic-backend-shared-sql-rg (shared across environments — do NOT rename)

Shared SQL Server

The SQL Server VM (20.50.120.95) is shared across non-production environments. Tenant databases are isolated by database name. Do not apply environment-destructive commands to the shared server.

Database-per-tenant isolation:

Database typeNamingPurpose
Admin DBMicrotecAdminCross-tenant metadata, tenant registry
Tenant DBTenant_{tenantId}All tenant-specific ERP data
Hangfire DBMicrotec_HangfireBackground job storage

Connection string management: All connection strings are stored in Key Vault. Never in appsettings.json or pipeline variables in plain text.

SSH access (emergency):

bash
ssh -i ~/.ssh/mic-shared-sql sqladmin@20.50.120.95

Cache

Azure Cache for Redis

SKU: C1 Standard (1 GB, dev/stage/preprod/uat) / C2 Standard (6 GB, prod)
Version: Redis 6.x (managed by Azure)
TLS: Enabled — port 10000 (SSL)
Auth: Password stored in Key Vault → RedisConfiguration--Password

Stage Redis endpoint: mic-erp-be-stage-redis.uksouth.redis.azure.net:10000

Usage patterns:

PatternImplementation
Output cache[OutputCache] attribute on controller actions
Distributed cacheIDistributedCache with GetStringAsync/SetStringAsync
Rate limitingRedis sliding window counter per client IP
Session dataAuth tokens and user context (TTL 30 min)
Tenant config cacheTenant settings — TTL 1 hour

Local dev: Redis 7.x runs as Docker container on port 6379 (no TLS).


Messaging

Azure Service Bus

SKU: Standard tier (supports topics, subscriptions, dead-letter queues, 256KB messages)
Role: Production async message broker for all inter-service events
MassTransit transport: Configured automatically in cloud environments via IServiceBusConfiguration

Topology:

Queue / TopicTypeProducersConsumers
erp-eventsTopicAppsPortal, HR, InventoryNotification, Workflow, Worker
notification-requestsQueueAny serviceNotification.Apis
zatca-submissionsQueueAppsPortalIntegration.Apis
import-jobsQueueAppsPortalImport.Apis
report-generationQueueAny serviceReporting.Apis

Dead-letter queues: Enabled for all queues — messages failing after 5 delivery attempts land in {queue}/$deadLetterQueue.

Local dev: RabbitMQ 3.13.x (Docker) on ports 5672 (AMQP) / 15672 (management UI). MassTransit swaps transport transparently.


Secrets Management

Azure Key Vault

SKU: Standard
Role: Central secrets store — all credentials, connection strings, API keys, certificates
Authentication: System-assigned managed identity on each Container App — no credentials stored in pipeline variables

KV names (inconsistent across envs — use exact names):

EnvironmentKey Vault Name
devmic-erp-be-dev-skv
stagemic-erp-stg-kv
preprodmic-erp-be-preprod-skv
uatmic-erp-uat-kv
production(contact platform team)

No naming formula for Key Vault

Key Vault names are not derived from a formula — they evolved organically. Always use the exact names in the table above.

Secret naming convention:

ASP.NET Core:    ConnectionStrings:DefaultConnection
Key Vault name:  ConnectionStrings--DefaultConnection  (double-dash replaces colon)

Reference in CAE environment variable:
  keyvaultref:https://{kv-name}.vault.azure.net/secrets/ConnectionStrings--DefaultConnection

Global Load Balancing & CDN

Azure Front Door (Standard)

SKU: Standard (WAF, CDN, custom domains, health probes)
Role: Global entry point — TLS termination, WAF, CDN for static assets, routing to backend and frontend origins

Origin groups:

Origin groupOriginRoutes
backend-originsPublic CAE — Gateway.API/api/*, /auth/*
frontend-originsAzure Static Web Apps/* (catch-all)

WAF policies:

  • OWASP Core Rule Set 3.2 (prevention mode in prod, detection in dev/stage)
  • Custom rules: block requests from restricted countries, rate-limit /api/auth/*

TLS: Auto-managed certificates — Azure-managed certificate per custom domain. No manual renewal.

Health probe: Every 30 seconds to /health/ready on each origin. Unhealthy origins removed from rotation automatically.

Custom domains by environment:

EnvironmentDomain
devmicrotec-test.com
stagemicrotecstage.com
uatmicrotec-uat.com
productiononlinemicrotec.com.sa

Frontend Hosting

Azure Static Web Apps (SWA)

SKU: Standard
Role: Hosts all Angular micro-frontend apps — global CDN delivery, built-in auth integration
Deployment: Azure DevOps pipeline uploads dist/ output via AzureStaticWebApp@0 task

SWA per app (10 total per environment):

AppSWA Name pattern
erp-homemic-erp-fr-{env}-home-swa
apps-accountingmic-erp-fr-{env}-accounting-swa
apps-hrmic-erp-fr-{env}-hr-swa
apps-financemic-erp-fr-{env}-finance-swa
apps-salesmic-erp-fr-{env}-sales-swa
apps-purchasemic-erp-fr-{env}-purchase-swa
apps-inventorymic-erp-fr-{env}-inventory-swa
app-distributionmic-erp-fr-{env}-distribution-swa
fixed-assetsmic-erp-fr-{env}-fixed-assets-swa
bussiness-ownersmic-erp-fr-{env}-bo-swa

SWA routing: staticwebapp.config.json configures SPA fallback ("navigationFallback") and CORS headers for Module Federation cross-origin remoteEntry.js loading.


Networking

Azure Virtual Network

SKU: Standard
Role: Isolates each environment's Container Apps from the internet and from each other
Topology: Per-environment VNet — no peering between environments

CIDR allocation:

EnvironmentVNet CIDRPublic SubnetPrivate SubnetPE Subnet
dev10.0.0.0/1610.0.0.0/2410.0.1.0/2410.0.2.0/24
stage10.1.0.0/1610.1.0.0/2410.1.1.0/2410.1.2.0/24
preprod10.6.0.0/1610.6.0.0/2410.6.1.0/2410.6.2.0/24
uat10.5.0.0/1610.5.0.0/2410.5.1.0/2410.5.2.0/24
production10.2.0.0/1610.2.0.0/2410.2.1.0/2410.2.2.0/24
shared-sql10.100.0.0/16N/AN/AN/A

Private endpoints: SQL, Redis, Service Bus, Key Vault, ACR, and Blob Storage all communicate with Container Apps exclusively over private endpoints — no public internet exposure.


Document / Object Storage

Azure Blob Storage

SKU: Standard LRS (dev/stage) / Standard ZRS (prod)
Role: Attachment storage (invoices, documents, profile photos)
Account naming: micerpbedevsa, micerpfrstageacr (alphanumeric, no dashes)
Access: Blob SAS tokens generated on-demand by Attachment.Apis (never expose account keys)


Document Database

MongoDB 7.0 (Non-Production)

Deployment: VM-based Docker container on shared infrastructure
Ports: 27017–27020
Use case: Workflow engine state storage, flexible document data in non-prod environments

MongoDB init bug

MONGO_INITDB_ROOT_* environment variables create a broken SCRAM auth in MongoDB 7.0. Workaround: start container with no auth, run db.updateUser(), then restart with auth enabled. This is a known gotcha — do not "fix" it.

Azure Cosmos DB (Production)

API: MongoDB-compatible
Role: Production document store — replaces MongoDB VM in production
Consistency: Session consistency (default)


Monitoring & APM

Application Insights

SKU: Log Analytics workspace-based
Role: APM, request tracing, exception tracking, custom metrics, availability tests
Integration: OpenTelemetry → Azure Monitor exporter (auto-configured by Microtec.Web.Hosting)
Retention: 90 days (cloud default)

Azure Monitor

Role: Central metrics and alerting platform
Alert types configured:

  • Container App replica count > max (scaling bottleneck)
  • HTTP 5xx rate > 1% (error rate alert)
  • SQL DTU utilisation > 80% (scale trigger)
  • Redis cache miss rate > 20% (cache effectiveness alert)

Internal Documentation — Microtec Platform Team