Context
A gateway in front of the services was rejected in ADR 0011. The owner’s answer on 2026-10-20 (mem L953) keeps that rejection and fills the gateway role with four generated layers, so no gateway service has to be written or run.Decision
- Edge (layer 1). Cloudflare, configured from
runway.yamland Pulumi. It provides TLS, WAF, DDoS protection, bot control and a coarse per-IP rate limit. It routes the hostsapi.figentra.com/{public,app,admin,platform}. - Encore gateway (layer 2).
stackra gengenerates the Encore built-in gateway. It has one authentication handler that verifies ZITADEL tokens into anActor, CORS per area, a request id, trace propagation, and path-to-service routing per topology (ADR 0169). - Per-endpoint middleware (layer 3). Modules declare
@Middleware({ phase })providers. An Explorer finds them, and they run in the order of their declared phase: version, tenant, limits, idempotency, and so on. The area gate chain (ADR 0138) runs here too, with audit on the admin and platform areas. - Action pipeline (layer 4). Tenancy, then iam, then policy, then entitlement, then the transaction, then effects (ADR 0138 and 0136).
- Manifest.
app-manifest.jsonlists every route, area, version and middleware chain (ADR 0158).
Consequences
- No gateway service exists to run, scale or secure separately.
- A route’s full chain is visible in one file, so a reviewer sees what runs before a handler.
Enforcement
planned — gen fails on a route with no area, and the middleware order is checked by the Explorer’s conformance test (ADR 0144).Supersedes and sources
Supersedes: none. Amends: 0082, 0118. Builds on 0011 (no gateway product). Sources: owner decision “API gateway (owner 2026-10-20 night): GENERATED, no gateway service” (stackra-decisions-2026-10-19.md L953, 2026-10-20).