Cloudflare Worker API
The React SPA talks to a Cloudflare Worker that authenticates requests and proxies named parameterised queries to ClickHouse.
Architecture
React SPA (served by Worker as static assets)
|
v
Cloudflare Worker (components/api/)
| URL-pattern routing -> query builder functions -> parameterised SQL
|
v
ClickHouse (HTTPS, parameterised queries)
Named queries live in the Worker, not the client. Query builder functions in src/queries/ (cost.ts, resources.ts, hierarchy.ts) return {sql, params} objects. The router calls these and forwards to ClickHouse. No raw SQL from the client ever reaches ClickHouse.
Authentication
Cloudflare Access JWT validation (src/auth.ts):
- Validates JWTs from
cf-access-tokenheader orCF_Authorizationcookie - Verifies against team JWKS endpoint
- Validates issuer, audience, and email claim
- Health endpoint (
/api/v1/health) requires no auth
Endpoints
Implemented
Cost
GET /api/v1/cost/by-customer ?days=30
GET /api/v1/cost/by-account-role ?days=30
GET /api/v1/cost/tree/:nodeId ?days=30
GET /api/v1/cost/trend/:nodeId ?days=90&granularity=day|hour
Resources
GET /api/v1/resources ?type=ec2:instance&state=running&account_role=...&customer=...&limit=100
GET /api/v1/resources/:arn
GET /api/v1/resources/:arn/children
GET /api/v1/resources/:arn/ancestors
Hierarchy
GET /api/v1/hierarchy/tree ?hierarchy=marqo_logical&root=...
GET /api/v1/hierarchy/node/:nodeId
System
GET /api/v1/health
Delta Decomposition
GET /api/v1/cost/delta ?currentStart=...¤tEnd=...&compareStart=...&compareEnd=...&hierarchy=...&parentNodeId=...
GET /api/v1/cost/delta/resources ?nodeId=...¤tStart=...¤tEnd=...&compareStart=...&compareEnd=...
GET /api/v1/cost/delta/events ?arn=...&start=...&end=...
Planned — Not Yet Implemented
Cost (additional)
GET /api/v1/cost/allocated/:nodeId ?days=30
GET /api/v1/forecast/:nodeId ?month=2025-04
Actions
POST /api/v1/actions/preview { suggestion_id }
POST /api/v1/actions/execute { suggestion_id, confirmed: true }
POST /api/v1/actions/dismiss { suggestion_id, reason }
GET /api/v1/actions/suggestions ?status=pending&sort=saving
GET /api/v1/actions/log ?days=30
GET /api/v1/actions/savings ?days=90
Governance
GET /api/v1/rules
POST /api/v1/rules
GET /api/v1/rules/violations ?severity=critical&status=open
GET /api/v1/anomalies ?days=30
GET /api/v1/changelog ?date=2025-03-28
System (additional)
GET /api/v1/system/status # collector health, account coverage
ClickHouse Client (src/clickhouse.ts)
- HTTPS POST to ClickHouse with basic auth
- ClickHouse native
{param:Type}parameterisation - 5s default timeout
- JSONEachRow response format
- Connection credentials from Wrangler secrets
Action Execution
Status: PLANNED — No POST endpoints or Lambda invocation logic exists yet.
The /api/v1/actions/execute endpoint will invoke the Action Lambda via AWS SDK (Lambda.invoke). The Worker will have an AWS API key for Lambda invocation only — not for EC2/EBS/etc. The Lambda will have its own polo-action-role.
Error Handling
All endpoints return consistent JSON error format:
{ "error": "message", "code": "NOT_FOUND" }
HTTP status codes: 200 (success), 400 (bad params), 401 (no auth), 403 (forbidden), 404 (not found), 500 (internal).