Files
2026-05-27 23:29:53 +01:00

5.3 KiB

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<T>, 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/.