Files
clean-architecture-backend-…/docs/superpowers/plans/2026-08-02-client-safe-error-boundary.md
DongHyeonkaandClaude Opus 5 5f10b791d3 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>
2026-08-11 16:48:43 +09:00

4.3 KiB

Client-Safe Error Boundary Implementation Plan

Execution: Follow superpowers:test-driven-development; request an independent code review before advancing to the next P1 batch.

Goal: Ensure public HTTP error envelopes contain only allowlisted messages and bounded safe metadata, never raw exceptions or request values.

Architecture: The inbound web adapter maps operational codes to fixed public messages. The sample consumer owns a parallel domain-code mapping. Exception diagnostics stay behind the transport boundary.

Tech Stack: Java 21, Spring Boot 4.0.0, JUnit 6/JUnit Jupiter, AssertJ, MockMvc.

Constraints

  • Preserve all completed P0 and verification-purity changes in the dirty worktree.
  • Preserve every error code/status/category/retryable value.
  • Preserve safe protocol details and required headers.
  • Do not leak request DTOs or transport types into application/domain.
  • Do not stage, commit, amend, or push.

Task 1: Operational Handler RED Contracts

Files:

  • Modify: src/adapter/inbound/web/src/test/java/dev/caskeleton/adapter/inbound/web/error/GlobalExceptionHandlerTest.java

  • Modify: src/adapter/inbound/web/src/test/java/dev/caskeleton/adapter/inbound/web/error/TransportErrorHandlingTest.java

  • Create: src/adapter/inbound/web/src/test/java/dev/caskeleton/adapter/inbound/web/error/NoResourceFoundErrorHandlingTest.java

  • Add secret-sentinel tests for mapping, illegal argument, adapter disabled, authentication, authorization, precondition, pagination, and cursor exceptions.

  • Add validation tests proving rejected values, interpolated/default messages, and iterable keys/indices are absent while normalized fields plus allowlisted reason codes/fixed messages remain.

  • Add transport tests proving raw request URLs and content-type values are not echoed.

  • Add a real MVC resource-resolver test for a sentinel-bearing static-resource 404.

  • Run the focused tests and record RED against the current raw-message implementation (30 tests, 9 expected failures).

Task 2: Operational Allowlist Implementation

Files:

  • Modify: src/adapter/inbound/web/src/main/java/dev/caskeleton/adapter/inbound/web/error/ClientSafeErrorMessages.java

  • Create: src/adapter/inbound/web/src/main/java/dev/caskeleton/adapter/inbound/web/error/ClientSafeValidationDetails.java

  • Modify: src/adapter/inbound/web/src/main/java/dev/caskeleton/adapter/inbound/web/error/GlobalExceptionHandler.java

  • Modify: src/adapter/inbound/web/README.md

  • Add code-specific fixed operational messages with a safe category fallback.

  • Replace every public ex.getMessage()/rejected-value/raw-URL path.

  • Discard validation message/value data, normalize field paths, strip iterable keys/indices, and emit only allowlisted reason codes with fixed messages.

  • Route both NoHandlerFoundException and NoResourceFoundException through the same safe 404 envelope.

  • Retain safe field/reason/expected-type/supported-method/media-type details and Allow.

  • Run the operational/transport tests and confirm GREEN.

Task 3: Sample Domain RED and Implementation

Files:

  • Create: src/sample-portfolio/src/main/java/dev/caskeleton/sample/portfolio/adapter/inbound/web/error/PortfolioClientSafeErrorMessages.java

  • Modify: src/sample-portfolio/src/main/java/dev/caskeleton/sample/portfolio/adapter/inbound/web/error/DomainExceptionHandler.java

  • Modify: src/sample-portfolio/src/test/java/dev/caskeleton/sample/portfolio/adapter/inbound/web/error/DomainExceptionHandlerTest.java

  • Add ID/title/reason sentinel tests and confirm RED (4 expected failures).

  • Map every PortfolioErrorCode to fixed public text and use it from the advice.

  • Confirm code/status/category remain unchanged and sentinels are absent.

Task 4: Focused and Architecture Verification

  • Run ./gradlew :adapter:inbound:web:test --console=plain.
  • Run ./gradlew :sample-portfolio:test --console=plain.
  • Run focused Spotless/Checkstyle/SpotBugs tasks for both modules.
  • Run ./gradlew verifyCleanArchitectureDependencies --console=plain.
  • Run git diff --check and request an independent read-only review.
  • Apply the independent review findings and receive a no-Critical/no-Important code re-review; align this design/plan with the final validation and resource-404 contract.