Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.campustable.be.domain.cart.controller;


import com.campustable.be.domain.cart.dto.CartRequest;
import com.campustable.be.domain.cart.dto.CartResponse;
import com.campustable.be.domain.cart.service.CartService;
import com.campustable.be.global.aop.LogMonitoringInvocation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/cart")
@RequiredArgsConstructor
@Slf4j
public class CartController implements CartControllerDocs{

private final CartService cartService;

@LogMonitoringInvocation
@Override
@PostMapping("/items")
public ResponseEntity<CartResponse> addOrUpdateItems(@RequestBody CartRequest request) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

요청 본문 유효성 검증 누락

@RequestBody 파라미터에 @Valid 애노테이션이 없어 요청 데이터의 유효성 검증이 이루어지지 않습니다. CartRequest의 필드(menu_id, quantity)에 대한 검증을 추가해야 합니다.

🔎 제안하는 수정 사항

1. Controller에 @Valid 추가

+import jakarta.validation.Valid;
+
-  public ResponseEntity<CartResponse> addOrUpdateItems(@RequestBody CartRequest request) {
+  public ResponseEntity<CartResponse> addOrUpdateItems(@Valid @RequestBody CartRequest request) {

2. CartRequest DTO에 유효성 검증 애노테이션 추가

CartRequest.java 파일에:

import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;

public class CartRequest {
  @NotNull(message = "메뉴 ID는 필수입니다")
  private Long menu_id;
  
  @Min(value = 0, message = "수량은 0 이상이어야 합니다")
  private int quantity;
}
📝 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.

Suggested change
public ResponseEntity<CartResponse> addOrUpdateItems(@RequestBody CartRequest request) {
import jakarta.validation.Valid;
public ResponseEntity<CartResponse> addOrUpdateItems(@Valid @RequestBody CartRequest request) {
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/cart/controller/CartController.java
around line 30, the @RequestBody parameter lacks @Valid so incoming CartRequest
fields aren't being validated; add the javax/jakarta.validation @Valid
annotation to the method parameter and update
src/main/java/com/campustable/be/domain/cart/controller/CartRequest.java to
annotate fields with validation constraints (e.g., @NotNull on menu_id and
@Min(0) on quantity) and import the appropriate jakarta.validation annotations;
ensure the project has a validation provider (hibernate-validator) on the
classpath so Spring will enforce these constraints at request binding.

CartResponse response = cartService.updateCartItem(request.getMenu_id(), request.getQuantity());

return ResponseEntity.ok(response);
}

@LogMonitoringInvocation
@Override
@GetMapping("/")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

GET 매핑 경로의 불필요한 슬래시

@GetMapping("/")의 슬래시가 불필요합니다. 일반적인 REST 관례에 따라 빈 문자열을 사용하는 것이 좋습니다.

🔎 제안하는 수정 사항
-  @GetMapping("/")
+  @GetMapping
   public ResponseEntity<CartResponse> getCart(){

이렇게 하면 경로가 /api/cart가 됩니다.

📝 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.

Suggested change
@GetMapping("/")
@GetMapping
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/cart/controller/CartController.java
around line 38, the @GetMapping("/") uses an unnecessary trailing slash; replace
it with an empty value (e.g., @GetMapping("") or simply @GetMapping) so the
endpoint maps to /api/cart per REST conventions and avoids a double-slash path.

public ResponseEntity<CartResponse> getCart(){

CartResponse response = cartService.getCart();

return ResponseEntity.ok(response);
}


@LogMonitoringInvocation
@Override
@DeleteMapping("/{cartId}")
public void deleteCart(@PathVariable Long cartId) {
cartService.deleteCart(cartId);
}

@LogMonitoringInvocation
@Override
@DeleteMapping("/items/{cartItemId}")
public void deleteCartItem(@PathVariable Long cartItemId) {
cartService.deleteCartItem(cartItemId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package com.campustable.be.domain.cart.controller;

import com.campustable.be.domain.cart.dto.CartRequest;
import com.campustable.be.domain.cart.dto.CartResponse;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;

public interface CartControllerDocs {

@Operation(
summary = "장바구니 메뉴 추가 또는 수량 변경",
description = """
### 요청 파라미터
- `menu_id` (Long, required): 장바구니에 담을 메뉴 ID
- `quantity` (int, required): 담을 수량
- 1 이상: 해당 수량으로 장바구니에 추가 또는 수정
- 0: 해당 메뉴를 장바구니에서 삭제

### 응답 데이터
- `cartId` (Long): 장바구니 ID
- `items` (List<CartItemDto>): 장바구니에 담긴 메뉴 목록
- `cartItemId` (Long): 장바구니 아이템 ID
- `menuName` (String): 메뉴 이름
- `quantity` (int): 담긴 수량
- `price` (int): 메뉴 단가
- `menuUrl` (String): 메뉴 이미지 URL
- `totalPrice` (int): 장바구니 전체 금액 (메뉴 단가 × 수량 합계)

### 사용 방법
1. 로그인 후 JWT 인증이 완료된 상태에서 요청합니다.
2. 메뉴 ID와 수량을 전달하면,
- 이미 장바구니에 존재하는 메뉴인 경우 수량이 변경됩니다.
- 장바구니에 없는 메뉴인 경우 새로 추가됩니다.
3. 수량을 0으로 전달하면 해당 메뉴는 장바구니에서 삭제됩니다.
4. 장바구니에 담긴 모든 메뉴가 삭제되면 장바구니 자체도 함께 삭제됩니다.
5. 처리 완료 후 현재 장바구니 상태를 응답으로 반환합니다.

### 유의 사항
- 인증되지 않은 사용자는 요청할 수 없습니다.
- `menu_id`는 실제 존재하는 메뉴 ID여야 합니다.
- 수량은 음수 값을 허용하지 않습니다.
- 장바구니는 사용자당 하나만 생성되며, 존재하지 않을 경우 자동 생성됩니다.
- 장바구니가 완전히 비워지면 DB에서 장바구니 엔티티가 삭제됩니다.

### 예외 처리
- `MENU_NOT_FOUND` (404 NOT_FOUND): 해당 메뉴를 찾을 수 없습니다.
- `USER_NOT_FOUND` (404 NOT_FOUND): 유저를 찾을 수 없습니다.
- `ACCESS_DENIED` (403 FORBIDDEN): 인증되지 않은 사용자의 접근
"""
)
ResponseEntity<CartResponse> addOrUpdateItems(
@RequestBody CartRequest request
);

@Operation(
summary = "장바구니 조회",
description = """
### 요청 파라미터
- 없음 (JWT 인증 정보로 사용자 식별)

### 응답 데이터
- `cartId` (Long): 장바구니 ID (존재하는 경우에만 반환)
- `items` (List<CartItemDto>): 장바구니에 담긴 메뉴 목록
- `cartItemId` (Long): 장바구니 아이템 ID
- `menuName` (String): 메뉴 이름
- `quantity` (int): 담긴 수량
- `price` (int): 메뉴 단가
- `menuUrl` (String): 메뉴 이미지 URL
- `totalPrice` (int): 장바구니 전체 금액

### 사용 방법
1. 로그인 후 JWT 인증이 완료된 상태에서 요청합니다.
2. 사용자의 장바구니가 존재하면 현재 장바구니 정보를 반환합니다.
3. 장바구니가 존재하지 않는 경우,
- `items`는 빈 배열
- `totalPrice`는 0
- `cartId`는 반환되지 않습니다.

### 유의 사항
- 장바구니가 없는 경우 새로 생성하지 않습니다.
- 조회 API는 장바구니 상태를 변경하지 않습니다.

### 예외 처리
- `USER_NOT_FOUND` (404 NOT_FOUND): 유저를 찾을 수 없습니다.
- `ACCESS_DENIED` (403 FORBIDDEN): 인증되지 않은 사용자의 접근
"""
)
ResponseEntity<CartResponse> getCart();

@Operation(
summary = "장바구니 삭제",
description = """
### 요청 파라미터
- `cartId` (Long, required): 삭제할 장바구니 ID

### 응답 데이터
- 없음 (HTTP 200 OK)

### 사용 방법
1. 삭제할 장바구니 ID를 Path Variable로 전달합니다.
2. 해당 장바구니가 DB에서 삭제됩니다.

### 유의 사항
- 장바구니 ID는 실제 존재하는 값이어야 합니다.
- 장바구니 삭제 시, 해당 장바구니에 속한 모든 아이템도 함께 삭제됩니다.
- 인증된 사용자만 요청할 수 있습니다.

### 예외 처리
- `INVALID_REQUEST` (400 BAD_REQUEST): 잘못된 요청 형식
"""
)
void deleteCart(@PathVariable Long cartId);

@Operation(
summary = "장바구니 특정 메뉴 삭제",
description = """
### 요청 파라미터
- `cartItemId` (Long, required): 삭제할 장바구니 아이템 ID

### 응답 데이터
- 없음 (HTTP 200 OK)

### 사용 방법
1. 삭제하려는 장바구니 아이템 ID를 Path Variable로 전달합니다.
2. 해당 장바구니 아이템이 DB에서 삭제됩니다.

### 유의 사항
- 장바구니 아이템 ID는 실제 존재하는 값이어야 합니다.
- 인증된 사용자만 요청할 수 있습니다.

### 예외 처리
- `INVALID_REQUEST` (400 BAD_REQUEST): 잘못된 요청 형식
"""
)
void deleteCartItem(@PathVariable Long cartItemId);
Comment on lines +92 to +137
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

API 문서의 예외 처리 정보 불완전

deleteCartdeleteCartItem 메서드의 문서에서 일부 예외 상황이 누락되었습니다. CartService 구현을 보면 다음 예외들이 발생할 수 있습니다:

  • deleteCart: CART_NOT_FOUND, ACCESS_DENIED
  • deleteCartItem: CART_ITEM_NOT_FOUND, ACCESS_DENIED
🔎 제안하는 수정 사항
       ### 예외 처리
+      - `CART_NOT_FOUND` (404 NOT_FOUND): 해당 장바구니를 찾을 수 없습니다.
+      - `ACCESS_DENIED` (403 FORBIDDEN): 본인의 장바구니만 삭제할 수 있습니다.
       - `INVALID_REQUEST` (400 BAD_REQUEST): 잘못된 요청 형식

그리고 deleteCartItem의 예외 처리 섹션:

       ### 예외 처리
+      - `CART_ITEM_NOT_FOUND` (404 NOT_FOUND): 해당 장바구니 아이템을 찾을 수 없습니다.
+      - `ACCESS_DENIED` (403 FORBIDDEN): 본인의 장바구니 아이템만 삭제할 수 있습니다.
       - `INVALID_REQUEST` (400 BAD_REQUEST): 잘못된 요청 형식
📝 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.

Suggested change
@Operation(
summary = "장바구니 삭제",
description = """
### 요청 파라미터
- `cartId` (Long, required): 삭제할 장바구니 ID
### 응답 데이터
- 없음 (HTTP 200 OK)
### 사용 방법
1. 삭제할 장바구니 ID를 Path Variable로 전달합니다.
2. 해당 장바구니가 DB에서 삭제됩니다.
### 유의 사항
- 장바구니 ID는 실제 존재하는 값이어야 합니다.
- 장바구니 삭제 , 해당 장바구니에 속한 모든 아이템도 함께 삭제됩니다.
- 인증된 사용자만 요청할 있습니다.
### 예외 처리
- `INVALID_REQUEST` (400 BAD_REQUEST): 잘못된 요청 형식
"""
)
void deleteCart(@PathVariable Long cartId);
@Operation(
summary = "장바구니 특정 메뉴 삭제",
description = """
### 요청 파라미터
- `cartItemId` (Long, required): 삭제할 장바구니 아이템 ID
### 응답 데이터
- 없음 (HTTP 200 OK)
### 사용 방법
1. 삭제하려는 장바구니 아이템 ID를 Path Variable로 전달합니다.
2. 해당 장바구니 아이템이 DB에서 삭제됩니다.
### 유의 사항
- 장바구니 아이템 ID는 실제 존재하는 값이어야 합니다.
- 인증된 사용자만 요청할 있습니다.
### 예외 처리
- `INVALID_REQUEST` (400 BAD_REQUEST): 잘못된 요청 형식
"""
)
void deleteCartItem(@PathVariable Long cartItemId);
@Operation(
summary = "장바구니 삭제",
description = """
### 요청 파라미터
- `cartId` (Long, required): 삭제할 장바구니 ID
### 응답 데이터
- 없음 (HTTP 200 OK)
### 사용 방법
1. 삭제할 장바구니 ID를 Path Variable로 전달합니다.
2. 해당 장바구니가 DB에서 삭제됩니다.
### 유의 사항
- 장바구니 ID는 실제 존재하는 값이어야 합니다.
- 장바구니 삭제 , 해당 장바구니에 속한 모든 아이템도 함께 삭제됩니다.
- 인증된 사용자만 요청할 있습니다.
### 예외 처리
- `CART_NOT_FOUND` (404 NOT_FOUND): 해당 장바구니를 찾을 없습니다.
- `ACCESS_DENIED` (403 FORBIDDEN): 본인의 장바구니만 삭제할 있습니다.
- `INVALID_REQUEST` (400 BAD_REQUEST): 잘못된 요청 형식
"""
)
void deleteCart(@PathVariable Long cartId);
@Operation(
summary = "장바구니 특정 메뉴 삭제",
description = """
### 요청 파라미터
- `cartItemId` (Long, required): 삭제할 장바구니 아이템 ID
### 응답 데이터
- 없음 (HTTP 200 OK)
### 사용 방법
1. 삭제하려는 장바구니 아이템 ID를 Path Variable로 전달합니다.
2. 해당 장바구니 아이템이 DB에서 삭제됩니다.
### 유의 사항
- 장바구니 아이템 ID는 실제 존재하는 값이어야 합니다.
- 인증된 사용자만 요청할 있습니다.
### 예외 처리
- `CART_ITEM_NOT_FOUND` (404 NOT_FOUND): 해당 장바구니 아이템을 찾을 없습니다.
- `ACCESS_DENIED` (403 FORBIDDEN): 본인의 장바구니 아이템만 삭제할 있습니다.
- `INVALID_REQUEST` (400 BAD_REQUEST): 잘못된 요청 형식
"""
)
void deleteCartItem(@PathVariable Long cartItemId);
🤖 Prompt for AI Agents
In
src/main/java/com/campustable/be/domain/cart/controller/CartControllerDocs.java
around lines 92-137, the OpenAPI descriptions for deleteCart and deleteCartItem
omit service-level exceptions; update the "예외 처리" sections to list the specific
exceptions and statuses thrown by CartService — for deleteCart add
`CART_NOT_FOUND` (404 NOT_FOUND) and `ACCESS_DENIED` (403 FORBIDDEN); for
deleteCartItem add `CART_ITEM_NOT_FOUND` (404 NOT_FOUND) and `ACCESS_DENIED`
(403 FORBIDDEN); keep existing `INVALID_REQUEST` and ensure wording matches the
project’s error-code convention so the API docs accurately reflect possible
error responses.

}
24 changes: 24 additions & 0 deletions src/main/java/com/campustable/be/domain/cart/dto/CartItemDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.campustable.be.domain.cart.dto;


import com.campustable.be.domain.cart.entity.CartItem;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class CartItemDto {
private String menuName;
private int quantity;
private int price;
private String menuUrl;
private Long cartItemId;

public CartItemDto(CartItem entity) {
this.menuName = entity.getMenu().getMenuName();
this.price = entity.getMenu().getPrice();
this.quantity = entity.getQuantity();
this.menuUrl = entity.getMenu().getMenuUrl();
this.cartItemId = entity.getCartItemId();
}
Comment on lines +17 to +23
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

생성자에 null 안전성 검사를 추가하세요.

생성자에서 entity.getMenu()의 null 체크가 없어 NPE(NullPointerException)가 발생할 수 있습니다. Menu가 null인 경우를 대비한 방어 로직이 필요합니다.

🔎 수정 제안
   public CartItemDto(CartItem entity) {
+    if (entity == null || entity.getMenu() == null) {
+      throw new IllegalArgumentException("CartItem과 Menu는 null일 수 없습니다.");
+    }
     this.menuName = entity.getMenu().getMenuName();
     this.price = entity.getMenu().getPrice();
     this.quantity = entity.getQuantity();
     this.menuUrl =  entity.getMenu().getMenuUrl();
     this.cartItemId = entity.getCartItemId();
   }
📝 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.

Suggested change
public CartItemDto(CartItem entity) {
this.menuName = entity.getMenu().getMenuName();
this.price = entity.getMenu().getPrice();
this.quantity = entity.getQuantity();
this.menuUrl = entity.getMenu().getMenuUrl();
this.cartItemId = entity.getCartItemId();
}
public CartItemDto(CartItem entity) {
if (entity == null || entity.getMenu() == null) {
throw new IllegalArgumentException("CartItem과 Menu는 null일 수 없습니다.");
}
this.menuName = entity.getMenu().getMenuName();
this.price = entity.getMenu().getPrice();
this.quantity = entity.getQuantity();
this.menuUrl = entity.getMenu().getMenuUrl();
this.cartItemId = entity.getCartItemId();
}
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/cart/dto/CartItemDto.java around
lines 17-23, the constructor assumes entity and entity.getMenu() are non-null
which can cause NPEs; add null-safety by first validating entity (throw
IllegalArgumentException or handle null) and then check Menu menu =
entity.getMenu(); if menu is null set menuName, price, menuUrl to safe defaults
(null or 0 as appropriate) instead of calling getters, otherwise read values
from menu; preserve quantity and cartItemId from entity after validating entity
is non-null.

}
11 changes: 11 additions & 0 deletions src/main/java/com/campustable/be/domain/cart/dto/CartRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.campustable.be.domain.cart.dto;


import lombok.Getter;

@Getter
public class CartRequest {

private Long menu_id;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

필드명 네이밍 컨벤션을 수정하세요.

Java 네이밍 컨벤션에 따라 menu_idmenuId로 변경해야 합니다. snake_case 대신 camelCase를 사용하는 것이 Java 표준입니다.

🔎 수정 제안
-  private Long menu_id;
+  private Long menuId;
📝 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.

Suggested change
private Long menu_id;
private Long menuId;
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/cart/dto/CartRequest.java around line
9, the field name uses snake_case (`menu_id`); rename it to camelCase (`menuId`)
to follow Java conventions, update the corresponding getter/setter names and any
constructors, JSON/property annotations (e.g., @JsonProperty) if present, and
refactor all usages across the codebase to the new name to avoid compile errors.

private int quantity;
}
15 changes: 15 additions & 0 deletions src/main/java/com/campustable/be/domain/cart/dto/CartResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.campustable.be.domain.cart.dto;

import java.util.List;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Builder
public class CartResponse {
private List<CartItemDto> items;
private int totalPrice;
private Long cartId;
}
41 changes: 41 additions & 0 deletions src/main/java/com/campustable/be/domain/cart/entity/Cart.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.campustable.be.domain.cart.entity;

import com.campustable.be.domain.user.entity.User;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import java.util.ArrayList;
import java.util.List;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Entity
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Cart {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cart_id")
private Long cart_id;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

필드명 네이밍 컨벤션을 수정하세요.

Java 네이밍 컨벤션에 따라 cart_idcartId로 변경해야 합니다. @Column(name = "cart_id")를 사용하여 데이터베이스 컬럼명은 유지하면서 필드명만 변경할 수 있습니다.

🔎 수정 제안
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "cart_id")
-  private Long cart_id;
+  private Long cartId;
📝 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.

Suggested change
private Long cart_id;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "cart_id")
private Long cartId;
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/cart/entity/Cart.java around line 28,
rename the field cart_id to cartId to follow Java camelCase conventions,
annotate it with @Column(name = "cart_id") to preserve the DB column mapping,
update all getters/setters/constructors/equals/hashCode/toString and any usages
in this class or other classes to reference cartId, and recompile/run tests to
ensure no remaining references to the old name remain.


@OneToOne
private User user;
Comment on lines +30 to +31
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

@OnetoOne 관계에 @joincolumn을 추가하세요.

Cart가 User와의 관계에서 소유 측(owning side)이므로 @JoinColumn 어노테이션을 추가하여 외래 키 컬럼을 명시적으로 지정해야 합니다. 이를 생략하면 JPA가 예상치 못한 테이블 구조를 생성할 수 있습니다.

🔎 수정 제안
-  @OneToOne
+  @OneToOne
+  @JoinColumn(name = "user_id")
   private User user;
📝 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.

Suggested change
@OneToOne
private User user;
@OneToOne
@JoinColumn(name = "user_id")
private User user;
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/cart/entity/Cart.java around lines
30-31, the @OneToOne mapping to User is missing a @JoinColumn; add a @JoinColumn
on the Cart.user field (e.g., @JoinColumn(name = "user_id", referencedColumnName
= "id", nullable = false, unique = true)) to make Cart the owning side and
explicitly define the foreign key column so JPA generates the correct table
structure.


@OneToMany(mappedBy = "cart", cascade = CascadeType.ALL, orphanRemoval = true)
private List<CartItem> cartItems = new ArrayList<>();

public Cart(User user) {
this.user = user;
}


}
41 changes: 41 additions & 0 deletions src/main/java/com/campustable/be/domain/cart/entity/CartItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.campustable.be.domain.cart.entity;

import com.campustable.be.domain.menu.entity.Menu;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Entity
@Getter
@Setter
@NoArgsConstructor
public class CartItem {

public CartItem(Cart cart, Menu menu){
this.cart = cart;
this.menu = menu;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name= "cart_item_id")
private Long cartItemId;

@ManyToOne(fetch = FetchType.LAZY)
private Menu menu;

@ManyToOne(fetch = FetchType.LAZY)
private Cart cart;

private int quantity;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

수량 필드 유효성 검증 누락

quantity가 음수가 될 수 있으나 검증이 없습니다. API 문서(CartControllerDocs)에서 음수를 허용하지 않는다고 명시했으므로, 엔티티 레벨 또는 서비스 레벨에서 검증을 추가해야 합니다.

🔎 제안하는 수정 사항

방법 1: JPA 제약 조건 추가 (권장)

+import jakarta.validation.constraints.Min;
+
 @Entity
 @Getter
 @NoArgsConstructor
 public class CartItem {
   // ...
   
+  @Min(value = 0, message = "수량은 0 이상이어야 합니다")
   private int quantity;

방법 2: CartService에서 검증 추가

updateCartItem 메서드에서 quantity 파라미터 검증:

if (quantity < 0) {
  throw new CustomException(ErrorCode.INVALID_REQUEST);
}
📝 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.

Suggested change
private int quantity;
import jakarta.validation.constraints.Min;
@Entity
@Getter
@NoArgsConstructor
public class CartItem {
// ... other fields
@Min(value = 0, message = "수량은 0 이상이어야 합니다")
private int quantity;
🤖 Prompt for AI Agents
In src/main/java/com/campustable/be/domain/cart/entity/CartItem.java at line 36,
the quantity field lacks validation allowing negative values; add validation to
enforce non-negative quantities — preferably at the entity level by applying a
JPA/Bean Validation constraint (e.g., @Min(0) and make the column non-nullable)
so persistence will reject negatives, and also add a service-level guard in
CartService.updateCartItem to check quantity < 0 and throw the existing
CustomException(ErrorCode.INVALID_REQUEST) as a secondary protection.





}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.campustable.be.domain.cart.repository;

import com.campustable.be.domain.cart.entity.Cart;
import com.campustable.be.domain.cart.entity.CartItem;
import com.campustable.be.domain.menu.entity.Menu;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CartItemRepository extends JpaRepository<CartItem, Long> {

Optional<CartItem> findByCartAndMenu(Cart cart, Menu menu);


List<CartItem> findByCart(Cart cart);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.campustable.be.domain.cart.repository;

import com.campustable.be.domain.cart.entity.Cart;
import com.campustable.be.domain.user.entity.User;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CartRepository extends JpaRepository<Cart, Long> {

Optional<Cart> findByUser(User user);

Optional<Cart> findByUserId(Long userId);
}
Loading