Appearance
API Gateway Core
The single boundary around resources, enforcing auth, rate limits, retries, circuit breakers, and observability.
Epic: Gateway Foundation ✓
Plan: Build a stateless, connector-based API gateway that routes requests to external resources (Salesforce, partners, databases, payments) through a uniform pipeline. The gateway is the single ingress point for all platform traffic.
Architectural Context: The gateway is stateless — any request can hit any replica. Connectors encapsulate vendor-specific logic (auth, API translation, error mapping). The request pipeline is a fixed chain: authenticate → rate limit → route to connector → vendor call → handle errors → log → respond. This design isolates vendor complexity from the rest of the platform.
Tasks
Build stateless request routing (any request hits any replica)Implement connector-based resource integration (Salesforce, partners, databases, payments)Build request flow pipeline: authenticate → rate limit → route to connector → vendor call → handle errors → log → respondImplement connector abstraction (vendor-specific auth, API translation, error mapping, rate limit tracking)
Epic: Authentication System ✓
Plan: Implement a two-layer auth system: inbound consumer auth (API key + secret, optional mTLS) and outbound vendor auth (OAuth 2.0 JWT Bearer for Salesforce). Credentials are stored in Doppler and rotated automatically.
Architectural Context: Inbound auth validates every incoming request against consumer credentials with scoped permissions. Outbound auth manages OAuth tokens for vendor APIs, with proactive refresh and Redis-cached tokens shared across gateway replicas. The system supports key rotation with a grace window for zero-downtime credential changes.
Tasks
Implement inbound consumer auth (API key + secret, mTLS option)Build per-consumer credential management with scoped permissionsImplement key rotation with grace window for old keysImplement outbound vendor auth (OAuth 2.0 JWT Bearer for Salesforce)Build token refresh worker (proactive, not reactive)Implement JWT token cache in Redis shared across gateway replicasStore all credentials in Doppler
Epic: Error Handling and Resilience
Plan: Build a resilient error handling layer with categorization, bounded retries, idempotency, and circuit breakers. Every error returns a uniform shape with actionable metadata.
Architectural Context: Errors are categorized as Transient (retryable), Permanent (not retryable), Quota (back off), or Unknown. The circuit breaker opens after >50% errors over 1 minute, with cool-down and half-open probes. Idempotency keys prevent duplicate writes on retry. This layer sits between the connector and the response, ensuring consistent error behavior across all vendors.
Tasks
- Implement error categorization (Transient, Permanent, Quota, Unknown)
- Build bounded retry strategy (max 3 attempts, 30s total, exponential backoff with jitter)
- Implement idempotency key requirement for all writes (24h Redis cache)
- Build circuit breaker (open after >50% errors over 1 minute, cool-down, half-open probes)
- Implement uniform error response shape with
code,message,retryable,vendor_code,request_id
Epic: Rate Limiting and Quota Management
Plan: Enforce per-consumer inbound rate limits and per-resource outbound quota tracking. Fail fast when quotas are exhausted, and apply backpressure with 429 + Retry-After headers.
Architectural Context: Inbound limits protect the gateway from consumer overload (requests_per_minute, requests_per_hour, concurrent_in_flight). Outbound quotas track Salesforce governor limits and partner API budgets, with pre-flight checks that fail fast when <10% remains. Salesforce uses a per-user connection pool with an org-wide budget tracker.
Tasks
- Implement per-consumer inbound limits (requests_per_minute, requests_per_hour, concurrent_in_flight)
- Build per-resource outbound quota tracking (Salesforce governor limits, partner API quotas)
- Implement Salesforce per-user connection pool and org-wide budget tracker
- Build pre-flight budget check (fail fast if <10% remains)
- Implement backpressure with 429 + Retry-After header