Files
foxhunt/docs/plans/2026-03-04-gateway-unification-design.md
jgrusewski 884d9579c0 docs: add gateway unification design (api_gateway + web-gateway → api)
Unify both gateways into a single gRPC-only `services/api/` with tonic-web
for browser access. Drop REST+WebSocket, keep full 6-layer auth.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:13:35 +01:00

4.3 KiB

Gateway Unification: api_gateway + web-gateway → api

Decision

Unify services/api_gateway/ and crates/web-gateway/ into a single services/api/ service. gRPC-only (no REST), with tonic-web for browser access. Full 6-layer auth preserved.

Context

Two gateways exist with overlapping functionality:

  • api_gateway (12.8K LOC, 357 tests): gRPC proxy to 9 backend services, 100+ endpoints, 6-layer auth (mTLS, JWT, Redis revocation, RBAC, rate limiting, audit), optional MFA
  • web-gateway (3K LOC, 104 tests): REST+WebSocket for React dashboard, JWT+rate limiting, 24 endpoints, 8 WS topics

Both do JWT auth, rate limiting (identical 3-tier), and proxy to trading/backtesting/ML services.

Architecture

Single Binary: api

services/api/
├── Cargo.toml          # name = "api", binary = "api"
├── build.rs
└── src/
    ├── main.rs         # gRPC + tonic-web server
    ├── lib.rs
    ├── auth/           # 6-layer auth (mTLS, JWT, revocation, RBAC, rate limit, audit)
    │   ├── interceptor.rs
    │   ├── jwt/        # JWT service, revocation, login endpoints
    │   ├── mfa/        # Optional TOTP (feature-gated)
    │   └── mtls/       # TLS 1.3, certificate validation, OCSP/CRL
    ├── grpc/           # 15 proxy implementations (all 9 backend services)
    ├── routing/        # Rate limiter (DashMap token bucket)
    ├── config/         # RBAC config, hot-reload
    ├── metrics/        # Prometheus exporter
    └── health.rs       # K8s probes

Ports

Port Protocol Purpose
50051 gRPC (HTTP/2) + grpc-web (HTTP/1.1) All API traffic
9091 HTTP Prometheus metrics + health probes

tonic-web Integration

Server::builder()
    .accept_http1(true)
    .layer(cors_layer)           // CORS for browser origins
    .layer(GrpcWebLayer::new())  // grpc-web ↔ gRPC translation
    .add_service(auth_interceptor.layer(trading_svc))
    .add_service(auth_interceptor.layer(backtesting_svc))
    // ... all services
    .serve(addr)

Port 50051 serves both native gRPC (HTTP/2) and grpc-web (HTTP/1.1) — no proxy needed.

What's Deleted

  • services/api_gateway/ — code moves to services/api/
  • crates/web-gateway/ — entirely deleted (REST+WS layer no longer needed)
  • infra/k8s/services/web-gateway.yaml
  • infra/k8s/network-policies/web-gateway.yaml
  • handlers/ directory (4 ML REST endpoints dropped)
  • Axum dependency removed from api service

What's Preserved

  • All 15 gRPC proxy implementations (100+ endpoints, 37+ streaming)
  • Full 6-layer auth stack
  • Optional MFA (TOTP, feature-gated)
  • Circuit breakers, health monitoring
  • Prometheus metrics, observability

What's Added

  • tonic-web crate dependency
  • tower-http CORS layer for grpc-web browser access
  • CORS_ORIGINS env var (from web-gateway)

Blast Radius

~25 files need updating:

Category Count Change
Workspace Cargo.toml 1 Remove old members, add services/api
trading_service/Cargo.toml 1 Update path dep api-gatewayapi
K8s manifests 4 Rename api-gateway, delete web-gateway
CI (.gitlab-ci.yml) 1 Binary name api-gatewayapi
Docker compose 2 Rename service, update ports
Prometheus config 3 Rename scrape targets
Scripts 4 Update binary/service references
FXT TUI 3 Update service name in pod/status fetching
Test crates 5 Update imports, fixture configs
Load test crate 1 Rename testing/api-gateway-load/testing/api-load/

Dashboard Migration (Separate Task)

The React dashboard (web-dashboard/) currently calls web-gateway REST endpoints. After unification:

  1. Replace fetch() calls with @connectrpc/connect-web or grpc-web client
  2. Server-streaming RPCs replace the 8 WebSocket topics
  3. JWT goes in gRPC metadata instead of Authorization header

This is a separate task — the dashboard will be temporarily broken until migrated.

Testing Strategy

  • Port all api_gateway tests (357) with updated imports
  • Delete web-gateway tests (104) — they test REST handlers that no longer exist
  • Add integration tests for tonic-web/grpc-web access
  • Rename testing/api-gateway-load/testing/api-load/, update load test targets