# Tasks: enterprise-api-shared **Change ID**: enterprise-api-shared **Package**: `@suaveplan/api-shared` **Target path**: `api/framework/api-shared` **Prerequisite packages on Verdaccio**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/logger`, `@suaveplan/api`, `@suaveplan/api-schemas` --- ## 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-shared/` with `src/`, `tests/`, `src/__benchmarks__/`, and all feature subdirectories. - [ ] Write `package.json` at version `0.1.0`: `"type": "module"`, `"sideEffects": false`, exports map with `"."` barrel + per-feature subpaths. - [ ] Write `tsconfig.json` extending `@suaveplan/typescript-config/library-node.json`. - [ ] Write `vitest.config.ts` using `createTestConfig()`. - [ ] Add `lint`, `typecheck`, `test`, `test:coverage`, `build`, `docs:check`, `bench` scripts. --- ## 2. Types and errors - [ ] Define shared TS interfaces in `src/types/common.ts`: `ApiSuccessResponse`, `ApiErrorResponse`, `ApiPaginatedResponse`, `PaginationMeta`, `PaginationQuery`, `SortQuery`, `FilterQuery`, `ResponseMeta`. - [ ] Write `src/types/common.md`. - [ ] Implement `src/errors/api-shared-errors.ts`: 4-code `ApiSharedErrorCode` union, metadata, `registerApiSharedErrorCodes()`. - [ ] Write `api-shared-errors.test.ts` and `api-shared-errors.md`. --- ## 3. Response helpers - [ ] Implement `successResponse`, `errorResponse`, `paginatedResponse`, `noContentResponse`. - [ ] `errorResponse` converts `SuaveplanError` to RFC 7807 `application/problem+json` body. - [ ] Write `response-helpers.test.ts` (success envelope shape, error problem+json, paginated shape, 204 status). - [ ] Write `response-helpers.md`. --- ## 4. Middleware: request-id - [ ] Read `X-Request-ID` header; generate UUID v4 via `crypto.randomUUID()` if absent; set on response headers and Hono context variable `c.set('requestId', ...)`. - [ ] Write `request-id.test.ts`: header forwarded, generated if missing. - [ ] Write `request-id.md`. --- ## 5. Middleware: correlation-id - [ ] Read `X-Correlation-ID`; propagate to response + context + OTel span attribute `correlation_id`. - [ ] Write `correlation-id.test.ts` and `correlation-id.md`. --- ## 6. Middleware: tenant-context - [ ] Extract `X-Tenant-ID` header; set `c.set('tenantId', ...)`. If missing and `required: true` option set, return 400 via `ApiSharedError(API_SHARED_MISSING_TENANT)`. - [ ] Write `tenant-context.test.ts`: header present, absent (pass-through), absent (required throws). - [ ] Write `tenant-context.md`. --- ## 7. Middleware: request-logging - [ ] On request start: log method, path, requestId at `debug`. - [ ] On response: log status, duration (ms), requestId at `info`. - [ ] Record `http.request_duration_ms` histogram with `http.method` + `http.status_code` attributes. - [ ] Write `request-logging.test.ts` (log entries emitted, duration recorded). - [ ] Write `request-logging.md`. --- ## 8. Middleware: error-handler - [ ] Catch unhandled errors in Hono; if `SuaveplanError`, call `errorResponse`; else wrap in a generic 500 problem detail. - [ ] Never leak stack traces in production (`NODE_ENV !== 'development'`). - [ ] Write `error-handler.test.ts`: SuaveplanError → problem+json, unknown error → 500. - [ ] Write `error-handler.md`. --- ## 9. Schema utilities - [ ] `parsePaginationQuery` — wraps `@suaveplan/api-schemas` `PaginationQuerySchema`; throws `ApiSharedError(API_SHARED_INVALID_PAGINATION)` on failure. - [ ] `parseSortQuery` — validates `sortBy` against `allowedFields`; throws `ApiSharedError(API_SHARED_INVALID_SORT)`. - [ ] `parseFilterQuery` — validates operator keys against `allowedFields`; throws `ApiSharedError(API_SHARED_INVALID_FILTER)`. - [ ] Write tests (valid, invalid, unknown field) and `.md` for each. --- ## 10. Benchmarks (`src/__benchmarks__/middleware.bench.ts`) - [ ] Benchmark 5-middleware chain (requestId + correlationId + tenantContext + requestLogging + errorHandler) on a Hono test app. --- ## 11. Integration tests (`tests/integration.test.ts`) - [ ] Mount all middleware on a test Hono app; verify request-id/correlation-id headers in response, tenant missing → 400, SuaveplanError → problem+json body. --- ## 12. Docs - [ ] All co-located `.md` files (≥200 words, both examples, full API reference). - [ ] Root `README.md`. - [ ] `docs:check` passes. --- ## 13. Verify and publish - [ ] `bunx turbo lint typecheck test --filter=@suaveplan/api-shared` — green. - [ ] `bunx turbo test:coverage --filter=@suaveplan/api-shared` — 100%. - [ ] `bun scripts/publish.ts --package @suaveplan/api-shared`. - [ ] Archive change → `openspec/archive/2026-04-24-enterprise-api-shared/`.