Runbook: Route the Dashboard Through API Gateway (HTTP)¶
Owner: backend infra (Grenguar / Igor) Branch: feat/api-gw-frontend-ingress (off dev) PR scope: introduce API Gateway as the frontend's HTTP path. No breaking change — the ALB stays publicly reachable. No DNS flip, no cert work, no SG lockdown in this PR.
WebSocket support lives in the stacked follow-up feat/api-gw-websocket.
What this PR does¶
- Adds
dashboard_alias_middlewareto the backend FastAPI app (services/backend/src/tradai/backend/api/dashboard_aliases.py). It rewrites the dashboard's unversioned paths (/api/catalog/*,/api/experiments,/api/runs/*) to their/api/v1/*equivalents before routing. - Extends
API_ROUTESininfra/shared/tradai_infra_shared/config.pywith the same unversioned paths so the existing API Gateway HTTP API (infra/edge/__main__.py) accepts and proxies them. - Adds a pytest smoke suite that hits the dev API Gateway execute-api URL with a Cognito M2M client_credentials token (
tests/e2e/test_api_gateway_smoke.py).
What this PR does not touch (deferred): - infra/edge/Pulumi.dev.yaml — api_domain / certificate_arn stay unset. The frontend will use the auto-generated <api_id>.execute-api… URL. - ALB security-group lockdown. - WAF re-association. - Squarespace DNS. - The legacy api-dev.tradai-system.com CNAME → ALB path. It stays live as the rollback path.
Current ⇄ target state (with this PR)¶
Today With this PR
───── ────────────
Browser → api-dev.tradai-system.com Browser → <api_id>.execute-api… ← NEW PATH
→ ALB (SG 0.0.0.0/0:443) → API GW (Cognito JWT)
→ FastAPI (JWT in app) → VPC Link → ALB → FastAPI
(alias middleware
rewrites /api/* → /api/v1/*)
Browser → api-dev.tradai-system.com ← unchanged rollback
→ ALB → FastAPI
How to verify¶
- Deploy the edge stack:
just infra-up-edge dev. - Fetch an M2M token:
- Run the smoke suite:
- Manual:
curl -H "Authorization: Bearer $TOKEN" "$TRADAI_E2E_BASE_URL/api/catalog/strategies"returns 200. - Regression:
curl https://api-dev.tradai-system.com/api/v1/healthstill returns 200 (ALB path intact).
Follow-ups, not in this PR¶
feat/api-gw-websocket(stacked PR) — add a WebSocket API forwss://.- Custom domain
apigw-dev.tradai-system.com(cert + DomainName + ApiMapping + Squarespace CNAME). - Lock ALB SG to VPC-Link SG only.
- Wire
M2M_CLIENT_SECRETretrieval to Secrets Manager in CI. - Rotate the M2M client secret in Cognito (the previous value was leaked in a chat log; the new value should live only in Secrets Manager — see
[TODO: secrets_manager_arn_for_m2m_secret]). Do NOT inline secret values in this runbook; reference the Secrets Manager ARN instead.
Interactions with in-flight PRs¶
- #516 (prod hardening) — touches the same
disable_execute_api_endpointline ininfra/edge/modules/api_gateway.pyand the WAF wiring ininfra/edge/__main__.py. On rebase, those two hunks need to be dropped (the conditional landed in79aebef1ondevalready). Self-coordinated (Grenguar). - #600 / #596–#599 (v4 prod chain) — orthogonal.
- #617 (this branch's predecessor, runbook docs) — supersede; close after merge.
Frontend (tradai-bot/tradai-dashboard) — separate PR¶
In the dashboard repo, set the Amplify-deployed env var to the API Gateway URL (or to a Squarespace CNAME pointing at API GW once domain work lands). Today the single value to change is VITE_API_BASE_URL.