@polymorphism-tech/morph-spec 8.46.0 → 8.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/CLAUDE.md +5 -5
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +1 -4
  4. package/bin/validate.js +4 -25
  5. package/claude-plugin.json +1 -1
  6. package/docs/CHEATSHEET.md +2 -2
  7. package/docs/QUICKSTART.md +1 -1
  8. package/framework/CLAUDE.md +1 -1
  9. package/framework/MORPH.md +8 -8
  10. package/framework/commands/create-umbraco-lp.md +2 -0
  11. package/framework/commands/migrate-lp-to-umbraco.md +2 -0
  12. package/framework/commands/morph-archive.md +1 -1
  13. package/framework/commands/morph-hotfix.md +1 -1
  14. package/framework/commands/morph-infra.md +17 -203
  15. package/framework/commands/morph-media.md +3 -0
  16. package/framework/commands/morph-preflight.md +5 -28
  17. package/framework/commands/morph-proposal.md +2 -2
  18. package/framework/commands/morph-troubleshoot.md +2 -14
  19. package/framework/docs/CLI.md +3 -3
  20. package/framework/hooks/claude-code/core/state-sync.js +13 -1
  21. package/framework/hooks/shared/e2e-check.js +3 -4
  22. package/framework/hooks/shared/state-writer.js +1 -0
  23. package/framework/rules/ai-agents-standards.md +18 -16
  24. package/framework/rules/asaas-standards.md +3 -1
  25. package/framework/rules/csharp-standards.md +10 -8
  26. package/framework/rules/data-standards.md +5 -5
  27. package/framework/rules/dotnet-templates.md +1 -1
  28. package/framework/rules/frontend-standards.md +4 -2
  29. package/framework/rules/gsap-standards.md +10 -5
  30. package/framework/rules/hangfire-standards.md +3 -1
  31. package/framework/rules/infrastructure-standards.md +4 -2
  32. package/framework/rules/morph-workflow.md +2 -2
  33. package/framework/rules/neon-auth-standards.md +3 -1
  34. package/framework/rules/neon-standards.md +6 -4
  35. package/framework/rules/nextjs-standards.md +13 -11
  36. package/framework/rules/nextjs-templates.md +1 -1
  37. package/framework/rules/resend-standards.md +3 -1
  38. package/framework/schemas/feature.schema.json +1 -3
  39. package/framework/skills/README.md +1 -1
  40. package/framework/skills/core/create-umbraco-lp/SKILL.md +3 -3
  41. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +3 -3
  42. package/framework/skills/core/morph-apply/SKILL.md +3 -3
  43. package/framework/skills/core/morph-brainstorming/SKILL.md +3 -3
  44. package/framework/skills/core/morph-hotfix/SKILL.md +4 -4
  45. package/framework/skills/core/morph-implement/SKILL.md +3 -3
  46. package/framework/skills/core/morph-machine/SKILL.md +3 -3
  47. package/framework/skills/core/morph-media/SKILL.md +3 -3
  48. package/framework/skills/core/morph-plan/SKILL.md +3 -3
  49. package/framework/skills/core/morph-proposal/SKILL.md +3 -3
  50. package/framework/skills/core/morph-review/SKILL.md +3 -3
  51. package/framework/skills/core/morph-stack-scan/SKILL.md +3 -3
  52. package/framework/skills/core/morph-standards/SKILL.md +6 -6
  53. package/framework/skills/core/morph-uiux/SKILL.md +3 -3
  54. package/framework/standards/STANDARDS.json +59 -56
  55. package/framework/standards/ai-agents/evals-with-cache.md +1 -1
  56. package/framework/standards/ai-agents/llm-runtime-defaults.md +1 -1
  57. package/framework/standards/ai-agents/modalities-speech-to-text.md +36 -26
  58. package/framework/standards/ai-agents/prompt-sources.md +6 -4
  59. package/framework/standards/ai-agents/providers/model-registry.md +1 -1
  60. package/framework/standards/ai-agents/rag-custom-pgvector.md +67 -39
  61. package/framework/standards/ai-agents/setup.md +1 -1
  62. package/framework/standards/ai-agents/structured-output.md +1 -1
  63. package/framework/standards/ai-agents/sweet-spot.md +1 -1
  64. package/framework/standards/architecture/code-comments.md +2 -2
  65. package/framework/standards/architecture/vertical-slice/vertical-slice.md +18 -9
  66. package/framework/standards/backend/api/validation.md +135 -47
  67. package/framework/standards/backend/database/postgresql/database.md +11 -7
  68. package/framework/standards/backend/database/vector-search-rag.md +207 -324
  69. package/framework/standards/backend/dotnet/fluent-validation-vsa.md +14 -8
  70. package/framework/standards/backend/dotnet/result-pattern.md +40 -6
  71. package/framework/standards/backend/dotnet/scalar-ui.md +13 -7
  72. package/framework/standards/backend/dotnet/scrutor.md +1 -1
  73. package/framework/standards/backend/dotnet/testing.md +1 -1
  74. package/framework/standards/backend/dotnet/vsa-handler-patterns.md +7 -7
  75. package/framework/standards/backend/integrations/asaas/asaas-api.md +309 -165
  76. package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +134 -154
  77. package/framework/standards/data/nosql/cache/redis.md +120 -44
  78. package/framework/standards/data/nosql/cosmos-db.md +114 -71
  79. package/framework/standards/frontend/design-system/animations.md +1 -1
  80. package/framework/standards/frontend/design-system/naming.md +1 -1
  81. package/framework/standards/frontend/nextjs/motion-patterns.md +45 -29
  82. package/framework/standards/frontend/nextjs/naming-conventions.md +1 -1
  83. package/framework/standards/infrastructure/docker/coolify-deploy.md +8 -6
  84. package/framework/standards/infrastructure/neon/neon-pgvector.md +120 -75
  85. package/framework/standards/infrastructure/neon/neon-setup.md +53 -31
  86. package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +2 -2
  87. package/framework/templates/code/dotnet/extensions/database-extensions.cs +1 -1
  88. package/framework/templates/code/dotnet/extensions/result-extensions.cs +27 -0
  89. package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +2 -2
  90. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +1 -1
  91. package/framework/templates/infrastructure/docker/coolify.template.json +3 -3
  92. package/framework/templates/infrastructure/github/README.md +2 -1
  93. package/framework/templates/infrastructure/github/workflows/deploy-coolify.yml.hbs +2 -1
  94. package/package.json +1 -1
  95. package/src/commands/observability/telemetry.js +3 -5
  96. package/src/commands/project/init.js +2 -1
  97. package/src/commands/project/update.js +16 -18
  98. package/src/commands/state/approve.js +17 -0
  99. package/src/commands/state/gate-check.js +4 -14
  100. package/src/commands/validation/verify.js +3 -12
  101. package/src/core/paths/output-schema.js +1 -1
  102. package/src/dashboard/app/App.jsx +0 -2
  103. package/src/dashboard/app/components/CommandPalette.jsx +2 -3
  104. package/src/dashboard/app/components/EntityLink.jsx +0 -1
  105. package/src/dashboard/app/components/Markdown.jsx +1 -1
  106. package/src/dashboard/app/components/Sidebar.jsx +1 -2
  107. package/src/dashboard/app/pages/RulesMap.jsx +3 -3
  108. package/src/dashboard/app/pages/SkillsLibrary.jsx +3 -3
  109. package/src/dashboard/scanner/activity-scanner.js +1 -1
  110. package/src/dashboard/scanner/docs-scanner.js +5 -23
  111. package/src/dashboard/scanner/features-scanner.js +1 -1
  112. package/src/dashboard/scanner/index.js +0 -2
  113. package/src/dashboard/scanner/rules-scanner.js +15 -10
  114. package/src/dashboard/scanner/skills-scanner.js +2 -3
  115. package/src/lib/evaluator-report.js +13 -0
  116. package/src/lib/risk-detector.js +8 -0
  117. package/src/lib/stack/stack-profile.js +1 -1
  118. package/src/lib/validators/reuse/reuse-validator.js +2 -3
  119. package/src/lib/validators/reuse/symbol-scanner.js +2 -4
  120. package/src/lib/validators/validation-runner.js +8 -88
  121. package/src/lib/validators/verify-runner.js +22 -72
  122. package/src/scripts/setup-infra.js +33 -22
  123. package/src/utils/agents-installer.js +20 -8
  124. package/src/utils/file-copier.js +7 -5
  125. package/framework/commands/commit.md +0 -166
  126. package/framework/rubrics/backend.json +0 -41
  127. package/framework/rubrics/default.json +0 -36
  128. package/framework/rubrics/frontend.json +0 -36
  129. package/framework/templates/project/validate.js +0 -97
  130. package/src/dashboard/app/pages/Rubrics.jsx +0 -97
  131. package/src/dashboard/scanner/rubrics-scanner.js +0 -12
  132. package/src/lib/validators/architecture/architecture-validator.js +0 -270
  133. package/src/lib/validators/architecture/index.js +0 -7
  134. package/src/lib/validators/css/css-validator.js +0 -340
  135. package/src/lib/validators/css/index.js +0 -7
  136. package/src/lib/validators/design-system/design-system-validator.js +0 -237
  137. package/src/lib/validators/design-system/index.js +0 -7
  138. package/src/lib/validators/score-aggregator.js +0 -244
  139. package/src/lib/validators/ui/index.js +0 -7
  140. package/src/lib/validators/ui/ui-contrast-validator.js +0 -422
@@ -1,11 +1,11 @@
1
1
  # FluentValidation in VSA Pipelines
2
2
 
3
3
  > **Scope:** dotnet-vsa
4
- > **Layer:** 0 (always load)
4
+ > **Layer:** 0 (resumo injetado pela rule `csharp-standards` ao editar `**/*.cs`/`**/*.csproj`; texto completo sob demanda via `morph-spec standards --find`)
5
5
  > **Keywords:** fluent-validation, validation, decorator, pipeline, vsa
6
6
  > **Load When:** dotnet VSA projects
7
7
 
8
- **Verified against:** .NET 10 + FluentValidation 11 (`AbstractValidator`/`RuleFor` API). Last-verified: 2026-05-20.
8
+ **Verified against:** .NET 10 (SDK 10.0.400-preview) + FluentValidation 12.1.1. The validator block and the decorator (its three blocks assembled into one class) compile with `TreatWarningsAsErrors` over the `Result`/`ValidationError` of `result-pattern.md`, and the validator was run with `FakeTimeProvider` across a year change to show the year is read per validation. Last-verified: 2026-10-03.
9
9
 
10
10
  ---
11
11
 
@@ -21,11 +21,10 @@ One validator per request DTO. Lives in the same feature folder as the handler:
21
21
 
22
22
  ```csharp
23
23
  // Features/BookFeature/CreateBook/CreateBookValidator.cs
24
- public class CreateBookValidator : AbstractValidator<CreateBookRequest>
24
+ using FluentValidation;
25
+
26
+ public sealed class CreateBookValidator : AbstractValidator<CreateBookRequest>
25
27
  {
26
- // TimeProvider injected, never DateTime.UtcNow read directly — see
27
- // backend-dotnet-testing (Rule 1): a validator that reads the real clock
28
- // cannot be tested deterministically with FakeTimeProvider.
29
28
  public CreateBookValidator(TimeProvider timeProvider)
30
29
  {
31
30
  RuleFor(c => c.Title)
@@ -44,12 +43,16 @@ public class CreateBookValidator : AbstractValidator<CreateBookRequest>
44
43
 
45
44
  RuleFor(c => c.PublishedYear)
46
45
  .GreaterThan(1000).WithMessage("Published year must be a valid year")
47
- .LessThanOrEqualTo(timeProvider.GetUtcNow().Year)
46
+ .LessThanOrEqualTo(_ => timeProvider.GetUtcNow().Year)
48
47
  .WithMessage("Published year cannot be in the future");
49
48
  }
50
49
  }
51
50
  ```
52
51
 
52
+ - `sealed`, like every class in the slice.
53
+ - The clock is `TimeProvider` (never `DateTime.UtcNow`), so `FakeTimeProvider` makes the rule testable (`backend-dotnet-testing`, Rule 1).
54
+ - The year is read **inside the rule** (`_ => timeProvider.GetUtcNow().Year`), on every validation. `AddValidatorsFromAssembly` registers validators as scoped by default, but a validator registered as singleton (or cached) that captured `GetUtcNow().Year` in the constructor would keep rejecting next year's books from 1 January on.
55
+
53
56
  ---
54
57
 
55
58
  ## Auto-Discovery
@@ -69,6 +72,9 @@ builder.Services.AddHandlersFromAssembly(typeof(Program).Assembly);
69
72
  The decorator wraps every `IHandler<TRequest, TResponse>` via Scrutor. It collects all `IValidator<TRequest>` from DI, runs them in parallel, and short-circuits on failure:
70
73
 
71
74
  ```csharp
75
+ using FluentValidation;
76
+ using FluentValidation.Results;
77
+
72
78
  public sealed class ValidationDecorator<TRequest, TResponse>(
73
79
  IEnumerable<IValidator<TRequest>> validators,
74
80
  IHandler<TRequest, TResponse> innerHandler) : IHandler<TRequest, TResponse>
@@ -194,7 +200,7 @@ Features/
194
200
 
195
201
  | Do NOT | Do Instead |
196
202
  |--------|------------|
197
- | Validate inside the handler | Use `AbstractValidator<T>` + decorator |
203
+ | Validate request shape inside the handler | Use `AbstractValidator<T>` + decorator (state/existence checks do belong in the handler -- `backend/api/validation.md`) |
198
204
  | Throw `ValidationException` | Return `Result.Failure(ValidationError)` |
199
205
  | Register validators after handlers | Register validators first: `AddValidatorsFromAssembly()` before `AddHandlersFromAssembly()` |
200
206
  | Put validation logic in endpoints | Endpoints only do `Match()` — validation is automatic |
@@ -1,11 +1,11 @@
1
1
  # Result Pattern — Railway-Oriented Programming
2
2
 
3
3
  > **Scope:** dotnet-vsa
4
- > **Layer:** 0 (always load)
4
+ > **Layer:** 0 (resumo injetado pela rule `csharp-standards` ao editar `**/*.cs`/`**/*.csproj`; texto completo sob demanda via `morph-spec standards --find`)
5
5
  > **Keywords:** result, error-handling, railway, match, monadic
6
6
  > **Load When:** dotnet VSA projects
7
7
 
8
- **Verified against:** .NET 10 (pure C# pattern — no external package). Last-verified: 2026-05-20.
8
+ **Verified against:** .NET 10 (SDK 10.0.400-preview) + the shared framework `Microsoft.AspNetCore.App` 10 — the HTTP mapping uses `Results`/`IResult`/`StatusCodes`; the `Error`, `ValidationError`, `ResultExtensions`, `ErrorHttpMapping`, endpoint usage and `BookErrors` blocks compile with `TreatWarningsAsErrors` (the Anatomy blocks carry `{ ... }` placeholders and were compiled through a concrete stand-in). Last-verified: 2026-10-03.
9
9
 
10
10
  ---
11
11
 
@@ -118,6 +118,7 @@ public enum ErrorType
118
118
  | `NotFound` | 404 | Entity lookup returned null |
119
119
  | `Unauthorized` | 401 | Missing or invalid auth token |
120
120
  | `Forbidden` | 403 | Authenticated but lacks permission |
121
+ | `Custom` | 400 | Domain-specific; a feature that needs another status maps it in its own endpoint |
121
122
 
122
123
  ---
123
124
 
@@ -145,7 +146,7 @@ public sealed record ValidationError : Error
145
146
 
146
147
  ## Match() Pattern
147
148
 
148
- Endpoints use `Match()` to convert `Result<T>` into HTTP responses — never access `.Value` directly:
149
+ Endpoints use `Match()` to convert `Result<T>` into HTTP responses — never access `.Value` directly (the success lambda receives the value; `Match` itself is the only reader of `.Value`):
149
150
 
150
151
  ```csharp
151
152
  public static class ResultExtensions
@@ -170,15 +171,48 @@ public static class ResultExtensions
170
171
  }
171
172
  ```
172
173
 
174
+ The failure side maps by `ErrorType`, following the table above — never `Results.BadRequest` for every error, which turns a missing entity into a 400 and a conflict into a 400:
175
+
176
+ ```csharp
177
+ public static class ErrorHttpMapping
178
+ {
179
+ public static int StatusCodeFor(ErrorType type) => type switch
180
+ {
181
+ ErrorType.Validation => StatusCodes.Status400BadRequest,
182
+ ErrorType.NotFound => StatusCodes.Status404NotFound,
183
+ ErrorType.Conflict => StatusCodes.Status409Conflict,
184
+ ErrorType.Unauthorized => StatusCodes.Status401Unauthorized,
185
+ ErrorType.Forbidden => StatusCodes.Status403Forbidden,
186
+ ErrorType.Unexpected => StatusCodes.Status500InternalServerError,
187
+ _ => StatusCodes.Status400BadRequest
188
+ };
189
+
190
+ public static IResult ToHttpResult(this Error error)
191
+ {
192
+ Dictionary<string, object?>? extensions = error is ValidationError validation
193
+ ? new() { ["errors"] = validation.Errors.Select(e => new { e.Code, e.Description }).ToArray() }
194
+ : null;
195
+
196
+ return Results.Problem(
197
+ title: error.Code,
198
+ detail: error.Description,
199
+ statusCode: StatusCodeFor(error.Type),
200
+ extensions: extensions);
201
+ }
202
+ }
203
+ ```
204
+
173
205
  Usage in an endpoint:
174
206
 
175
207
  ```csharp
176
- var result = await handler.HandleAsync(command, cancellationToken);
208
+ var result = await handler.HandleAsync(query, cancellationToken);
177
209
  return result.Match(
178
- onSuccess: () => Results.Ok(result.Value),
179
- onFailure: error => Results.BadRequest(error));
210
+ onSuccess: book => Results.Ok(book),
211
+ onFailure: error => error.ToHttpResult());
180
212
  ```
181
213
 
214
+ For a handler that returns `Result` (no value), the success lambda takes no argument: `result.Match(onSuccess: () => Results.NoContent(), onFailure: error => error.ToHttpResult())`.
215
+
182
216
  ---
183
217
 
184
218
  ## Defining Feature Errors
@@ -1,11 +1,11 @@
1
1
  # Scalar.AspNetCore — API Documentation UI
2
2
 
3
3
  > **Scope:** dotnet-vsa
4
- > **Layer:** 0 (always load)
4
+ > **Layer:** 0 (resumo injetado pela rule `csharp-standards` ao editar `**/*.cs`/`**/*.csproj`; texto completo sob demanda via `morph-spec standards --find`)
5
5
  > **Keywords:** scalar, openapi, swagger, api-docs, documentation
6
6
  > **Load When:** dotnet VSA projects
7
7
 
8
- **Verified against:** .NET 10 + Scalar.AspNetCore 2.x + Microsoft.AspNetCore.OpenApi 10. Last-verified: 2026-05-20.
8
+ **Verified against:** .NET 10 (SDK 10.0.400-preview) + Scalar.AspNetCore 2.x + Microsoft.AspNetCore.OpenApi 10. The `ApiTags` and tagged-endpoint blocks compile with `TreatWarningsAsErrors` over the `Result`/`ErrorHttpMapping` of `result-pattern.md` (ApiTags placed in `ProjectName.Constants`); the startup and metadata snippets (`async (...) => { ... }`) are fragments, checked against the docs only. Last-verified: 2026-10-03.
9
9
 
10
10
  ---
11
11
 
@@ -91,6 +91,10 @@ public static class ApiTags
91
91
  Apply tags in endpoints:
92
92
 
93
93
  ```csharp
94
+ using ProjectName.Abstractions;
95
+ using ProjectName.Constants;
96
+ using ProjectName.Extensions;
97
+
94
98
  internal sealed class CreateBookEndpoint : IApiEndpoint
95
99
  {
96
100
  public void MapEndpoint(IEndpointRouteBuilder app)
@@ -102,16 +106,18 @@ internal sealed class CreateBookEndpoint : IApiEndpoint
102
106
  {
103
107
  var result = await handler.HandleAsync(command, cancellationToken);
104
108
  return result.Match(
105
- onSuccess: () => Results.Ok(result.Value),
106
- onFailure: error => Results.BadRequest(error));
109
+ onSuccess: response => Results.Ok(response),
110
+ onFailure: error => error.ToHttpResult());
107
111
  })
108
112
  .WithTags(ApiTags.Books)
109
113
  .Produces<CreateBookResponse>(StatusCodes.Status200OK)
110
- .Produces(StatusCodes.Status400BadRequest);
114
+ .ProducesProblem(StatusCodes.Status400BadRequest);
111
115
  }
112
116
  }
113
117
  ```
114
118
 
119
+ The failure side is `error.ToHttpResult()` (`Extensions/ErrorHttpMapping.cs`, see `backend/dotnet/result-pattern.md`): the `ErrorType` picks the status and the body is ProblemDetails, so document every failure status the slice can return with `.ProducesProblem(status)` — a 404/409 the endpoint can emit but does not declare is a lie in the Scalar docs.
120
+
115
121
  ---
116
122
 
117
123
  ## Endpoint Metadata
@@ -124,12 +130,12 @@ app.MapGet("books/{id:guid}", async (...) => { ... })
124
130
  .WithName("GetBookById")
125
131
  .WithSummary("Get a book by its unique identifier")
126
132
  .Produces<GetBookResponse>(StatusCodes.Status200OK)
127
- .Produces(StatusCodes.Status404NotFound);
133
+ .ProducesProblem(StatusCodes.Status404NotFound);
128
134
 
129
135
  app.MapDelete("books/{id:guid}", async (...) => { ... })
130
136
  .WithTags(ApiTags.Books)
131
137
  .Produces(StatusCodes.Status204NoContent)
132
- .Produces(StatusCodes.Status404NotFound);
138
+ .ProducesProblem(StatusCodes.Status404NotFound);
133
139
  ```
134
140
 
135
141
  ### Common Metadata Methods
@@ -1,7 +1,7 @@
1
1
  # Scrutor 7.0.0 — Auto-Discovery & Decorator Registration
2
2
 
3
3
  > **Scope:** dotnet-vsa
4
- > **Layer:** 0 (always load)
4
+ > **Layer:** 0 (resumo injetado pela rule `csharp-standards` ao editar `**/*.cs`/`**/*.csproj`; texto completo sob demanda via `morph-spec standards --find`)
5
5
  > **Keywords:** scrutor, di, decorators, auto-discovery, assembly-scanning
6
6
  > **Load When:** dotnet VSA projects
7
7
 
@@ -1,7 +1,7 @@
1
1
  # .NET Integration Testing — VSA
2
2
 
3
3
  > **Scope:** dotnet-vsa
4
- > **Layer:** 0 (always load)
4
+ > **Layer:** 1 (lista das personas `dotnet-senior`, `ef-modeler`, `maf-expert` e `infra-engineer`; nenhuma rule o resume — fora delas, sob demanda via `morph-spec standards --find`)
5
5
  > **Keywords:** testing, xunit, integration test, TimeProvider, FakeTimeProvider, WebApplicationFactory, ProblemDetails, error body assertion
6
6
  > **Load When:** writing or reviewing tests for a dotnet VSA project
7
7
 
@@ -1,11 +1,11 @@
1
1
  # VSA Handler Patterns — Complete Feature Slice Guide
2
2
 
3
3
  > **Scope:** dotnet-vsa
4
- > **Layer:** 0 (always load)
4
+ > **Layer:** 0 (resumo injetado pela rule `csharp-standards` ao editar `**/*.cs`/`**/*.csproj`; texto completo sob demanda via `morph-spec standards --find`)
5
5
  > **Keywords:** vsa, handler, feature-slice, vertical-slice, minimal-api, endpoint
6
6
  > **Load When:** dotnet VSA projects
7
7
 
8
- **Verified against:** .NET 10 (minimal APIs, primary constructors, `Guid.CreateVersion7()`). Last-verified: 2026-05-20.
8
+ **Verified against:** .NET 10 (SDK 10.0.400-preview; minimal APIs, primary constructors, `Guid.CreateVersion7()`). The "Complete Endpoint Example" block compiles with `TreatWarningsAsErrors` over the `Result`/`ErrorHttpMapping` of `result-pattern.md` (in `ProjectName.Abstractions`/`ProjectName.Extensions`, reached only through the block's own `using`s); the other blocks are documentary. Last-verified: 2026-10-03.
9
9
 
10
10
  ---
11
11
 
@@ -137,12 +137,12 @@ internal sealed class CreateBookEndpoint : IApiEndpoint
137
137
  {
138
138
  var result = await handler.HandleAsync(command, cancellationToken);
139
139
  return result.Match(
140
- onSuccess: () => Results.Ok(result.Value),
141
- onFailure: error => Results.BadRequest(error));
140
+ onSuccess: response => Results.Ok(response),
141
+ onFailure: error => error.ToHttpResult());
142
142
  })
143
143
  .WithTags(ApiTags.Books)
144
144
  .Produces<CreateBookResponse>(StatusCodes.Status200OK)
145
- .Produces(StatusCodes.Status400BadRequest);
145
+ .ProducesProblem(StatusCodes.Status400BadRequest);
146
146
  }
147
147
  }
148
148
  ```
@@ -152,9 +152,9 @@ internal sealed class CreateBookEndpoint : IApiEndpoint
152
152
  - **`internal sealed`** — endpoints are not public API
153
153
  - **`IApiEndpoint`** — single interface for auto-discovery
154
154
  - **Handler injected via DI** — resolved as `IHandler<TReq, TRes>` parameter
155
- - **`Match()` for responses** — never access `.Value` directly
155
+ - **`Match()` for responses** — the success lambda receives the value (never read `.Value` directly); the failure lambda is `error.ToHttpResult()` from `Extensions/ErrorHttpMapping.cs` (`backend/dotnet/result-pattern.md`), which maps `ErrorType` to the status — never `Results.BadRequest` for every error
156
156
  - **`.WithTags()`** — always tag for Scalar API docs
157
- - **`.Produces<T>()`** — always document response types
157
+ - **`.Produces<T>()` + `.ProducesProblem(status)`** — document the success type and every failure status the slice can return
158
158
 
159
159
  ---
160
160