chore: record pre-existing uncommitted repository state
Snapshot of the in-flight state that already existed, identically, in both this worktree and the main checkout before this session began: the initial HTTP Client platform implementation (previously untracked), the redis-lab removal, and the JPA / object-storage / notification integration work. Kept separate from this session's HTTP Client review response, which lands in the following commit, so the two bodies of work stay reviewable apart. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1a3b560678
commit
5f10b791d3
@@ -0,0 +1,74 @@
|
||||
# Client-Safe Error Boundary Design
|
||||
|
||||
**Date:** 2026-08-02
|
||||
**Status:** approved by the user's instruction to apply the detailed P1/P2 review sequentially
|
||||
**Scope:** HTTP error envelopes in `adapter:inbound:web` and the `sample-portfolio` domain advice
|
||||
|
||||
## Context
|
||||
|
||||
Several handlers pass `Exception#getMessage()`, rejected request values, or a raw request URL into
|
||||
the public error envelope. Those values are not a stable API contract and can contain identifiers,
|
||||
tokens, uploaded values, configuration details, or internal diagnostics. Persistence and outbound
|
||||
dependency failures already use fixed client-safe messages; the rest of the HTTP boundary must
|
||||
follow the same rule.
|
||||
|
||||
## Decision
|
||||
|
||||
The inbound adapter owns a message allowlist keyed by stable error code. Handlers may expose only:
|
||||
|
||||
- stable `code`, `category`, HTTP status, and `retryable` from `ApiErrorCode`;
|
||||
- fixed, code-specific client messages;
|
||||
- bounded structural details such as field name, validation reason code, expected Java type,
|
||||
supported HTTP methods, or supported media types.
|
||||
|
||||
They must not expose exception messages, rejected values, raw request URLs, adapter/configuration
|
||||
diagnostics, opaque cursors, authentication diagnostics, resource identifiers, or duplicate domain
|
||||
values. Bean Validation interpolated/default messages are also discarded because custom templates
|
||||
can include the validated value. Validation details contain only normalized server-owned property
|
||||
names plus allowlisted reason codes and fixed messages; collection/map keys and indices are removed.
|
||||
|
||||
`ClientSafeErrorMessages` is extended for skeleton-wide operational codes. The sample keeps its
|
||||
domain wording in a separate package-private `PortfolioClientSafeErrorMessages`, preserving the
|
||||
rule that production modules do not know sample business concepts.
|
||||
|
||||
## Public Messages
|
||||
|
||||
Representative mappings are fixed as follows:
|
||||
|
||||
- `MAPPING_FAILED` → `Request data could not be mapped`;
|
||||
- `BAD_PARAMETER` → `Request parameter is invalid`;
|
||||
- `INVALID_TOKEN` → `Authentication token is invalid`;
|
||||
- `UNAUTHENTICATED` → `Authentication is required`;
|
||||
- authorization denials → `Access is denied`;
|
||||
- `PRECONDITION_FAILED` → `Resource state changed; refresh and retry`;
|
||||
- page/cursor failures → generic corrective text, with safe field/reason details retained;
|
||||
- `ADAPTER_DISABLED` and internal classifications → `Internal server error`;
|
||||
- domain not-found/conflict/invariant codes → fixed noun-level text with no ID/title value.
|
||||
|
||||
Transport overrides use fixed wording and retain only safe protocol metadata. For example, 405
|
||||
still emits `Allow`, while both controller-route (`NoHandlerFoundException`) and static-resource
|
||||
(`NoResourceFoundException`) 404s use the same envelope without echoing the request URL.
|
||||
|
||||
## Testing
|
||||
|
||||
Tests inject conspicuous secret sentinels into exception messages, rejected values, URLs, tokens,
|
||||
IDs, and duplicate titles. Every resulting response must preserve its status/code/category while
|
||||
excluding the sentinel from both `error.message` and `error.details`.
|
||||
|
||||
Validation tests additionally place sentinels in interpolated/default messages and iterable
|
||||
keys/indices. A real MockMvc resource-resolution request verifies the Spring 7
|
||||
`NoResourceFoundException` path rather than calling the advice method directly.
|
||||
|
||||
The focused module suites remain the primary verification:
|
||||
|
||||
- `:adapter:inbound:web:test` for operational and transport handlers;
|
||||
- `:sample-portfolio:test` for domain advice and sample wire behavior;
|
||||
- `verifyCleanArchitectureDependencies` for dependency direction.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- no change to error codes, categories, statuses, or retryability;
|
||||
- no suppression of server-side logs or tracing in this batch;
|
||||
- no application/domain dependency on HTTP response types;
|
||||
- no generic exception-message sanitizer based on regexes or truncation;
|
||||
- no staging, commit, amend, or push by an agent.
|
||||
Reference in New Issue
Block a user