ums

ADR-0058: API Gateway Evolution — YARP for Multi-Client SaaS

Status

Proposed

Date

2026-05-22

Context

UMS currently uses nginx embedded inside the ums.web-app Docker image as both a static file server and a reverse proxy to the backend API. This approach is cohesive and sufficient for a single web client.

The planned SaaS evolution introduces at minimum two distinct client surfaces:

With multiple clients, the embedded nginx reverse proxy becomes a liability:

UMS already has Yarp.ReverseProxy as a declared dependency in Ums.Presentation, and the existing IAuthenticationPort abstraction is gateway-compatible. The technology is already present in the stack.


Decision

Introduce ums.gateway as a dedicated ASP.NET Core application using YARP as the centralized API Gateway for all UMS clients.

The gateway will be the single entry point for all inbound traffic. nginx will be reduced to a pure static file server with no proxy responsibility.

Scope of Responsibilities

Concern Current Owner Target Owner
Static file serving (SPA) nginx nginx (unchanged)
Reverse proxy to API nginx (per client) YARP gateway (centralized)
Security headers nginx.conf YARP middleware
Rate limiting Not implemented YARP + IPartitionedRateLimiter
Tenant routing Not implemented YARP gateway
Mobile API access Direct to API YARP gateway
Auth token validation API layer YARP gateway (pre-routing)

Target Architecture

Internet
    │
    ▼
┌──────────────────────────────┐
│  ums.gateway  (YARP)         │  port 443 / 80
│  ASP.NET Core                │  Security headers, Rate limit,
│                              │  Tenant routing, Auth check
└────────────┬─────────────────┘
             │
    ┌────────┴──────────┐
    ▼                   ▼
┌──────────┐      ┌──────────────┐
│ ums.api  │      │ ums.web-app  │  nginx: static only
│ :8080    │      │ :80          │  no proxy logic
└──────────┘      └──────────────┘
                        ▲
                  ums.mobile-app
                  (future client,
                   routes via gateway)

What nginx.conf Becomes

server {
    listen 80;
    location / {
        root /usr/share/nginx/html;
        try_files $uri $uri/ /index.html;
    }
}

All security headers, CSP policies, and proxy configuration migrate to the YARP gateway.


Trigger for Implementation

This ADR is Proposed and should not be implemented until the mobile client development begins. The current nginx-embedded approach remains valid for the MVP with a single web client.

Implementation is triggered when any of the following occurs:

  1. ums.mobile-app project is created.
  2. A second consumer of the API requires independent routing or security policy.
  3. Rate limiting or tenant-aware routing becomes a product requirement.

Consequences

Positive

Negative

Neutral


References


ADR Registry Architecture Portal