Appearance
Gateway API
The Gateway is the single internet-facing entry point for all Microtec ERP traffic. It runs on the Public CAE and uses YARP (Yet Another Reverse Proxy) to route requests to nine downstream microservices on the Private CAE.
Overview
| Property | Value |
|---|---|
| Technology | .NET 8 + YARP |
| CAE placement | Public CAE |
| Resources | 0.25 CPU / 0.5 Gi RAM minimum |
| Source | Platforms/Src/Gateway/Gateway.Yarp/ |
| Internet-facing | Yes (Azure Container App ingress enabled) |
Downstream Clusters
The Gateway routes to ten backend clusters. All downstream services run on the Private CAE and are reachable via internal DNS.
| Cluster | Downstream Service | Route Prefix |
|---|---|---|
erp-cluster | AppsPortal.Apis | /erp-apis/ |
inventory-cluster | Inventory.Apis | /inventory-apis/ |
business-owners-cluster | BusinessOwners.Apis | /business-owners-apis/ |
admin-portal-cluster | BusinessOwners.AdminPortal | /admin-portal-apis/ |
hr-cluster | Hr.Personnel.Apis | /hr-apis/ |
integration-cluster | Integration.Apis | /integration-apis/ |
attachments-cluster | Attachment.Apis | /attachments-apis/ |
notifications-cluster | Notification.Apis | /notifications-apis/ |
workflow-cluster | Workflows.Apis | /workflow-apis/ |
template-cluster | Template.Blazor | /template-apis/ |
Request Flow
Authentication Passthrough
The Gateway validates the JWT signature using Keycloak's public key (fetched from the OIDC discovery endpoint at startup). It does not decode or interpret claims — claim-based authorization is enforced by each downstream service individually.
json
// appsettings.json (Gateway)
{
"Authentication": {
"Authority": "https://<keycloak-host>/realms/microtec",
"Audience": "account",
"ValidateAudience": true,
"ValidateIssuer": true
}
}Downstream services receive the original Authorization: Bearer <token> header unchanged.
Rate Limiting
Rate limiting is enforced upstream by Azure Front Door WAF (default: 10,000 requests per 5 minutes per client IP). The Gateway itself does not apply an additional rate limiting layer — downstream services handle per-operation throttling as needed.
Health Check Aggregation
The Gateway exposes an aggregated health endpoint at /health that pings all nine downstream services:
GET /healthResponse:
json
{
"status": "Healthy",
"entries": {
"erp-cluster": { "status": "Healthy" },
"inventory-cluster": { "status": "Healthy" },
"business-owners-cluster": { "status": "Healthy" },
"admin-portal-cluster": { "status": "Healthy" },
"hr-cluster": { "status": "Healthy" },
"integration-cluster": { "status": "Healthy" },
"attachments-cluster": { "status": "Healthy" },
"notifications-cluster": { "status": "Healthy" },
"workflow-cluster": { "status": "Healthy" },
"template-cluster": { "status": "Healthy" }
}
}WARNING
The /health endpoint itself is not rate limited. Monitoring systems poll it every 30 seconds.
YARP Configuration
YARP is configured via appsettings.json using the ReverseProxy section. Each cluster points to the internal ACA DNS name for the corresponding environment:
json
{
"ReverseProxy": {
"Routes": {
"erp-apis": {
"ClusterId": "erp-cluster",
"Match": { "Path": "/erp-apis/{**catch-all}" }
},
"inventory-apis": {
"ClusterId": "inventory-cluster",
"Match": { "Path": "/inventory-apis/{**catch-all}" }
},
"business-owners-apis": {
"ClusterId": "business-owners-cluster",
"Match": { "Path": "/business-owners-apis/{**catch-all}" }
},
"admin-portal-apis": {
"ClusterId": "admin-portal-cluster",
"Match": { "Path": "/admin-portal-apis/{**catch-all}" }
},
"attachments-apis": {
"ClusterId": "attachments-cluster",
"Match": { "Path": "/attachments-apis/api/{**catch-all}" }
},
"notifications-apis": {
"ClusterId": "notifications-cluster",
"Match": { "Path": "/notifications-apis/{**catch-all}" }
},
"integration-apis": {
"ClusterId": "integration-cluster",
"Match": { "Path": "/integration-apis/{**catch-all}" }
},
"workflow-apis": {
"ClusterId": "workflow-cluster",
"Match": { "Path": "/workflow-apis/{**catch-all}" }
},
"hr-apis": {
"ClusterId": "hr-cluster",
"Match": { "Path": "/hr-apis/{**catch-all}" }
},
"template-apis": {
"ClusterId": "template-cluster",
"Match": { "Path": "/template-apis/{**catch-all}" }
}
},
"Clusters": {
"erp-cluster": {
"Destinations": {
"erp-cluster/destination1": {
"Address": "https://mic-erp-be-appsportal.internal.<env>.azurecontainerapps.io/"
}
}
},
"hr-cluster": {
"Destinations": {
"hr-cluster/destination1": {
"Address": "https://mic-erp-be-hr.internal.<env>.azurecontainerapps.io/"
}
}
}
}
}
}Replace <env> with the Container App environment suffix (e.g., dev, stage, prod).
Local Development Addresses
In local development, clusters point to http://localhost with per-service ports: erp-cluster → :2005, inventory-cluster → :2008, business-owners-cluster → :2003, admin-portal-cluster → :2007, attachments-cluster → :2030, notifications-cluster → :2031, integration-cluster → :2033, workflow-cluster → :2035, hr-cluster → :2046, template-cluster → :2036.
Resource Sizing
The Gateway is intentionally lightweight — it does no business logic:
| Resource | Minimum | Maximum (scale-out) |
|---|---|---|
| CPU | 0.25 vCPU | 1.0 vCPU |
| Memory | 0.5 Gi | 2 Gi |
| Replicas | 1 | 5 (auto-scale on HTTP concurrency) |
Auto-scaling is triggered when concurrent HTTP connections exceed 100 per replica.
Logging & Observability
- Structured logs sent to Seq (port 1234) via
Microtec.Web.Coremiddleware. - Each request receives a
X-Correlation-Idheader (generated by the Gateway if absent, forwarded downstream). - Prometheus metrics exposed at
/metrics(scraped by Azure Monitor or Prometheus agent). - OpenTelemetry traces exported to the OTLP collector (
http://otel-collector:4317).
Local Development
For local development, bypass the Gateway and call downstream services directly on their individual ports:
| Service | Local Port |
|---|---|
| AppsPortal.Apis | http://localhost:2005 |
| Inventory.Apis | http://localhost:2008 |
| BusinessOwners.Apis | http://localhost:2003 |
| BusinessOwners.AdminPortal | http://localhost:2007 |
| Attachment.Apis | http://localhost:2030 |
| Notification.Apis | http://localhost:2031 |
| Integration.Apis | http://localhost:2033 |
| Workflows.Apis | http://localhost:2035 |
| Hr.Personnel.Apis | http://localhost:2046 |
| Template.Blazor | http://localhost:2036 |
Use the .NET Aspire orchestrator (Platforms/Src/Gateway/Microtec.Platforms.AppHost/) to spin up all services together in a single F5 session.