포인트 상점 탭 분리 기능 구현#395
Conversation
WalkthroughCentralizes admin point-shop write operations (create, update, delete) into a new PointShopAdminController that dispatches to either PointItemService or PointProductService based on PointShopType. Adds Category field to PointItem and PointProduct entities. Removes write endpoints from existing item and product admin controllers. Changes
Sequence Diagram(s)sequenceDiagram
participant Admin as Admin API
participant ShopCtrl as PointShopAdminController
participant ShopSvc as PointShopAdminService
participant ItemSvc as PointItemService
participant ItemRepo as PointItemRepository
participant ProdSvc as PointProductService
participant ProdRepo as PointProductRepository
rect rgb(200, 240, 200)
Note over Admin,ProdRepo: Create Operation (Type-based routing)
Admin->>ShopCtrl: POST /api/admin/point-shop/create<br/>AdminCreatePointShopRequest
ShopCtrl->>ShopSvc: create(request)
alt Type == ITEM
ShopSvc->>ItemSvc: create(PointItemCreateCommand)
ItemSvc-->>ShopSvc: Long itemId
else Type == PRODUCT
ShopSvc->>ProdSvc: create(PointProductCreateCommand)
ProdSvc-->>ShopSvc: Long productId
else Unknown Type
ShopSvc-->>ShopCtrl: PointShopAdminException(NOT_FOUND_CATEGORY)
end
ShopCtrl-->>Admin: 200 OK with ApiTemplate<Long>
end
rect rgb(200, 220, 240)
Note over Admin,ProdRepo: Update Operation (Fallback lookup)
Admin->>ShopCtrl: PUT /api/admin/point-shop/update/{id}<br/>AdminUpdatePointShopRequest
ShopCtrl->>ShopSvc: update(request, id)
ShopSvc->>ItemRepo: findById(id)
alt Item Found
ItemRepo-->>ShopSvc: PointItem
ShopSvc->>ItemSvc: updatePointItem(PointItemUpdateCommand)
else Item Not Found
ShopSvc->>ProdRepo: findById(id)
alt Product Found
ProdRepo-->>ShopSvc: PointProduct
ShopSvc->>ProdSvc: update(PointProductUpdateCommand)
else Product Not Found
ShopSvc-->>ShopCtrl: PointShopAdminException(NOT_FOUND_PRODUCT)
end
end
ShopCtrl-->>Admin: 200 OK with NoContent
end
rect rgb(240, 200, 200)
Note over Admin,ProdRepo: Delete Operation (Fallback lookup)
Admin->>ShopCtrl: DELETE /api/admin/point-shop/delete/{id}
ShopCtrl->>ShopSvc: delete(id)
ShopSvc->>ItemRepo: findById(id)
alt Item Found
ItemRepo-->>ShopSvc: PointItem
ShopSvc->>ItemSvc: delete(itemId)
else Item Not Found
ShopSvc->>ProdRepo: findById(id)
alt Product Found
ProdRepo-->>ShopSvc: PointProduct
ShopSvc->>ProdSvc: delete(productId)
else Product Not Found
ShopSvc-->>ShopCtrl: PointShopAdminException(NOT_FOUND_PRODUCT)
end
end
ShopCtrl-->>Admin: 200 OK with NoContent
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Areas requiring extra attention:
Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/com/example/green/domain/pointshop/item/entity/PointItem.java (1)
86-92: Add validation for the requiredcategoryfield.The
categoryfield is markednullable = falsebut is not validated invalidatePointItem. All other required fields (itemCode,itemBasicInfo,itemMedia,itemPrice) are validated withvalidateNullData.Apply this diff to add category validation:
private static void validatePointItem(ItemCode itemCode, ItemBasicInfo itemBasicInfo, ItemMedia itemMedia, - ItemPrice itemPrice) { + ItemPrice itemPrice, Category category) { validateNullData(itemCode, REQUIRED_ITEM_CODE); validateNullData(itemBasicInfo, REQUIRED_ITEM_BASIC_INFO); validateNullData(itemMedia, REQUIRED_ITEM_MEDIA); validateNullData(itemPrice, REQUIRED_ITEM_PRICE); + validateNullData(category, "Category is required"); }And update the constructor to call the updated validation:
public PointItem(ItemCode itemCode, ItemBasicInfo itemBasicInfo, ItemMedia itemMedia, ItemPrice itemPrice, Category category) { - validatePointItem(itemCode, itemBasicInfo, itemMedia, itemPrice); + validatePointItem(itemCode, itemBasicInfo, itemMedia, itemPrice, category); this.itemCode = itemCode;
🧹 Nitpick comments (10)
src/main/java/com/example/green/domain/pointshop/item/service/command/PointItemUpdateCommand.java (1)
3-15: Consider null-safety forcategoryand reduce “positional constructor” footgunsAdding
Category categorychanges the record’s canonical constructor signature/order (Lines 9-15). IfPointItemUpdateCommandis constructed positionally in multiple places, it’s easy to swapprice/categoryaccidentally—consider adding a static factory (named params) or at least ensuring validation rejects null category early (e.g.,Objects.requireNonNull(category)in a compact constructor).src/main/java/com/example/green/domain/pointshop/product/controller/PointProductAdminController.java (1)
44-67: Rename the Excel export handler to avoid confusing overloadsThere are two
findPointProducts(...)methods (Lines 45-50, 59-67) with different behaviors (paged query vs excel streaming). Recommend renaming the excel one (e.g.,downloadPointProductsExcel) to keep controller intent obvious and make tracing/metrics clearer.src/main/java/com/example/green/domain/pointshop/product/service/command/PointProductUpdateCommand.java (1)
3-3: Consider relocating Category to a shared package.The
Categoryenum is imported from the item domain (com.example.green.domain.pointshop.item.entity.vo.Category) but is used by both product and item domains. This creates a cross-domain dependency where the product domain depends on item domain for a shared concept.Consider moving
Categoryto a shared location such as:
com.example.green.domain.pointshop.common.vo.Category, orcom.example.green.domain.pointshop.vo.CategoryThis would eliminate the cross-domain dependency and better represent that
Categoryis a shared concept across both items and products.src/main/java/com/example/green/domain/pointshop/admin/service/PointShopType.java (1)
3-6: Clarify the distinction between PointShopType and Category enums.Both
PointShopType(this enum) andCategory(incom.example.green.domain.pointshop.item.entity.vo.Category) defineITEMandPRODUCTvalues. While they may serve different purposes (admin API type discrimination vs. domain entity categorization), having two enums with identical values can lead to confusion and maintenance issues.Consider one of the following approaches:
- If they serve the same conceptual purpose, unify them into a single enum
- If they serve distinct purposes, add documentation to clarify when to use each
- Add a mapping method or validation to ensure consistency between them
Alternatively, if PointShopType is purely for API layer routing, you might consider using the domain Category enum directly in the admin API to reduce duplication.
src/main/java/com/example/green/domain/pointshop/product/entity/PointProduct.java (1)
74-89: Consider adding null validation for Category.While the database constraint ensures Category is non-null, adding validation in
validatePointProductwould provide earlier feedback and maintain consistency with other required fields (code, basicInfo, media, price, stock).Apply this diff to add validation:
private static void validatePointProduct(Code code, BasicInfo basicInfo, Media media, Price price, Stock stock) { validateNullData(code, REQUIRED_CODE); validateNullData(basicInfo, REQUIRED_BASIC_INFO); validateNullData(media, REQUIRED_MEDIA); validateNullData(price, REQUIRED_PRICE); validateNullData(stock, REQUIRED_STOCK); + validateNullData(category, REQUIRED_CATEGORY); if (stock.isSoldOut()) { throw new PointProductException(PointProductExceptionMessage.INVALID_PRODUCT_STOCK_CREATION); } }Note: You'll need to add the Category parameter to validatePointProduct signature and define REQUIRED_CATEGORY in PointProductExceptionMessage.
src/test/java/com/example/green/domain/pointshop/product/entity/PointProductTest.java (1)
228-237: Add test case for nullcategoryvalidation.The test cases validate that
code,basicInfo,media,price, andstockcannot be null, but there's no test case for a nullcategory. For consistency and completeness, add a test case to verify thatPointProduct.createthrows an exception whencategoryis null.Apply this diff to add the missing test case:
static Stream<Arguments> invalidPointProductTestCases() { return Stream.of( - Arguments.of(null, basicInfo, media, price, stock), - Arguments.of(code, null, media, price, stock), - Arguments.of(code, basicInfo, null, price, stock), - Arguments.of(code, basicInfo, media, null, stock), - Arguments.of(code, basicInfo, media, price, null), - Arguments.of(code, basicInfo, media, price, new Stock(0)) + Arguments.of(null, basicInfo, media, price, stock, category), + Arguments.of(code, null, media, price, stock, category), + Arguments.of(code, basicInfo, null, price, stock, category), + Arguments.of(code, basicInfo, media, null, stock, category), + Arguments.of(code, basicInfo, media, price, null, category), + Arguments.of(code, basicInfo, media, price, new Stock(0), category), + Arguments.of(code, basicInfo, media, price, stock, null) ); }src/main/java/com/example/green/domain/pointshop/admin/dto/request/AdminUpdatePointShopRequest.java (1)
40-41: Consider conditional validation forstockbased ontype.The
stockfield is nullable and has no validation. However, forPRODUCTtype entities, stock is typically required, while forITEMtype entities, stock may not apply. Consider adding conditional validation or documenting the expected behavior whenstockis null for each type.You might want to either:
- Add a custom validator that checks stock is provided when type is PRODUCT
- Document that null stock means "no change" for updates
- Use separate DTOs for item vs. product updates
Which approach aligns with your business requirements?
src/main/java/com/example/green/domain/pointshop/admin/dto/request/AdminCreatePointShopRequest.java (1)
40-41: Add conditional validation forstockbased ontype.The
stockfield should be required forPRODUCTtype but may not apply toITEMtype. Consider adding validation to enforce this business rule, such as:
- A custom validator that requires stock when type is PRODUCT
- Bean validation groups to apply different constraints based on type
- Separate request DTOs for items vs. products
Which approach best fits your domain model?
src/test/java/com/example/green/domain/pointshop/admin/controller/PointShopAdminControllerTest.java (1)
33-112: Add test coverage for validation failures and different types.The current tests only cover happy-path scenarios. Consider adding tests for:
- Validation failures (invalid/missing required fields) → expecting 400 Bad Request
- Entity not found scenarios for update/delete → expecting 404 Not Found
- Different behavior for
ITEMvs.PRODUCTtypesExample test structure:
@Test void 필수_필드가_없으면_400_에러가_발생한다() { AdminCreatePointShopRequest request = AdminCreatePointShopRequest.builder() // missing required fields .build(); RestAssuredMockMvc .given().contentType(MediaType.APPLICATION_JSON).body(request) .when().post("/api/admin/point-shop/create") .then().status(HttpStatus.BAD_REQUEST); }src/main/java/com/example/green/domain/pointshop/admin/service/PointShopAdminService.java (1)
46-55: RedundantCategoryparameter.
Category.ITEMis included in thePointItemCreateCommand(line 52) and also passed separately topointItemService.create()(line 54). This duplication risks inconsistency if they diverge. Consider removing the redundant parameter from either the command or the service method signature.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (37)
src/main/java/com/example/green/domain/pointshop/admin/controller/PointShopAdminController.java(1 hunks)src/main/java/com/example/green/domain/pointshop/admin/controller/docs/PointShopAdminControllerDocs.java(1 hunks)src/main/java/com/example/green/domain/pointshop/admin/controller/message/PointShopAdminResponseMessage.java(1 hunks)src/main/java/com/example/green/domain/pointshop/admin/dto/request/AdminCreatePointShopRequest.java(1 hunks)src/main/java/com/example/green/domain/pointshop/admin/dto/request/AdminUpdatePointShopRequest.java(1 hunks)src/main/java/com/example/green/domain/pointshop/admin/exception/PointShopAdminException.java(1 hunks)src/main/java/com/example/green/domain/pointshop/admin/exception/PointShopAdminExceptionMessage.java(1 hunks)src/main/java/com/example/green/domain/pointshop/admin/service/PointShopAdminService.java(1 hunks)src/main/java/com/example/green/domain/pointshop/admin/service/PointShopType.java(1 hunks)src/main/java/com/example/green/domain/pointshop/item/controller/PointItemAdminController.java(0 hunks)src/main/java/com/example/green/domain/pointshop/item/controller/docs/PointItemAdminControllerDocs.java(0 hunks)src/main/java/com/example/green/domain/pointshop/item/dto/request/CreatePointItemRequest.java(2 hunks)src/main/java/com/example/green/domain/pointshop/item/dto/response/PointItemResponse.java(1 hunks)src/main/java/com/example/green/domain/pointshop/item/entity/PointItem.java(2 hunks)src/main/java/com/example/green/domain/pointshop/item/entity/vo/Category.java(1 hunks)src/main/java/com/example/green/domain/pointshop/item/service/PointItemService.java(2 hunks)src/main/java/com/example/green/domain/pointshop/item/service/command/PointItemCreateCommand.java(2 hunks)src/main/java/com/example/green/domain/pointshop/item/service/command/PointItemUpdateCommand.java(2 hunks)src/main/java/com/example/green/domain/pointshop/product/controller/PointProductAdminController.java(1 hunks)src/main/java/com/example/green/domain/pointshop/product/controller/docs/PointProductAdminControllerDocs.java(0 hunks)src/main/java/com/example/green/domain/pointshop/product/entity/PointProduct.java(3 hunks)src/main/java/com/example/green/domain/pointshop/product/service/PointProductService.java(2 hunks)src/main/java/com/example/green/domain/pointshop/product/service/command/PointProductUpdateCommand.java(2 hunks)src/main/resources/db/migration/V14__add_category_to_point_tables.sql(1 hunks)src/test/java/com/example/green/domain/pointshop/admin/controller/PointShopAdminControllerTest.java(1 hunks)src/test/java/com/example/green/domain/pointshop/admin/service/PointShopAdminServiceTest.java(1 hunks)src/test/java/com/example/green/domain/pointshop/item/controller/DummyData.java(0 hunks)src/test/java/com/example/green/domain/pointshop/item/controller/PointItemAdminControllerTest.java(0 hunks)src/test/java/com/example/green/domain/pointshop/item/controller/PointItemOrderServiceControllerTest.java(2 hunks)src/test/java/com/example/green/domain/pointshop/item/service/PointItemQueryServiceTest.java(2 hunks)src/test/java/com/example/green/domain/pointshop/item/service/PointItemServiceTest.java(0 hunks)src/test/java/com/example/green/domain/pointshop/product/controller/DtoGenerator.java(0 hunks)src/test/java/com/example/green/domain/pointshop/product/controller/PointProductAdminControllerTest.java(1 hunks)src/test/java/com/example/green/domain/pointshop/product/controller/PointProductControllerTest.java(2 hunks)src/test/java/com/example/green/domain/pointshop/product/entity/PointProductTest.java(11 hunks)src/test/java/com/example/green/domain/pointshop/product/service/PointProductServiceTest.java(1 hunks)src/test/java/com/example/integration/pointproduct/PointProductConcurrencyTest.java(2 hunks)
💤 Files with no reviewable changes (7)
- src/main/java/com/example/green/domain/pointshop/product/controller/docs/PointProductAdminControllerDocs.java
- src/test/java/com/example/green/domain/pointshop/product/controller/DtoGenerator.java
- src/main/java/com/example/green/domain/pointshop/item/controller/docs/PointItemAdminControllerDocs.java
- src/main/java/com/example/green/domain/pointshop/item/controller/PointItemAdminController.java
- src/test/java/com/example/green/domain/pointshop/item/service/PointItemServiceTest.java
- src/test/java/com/example/green/domain/pointshop/item/controller/PointItemAdminControllerTest.java
- src/test/java/com/example/green/domain/pointshop/item/controller/DummyData.java
🧰 Additional context used
🧬 Code graph analysis (2)
src/main/java/com/example/green/domain/pointshop/admin/service/PointShopAdminService.java (3)
src/main/java/com/example/green/domain/pointshop/item/service/PointItemService.java (1)
Service(22-109)src/main/java/com/example/green/domain/pointshop/product/service/PointProductService.java (1)
Service(19-95)src/main/java/com/example/green/domain/pointshop/admin/exception/PointShopAdminException.java (1)
PointShopAdminException(6-11)
src/main/java/com/example/green/domain/pointshop/admin/controller/PointShopAdminController.java (2)
src/main/java/com/example/green/domain/pointshop/product/controller/PointProductAdminController.java (1)
RestController(33-80)src/main/java/com/example/green/domain/pointshop/item/controller/PointItemAdminController.java (1)
RestController(36-96)
🔇 Additional comments (20)
src/main/java/com/example/green/domain/pointshop/product/controller/PointProductAdminController.java (1)
33-80: Verify API contract after removing create/update/delete from this controllerGiven the removed endpoints, please double-check clients/docs/tests now point to the new admin controller for create/update/delete, and that no internal tooling still calls
/api/admin/point-productsPOST/PUT/DELETE.src/main/java/com/example/green/domain/pointshop/item/dto/response/PointItemResponse.java (1)
5-10: Breaking response-shape change: ensure consumers are updated (or versioned)Removing
SellingStatusfromPointItemResponsechanges the JSON contract (Lines 5-10). Please ensure all API consumers (front-end/batch/partners) and any serialization-based tests/docs are updated accordingly, or consider response versioning if backward compatibility is required.src/main/java/com/example/green/domain/pointshop/item/service/command/PointItemCreateCommand.java (1)
9-15: LGTM!The addition of the
Categoryfield to the create command aligns well with the broader refactor to support category-based point shop tab separation.src/main/java/com/example/green/domain/pointshop/admin/exception/PointShopAdminException.java (1)
6-11: LGTM!The exception class follows standard patterns, correctly extends
BusinessException, and provides appropriate constructor for exception message handling.src/test/java/com/example/integration/pointproduct/PointProductConcurrencyTest.java (1)
39-46: LGTM!The test correctly passes
Category.PRODUCTto the updatedPointProduct.createmethod, maintaining test validity while aligning with the new category-aware entity creation flow.src/test/java/com/example/green/domain/pointshop/item/service/PointItemQueryServiceTest.java (1)
73-80: LGTM!The test correctly constructs the
PointItemwithCategory.ITEM, properly aligning with the extended entity constructor signature.src/main/java/com/example/green/domain/pointshop/item/service/PointItemService.java (1)
31-43: No action required—all callers have been updated.The sole production caller of
PointItemService.create()inPointShopAdminService.java(line 54) correctly provides both thePointItemCreateCommandandCategoryparameters. The method signature change is fully implemented.src/test/java/com/example/green/domain/pointshop/product/controller/PointProductAdminControllerTest.java (1)
43-104: The point product create, update, and delete operations are adequately covered inPointShopAdminControllerTest, which tests unified admin operations for both point items and point products throughPointShopAdminService. The test class includes coverage for create, update, and delete operations via the three test methods present.src/test/java/com/example/green/domain/pointshop/item/controller/PointItemOrderServiceControllerTest.java (1)
22-22: LGTM!The Category import and its usage in the PointItem constructor are correct. The test properly reflects the updated entity signature.
Also applies to: 55-55
src/test/java/com/example/green/domain/pointshop/product/controller/PointProductControllerTest.java (1)
15-15: LGTM!The test correctly uses
Category.PRODUCTfor product entity creation, properly reflecting the domain model changes.Also applies to: 74-75
src/main/java/com/example/green/domain/pointshop/product/entity/PointProduct.java (1)
69-71: LGTM - Category field properly configured.The Category field is correctly defined with non-null constraint and STRING enumeration. Using STRING enumeration is a good practice for maintainability.
src/test/java/com/example/green/domain/pointshop/admin/service/PointShopAdminServiceTest.java (3)
48-95: LGTM - Comprehensive create routing tests.The tests properly verify that create operations are routed to the correct service (PointItemService or PointProductService) based on the request type, with appropriate verification of service interactions.
97-157: LGTM - Update routing logic well tested.The tests comprehensively cover update scenarios including fallback behavior when an item doesn't exist but a product does, and proper exception handling when neither exists.
159-197: LGTM - Delete routing logic properly tested.The delete tests mirror the update test structure and provide comprehensive coverage of the routing logic with proper exception handling.
src/test/java/com/example/green/domain/pointshop/product/service/PointProductServiceTest.java (1)
1-99: Test scope appropriately adjusted for architectural changes.The removal of create, update, and delete tests from this file aligns with the PR's centralization of admin operations into
PointShopAdminService. These operations are now tested inPointShopAdminServiceTest.java. The remaining tests focus on non-admin product operations (display toggles, snapshots, stock management).src/main/java/com/example/green/domain/pointshop/product/service/PointProductService.java (1)
28-41: All callers have been properly updated.The method signature change to include the Category parameter has been fully implemented. PointShopAdminService.create() passes Category.PRODUCT at line 65, and the corresponding test mock at line 85 properly accepts the additional parameter.
src/main/java/com/example/green/domain/pointshop/item/entity/PointItem.java (1)
65-67: Consider whethercategoryshould be mutable.Unlike other fields (
itemCode,itemBasicInfo,itemMedia,itemPrice), there is noupdateCategorymethod. If the category is intended to be immutable after creation, this is fine. Otherwise, consider adding an update method for consistency.Is the
categoryfield intended to be immutable, or should it support updates like other entity fields?src/main/java/com/example/green/domain/pointshop/item/entity/vo/Category.java (1)
1-16: LGTM! Clean enum implementation.The
Categoryenum is well-designed with clear constant names and Korean display values. The use of@JsonValueensures proper JSON serialization, and Lombok annotations eliminate boilerplate. This provides a type-safe way to distinguish between products and items.src/main/java/com/example/green/domain/pointshop/admin/controller/docs/PointShopAdminControllerDocs.java (1)
1-45: LGTM! Comprehensive OpenAPI documentation.The interface provides clear API documentation with appropriate response codes and error schemas. The operation summaries and descriptions are informative, and the consistent use of
ExceptionResponsefor error cases follows best practices.src/main/java/com/example/green/domain/pointshop/admin/controller/PointShopAdminController.java (1)
24-51: Update the review with accurate information about the existing controllers.The existing
PointItemAdminControllerandPointProductAdminControllerhave no create/update/delete endpoints—only read operations (GET) and partial updates (PATCH for display visibility). The newPointShopAdminControllerprovides a unified CUD API for both items and products, determined by thetypefield in the request. This is intentional by design (documented in the controller docs), not redundant with existing endpoints.However, clarify the architectural rationale: Why consolidate items and products under a single endpoint when separate domain controllers exist? Consider documenting whether this unified approach is part of a broader admin API refactoring strategy or if there's a specific reason to merge CUD operations at the
/api/admin/point-shoplevel.
|
|
||
| POINT_ITEM_CREATION_SUCCESS("포인트 상점 아이템 / 상품 생성에 성공했습니다."), | ||
| POINT_ITEM_UPDATE_SUCCESS("포인트 상점 아이템 / 상품 수정에 성공했습니다."), | ||
| POINT_ITEM_DELETE_SUCCESS("아이템 / 상품수정 삭제에 성공했습니다."); |
There was a problem hiding this comment.
Fix typo in delete success message.
The message contains "상품수정 삭제" where "수정" (modification) appears incorrectly. It should be "상품 삭제" (product deletion).
Apply this diff to correct the message:
POINT_ITEM_CREATION_SUCCESS("포인트 상점 아이템 / 상품 생성에 성공했습니다."),
POINT_ITEM_UPDATE_SUCCESS("포인트 상점 아이템 / 상품 수정에 성공했습니다."),
- POINT_ITEM_DELETE_SUCCESS("아이템 / 상품수정 삭제에 성공했습니다.");
+ POINT_ITEM_DELETE_SUCCESS("아이템 / 상품 삭제에 성공했습니다.");📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| POINT_ITEM_DELETE_SUCCESS("아이템 / 상품수정 삭제에 성공했습니다."); | |
| POINT_ITEM_CREATION_SUCCESS("포인트 상점 아이템 / 상품 생성에 성공했습니다."), | |
| POINT_ITEM_UPDATE_SUCCESS("포인트 상점 아이템 / 상품 수정에 성공했습니다."), | |
| POINT_ITEM_DELETE_SUCCESS("아이템 / 상품 삭제에 성공했습니다."); |
🤖 Prompt for AI Agents
In
src/main/java/com/example/green/domain/pointshop/admin/controller/message/PointShopAdminResponseMessage.java
around line 14, the enum constant message contains a typo "아이템 / 상품수정 삭제에
성공했습니다." — replace "상품수정" with "상품" so the message reads "아이템 / 상품 삭제에 성공했습니다."
and save the file.
| @PostMapping("/create") | ||
| public ApiTemplate<Long> create(@RequestBody @Valid AdminCreatePointShopRequest createPointShopRequest) { | ||
| Long result = pointShopAdminService.create(createPointShopRequest); | ||
| return ApiTemplate.ok(POINT_ITEM_CREATION_SUCCESS, result); |
There was a problem hiding this comment.
Use type-agnostic message constants or conditional messages.
The endpoint uses POINT_ITEM_CREATION_SUCCESS for all creations, but this controller handles both items and products. Consider either:
- Renaming the constants to be generic (e.g.,
POINT_SHOP_CREATION_SUCCESS) - Using conditional messages based on the request type
The same issue applies to lines 44 and 50 with POINT_ITEM_UPDATE_SUCCESS and POINT_ITEM_DELETE_SUCCESS.
🤖 Prompt for AI Agents
In
src/main/java/com/example/green/domain/pointshop/admin/controller/PointShopAdminController.java
around lines 35, 44 and 50, the controller currently returns
POINT_ITEM_CREATION_SUCCESS, POINT_ITEM_UPDATE_SUCCESS and
POINT_ITEM_DELETE_SUCCESS for both item and product operations; change to use
type-agnostic constants (e.g., POINT_SHOP_CREATION_SUCCESS,
POINT_SHOP_UPDATE_SUCCESS, POINT_SHOP_DELETE_SUCCESS) or select the message
conditionally based on the incoming DTO/type before calling ApiTemplate.ok, and
update usages/imports accordingly so responses reflect the correct generic or
conditional message.
| @Schema(description = "상품 생성 요청") | ||
| @Builder | ||
| public record AdminCreatePointShopRequest( | ||
| PointShopType type, |
There was a problem hiding this comment.
Add @NotNull validation to the type field.
The type field is essential for determining whether to create an item or a product, but it lacks validation. Without @NotNull, the field could be null, causing routing failures in the service layer.
Apply this diff to add validation:
public record AdminCreatePointShopRequest(
+ @NotNull(message = "상품 타입은 필수입니다.")
PointShopType type,📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| PointShopType type, | |
| @NotNull(message = "상품 타입은 필수입니다.") | |
| PointShopType type, |
🤖 Prompt for AI Agents
In
src/main/java/com/example/green/domain/pointshop/admin/dto/request/AdminCreatePointShopRequest.java
around line 16, the PointShopType type field lacks validation; add the
javax.validation constraint @NotNull to the type field declaration (and import
javax.validation.constraints.NotNull if missing) so the DTO enforces non-null
input and prevents null routing to the service layer.
| @Schema(description = "상품 수정 요청") | ||
| @Builder | ||
| public record AdminUpdatePointShopRequest( | ||
| PointShopType type, |
There was a problem hiding this comment.
Add @NotNull validation to the type field.
The type field is essential for determining whether the request updates an item or a product, but it lacks validation. Without @NotNull, the field could be null, leading to potential NullPointerException in the service layer.
Apply this diff to add validation:
public record AdminUpdatePointShopRequest(
+ @NotNull(message = "상품 타입은 필수입니다.")
PointShopType type,📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| PointShopType type, | |
| @NotNull(message = "상품 타입은 필수입니다.") | |
| PointShopType type, |
🤖 Prompt for AI Agents
In
src/main/java/com/example/green/domain/pointshop/admin/dto/request/AdminUpdatePointShopRequest.java
around line 16, the PointShopType type field lacks validation; add the
javax.validation constraint @NotNull to the type field declaration and import
the annotation so the field is validated on request binding, ensuring null
values are rejected before reaching the service layer.
| @RequiredArgsConstructor | ||
| @Getter | ||
| public enum PointShopAdminExceptionMessage implements ExceptionMessage { | ||
|
|
||
| NOT_FOUND_CATEGORY(NOT_FOUND, "카테고리를 찾을 수가 없습니다"), | ||
| NOT_FOUND_PRODUCT(NOT_FOUND, "등록된 상품 / 아이템을 찾을 수 없습니다"); | ||
|
|
||
| private final HttpStatus httpStatus; | ||
| private final String message; | ||
|
|
||
| } |
There was a problem hiding this comment.
Polish error message Korean phrasing for consistency
"카테고리를 찾을 수가 없습니다" (Line 16) reads unnatural; usually "카테고리를 찾을 수 없습니다". Same suggestion if other enums standardize on that phrasing.
- NOT_FOUND_CATEGORY(NOT_FOUND, "카테고리를 찾을 수가 없습니다"),
+ NOT_FOUND_CATEGORY(NOT_FOUND, "카테고리를 찾을 수 없습니다"),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @RequiredArgsConstructor | |
| @Getter | |
| public enum PointShopAdminExceptionMessage implements ExceptionMessage { | |
| NOT_FOUND_CATEGORY(NOT_FOUND, "카테고리를 찾을 수가 없습니다"), | |
| NOT_FOUND_PRODUCT(NOT_FOUND, "등록된 상품 / 아이템을 찾을 수 없습니다"); | |
| private final HttpStatus httpStatus; | |
| private final String message; | |
| } | |
| @RequiredArgsConstructor | |
| @Getter | |
| public enum PointShopAdminExceptionMessage implements ExceptionMessage { | |
| NOT_FOUND_CATEGORY(NOT_FOUND, "카테고리를 찾을 수 없습니다"), | |
| NOT_FOUND_PRODUCT(NOT_FOUND, "등록된 상품 / 아이템을 찾을 수 없습니다"); | |
| private final HttpStatus httpStatus; | |
| private final String message; | |
| } |
🤖 Prompt for AI Agents
In
src/main/java/com/example/green/domain/pointshop/admin/exception/PointShopAdminExceptionMessage.java
around lines 12 to 22, the Korean message for NOT_FOUND_CATEGORY uses the less
natural phrasing "카테고리를 찾을 수가 없습니다"; update it to the more natural "카테고리를 찾을 수
없습니다" and ensure other enum entries follow the same phrasing convention for
consistency (adjust strings accordingly).
| public void delete(Long productId) { | ||
| Optional<PointItem> pointItem = pointItemRepository.findById(productId); | ||
| if (pointItem.isPresent()) { | ||
| pointItemService.delete(productId); | ||
| return; | ||
| } | ||
| Optional<PointProduct> pointProduct = pointProductRepository.findById(productId); | ||
| if (pointProduct.isPresent()) { | ||
| pointProductService.delete(productId); | ||
| return; | ||
| } | ||
| throw new PointShopAdminException(PointShopAdminExceptionMessage.NOT_FOUND_PRODUCT); | ||
| } |
There was a problem hiding this comment.
Same ID collision issue as update(); also inefficient existence check.
This method has the same problem: if both tables have an entity with the same ID, the PointItem is always deleted. Consider adding a PointShopType parameter to explicitly route to the correct service.
Additionally, findById fetches the entire entity just to check existence. Use existsById for efficiency if you retain the probing approach:
public void delete(Long productId) {
- Optional<PointItem> pointItem = pointItemRepository.findById(productId);
- if (pointItem.isPresent()) {
+ if (pointItemRepository.existsById(productId)) {
pointItemService.delete(productId);
return;
}
- Optional<PointProduct> pointProduct = pointProductRepository.findById(productId);
- if (pointProduct.isPresent()) {
+ if (pointProductRepository.existsById(productId)) {
pointProductService.delete(productId);
return;
}
throw new PointShopAdminException(PointShopAdminExceptionMessage.NOT_FOUND_PRODUCT);
}However, the preferred fix is to require a type discriminator like create() does.
| BigDecimal price, | ||
|
|
||
| @Schema(description = "분류 카테고리", example = "ITEM") | ||
| Category category | ||
|
|
||
| ) { | ||
| public PointItemCreateCommand toCommand() { | ||
| return new PointItemCreateCommand( | ||
| new ItemCode(code), | ||
| new ItemBasicInfo(name, description), | ||
| new ItemMedia(thumbnailUrl), | ||
| new ItemPrice(price) | ||
| new ItemPrice(price), | ||
| category | ||
| ); |
There was a problem hiding this comment.
Add validation constraint for required category field.
The category field lacks a @NotNull validation annotation, unlike other required fields in this DTO. This could allow null values to pass through to the service layer, causing issues when creating entities that expect non-null categories.
Apply this diff to add validation:
@NotNull(message = "아이템 상품 가격은 필수입니다.")
@Schema(description = "아이템 상품 가격", example = "10000")
BigDecimal price,
+ @NotNull(message = "아이템 카테고리는 필수입니다.")
@Schema(description = "분류 카테고리", example = "ITEM")
Category category📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| BigDecimal price, | |
| @Schema(description = "분류 카테고리", example = "ITEM") | |
| Category category | |
| ) { | |
| public PointItemCreateCommand toCommand() { | |
| return new PointItemCreateCommand( | |
| new ItemCode(code), | |
| new ItemBasicInfo(name, description), | |
| new ItemMedia(thumbnailUrl), | |
| new ItemPrice(price) | |
| new ItemPrice(price), | |
| category | |
| ); | |
| BigDecimal price, | |
| @NotNull(message = "아이템 카테고리는 필수입니다.") | |
| @Schema(description = "분류 카테고리", example = "ITEM") | |
| Category category | |
| ) { | |
| public PointItemCreateCommand toCommand() { | |
| return new PointItemCreateCommand( | |
| new ItemCode(code), | |
| new ItemBasicInfo(name, description), | |
| new ItemMedia(thumbnailUrl), | |
| new ItemPrice(price), | |
| category | |
| ); |
🤖 Prompt for AI Agents
In
src/main/java/com/example/green/domain/pointshop/item/dto/request/CreatePointItemRequest.java
around lines 38 to 51, the Category field is missing a @NotNull validation; add
the javax.validation.constraints.NotNull annotation to the category field
declaration (above the @Schema) so it cannot be null, and add the corresponding
import statement for NotNull at the top of the file.
| private final FileClient fileClient; | ||
|
|
||
| public Long create(PointItemCreateCommand createCommand) { | ||
| public Long create(PointItemCreateCommand createCommand, Category category) { |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Add validation or documentation for the Category parameter.
The create method now accepts a Category parameter without validation or null checks. While the parameter may come from a command object that enforces non-null, the service method should be defensive.
Consider adding:
- Parameter validation (e.g.,
Objects.requireNonNull(category, "category must not be null")) - JavaDoc documentation explaining valid category values and their significance
+ /**
+ * Creates a new point item with the specified category.
+ * @param createCommand the command containing item details
+ * @param category the category for the point item (must not be null)
+ * @return the ID of the created point item
+ */
public Long create(PointItemCreateCommand createCommand, Category category) {
+ Objects.requireNonNull(category, "category must not be null");
validatePointItemCode(createCommand.itemCode());🤖 Prompt for AI Agents
In
src/main/java/com/example/green/domain/pointshop/item/service/PointItemService.java
around line 31, the create(PointItemCreateCommand createCommand, Category
category) method accepts a Category without validation or documentation; add a
defensive null-check (e.g., Objects.requireNonNull(category, "category must not
be null") or equivalent validation for allowed values) at the start of the
method and add JavaDoc to the method signature describing that category must be
non-null and listing/pointing to valid Category values and their meaning.
| -- point_item 테이블에 category 컬럼 추가 | ||
| ALTER TABLE point_item | ||
| ADD COLUMN category VARCHAR(20); | ||
|
|
||
| -- 기존 point_item 데이터 → ITEM | ||
| UPDATE point_item | ||
| SET category = 'ITEM' | ||
| WHERE category IS NULL; | ||
|
|
||
| -- NOT NULL 제약 추가 | ||
| ALTER TABLE point_item | ||
| ALTER COLUMN category SET NOT NULL; | ||
|
|
There was a problem hiding this comment.
Add a DB-level DEFAULT (and optionally a CHECK) for category
Right now there’s no default, so inserts that omit category will fail once NOT NULL is enforced (Lines 10-13, 24-26). Consider setting a per-table default, and (optionally) a CHECK constraint to prevent invalid strings.
-- point_item 테이블에 category 컬럼 추가
ALTER TABLE point_item
-ADD COLUMN category VARCHAR(20);
+ADD COLUMN category VARCHAR(20) NOT NULL DEFAULT 'ITEM';
--- 기존 point_item 데이터 → ITEM
-UPDATE point_item
-SET category = 'ITEM'
-WHERE category IS NULL;
-
--- NOT NULL 제약 추가
-ALTER TABLE point_item
-ALTER COLUMN category SET NOT NULL;
+-- (optional) 값 제한
+-- ALTER TABLE point_item ADD CONSTRAINT chk_point_item_category CHECK (category IN ('ITEM'));
@@
ALTER TABLE point_products
-ADD COLUMN category VARCHAR(20);
+ADD COLUMN category VARCHAR(20) NOT NULL DEFAULT 'PRODUCT';
--- 기존 point_products 데이터 → PRODUCT
-UPDATE point_products
-SET category = 'PRODUCT'
-WHERE category IS NULL;
-
--- NOT NULL 제약 추가
-ALTER TABLE point_products
-ALTER COLUMN category SET NOT NULL;
+-- (optional) 값 제한
+-- ALTER TABLE point_products ADD CONSTRAINT chk_point_products_category CHECK (category IN ('PRODUCT'));Also applies to: 15-26
🤖 Prompt for AI Agents
In src/main/resources/db/migration/V14__add_category_to_point_tables.sql around
lines 1-13 (and similarly for the later block around 15-26), the migration adds
a NOT NULL category column but does not define a DB-level DEFAULT or a CHECK
constraint; add a DEFAULT 'ITEM' to the column definition (or via ALTER COLUMN
SET DEFAULT) so inserts that omit category succeed, run the backfill to set
existing NULLs to 'ITEM', then set NOT NULL, and optionally add a CHECK
constraint limiting allowed values (e.g. category IN ('ITEM', ...)) to prevent
invalid strings; ensure the migration orders are: add column with DEFAULT,
update NULLs, add CHECK (if desired), then ALTER COLUMN ... SET NOT NULL.
| AdminCreatePointShopRequest request = AdminCreatePointShopRequest.builder() | ||
| .code("ITEM001") | ||
| .name("테스트 상품") | ||
| .description("테스트 설명") | ||
| .thumbnailUrl("https://test.com/image.png") | ||
| .price(BigDecimal.valueOf(1000)) | ||
| .build(); |
There was a problem hiding this comment.
Add the required type field to the test request.
The test builds an AdminCreatePointShopRequest without setting the type field, which means type will be null. Since the service logic routes based on this field, the test should specify whether it's creating a PRODUCT or an ITEM.
Apply this diff to fix the test:
AdminCreatePointShopRequest request = AdminCreatePointShopRequest.builder()
+ .type(PointShopType.ITEM) // or PRODUCT
.code("ITEM001")
.name("테스트 상품")
.description("테스트 설명")The same issue exists in the update test at lines 70-76.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| AdminCreatePointShopRequest request = AdminCreatePointShopRequest.builder() | |
| .code("ITEM001") | |
| .name("테스트 상품") | |
| .description("테스트 설명") | |
| .thumbnailUrl("https://test.com/image.png") | |
| .price(BigDecimal.valueOf(1000)) | |
| .build(); | |
| AdminCreatePointShopRequest request = AdminCreatePointShopRequest.builder() | |
| .type(PointShopType.ITEM) | |
| .code("ITEM001") | |
| .name("테스트 상품") | |
| .description("테스트 설명") | |
| .thumbnailUrl("https://test.com/image.png") | |
| .price(BigDecimal.valueOf(1000)) | |
| .build(); |
🤖 Prompt for AI Agents
In
src/test/java/com/example/green/domain/pointshop/admin/controller/PointShopAdminControllerTest.java
around lines 35-41 and 70-76, the test request builders omit the required type
field causing null routing; update both the create and update
AdminCreatePointShopRequest/AdminUpdatePointShopRequest builders to set the type
explicitly (e.g., PointShopType.PRODUCT or PointShopType.ITEM) so the service
routing logic has a non-null value and tests exercise the intended branch.
Unit Test Coverage Report
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/test/java/com/example/green/domain/pointshop/product/entity/PointProductTest.java (1)
218-228: Remove unused test data method.The
invalidPointProductTestCases()method is not referenced by any@ParameterizedTestin this file. According to the AI summary, the invalid-argument parameterized test was removed, making this method dead code.Remove the unused method:
- static Stream<Arguments> invalidPointProductTestCases() { - return Stream.of( - Arguments.of(null, basicInfo, media, price, stock, category), - Arguments.of(code, null, media, price, stock, category), - Arguments.of(code, basicInfo, null, price, stock, category), - Arguments.of(code, basicInfo, media, null, stock, category), - Arguments.of(code, basicInfo, media, price, null, category), - Arguments.of(code, basicInfo, media, price, new Stock(0), category), - Arguments.of(code, basicInfo, media, price, stock, Category.PRODUCT) - ); - }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/test/java/com/example/green/domain/pointshop/product/entity/PointProductTest.java(10 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: check
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (3)
src/main/java/com/example/green/domain/pointshop/admin/service/PointShopAdminService.java (3)
34-36: Missing@Transactionalannotation (already flagged).This issue was raised in a previous review. Both delegate services use
@Transactionalat the class level, and this service performs multi-step operations (lookup + delegate) that should be atomic.
72-101: ID collision risk when probing both repositories (already flagged).This issue was raised in a previous review. When PointItem and PointProduct have separate ID sequences, overlapping IDs cause misrouting. The past comment recommended adding a
PointShopTypediscriminator to the request (similar tocreate()) to route directly.
104-116: Same ID collision issue asupdate()(already flagged).This method has the same probing-by-ID problem that was raised in the previous review. Consider requiring a type discriminator to route correctly when IDs overlap across tables.
🧹 Nitpick comments (2)
src/main/java/com/example/green/domain/pointshop/admin/service/PointShopAdminService.java (1)
46-68: Consider whether Category and PointShopType represent the same concept.The code hardcodes
Category.ITEMwhenrequest.type() == PointShopType.ITEM(line 52) and presumablyCategory.PRODUCTforPointShopType.PRODUCT. If these enums are always mapped 1:1, maintaining both creates redundancy and potential for drift. Consider deriving Category from PointShopType or consolidating into a single enum.src/main/java/com/example/green/domain/pointshop/item/entity/PointItem.java (1)
94-112: Consider whether category should be mutable.The class provides update methods for other fields (
updateItemCode,updateItemBasicInfo, etc.), but not forcategory. Ifcategoryis intentionally immutable after entity creation, this is fine. However, if it should be mutable, consider adding anupdateCategorymethod for consistency with the existing design pattern.If category should be mutable, apply this diff:
public void updateItemPrice(ItemPrice itemPrice) { validateNullData(itemPrice, REQUIRED_ITEM_PRICE); this.itemPrice = itemPrice; } + + public void updateCategory(Category category) { + validateNullData(category, "카테고리는 필수입니다."); + this.category = category; + } public boolean isNewImage(ItemMedia media) {
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/main/java/com/example/green/domain/pointshop/admin/service/PointShopAdminService.java(1 hunks)src/main/java/com/example/green/domain/pointshop/item/entity/PointItem.java(2 hunks)src/main/java/com/example/green/domain/pointshop/product/entity/PointProduct.java(3 hunks)src/test/java/com/example/green/domain/pointshop/admin/service/PointShopAdminServiceTest.java(1 hunks)src/test/java/com/example/green/domain/pointshop/product/controller/PointProductControllerTest.java(1 hunks)src/test/java/com/example/green/domain/pointshop/product/entity/PointProductTest.java(3 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/test/java/com/example/green/domain/pointshop/product/controller/PointProductControllerTest.java
🚧 Files skipped from review as they are similar to previous changes (3)
- src/test/java/com/example/green/domain/pointshop/admin/service/PointShopAdminServiceTest.java
- src/main/java/com/example/green/domain/pointshop/product/entity/PointProduct.java
- src/test/java/com/example/green/domain/pointshop/product/entity/PointProductTest.java
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/com/example/green/domain/pointshop/admin/service/PointShopAdminService.java (3)
src/main/java/com/example/green/domain/pointshop/product/service/PointProductService.java (1)
Service(18-93)src/main/java/com/example/green/domain/pointshop/item/service/PointItemService.java (1)
Service(21-107)src/main/java/com/example/green/domain/pointshop/admin/exception/PointShopAdminException.java (1)
PointShopAdminException(6-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: check
🔇 Additional comments (3)
src/main/java/com/example/green/domain/pointshop/item/entity/PointItem.java (3)
7-7: LGTM!The import for the new
Categoryenum is properly added.
65-67: LGTM!The
categoryfield is properly declared with appropriate JPA annotations. UsingEnumType.STRINGensures database readability and thenullable = falseconstraint maintains data integrity.
81-84: LGTM!The static factory method provides backward compatibility by defaulting to
Category.ITEM, which is appropriate for thePointItementity.
| public PointItem(ItemCode itemCode, ItemBasicInfo itemBasicInfo, ItemMedia itemMedia, ItemPrice itemPrice, | ||
| Category category) { | ||
| validatePointItem(itemCode, itemBasicInfo, itemMedia, itemPrice); |
There was a problem hiding this comment.
Add validation for the category parameter.
The constructor accepts a category parameter and assigns it (line 78), but the validation method validatePointItem (line 72) does not validate it. Since the database column is marked as nullable = false (line 65), passing a null category will cause a constraint violation at persist time.
Apply this diff to add validation for the category parameter:
private static void validatePointItem(ItemCode itemCode, ItemBasicInfo itemBasicInfo, ItemMedia itemMedia,
- ItemPrice itemPrice) {
+ ItemPrice itemPrice, Category category) {
validateNullData(itemCode, REQUIRED_ITEM_CODE);
validateNullData(itemBasicInfo, REQUIRED_ITEM_BASIC_INFO);
validateNullData(itemMedia, REQUIRED_ITEM_MEDIA);
validateNullData(itemPrice, REQUIRED_ITEM_PRICE);
+ validateNullData(category, "카테고리는 필수입니다.");
}Then update the constructor call:
public PointItem(ItemCode itemCode, ItemBasicInfo itemBasicInfo, ItemMedia itemMedia, ItemPrice itemPrice,
Category category) {
- validatePointItem(itemCode, itemBasicInfo, itemMedia, itemPrice);
+ validatePointItem(itemCode, itemBasicInfo, itemMedia, itemPrice, category);
this.itemCode = itemCode;Note: You'll need to add a constant for the category validation message (e.g., REQUIRED_CATEGORY) in the exception message class, similar to the other REQUIRED_* constants.
Also applies to: 78-78
🤖 Prompt for AI Agents
In src/main/java/com/example/green/domain/pointshop/item/entity/PointItem.java
around lines 70-78, the constructor accepts a Category but
validatePointItem(...) is not checking it, causing potential DB constraint
violations; update validation to check category != null and throw the domain
validation exception with a new message constant REQUIRED_CATEGORY, add that
REQUIRED_CATEGORY constant to the exception message class to match existing
REQUIRED_* constants, and adjust the constructor to call the updated
validatePointItem (or include a separate null check) before assigning the
category field.
#️⃣ 연관된 이슈
📝 작업 내용
📷 스크린샷
💬 리뷰 요구사항(선택)
📌 PR 진행 시 참고사항
P1: 꼭 반영해 주세요 (Request Changes) – 이슈나 취약점 관련P2: 반영을 고려해 주세요 (Comment) – 개선 의견P3: 단순 제안 (Chore)Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.