Skip to content

Menu-host analytics proxy design

Goal

Allow every published menu host to submit privacy-safe analytics to the API without changing the host-bound publication-token contract.

Approved architecture

Published HTML uses the same-origin path /menu-analytics/events. The menu gateway accepts only the public analytics POST route and forwards it to the internal API service at http://api:3000, preserving the original normalized menu Host header. The API continues to validate the HMAC token against that menu host and publication ID.

Boundaries

  • The gateway never trusts a client-provided X-Menu-Host header.
  • The gateway forwards only the first valid client IP from the trusted ingress X-Forwarded-For chain for API rate limiting; it strips the rest of the chain.
  • The gateway forwards only POST /menu-analytics/events.
  • Request bodies are capped at 4 KiB, matching the event contract.
  • The internal API origin is private container-network configuration.
  • GET, HEAD, unsupported paths, oversized bodies, and malformed forwarding responses fail closed.
  • Existing absolute HTTPS analytics endpoints remain accepted for compatibility, but the default deployment value is the same-origin path.

Configuration

  • MENU_ANALYTICS_ENDPOINT=/menu-analytics/events in staging and production.
  • MENU_ANALYTICS_API_ORIGIN=http://api:3000 in the menu gateway runtime.
  • MENU_ANALYTICS_ACTIVE_KEY_ID remains an Environment variable.
  • MENU_ANALYTICS_KEYS_JSON remains an Environment secret.

Acceptance criteria

  1. A published page emits the same-origin endpoint and keeps CSP connect-src same-origin.
  2. A gateway POST forwards the raw body and original menu Host to the API.
  3. The gateway rejects non-POST analytics requests and bodies larger than 4 KiB.
  4. API host-bound token validation still succeeds for the forwarded menu host.
  5. Staging and production workflows write all analytics configuration to the API env file and the internal API origin to the menu gateway env file.
  6. Focused gateway/config tests, API typecheck, formatting, lint, and diff checks pass.