Skip to content

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

PropertyValue
Technology.NET 8 + YARP
CAE placementPublic CAE
Resources0.25 CPU / 0.5 Gi RAM minimum
SourcePlatforms/Src/Gateway/Gateway.Yarp/
Internet-facingYes (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.

ClusterDownstream ServiceRoute Prefix
erp-clusterAppsPortal.Apis/erp-apis/
inventory-clusterInventory.Apis/inventory-apis/
business-owners-clusterBusinessOwners.Apis/business-owners-apis/
admin-portal-clusterBusinessOwners.AdminPortal/admin-portal-apis/
hr-clusterHr.Personnel.Apis/hr-apis/
integration-clusterIntegration.Apis/integration-apis/
attachments-clusterAttachment.Apis/attachments-apis/
notifications-clusterNotification.Apis/notifications-apis/
workflow-clusterWorkflows.Apis/workflow-apis/
template-clusterTemplate.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 /health

Response:

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:

ResourceMinimumMaximum (scale-out)
CPU0.25 vCPU1.0 vCPU
Memory0.5 Gi2 Gi
Replicas15 (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.Core middleware.
  • Each request receives a X-Correlation-Id header (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:

ServiceLocal Port
AppsPortal.Apishttp://localhost:2005
Inventory.Apishttp://localhost:2008
BusinessOwners.Apishttp://localhost:2003
BusinessOwners.AdminPortalhttp://localhost:2007
Attachment.Apishttp://localhost:2030
Notification.Apishttp://localhost:2031
Integration.Apishttp://localhost:2033
Workflows.Apishttp://localhost:2035
Hr.Personnel.Apishttp://localhost:2046
Template.Blazorhttp://localhost:2036

Use the .NET Aspire orchestrator (Platforms/Src/Gateway/Microtec.Platforms.AppHost/) to spin up all services together in a single F5 session.

Internal Documentation — Microtec Platform Team