AZ-003 — API errors and mobile feedback
Status
Done
Context
Read README. Backend app.ts has centralized handled errors and safe error strings;
unknown-route 404s are an exception. Frontend api-client.ts distinguishes API/network failures but
always parses successful JSON, so 204 is not supported and malformed success JSON is not normalized.
Existing components/async-states.tsx and Home tests already cover loading/errors. AZ-002 supplies
MUI/theme/localization. Extend these mechanisms instead of adding a second client.
Goal
Establish compatible error contracts and usable mobile loading/validation/notification behavior for the forthcoming forms and account operations.
Requirements
- Retain required safe
{ "error": "..." }; add optional stablecode, allowlisted field issues (field,code, optional safe message), andrequestId. Existing message endpoint's status and descriptions stay compatible; added fields must be documented. Do not replace the body wholesale with Problem Details or return framework stacks/SQL/raw schema errors. - Define a small error-code vocabulary for invalid request/validation, unauthenticated, invalid
credentials, rate limiting, not found, conflict and internal failure. Map meaningful application
errors in HTTP code; application services do not contain status/header objects. Feature tasks add
specific codes to this convention. Unknown
/api/*routes use the same safe 404 shape; keep/healthliveness and SPA fallback behavior unchanged. - Input validation for new JSON forms uses backend Zod or existing Fastify validation at the HTTP boundary with explicit size/field constraints. Normalize malformed JSON, unknown fields, field errors and oversized input safely; the message endpoint continues rejecting query input. No generic schema/CRUD framework or duplicate frontend/backend source package.
- Extend
ApiErrorto retain known optional code/issues/request ID while tolerating the legacy body and non-JSON error responses. Normalize malformed success JSON as a distinct safe response error. Support JSON operations and successful no-content responses deliberately, with typed endpoint wrappers; do not silently cast 204 to arbitrary data or parse it as JSON. - Keep fetch, headers, URL resolution, abort handling and status parsing in
app/api/. Expected abort/cancellation should not surface as alarming network failure. Feature pages use endpoint operations and translated error mappings, never fetch or response parsing. - Add a small central code → translation mapping with safe generic fallback. Client text does not render arbitrary server exception messages or field values. A correlation ID may be shown for unexpected failures as support detail, once AZ-004 supplies it. Database message content remains literal business data.
- Evolve shared MUI loading/error/empty-state presentation and a narrow notification context with Snackbar/Alert. Loading respects reduced motion and announces relevant progress; empty differs from failure. Field failures appear beside labeled fields plus an accessible summary as needed; focus moves to the first invalid field after submit. Use ordinary flow content on narrow screens, not a blocking desktop dialog.
- Notifications wrap within viewport, avoid covering required controls indefinitely, announce with appropriate status/alert semantics, and have accessible dismissal. Do not send every query failure through both inline error and global snackbar. Keep notification state outside Redux unless a concrete cross-task requirement emerges; no generic event bus/queue framework.
- Add a top-level React error boundary with localized safe fallback and retry/reload action. Route failures/not-found have an accessible recovery destination; expected API failures remain inline. AZ-004 supplies sanitized reporting, rather than introducing a remote error vendor.
Non-goals
No auth endpoints, global automatic retries for mutations, domain validation engine, logging platform, server internationalization, or redesign of the existing message contract.
Implementation guidance
Extend backend error handling and OpenAPI shared components with API tests. Reuse existing frontend error types/async states and providers, and retain TanStack Query ownership. Test new error/empty/boundary presentations through controlled collaborators rather than adding fake production pages just to demonstrate notifications. Rate-limit retry metadata is a safe header, not a request to automatically retry non-idempotent mutations. No arbitrary percentage target: the existing 100% source coverage remains mandatory.
Acceptance criteria
- Legacy message errors, extended validation errors and unknown API routes share compatible safe handling; malformed/oversized input does not leak internals.
- Transport distinguishes network, API, malformed success, cancellation and no-content.
- Known codes/issues translate; unknown/untrusted bodies yield safe generic messages.
- Inline errors, empty/loading states, snackbar and unexpected-error boundary are usable with keyboard/screen reader and at 320/360px widths, with no duplicate announcements.
- OpenAPI and route-surface/HTTP behavior tests agree, and Home still loads real data.
Items 1–3 and 5 have component/API/integration evidence recorded in current state. Item 4's keyboard/screen-reader semantics, first-invalid-field focus, and non-duplication of inline versus snackbar feedback are covered by component tests; its 320/360px viewport review is still outstanding.
Verification
pnpm quality
pnpm test
pnpm test:coverage
pnpm build
Aggregate coverage needs local/test PostgreSQL per the existing testing guide. Add backend injection cases and frontend transport/RTL tests for all changed categories. Manually check long translated errors and snackbar dismissal at 360×800, 320px and desktop, keyboard focus and reduced motion. Normal CI supplies full Docker/integration evidence; add local browser verification if a changed scrolling/focus behavior cannot be reliably checked with RTL.
Documentation
Update OpenAPI, architecture error/API conventions, development form/feedback guidance, testing,
current-state/handover. Keep required error compatibility and optional field semantics explicit.
Dependencies
AZ-002 (which includes AZ-001); existing central backend/frontend error boundaries.