Files
mercadodevida/work/artifacts/F-003/implementer.md
rikrdo 41f144d7bd feat(F-003): HTTP foundation with request context and error envelope
- request_id generated or sanitized-propagated on every request (x-request-id)
- structured JSON logging (pino), one correlated line per request, injectable logger
- error envelope v2 { error: { statusCode, code, message, details? }, requestId }
- 5xx messages always generic; stack traces stay in server logs only
- explicit parseJson (zod) input validation hook at the API layer
- README HTTP contract section; deps justified in spec/tech.md
- all gates approved; verify.sh green
2026-08-14 22:13:28 +02:00

2.3 KiB

Implementer — F-003 HTTP foundation and request context

done -> work/artifacts/F-003/implementer.md

Files created

  • src/infrastructure/logging/logger.ts (pino factory; JSON only; injectable destination for tests)
  • src/shared/http-input.ts (parseJson zod helper -> AppError 400 VALIDATION_ERROR with field paths)
  • src/app/tests/http-foundation.test.ts (9 tests: id generation/propagation/sanitization, log correlation, envelope stability, no stack leak, one log line per request)
  • src/shared/tests/http-input.test.ts (3 tests)

Files modified

  • src/shared/errors.ts: AppError class + error envelope v2 { error: { statusCode, code, message, details? }, requestId } (additive over F-001 shape)
  • src/app/build-app.ts: genReqId sanitization (^[A-Za-z0-9._-]{1,128}$ else randomUUID), onRequest/onResponse hooks (x-request-id header + one JSON log line per request), explicit setErrorHandler/setNotFoundHandler with requestId; buildApp({ logger? }) injectable
  • src/infrastructure/http/server.ts: startup/shutdown logging via injected logger
  • spec/tech.md: pino + zod justification
  • package.json: deps pino, zod

API changes

  • Every response now carries x-request-id header
  • Error body v2: { error: { statusCode, code, message, details? }, requestId }
  • GET /health body unchanged

Tests passed (evidence)

npm run lint:boundaries -> Boundary check OK: 16 file(s) checked
npm run lint            -> OK
npm run typecheck       -> exit 0
npm run build           -> exit 0
npm test                -> 6 files passed, 2 skipped (integration, no DB in unit run); 23 passed | 6 skipped
live smoke (PORT=3998):
  GET /health        -> 200, x-request-id: 65b38aee-..., body {"status":"ok"}
  GET /nope          -> 404 envelope v2 with requestId matching log line
  POST /health bad json -> 400; log code FST_ERR_CTP_INVALID_JSON_BODY with same requestId as response
  server logs: one "request completed" JSON line per request carrying requestId

Known limitations

  • Fastify 4xx parse-error messages are exposed as-is (e.g. "Unexpected token"); they carry no internals and are standard.
  • Validation hook is exercised via a test-only route (/__test/echo registered in composition test); first production consumer arrives with F-005.

Follow-up work

  • F-004 config/flags will centralize LOG_LEVEL handling.
  • F-005 identity first real parseJson consumer.