Skip to content

ADR-0002: Deny-by-Default Gateway Chain Routing

Status: ACCEPTED Date: 2026-03-22 Supersedes: N/A Superseded by: N/A

Context

The gateway framework (slaunchx-infra-gateway) validates every HTTP request through an ordered chain of handlers. The question was whether endpoints without explicit gateway annotations should be silently allowed (open-by-default) or rejected (deny-by-default).

Source: slaunchx-infra-gateway/docs/MODULE-SPEC.md, slaunchx-app-prometheus/docs/domain/gateway/DESIGN-gateway-validation-chain.md, DevPortal design spec (Principle 6)

Decision

Every controller must carry @GatewayValidation declaring its chainType (WEB or API) and portal restrictions. Unannotated controllers are rejected at startup validation. The API chain further requires @ApiScope on every endpoint; endpoints without it are invisible to API consumers. The DevPortal parser enforces this by failing with a parse error on unannotated controllers, preventing undocumented endpoints from reaching production.

Consequences

  • Zero chance of an endpoint being accidentally exposed without authentication or authorization.
  • Every endpoint's chain type, portal scope, and API scope are explicitly declared in source code.
  • Adding a new endpoint requires choosing its chain and portal assignment upfront, which adds a small amount of ceremony but eliminates security oversights.
  • CI catches missing annotations before code reaches test environments.

Alternatives Considered

  • Open-by-default with opt-in security: Rejected because it creates a class of bugs where developers forget annotations and endpoints are silently unprotected.
  • Centralized route table (YAML/properties): Rejected because annotations co-locate security metadata with the code, reducing drift between config and implementation.

Internal Handbook