Feat/unified error envelope, unified response migration, and validation hardening#77
Merged
Conversation
…ardening Phase 1 — Envelope correctness (no contract change) - ExceptionHandlingMiddleware: locale resolved from Accept-Language header - UnauthorizedAccessException maps to 401; correlationId added to envelope body - BAD_REQUEST message made distinct from VALIDATION_ERROR - General.NOT_FOUND renamed to RESOURCE_NOT_FOUND_GENERIC - GetShareLinkQueryHandler consumer fixed - 6/6 middleware tests pass Phase 2 — Contract changes + handler migration - DomainException → 422 BUSINESS_RULE_VIOLATION (ERR910) - Rate-limit 429 envelope via EnvelopeWriter (replaced External plain-text, added Internal OnRejected) - JWT 401/403 envelope via OnChallenge/OnForbidden - EnvelopeWriter, EnvelopeResult, EnvelopeResults created as single serialization/status-mapping source of truth - ~40 handlers migrated to Response<T>; all endpoint files processed Phase 3 — Dead Result<T> deletion - Deleted: Result.cs, Error.cs, OkApiResult.cs, CreatedApiResult.cs, NoContentApiResult.cs, ResultExtensions.cs, ResultValidationBehavior.cs, ValidationBehavior.cs - All source projects build Phase 4 — Cleanup and hardening - ApplicationErrors → DomainKeys; moved Errors/ → Messages/; namespace CCE.Application.Errors → CCE.Application.Messages - Bulk-replaced 193 ApplicationErrors. references and 51 using directives - Hellang ProblemDetails dependency removed - LoggingBehavior + ValidationBehavior registrations removed - CSP hardened: X-Frame-Options, base-uri, form-action, object-src added - Fixed middleware order comment in External/Program.cs Phase 5 — Build integrity + DomainKeys completeness - Added DomainKeysIntegrityTests (3 tests) in CCE.ArchitectureTests: bidirectional consistency between DomainKeys and SystemCodeMap — all pass - Fixed missing using Microsoft.Extensions.Configuration in EnvelopeWriter.cs - Filled 33 orphaned SystemCodeMap entries as new DomainKeys constants (General, Identity, Content, Verification, Validation, new InterestTopic class) - Added 5 missing SystemCodeMap entries + SystemCode constants (ERR032, CON073–CON076) Phase 6 — Validator hardening + SystemCodeMap completion (code review fixes) - Add .WithErrorCode(MessageKeys.Validation.*) to Login, ForgotPassword, RefreshToken, Logout, UpdateMyProfile, CreateUser, SubmitExpertRequest validators — all were emitting ERR900 on validation failure - Replace all remaining .WithMessage() with .WithErrorCode() - RegisterUserCommandValidator: add RuleLevelCascadeMode = CascadeMode.Stop to prevent double REQUIRED_FIELD + INVALID_FORMAT on empty fields; add .NotEmpty() guards before Password Must() and ConfirmPassword Equal() - Rename MatchStoryPasswordPolicy → MatchStrongPasswordPolicy (typo) - ResetPasswordCommandValidator: add .NotEmpty() guards on NewPassword and ConfirmPassword; update method reference to renamed policy check - Add ERR410 ROLE_NOT_FOUND, ERR411 INVALID_RESET_TOKEN, ERR412 EMAIL_CHANGE_FAILED, ERR127 OTP_UNAUTHORIZED to SystemCode + SystemCodeMap + Resources.yaml - Add CON077–CON082 claims/permissions grant/revoke/update; CON083 AD_LOGIN_SUCCESS; CON084 NEWSLETTER_SUBSCRIBED; CON085 TOPICS_LISTED; CON086 SECTION_REORDERED — all branch feature keys that were falling back to ERR900 - ExceptionHandlingMiddleware: remove ex.Message fallback from UnauthorizedAccessException to prevent internal message leakage - ListRedisKeysQuery: replace raw "ITEMS_LISTED" with MessageKeys.General.ITEMS_LISTED All source projects build with 0 errors, 0 warnings.
…ll pattern Deleted all 52 convenience shortcut methods from MessageFactory, leaving exactly 9 core methods (Ok, NotFound, Conflict, Unauthorized, Forbidden, BusinessRule, ValidationError, Field). Updated ~130 handlers across CCE.Application to call the generic API directly with explicit MessageKeys constants. Previously 83% of handlers used generic calls while 17% used shortcuts, forcing every reader to check whether a shortcut exists before writing a handler. Three handlers already mixed both styles. The factory now has one pattern with no exceptions. Rule going forward: new outcomes add a MessageKeys constant, a SystemCodeMap entry, and a Resources.yaml string — nothing else touches MessageFactory.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
refactor: unify error messages and responses across all API layers
Summary
Enforces
Response<T>as the single response contract across the entire API surface, ensuring consistent response payloads regardless of where a request is handled.This change completes the response standardization effort by covering handlers, middleware, authentication, rate limiting, validation, and short-circuit endpoints.
Changes
Handler Layer
Standardized all handler responses through
Response<T>.Ok()/Response<T>.Fail()All endpoints return via
.ToHttpResult()Middleware Layer
Updated
ExceptionHandlingMiddlewareto emit the same response envelope structure:Authentication & Authorization
JWT
OnChallengeresponses use the shared envelopeJWT
OnForbiddenresponses use the shared envelopeRate limiting
OnRejectedresponses useEnvelopeWriterShort-Circuit Endpoints
Replaced inline
Results.StatusCode(...)Replaced inline
Results.Ok(...)Standardized responses through:
EnvelopeResults.*Response<T>.Ok().ToHttpResult()Validation
FluentValidation failures return the standard envelope
Domain validation failures return the standard envelope
Unified field-level validation errors through a shared
FieldErrorstructureContent Endpoints
The following remain raw responses by design:
File downloads
iCal responses
HTTP 204 No Content responses
All error paths for these endpoints still return the standard envelope.
Development Endpoints
/dev/*endpoints are intentionally excluded from envelope enforcementRemaining Flat-Response Violations
This PR closes the final three known flat-response violations:
Before | After -- | -- Results.StatusCode(415) | EnvelopeResults.UnsupportedMediaType() Results.StatusCode(415) | EnvelopeResults.UnsupportedMediaType() Results.Ok(summary) | Response.Ok(summary).ToHttpResult()Result
✅ Single response contract across all API layers
✅ Consistent success and error payloads
✅ Unified validation error structure
✅ Authentication, middleware, and rate-limiting responses aligned
✅ All known flat-response violations eliminated