Stage 7 · Master
The Gateway Service
The API Gateway Pattern
Why a microservices platform needs one public entrypoint, what responsibilities belong at that boundary, and how Meridian's existing gateway scaffolding should evolve into a reverse-proxy service without becoming a second monolith.
Why a Gateway Exists
A gateway exists because public concerns are not the same as service-local business concerns. External clients need one address, one authentication story, one versioning surface, one rate-limiting policy, and one place where tenant context enters the platform. Internal services need to focus on their bounded contexts. When those two responsibility sets are mixed, either every service becomes half gateway or the gateway becomes a hidden monolith that owns everyone else's domain logic.
The central architectural rule is simple: clients talk only to the gateway. identity-service, community-service, and billing-service are internal. This is not decorative indirection. It is the mechanism that guarantees every request crosses the same trust boundary before it reaches tenant data.
| Traffic shape | Short-term attraction | Long-term consequence |
|---|---|---|
| Browser -> individual services directly | Fewer moving parts at first | Duplicates auth, rate limits, and versioning everywhere |
| Browser -> gateway -> internal services | One extra hop to operate | Chosen because one boundary owns cross-cutting edge policy |
| Mixed direct and gateway access | Looks flexible | Creates inconsistent trust assumptions and impossible-to-audit client behavior |
What the Gateway Owns
A well-designed gateway owns cross-cutting edge behavior: request admission, coarse authentication and authorization, tenant resolution, request shaping, reverse proxying, and consistent failure behavior for unreachable upstreams. A well-designed gateway does not own resident business rules, billing calculations, or complaint workflow semantics. That distinction is the difference between a gateway and a distributed monolith's most dangerous file.
How Meridian Is Structured Today
The repository already contains the gateway module and its startup path. apps/gateway/cmd/gateway/main.go loads config, constructs a logger, wraps the router with recovery middleware, and starts an http.Server. apps/gateway/internal/router/router.go currently registers only GET /healthz. apps/gateway/internal/middleware/middleware.go currently contains only panic recovery. That is scaffolding, not failure. It means the architectural seam exists before the feature complexity arrives.
Designing the Public Route Map
The next step is not to make the gateway clever. It is to make the route map explicit. A public /v1/auth/* prefix can proxy to identity-service. Community routes can proxy to community-service. Billing routes can proxy to billing-service. The map should preserve ownership rather than hiding everything behind one giant catch-all proxy. If an incident affects invoice creation, the route map should still make it obvious that billing-service owns that business path.
Reverse proxying also changes failure handling. If community-service is down, the gateway should return a controlled 502 or 504 rather than leaking a transport error or retrying unsafe writes blindly. The gateway is where upstream failure becomes a platform-visible API failure. That is another reason it must remain narrow and deliberate.
Current Repository Status
README.md and docs/architecture/services.md explicitly state that reverse-proxy routes are planned and that every service currently exposes only /healthz. This chapter therefore explains the gateway pattern and Meridian's intended shape without claiming that internal routing is already implemented.
apps/gateway/internal/config/config.gomodifyResponsibility: Already contains downstream service URLs and will remain the place where proxy targets are configured.
Why now: Only the gateway should know the network addresses of all internal services.
apps/gateway/internal/router/router.gomodifyResponsibility: Will expand from /healthz-only routing to the explicit reverse-proxy route map.
Why now: Public route ownership should be readable in one file.
apps/gateway/internal/middleware/middleware.gomodifyResponsibility: Will grow beyond panic recovery into request logging, tenant resolution, auth checks, and standardized upstream error handling.
Why now: Cross-cutting edge behavior belongs at the gateway boundary, not scattered across downstream services.
- Expose exactly one public entrypoint and make all internal services private behind it.
- Keep the gateway responsible for edge concerns, not downstream business rules.
- Preserve service ownership in the public route map rather than hiding everything behind one opaque proxy.
- Treat controlled upstream-failure behavior as part of the gateway's contract.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.