AZ-004 — Structured diagnostics
Status
Done
Context
Read README. request.log.error is currently ineffective as a logging foundation
because buildApp uses Fastify() without logging. AZ-003 supplies optional correlation metadata
and a frontend unexpected-error boundary. Configuration is validated in backend config.ts and
composed in server.ts; Docker logs are the existing operational destination.
Goal
Make failures traceable using structured request/integration event conventions without leaking credentials, account information or token-bearing URLs.
Requirements
- Enable Fastify's built-in Pino logger at the composition/configuration boundary. Inject a logger/sink or options for tests, with quiet deterministic fast-test defaults. Do not add a second backend logging library, external platform, collector or telemetry database.
- Introduce validated
LOG_LEVELwith sensible development/staging/production defaults and a clear override. JSON stdout is canonical and works in Compose/platform logs; optional local pretty output may be omitted. Invalid level fails startup without printing secrets. - Generate server-owned request IDs; return
X-Request-IDon API successes/errors and AZ-003 errorrequestIdfor failures. Never blindly trust arbitrary incoming IDs: either generate afresh always (preferred baseline), or accept only a documented trusted-proxy bounded format. Test spoofed/control-character/oversized inputs and ensure logs cannot be injected. - Capture method, safe route template, status, duration and request ID. Do not log raw URL/query strings (reset tokens may appear), bodies, Authorization, Cookie, Set-Cookie, database URLs, email addresses, passwords, hashes, provider keys or mail payloads. Use allowlisted serializers plus defense-in-depth redaction, including unexpected error serialization/cause chains.
- Log expected validation/not-found errors at appropriate low levels, authentication/rate-limit events as sanitized security events, and unexpected failures as error with enough safe operation/category detail. Do not dump raw third-party errors merely because Pino supports it.
- Expose a small typed sanitized event/reporting convention usable by authentication and the future email adapter: operation, outcome, duration, request ID, safe provider label/status. Application contracts carry optional operation context without importing Fastify/Pino. Propagate correlation internally to outbound transport; send a provider correlation header only if supported and useful, otherwise retain local association. No distributed tracing system.
- Frontend unexpected boundary/transport diagnostics use one sanitized reporting function: category, app version and bounded correlation ID, with console reporting as baseline. No raw network body, credentials, full URL, form state or localStorage dump. Treat expected validation, logout/expiry and cancellation as user behavior, not unexpected crashes. Avoid repeating the same query error on each render. Do not add browser-to-server reporting endpoints solely now.
- Register explicit SIGTERM/SIGINT shutdown at
server.ts: close Fastify and repositories once, report safe shutdown failures, avoid duplicate signal handling/hanging connections. Preserve existingonClosedatabase cleanup; keep process wiring thin and exercise packaged lifecycle.
Non-goals
No Prometheus/Grafana/Sentry/OpenTelemetry stack, dashboards, analytics, persisted audit-log system, IP/email security history, new readiness contract, or frontend remote error service.
Implementation guidance
Use Fastify logger configuration and safe serializers, not calls to console.log in services. Test
sinks parse actual JSON events and verify presence AND absence of sensitive sentinels across
success/error/validation cases. Use deterministic injected clock/IDs only where needed for behavior
tests. Docker signal smoke checks are targeted lifecycle tests; no blanket no-cache build. Respect
TypeDoc's intentional public entry points when extending BuildAppOptions.
Acceptance criteria
- A real backend API failure produces structured safe diagnostics with the same ID received by the client; successes also expose the ID.
- Invalid levels and malicious incoming ID strings do not degrade logging integrity.
- Sentinel passwords/cookies/URLs/provider keys/error causes never appear in captured logs.
- Expected errors and frontend repeated renders do not flood unexpected-error reporting.
- Shutdown closes the application/database once and completes on SIGTERM in Compose.
Verification
pnpm quality
pnpm test
pnpm test:coverage
pnpm build
pnpm validate:docker
Add injection/logger-sink and frontend reporting tests. Check Compose backend stdout for JSON, request/status/duration/ID on a safe test request and failure, then perform a targeted container termination/restart check with no business data loss. Validate using an isolated local project; never exercise synthetic failures on hosted staging. No UI layout change is required, but any correlation detail shown by AZ-003 must wrap at 360px.
Documentation
Update development (levels, safe event examples, local log inspection), architecture (context and
redaction), Docker (signal lifecycle), testing, OpenAPI (X-Request-ID), current-state/handover.
Dependencies
AZ-003; existing validated backend configuration, Fastify composition, frontend error conventions.