# Tasks: enterprise-api-gateway **Change ID**: enterprise-api-gateway **Package**: `@suaveplan/api-gateway` **Target path**: `api/framework/api-gateway` **Prerequisite packages on Verdaccio**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/logger`, `@suaveplan/retry`, `@suaveplan/rate-limiter`, `@suaveplan/events`, `@suaveplan/api` --- ## 0. Pre-flight (non-negotiable) - [ ] 0.1 Confirm clean working tree (`git status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in each) - [ ] 0.2 If any worktrees exist under `.claude/worktrees/`, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (`git worktree remove`) before opening a new one — code that has been lost twice on main is the failure mode this guards against. - [ ] 0.3 Confirm the package set in `MANIFEST.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest. ## 1. Scaffold - [ ] Create `api/framework/api-gateway/` with all subdirs per layout. - [ ] `package.json` v0.0.0, `"sideEffects": false`, subpath exports per feature module. - [ ] `tsconfig.json` extending `library-node.json`. - [ ] `vitest.config.ts` via `createTestConfig()`. - [ ] Scripts: `lint`, `typecheck`, `test`, `test:coverage`, `build`, `docs:check`, `bench`. --- ## 2. Types, schemas, errors - [ ] `src/types/common.ts` — all interfaces and type aliases listed in proposal. - [ ] `src/types/common.md` (≥200 words, API reference, both examples). - [ ] `src/schemas/config.schema.ts`, `route.schema.ts`, `circuit-breaker.schema.ts` — Zod schemas; `createGateway` parses with `GatewayConfigSchema.parse(config)`. - [ ] `src/errors/gateway-errors.ts` — 6-code union, metadata, `registerGatewayErrorCodes()`, `GatewayError` re-export. - [ ] `gateway-errors.test.ts` and `gateway-errors.md`. --- ## 3. Router - [ ] `Router`: path-pattern matching (static + `:param` + wildcard `*`), method matching, ordered by specificity (static > param > wildcard). - [ ] `match(req)` returns first match or `null`. - [ ] `router.test.ts`: static match, param extraction, wildcard, method mismatch returns null, method `*` matches any. - [ ] `router.md`. --- ## 4. LoadBalancer - [ ] Strategies: `round-robin` (stateful counter), `random`, `weighted` (weight-proportional selection), `consistent-hash` (FNV-1a on a configurable key). - [ ] Skip targets with `health === 'unhealthy'`. - [ ] `balancer.test.ts`: each strategy, all-unhealthy throws `GatewayError(GATEWAY_NO_ROUTE)`. - [ ] `balancer.md`. --- ## 5. TransformerPipeline + helpers - [ ] `TransformerPipeline`: ordered list of `RequestTransformer | ResponseTransformer`; `run` applies request transformers, `runResponse` applies response transformers; catch on transformer throws `GatewayError(GATEWAY_TRANSFORM_FAILED)`. - [ ] Implement all six helper factories listed in proposal. - [ ] `transformer.test.ts`: each helper, pipeline ordering, error wrapping. - [ ] `transformer.md`. --- ## 6. GatewayCircuitBreaker - [ ] States: `closed` → `open` (after `failureThreshold` consecutive failures) → `half-open` (after `resetTimeout` ms) → `closed` (after `successThreshold` successes in half-open). - [ ] `record(success)` transitions state; emits `gateway:circuit:state` event on `@suaveplan/events` bus when state changes. - [ ] Injectable `Clock` for timeout tracking. - [ ] `circuit-breaker.test.ts`: full state machine cycle; half-open success restores, failure re-opens; open throws `GatewayError(GATEWAY_CIRCUIT_OPEN)`. - [ ] `circuit-breaker.md`. --- ## 7. HealthChecker - [ ] `HealthChecker` interface: `start()`, `stop()`, `getHealth(targetId): TargetHealth`. - [ ] Default interval-based implementation: probe via configurable `probe: (target: Target) => Promise`; update `target.health`; emit `gateway:target:health` event on state change. - [ ] `health.test.ts`: probe called on interval, healthy → unhealthy transition emits event, `stop()` clears interval. - [ ] `health.md`. --- ## 8. Gateway - [ ] `createGateway(config)`: parse config via Zod, construct router + balancer + circuit-breaker + transformer pipeline. - [ ] `handle(request)`: 1. Rate-limit check (if limiter injected) → 429 via `GatewayError`. 2. `Router.match` → null throws `GatewayError(GATEWAY_NO_ROUTE)`. 3. Circuit-breaker open → throws `GatewayError(GATEWAY_CIRCUIT_OPEN)`. 4. Load-balance to target. 5. Apply request transformers. 6. Call `config.fetcher` with retry policy (`@suaveplan/retry`). 7. Apply response transformers. 8. Record circuit-breaker outcome. 9. Return `GatewayResult`. - [ ] Wrap entire flow in OTel span `gateway.handle`. - [ ] `gateway.test.ts` (≤500 lines): happy path, no-route, circuit open, upstream timeout, retry succeeds on second attempt, transformer rewrite applied. - [ ] `gateway.md`. --- ## 9. Hono adapter - [ ] `gatewayMiddleware(gateway: IGateway): MiddlewareHandler` — converts Hono `Request` → `GatewayRequest`, calls `gateway.handle`, maps `GatewayResult` → Hono `Response`. - [ ] `hono-adapter.test.ts`: 200 forwarded, 404 no-route, circuit-open → 503. - [ ] `hono-adapter.md`. --- ## 10. Property-based tests (`tests/property.test.ts`) - [ ] **Router invariant**: for any route table + request, `match` returns either a consistent route or null (never throws); matched route's method contains the request method. - [ ] **Balancer fairness**: round-robin distributes N requests across K healthy targets with equal ±1 frequency. - [ ] **Circuit-breaker monotonicity**: for any sequence of boolean outcomes, the state sequence never transitions `open → closed` directly (always through `half-open`). - [ ] Timeout 30 000 ms on each `it()`. --- ## 11. Benchmarks (`src/__benchmarks__/gateway.bench.ts`) - [ ] `gateway_handle_passthrough`: `handle()` with 1 target, no transforms, in-process no-op fetcher. - [ ] `gateway_handle_5_transforms`: same but with 5 transformers. --- ## 12. Integration tests (`tests/integration.test.ts`) - [ ] Wire a real Hono upstream server; `Gateway.handle` proxies to it; assert response forwarded correctly. - [ ] Circuit-breaker trips after threshold; half-open probe restores. --- ## 13. Docs and publish - [ ] All co-located `.md` files (≥200 words, both examples, full API reference). - [ ] Root `README.md`. - [ ] `bunx turbo lint typecheck test --filter=@suaveplan/api-gateway` — green. - [ ] `bunx turbo test:coverage --filter=@suaveplan/api-gateway` — 100%. - [ ] `bun scripts/publish.ts --package @suaveplan/api-gateway`. - [ ] Archive → `openspec/archive/2026-04-24-enterprise-api-gateway/`.