Conversation
zribktad
commented
Apr 3, 2026
- Add ProductDataResponse and its subtypes for polymorphic product data representation.
- Introduce ProductMappings for EF Core projections from Product entities to ProductResponse DTOs.
- Create ProductPriceFacetBucketResponse and ProductPriceFacetSpecification for price facet handling.
- Establish ProductRequestValidatorBase for shared validation rules across product requests.
- Define ProductResponse and ProductSearchFacetsResponse for API responses.
- Implement ProductSortFields for sorting product queries.
- Develop ProductValidationHelper for validating product references in batch operations.
- Create specifications for loading products and categories with tenant context for soft deletes.
- Implement TenantCascadeDeleteHandler for cascading soft deletes on tenant deletion.
- Add UpdateCategories and UpdateProducts features with batch processing and validation.
- Introduce controllers for handling update requests for categories and products.
- Define request and response models for updating categories and products.
- Implement validators for ensuring data integrity during updates.
- Add IProductRepository interface for product-specific repository operations.
- Add ProductDataResponse and its subtypes for polymorphic product data representation. - Introduce ProductMappings for EF Core projections from Product entities to ProductResponse DTOs. - Create ProductPriceFacetBucketResponse and ProductPriceFacetSpecification for price facet handling. - Establish ProductRequestValidatorBase for shared validation rules across product requests. - Define ProductResponse and ProductSearchFacetsResponse for API responses. - Implement ProductSortFields for sorting product queries. - Develop ProductValidationHelper for validating product references in batch operations. - Create specifications for loading products and categories with tenant context for soft deletes. - Implement TenantCascadeDeleteHandler for cascading soft deletes on tenant deletion. - Add UpdateCategories and UpdateProducts features with batch processing and validation. - Introduce controllers for handling update requests for categories and products. - Define request and response models for updating categories and products. - Implement validators for ensuring data integrity during updates. - Add IProductRepository interface for product-specific repository operations.
There was a problem hiding this comment.
Code Review
This pull request performs a significant refactoring of the ProductCatalog module, transitioning from a controller-based organization to a feature-sliced architecture. Key changes include splitting monolithic controllers into feature-specific ones (e.g., CreateCategories, GetProducts), reorganizing DTOs, validators, and commands into corresponding feature folders, and updating namespaces to reflect this new structure. Additionally, a GlobalUsings file was introduced to streamline imports, and the module registration was updated to support the decentralized controller and validator setup. I have no feedback to provide as there are no review comments.
There was a problem hiding this comment.
Pull request overview
This PR implements and reorganizes ProductCatalog functionality into feature-focused endpoints and shared DTO/specification infrastructure, including batch create/update/delete operations and tenant soft-delete cascading.
Changes:
- Split ProductCatalog HTTP endpoints into per-feature controllers/commands (get/create/update/delete for products, categories, product-data, plus examples like idempotent create and patch).
- Introduce/relocate shared DTOs, mappings, facet specs, sort fields, and validation helpers under
Features/Shared, and migrate repository contracts toProductCatalog.Interfaces. - Consolidate ProductCatalog global usings into a single
src/Modules/ProductCatalog/GlobalUsings.csand moveErrors/CacheTagsunderProductCatalog.Common.*.
Reviewed changes
Copilot reviewed 120 out of 120 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/APITemplate.Tests/Unit/Validators/UpdateProductRequestValidatorTests.cs | Update validator test imports to new UpdateProducts feature namespace. |
| tests/APITemplate.Tests/Unit/Validators/CreateProductRequestValidatorTests.cs | Update validator test imports to new CreateProducts feature namespace. |
| tests/APITemplate.Tests/Unit/ProductCatalog/ProductCatalogModuleTests.cs | Update imports to new feature namespaces for batch rule registration tests. |
| tests/APITemplate.Tests/Unit/ProductCatalog/PatchProductCommandHandlerTests.cs | Update imports to new namespaces (Common.Events, Interfaces, Features.Shared). |
| tests/APITemplate.Tests/Integration/Features/IdempotentControllerTests.cs | Update imports to new IdempotentCreate feature namespace. |
| src/Modules/ProductCatalog/ValueObjects/Price.cs | Update error namespace to ProductCatalog.Common.Errors. |
| src/Modules/ProductCatalog/Repositories/ProductRepository.cs | Update repository contract alias and add GetProducts types usage. |
| src/Modules/ProductCatalog/ProductCatalogModule.cs | Update validator assembly scanning marker, controller application part, and repository contract alias. |
| src/Modules/ProductCatalog/ProductCatalog.Infrastructure.GlobalUsings.cs | Remove old infra global usings file (consolidation). |
| src/Modules/ProductCatalog/ProductCatalog.Domain.GlobalUsings.cs | Remove old domain global usings file (consolidation). |
| src/Modules/ProductCatalog/ProductCatalog.Application.GlobalUsings.cs | Remove old application global usings file (consolidation). |
| src/Modules/ProductCatalog/ProductCatalog.Api.GlobalUsings.cs | Remove old API global usings file (consolidation). |
| src/Modules/ProductCatalog/Interfaces/IProductRepository.cs | Move repository contract to ProductCatalog.Interfaces and update dependencies. |
| src/Modules/ProductCatalog/GraphQL/Queries/ProductQueries.cs | Update query dependencies to new GetProductById/GetProducts features. |
| src/Modules/ProductCatalog/GraphQL/Queries/CategoryQueries.cs | Update query dependencies to new GetCategoryById/GetCategories features. |
| src/Modules/ProductCatalog/GraphQL/Mutations/ProductMutations.cs | Update mutation dependencies to new CreateProducts/DeleteProducts features. |
| src/Modules/ProductCatalog/GlobalUsings.cs | Add consolidated module-wide global usings. |
| src/Modules/ProductCatalog/Features/ValidateProductExists/ValidateProductExistsQueryHandler.cs | Move handler to ValidateProductExists feature and update repository injection type. |
| src/Modules/ProductCatalog/Features/UpdateProducts/UpdateProductsRequest.cs | Move DTOs to UpdateProducts feature namespace. |
| src/Modules/ProductCatalog/Features/UpdateProducts/UpdateProductsController.cs | New controller for batch product update. |
| src/Modules/ProductCatalog/Features/UpdateProducts/UpdateProductsCommand.cs | Move batch update command/handler into UpdateProducts feature and update repository contract alias. |
| src/Modules/ProductCatalog/Features/UpdateProducts/UpdateProductRequestValidator.cs | Move validator to UpdateProducts feature namespace. |
| src/Modules/ProductCatalog/Features/UpdateProducts/UpdateProductRequest.cs | Move DTO to UpdateProducts feature namespace. |
| src/Modules/ProductCatalog/Features/UpdateProducts/UpdateProductItemValidator.cs | Move validator to UpdateProducts feature namespace. |
| src/Modules/ProductCatalog/Features/UpdateCategories/UpdateCategoryRequest.cs | Move DTO to UpdateCategories feature namespace. |
| src/Modules/ProductCatalog/Features/UpdateCategories/UpdateCategoryItemValidator.cs | Move validator to UpdateCategories feature namespace. |
| src/Modules/ProductCatalog/Features/UpdateCategories/UpdateCategoriesRequest.cs | Move batch DTO to UpdateCategories feature namespace. |
| src/Modules/ProductCatalog/Features/UpdateCategories/UpdateCategoriesController.cs | New controller for batch category update. |
| src/Modules/ProductCatalog/Features/UpdateCategories/UpdateCategoriesCommand.cs | Move batch update command/handler into UpdateCategories feature namespace. |
| src/Modules/ProductCatalog/Features/TenantCascadeDelete/TenantCascadeDeleteHandler.cs | Move tenant cascade delete handler to TenantCascadeDelete feature namespace. |
| src/Modules/ProductCatalog/Features/TenantCascadeDelete/ProductsForTenantSoftDeleteSpecification.cs | Move tenant soft-delete spec to TenantCascadeDelete feature namespace. |
| src/Modules/ProductCatalog/Features/TenantCascadeDelete/CategoriesForTenantSoftDeleteSpecification.cs | Move tenant soft-delete spec to TenantCascadeDelete feature namespace. |
| src/Modules/ProductCatalog/Features/Shared/ProductValidationHelper.cs | Move helper to Features.Shared and update spec usage. |
| src/Modules/ProductCatalog/Features/Shared/ProductsResponse.cs | Move response DTO to Features.Shared. |
| src/Modules/ProductCatalog/Features/Shared/ProductSortFields.cs | Move sort field map to Features.Shared. |
| src/Modules/ProductCatalog/Features/Shared/ProductSearchFacetsResponse.cs | Move facets DTO to Features.Shared. |
| src/Modules/ProductCatalog/Features/Shared/ProductsByIdsWithLinksSpecification.cs | Move spec to Features.Shared. |
| src/Modules/ProductCatalog/Features/Shared/ProductResponse.cs | Move product response DTO to Features.Shared. |
| src/Modules/ProductCatalog/Features/Shared/ProductRequestValidatorBase.cs | Move shared validator base to Features.Shared. |
| src/Modules/ProductCatalog/Features/Shared/ProductPriceFacetSpecification.cs | Move facet spec to Features.Shared and update filter type dependency. |
| src/Modules/ProductCatalog/Features/Shared/ProductPriceFacetBucketResponse.cs | Move bucket DTO to Features.Shared. |
| src/Modules/ProductCatalog/Features/Shared/ProductMappings.cs | Move EF Core projection/mapping helpers to Features.Shared. |
| src/Modules/ProductCatalog/Features/Shared/ProductDataResponse.cs | Move polymorphic product-data response DTOs to Features.Shared. |
| src/Modules/ProductCatalog/Features/Shared/ProductDataMappings.cs | Move product-data mapping helpers to Features.Shared. |
| src/Modules/ProductCatalog/Features/Shared/ProductCategoryFacetValue.cs | Move category facet DTO to Features.Shared. |
| src/Modules/ProductCatalog/Features/Shared/ProductCategoryFacetSpecification.cs | Move facet spec to Features.Shared and update filter type dependency. |
| src/Modules/ProductCatalog/Features/Shared/IProductRequest.cs | Move shared product request contract to Features.Shared. |
| src/Modules/ProductCatalog/Features/Shared/CategorySortFields.cs | Move category sort fields to Features.Shared. |
| src/Modules/ProductCatalog/Features/Shared/CategoryResponse.cs | Move category response DTO to Features.Shared. |
| src/Modules/ProductCatalog/Features/Shared/CategoryMappings.cs | Move category mapping helpers to Features.Shared (remove stats mapping). |
| src/Modules/ProductCatalog/Features/Shared/CategoriesByIdsSpecification.cs | Move spec to Features.Shared. |
| src/Modules/ProductCatalog/Features/PatchProduct/PatchProductController.cs | Move/rename patch controller under PatchProduct feature. |
| src/Modules/ProductCatalog/Features/PatchProduct/PatchProductCommand.cs | Move patch command/handler under PatchProduct feature and update repository contract alias. |
| src/Modules/ProductCatalog/Features/PatchProduct/PatchableProductDtoValidator.cs | Move patch DTO validator under PatchProduct feature. |
| src/Modules/ProductCatalog/Features/PatchProduct/PatchableProductDto.cs | Move patch DTO under PatchProduct feature. |
| src/Modules/ProductCatalog/Features/IdempotentCreate/IdempotentCreateResponse.cs | Move idempotent DTO under IdempotentCreate feature. |
| src/Modules/ProductCatalog/Features/IdempotentCreate/IdempotentCreateRequestValidator.cs | Move idempotent validator under IdempotentCreate feature. |
| src/Modules/ProductCatalog/Features/IdempotentCreate/IdempotentCreateRequest.cs | Move idempotent request under IdempotentCreate feature. |
| src/Modules/ProductCatalog/Features/IdempotentCreate/IdempotentCreateController.cs | Move/rename idempotent controller under IdempotentCreate feature. |
| src/Modules/ProductCatalog/Features/IdempotentCreate/IdempotentCreateCommand.cs | Move idempotent command/handler under IdempotentCreate feature and update repository alias. |
| src/Modules/ProductCatalog/Features/GetProducts/ProductSpecification.cs | Move product query spec under GetProducts feature. |
| src/Modules/ProductCatalog/Features/GetProducts/ProductFilterValidator.cs | Move filter validator under GetProducts feature. |
| src/Modules/ProductCatalog/Features/GetProducts/ProductFilterCriteria.cs | Move filter criteria helper under GetProducts feature. |
| src/Modules/ProductCatalog/Features/GetProducts/ProductFilter.cs | Move filter DTO under GetProducts feature. |
| src/Modules/ProductCatalog/Features/GetProducts/GetProductsQuery.cs | Move query under GetProducts feature and update repository contract alias. |
| src/Modules/ProductCatalog/Features/GetProducts/GetProductsController.cs | New controller for product list + facets. |
| src/Modules/ProductCatalog/Features/GetProductDataById/GetProductDataByIdQuery.cs | Move query under GetProductDataById feature. |
| src/Modules/ProductCatalog/Features/GetProductDataById/GetProductDataByIdController.cs | New controller for product-data get-by-id. |
| src/Modules/ProductCatalog/Features/GetProductData/GetProductDataQuery.cs | Move query under GetProductData feature. |
| src/Modules/ProductCatalog/Features/GetProductData/GetProductDataController.cs | New controller for product-data listing. |
| src/Modules/ProductCatalog/Features/GetProductById/ProductByIdWithLinksSpecification.cs | Move spec under GetProductById feature. |
| src/Modules/ProductCatalog/Features/GetProductById/ProductByIdSpecification.cs | Move spec under GetProductById feature. |
| src/Modules/ProductCatalog/Features/GetProductById/GetProductByIdQuery.cs | Move query under GetProductById feature and update repository alias. |
| src/Modules/ProductCatalog/Features/GetProductById/GetProductByIdController.cs | New controller for product get-by-id. |
| src/Modules/ProductCatalog/Features/GetCategoryStats/ProductCategoryStatsResponse.cs | Move stats response DTO under GetCategoryStats feature. |
| src/Modules/ProductCatalog/Features/GetCategoryStats/GetCategoryStatsQuery.cs | Move stats query under GetCategoryStats feature and inline mapping. |
| src/Modules/ProductCatalog/Features/GetCategoryStats/GetCategoryStatsController.cs | New controller for category stats. |
| src/Modules/ProductCatalog/Features/GetCategoryById/GetCategoryByIdQuery.cs | Move query under GetCategoryById feature. |
| src/Modules/ProductCatalog/Features/GetCategoryById/GetCategoryByIdController.cs | New controller for category get-by-id. |
| src/Modules/ProductCatalog/Features/GetCategoryById/CategoryByIdSpecification.cs | Move spec under GetCategoryById feature. |
| src/Modules/ProductCatalog/Features/GetCategories/GetCategoriesQuery.cs | Move query under GetCategories feature. |
| src/Modules/ProductCatalog/Features/GetCategories/GetCategoriesController.cs | New controller for category listing. |
| src/Modules/ProductCatalog/Features/GetCategories/CategorySpecification.cs | Move spec under GetCategories feature. |
| src/Modules/ProductCatalog/Features/GetCategories/CategoryFilterValidator.cs | Move filter validator under GetCategories feature. |
| src/Modules/ProductCatalog/Features/GetCategories/CategoryFilterCriteria.cs | Move criteria helper under GetCategories feature. |
| src/Modules/ProductCatalog/Features/GetCategories/CategoryFilter.cs | Move filter DTO under GetCategories feature. |
| src/Modules/ProductCatalog/Features/DeleteProducts/DeleteProductsController.cs | New controller for batch product delete. |
| src/Modules/ProductCatalog/Features/DeleteProducts/DeleteProductsCommand.cs | Move delete command/handler under DeleteProducts feature and update repository alias. |
| src/Modules/ProductCatalog/Features/DeleteProductData/ProductDataCascadeDeleteHandler.cs | Move handler under DeleteProductData feature namespace. |
| src/Modules/ProductCatalog/Features/DeleteProductData/DeleteProductDataController.cs | New controller for product-data delete. |
| src/Modules/ProductCatalog/Features/DeleteProductData/DeleteProductDataCommand.cs | Move command/handler under DeleteProductData feature namespace. |
| src/Modules/ProductCatalog/Features/DeleteCategories/DeleteCategoriesController.cs | New controller for batch category delete. |
| src/Modules/ProductCatalog/Features/DeleteCategories/DeleteCategoriesCommand.cs | Move delete command/handler under DeleteCategories feature namespace. |
| src/Modules/ProductCatalog/Features/CreateVideoProductData/CreateVideoProductDataRequestValidator.cs | Move validator under CreateVideoProductData feature namespace. |
| src/Modules/ProductCatalog/Features/CreateVideoProductData/CreateVideoProductDataRequest.cs | Move request under CreateVideoProductData feature namespace. |
| src/Modules/ProductCatalog/Features/CreateVideoProductData/CreateVideoProductDataController.cs | New controller for creating video product-data. |
| src/Modules/ProductCatalog/Features/CreateVideoProductData/CreateVideoProductDataCommand.cs | Move command/handler under CreateVideoProductData feature namespace. |
| src/Modules/ProductCatalog/Features/CreateProducts/CreateProductsRequest.cs | Move batch create request under CreateProducts feature namespace. |
| src/Modules/ProductCatalog/Features/CreateProducts/CreateProductsController.cs | New controller for batch product create. |
| src/Modules/ProductCatalog/Features/CreateProducts/CreateProductsCommand.cs | Move create command/handler under CreateProducts feature and update repository alias. |
| src/Modules/ProductCatalog/Features/CreateProducts/CreateProductRequestValidator.cs | Move validator under CreateProducts feature namespace. |
| src/Modules/ProductCatalog/Features/CreateProducts/CreateProductRequest.cs | Move request under CreateProducts feature namespace. |
| src/Modules/ProductCatalog/Features/CreateImageProductData/CreateImageProductDataRequestValidator.cs | Move validator under CreateImageProductData feature namespace. |
| src/Modules/ProductCatalog/Features/CreateImageProductData/CreateImageProductDataRequest.cs | Move request under CreateImageProductData feature namespace. |
| src/Modules/ProductCatalog/Features/CreateImageProductData/CreateImageProductDataController.cs | New controller for creating image product-data. |
| src/Modules/ProductCatalog/Features/CreateImageProductData/CreateImageProductDataCommand.cs | Move command/handler under CreateImageProductData feature namespace. |
| src/Modules/ProductCatalog/Features/CreateCategories/CreateCategoryRequestValidator.cs | Move validator under CreateCategories feature namespace. |
| src/Modules/ProductCatalog/Features/CreateCategories/CreateCategoryRequest.cs | Move request under CreateCategories feature namespace. |
| src/Modules/ProductCatalog/Features/CreateCategories/CreateCategoriesRequest.cs | Move batch create request under CreateCategories feature namespace. |
| src/Modules/ProductCatalog/Features/CreateCategories/CreateCategoriesController.cs | New controller for batch category create. |
| src/Modules/ProductCatalog/Features/CreateCategories/CreateCategoriesCommand.cs | Move command/handler under CreateCategories feature namespace. |
| src/Modules/ProductCatalog/Controllers/V1/ProductsController.cs | Remove old combined products controller (replaced by feature controllers). |
| src/Modules/ProductCatalog/Controllers/V1/ProductDataController.cs | Remove old combined product-data controller (replaced by feature controllers). |
| src/Modules/ProductCatalog/Controllers/V1/CategoriesController.cs | Remove old combined categories controller (replaced by feature controllers). |
| src/Modules/ProductCatalog/Common/Events/CacheTags.cs | Move cache tags to ProductCatalog.Common.Events. |
| src/Modules/ProductCatalog/Common/Errors/ProductCatalogDomainErrors.cs | Move domain errors to ProductCatalog.Common.Errors. |
| src/Modules/ProductCatalog/Common/Errors/ErrorCatalog.cs | Move error catalog to ProductCatalog.Common.Errors. |
| src/Modules/ProductCatalog/Common/Errors/DomainErrors.cs | Move domain errors to ProductCatalog.Common.Errors. |
| src/APITemplate/Api/Program.cs | Update Wolverine discovery to include new ProductCatalog feature assembly anchor type. |
| src/APITemplate/Api/Extensions/ApiServiceCollectionExtensions.cs | Update cache tag alias namespace to ProductCatalog.Common.Events. |
Comments suppressed due to low confidence (4)
src/Modules/ProductCatalog/Features/IdempotentCreate/IdempotentCreateController.cs:22
- This controller currently routes as
POST /api/v1/IdempotentCreate(ApiControllerBase uses[controller]), but integration tests and existing API calls usePOST /api/v1/idempotent. Add an explicit[Route("api/v{version:apiVersion}/idempotent")]to preserve the endpoint.
src/Modules/ProductCatalog/Features/IdempotentCreate/IdempotentCreateController.cs:33 - The action returns
Ok(...)(HTTP 200), but integration tests expect201 Createdfor the first idempotent request, and the XML docs describe create semantics. Return a 201 response (ideally with a Location header) so the idempotency filter can cache the correct status code.
src/Modules/ProductCatalog/Features/PatchProduct/PatchProductController.cs:16 - Without a controller-level
[Route], this endpoint becomes/api/v1/PatchProduct/products/{id}(ApiControllerBase uses[controller]). Integration tests call/api/v1/patch/products/{id}. Add[Route("api/v{version:apiVersion}/patch")](or adjust the action route) to match the expected URL.
src/Modules/ProductCatalog/Features/PatchProduct/PatchProductController.cs:16 - This endpoint patches products but is protected by
Permission.Examples.Update. That grants access based on the examples permission set rather than product update permissions, which is likely incorrect for a product write operation. Consider switching toPermission.Products.Updateto align authorization with the resource being modified.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| [ApiVersion(1.0)] | ||
| public sealed class GetProductsController(IMessageBus bus) : ApiControllerBase | ||
| { | ||
| /// <summary>Returns a filtered, paginated product list including search facets.</summary> | ||
| [HttpGet] | ||
| [RequirePermission(Permission.Products.Read)] |
There was a problem hiding this comment.
ApiControllerBase uses route template api/v{version:apiVersion}/[controller]. With this controller name, the endpoint becomes /api/v1/GetProducts instead of the existing /api/v1/products used throughout integration tests and likely by clients. Add an explicit [Route("api/v{version:apiVersion}/products")] (or similar resource route) to preserve the public API path.
| [ApiVersion(1.0)] | ||
| public sealed class GetProductByIdController(IMessageBus bus) : ApiControllerBase | ||
| { | ||
| /// <summary>Returns a single product by its identifier, or 404 if not found.</summary> | ||
| [HttpGet("{id:guid}")] | ||
| [RequirePermission(Permission.Products.Read)] | ||
| [OutputCache(PolicyName = CacheTags.Products)] | ||
| public async Task<ActionResult<ProductResponse>> GetById(Guid id, CancellationToken ct) |
There was a problem hiding this comment.
ApiControllerBase routes by [controller], so this controller will map to /api/v1/GetProductById rather than /api/v1/products/{id}. Add an explicit controller-level route like [Route("api/v{version:apiVersion}/products")] so [HttpGet("{id:guid}")] matches the established endpoint shape.
| [ApiVersion(1.0)] | ||
| public sealed class CreateProductsController(IMessageBus bus) : ApiControllerBase | ||
| { | ||
| /// <summary>Creates multiple products in a single batch operation.</summary> | ||
| [HttpPost] | ||
| [RequirePermission(Permission.Products.Create)] | ||
| public async Task<ActionResult<BatchResponse>> Create( |
There was a problem hiding this comment.
Without an explicit [Route], this will be POST /api/v1/CreateProducts due to ApiControllerBase’s [controller] route. Existing API/tests use POST /api/v1/products. Add [Route("api/v{version:apiVersion}/products")] (same as the other product controllers) to avoid breaking the public API.
| [ApiVersion(1.0)] | ||
| public sealed class UpdateProductsController(IMessageBus bus) : ApiControllerBase | ||
| { | ||
| /// <summary>Updates multiple products in a single batch operation.</summary> | ||
| [HttpPut] | ||
| [RequirePermission(Permission.Products.Update)] | ||
| public async Task<ActionResult<BatchResponse>> Update( |
There was a problem hiding this comment.
With ApiControllerBase’s [controller] route template, this endpoint becomes PUT /api/v1/UpdateProducts instead of PUT /api/v1/products. Add a controller-level [Route("api/v{version:apiVersion}/products")] to preserve the existing REST route.
| [ApiVersion(1.0)] | ||
| public sealed class DeleteProductsController(IMessageBus bus) : ApiControllerBase | ||
| { | ||
| /// <summary>Soft-deletes multiple products in a single batch operation.</summary> | ||
| [HttpDelete] | ||
| [RequirePermission(Permission.Products.Delete)] | ||
| public async Task<ActionResult<BatchResponse>> Delete( |
There was a problem hiding this comment.
Without an explicit controller route, this will be DELETE /api/v1/DeleteProducts rather than DELETE /api/v1/products (ApiControllerBase routes by [controller]). Add [Route("api/v{version:apiVersion}/products")] to avoid breaking clients/tests.
| [ApiVersion(1.0)] | ||
| public sealed class GetCategoryByIdController(IMessageBus bus) : ApiControllerBase | ||
| { | ||
| /// <summary>Returns a single category by its identifier, or 404 if not found.</summary> | ||
| [HttpGet("{id:guid}")] | ||
| [RequirePermission(Permission.Categories.Read)] | ||
| [OutputCache(PolicyName = CacheTags.Categories)] | ||
| public async Task<ActionResult<CategoryResponse>> GetById(Guid id, CancellationToken ct) |
There was a problem hiding this comment.
This will route as /api/v1/GetCategoryById/{id} (ApiControllerBase uses [controller]) instead of /api/v1/categories/{id}. Add [Route("api/v{version:apiVersion}/categories")] so [HttpGet("{id:guid}")] matches the existing endpoint.
| [ApiVersion(1.0)] | ||
| public sealed class GetCategoryStatsController(IMessageBus bus) : ApiControllerBase | ||
| { | ||
| /// <summary> | ||
| /// Returns aggregated statistics for a category by calling the | ||
| /// <c>get_product_category_stats(p_category_id)</c> stored procedure via EF Core FromSql. | ||
| /// </summary> | ||
| [HttpGet("{id:guid}/stats")] | ||
| [RequirePermission(Permission.Categories.Read)] | ||
| [OutputCache(PolicyName = CacheTags.Categories)] | ||
| public async Task<ActionResult<ProductCategoryStatsResponse>> GetStats( |
There was a problem hiding this comment.
Without a controller-level [Route], this maps to /api/v1/GetCategoryStats/{id}/stats instead of /api/v1/categories/{id}/stats used by tests/clients. Add [Route("api/v{version:apiVersion}/categories")] to preserve the existing REST route shape.
| [ApiVersion(1.0)] | ||
| public sealed class CreateCategoriesController(IMessageBus bus) : ApiControllerBase | ||
| { | ||
| /// <summary>Creates multiple categories in a single batch operation.</summary> | ||
| [HttpPost] | ||
| [RequirePermission(Permission.Categories.Create)] | ||
| public async Task<ActionResult<BatchResponse>> Create( |
There was a problem hiding this comment.
ApiControllerBase routes by [controller], so this becomes POST /api/v1/CreateCategories rather than POST /api/v1/categories. Add [Route("api/v{version:apiVersion}/categories")] to preserve the established API path.
| [ApiVersion(1.0)] | ||
| public sealed class UpdateCategoriesController(IMessageBus bus) : ApiControllerBase | ||
| { | ||
| /// <summary>Updates multiple categories in a single batch operation.</summary> | ||
| [HttpPut] | ||
| [RequirePermission(Permission.Categories.Update)] | ||
| public async Task<ActionResult<BatchResponse>> Update( |
There was a problem hiding this comment.
With ApiControllerBase’s [controller] route, this becomes PUT /api/v1/UpdateCategories instead of PUT /api/v1/categories. Add [Route("api/v{version:apiVersion}/categories")] to avoid a breaking route change.
| [ApiVersion(1.0)] | ||
| public sealed class DeleteCategoriesController(IMessageBus bus) : ApiControllerBase | ||
| { | ||
| /// <summary>Soft-deletes multiple categories in a single batch operation.</summary> | ||
| [HttpDelete] | ||
| [RequirePermission(Permission.Categories.Delete)] | ||
| public async Task<ActionResult<BatchResponse>> Delete( |
There was a problem hiding this comment.
Without an explicit route, this maps to DELETE /api/v1/DeleteCategories rather than DELETE /api/v1/categories due to ApiControllerBase’s [controller] routing. Add [Route("api/v{version:apiVersion}/categories")] to preserve the existing API endpoint.