Skip to content
Merged
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
Expand Up @@ -33,15 +33,15 @@ public class ReservationController {
private final ReservationService reservationService;

@GetMapping("/admin/{storeId}/waiting/users")
@Operation(summary = "주점별 전체 대기 리스트 조회", description = "주점에 대한 대기 리스트 조회(WAITING,CALLING)")
@Operation(summary = "주점별 전체 대기/호출중 리스트 조회", description = "주점에 대한 대기 리스트 조회(WAITING,CALLING)")
@ApiResponse(responseCode = "200", description = "주점별 전체 대기 리스트 조회")
public ResponseEntity<List<WaitingUserResponse>> getWaitingUsersWithScore(@PathVariable Long storeId) {
List<WaitingUserResponse> response = reservationService.getAllWaitingUserDetails(storeId);
return ResponseEntity.ok(response);
}

@GetMapping("/admin/{storeId}/completed")
@Operation(summary = "주점별 전체 완료 리스트 조회", description = "주점에 대한 완료/취소 리스트 조회(CANCELED,CONFIRMED)")
@Operation(summary = "주점별 전체 취소/완료 리스트 조회", description = "주점에 대한 완료/취소 리스트 조회(CANCELED,CONFIRMED)")
@ApiResponse(responseCode = "200", description = "주점별 전체 완료/취소 리스트 조회")
public ResponseEntity<?> getCompletedReservationList(
@PathVariable Long storeId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
@Schema(description = "대기 사용자 응답 DTO")
public class WaitingUserResponse {

@Schema(description = "유저 ID", example = "1201")
private String id; // userId
@Schema(description = "예약 ID", example = "1201")
private String id; // reservationId

@Schema(description = "유저 ID", example = "16")
private String userId;

@Schema(description = "파티 인원", example = "3")
private Integer partySize;
Expand All @@ -37,6 +40,7 @@ public class WaitingUserResponse {
public static WaitingUserResponse fromEntity(Reservation reservation) {
return WaitingUserResponse.builder()
.id(reservation.getId().toString())
.userId(reservation.getUser().getId().toString())
.partySize(reservation.getPartySize())
.userName(reservation.getUser().getNickname())
.createdAt(reservation.getRequestedAt())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.nowait.applicationuser.store.dto.StoreWaitingInfo;
import com.nowait.applicationuser.store.service.StoreService;
import com.nowait.common.api.ApiUtils;

Expand Down Expand Up @@ -97,4 +98,20 @@ public ResponseEntity<?> searchStores(@RequestParam("name") String name) {
)
);
}

@GetMapping("/waiting-list")
@Operation(summary = "예약 많은순/적은순 주점 리스트 조회", description = "desc(대기 많은순) , asc(대기 적은순)")
@ApiResponse(responseCode = "200", description = "주점 대기순 정렬")
public ResponseEntity<?> getStoreWaitingList(
@RequestParam(defaultValue = "desc") String order) {
boolean desc = !"asc".equalsIgnoreCase(order); // 기본: 대기 많은 순

return ResponseEntity
.ok()
.body(
ApiUtils.success(
storeService.getStoresByWaitingCount(desc)
)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.nowait.applicationuser.store.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
@Schema(description = "주점 대기 현황 정보 DTO")
public class StoreWaitingInfo {
@Schema(description = "주점 ID", example = "1")
private String storeId;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

storeId 타입 일관성을 확인하세요.

다른 부분에서 storeId가 Long 타입으로 사용되는데, 여기서는 String으로 정의되어 있습니다. 타입 일관성을 위해 Long 타입 사용을 고려해보세요.

다음 스크립트로 storeId 타입 사용 패턴을 확인해보겠습니다:


🏁 Script executed:

#!/bin/bash
# storeId 필드의 타입 사용 패턴 확인
rg -A 2 -B 2 "storeId.*Long|Long.*storeId" --type java
rg -A 2 -B 2 "storeId.*String|String.*storeId" --type java

Length of output: 143956


🏁 Script executed:

#!/bin/bash
cat nowait-app-user-api/src/main/java/com/nowait/applicationuser/store/dto/StoreWaitingInfo.java

Length of output: 586


StoreWaitingInfo DTO의 storeId를 Long 타입으로 변경하세요.

일관된 타입 사용을 위해 아래를 수정해주세요:

• nowait-app-user-api/src/main/java/com/nowait/applicationuser/store/dto/StoreWaitingInfo.java

- @Schema(description = "주점 ID", example = "1")
- private String storeId;
+ @Schema(description = "주점 ID", example = "1")
+ private Long storeId;

• 서비스 구현부(nowait-app-user-api/src/main/java/com/nowait/applicationuser/store/service/StoreServiceImpl.java)
• key에서 추출한 storeId를 String이 아닌 Long으로 파싱
new StoreWaitingInfo(storeId, …) 호출부의 첫 번째 인자도 Long으로 변경

이렇게 하면 전체 코드베이스에서 storeId가 Long으로 통일되어 의도치 않은 형 변환 오류를 방지할 수 있습니다.

📝 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 String storeId;
@Schema(description = "주점 ID", example = "1")
private Long storeId;
🤖 Prompt for AI Agents
In
nowait-app-user-api/src/main/java/com/nowait/applicationuser/store/dto/StoreWaitingInfo.java
at line 12, change the type of the storeId field from String to Long. Then, in
nowait-app-user-api/src/main/java/com/nowait/applicationuser/store/service/StoreServiceImpl.java,
update the code to parse the storeId key as a Long instead of a String and
modify all calls to the StoreWaitingInfo constructor to pass a Long storeId.
This ensures consistent use of Long for storeId across the codebase and prevents
type conversion errors.


@Schema(description = "주점명", example = "노웨이팅 치킨")
private String storeName;

@Schema(description = "대기 인원 수", example = "12")
private Long waitingCount;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.nowait.applicationuser.store.dto.StorePageReadDto;
import com.nowait.applicationuser.store.dto.StoreReadDto;
import com.nowait.applicationuser.store.dto.StoreReadResponse;
import com.nowait.applicationuser.store.dto.StoreWaitingInfo;

public interface StoreService {

Expand All @@ -21,4 +22,6 @@ public interface StoreService {

List<StorePageReadDto> searchStoresByName(String name);

List<StoreWaitingInfo> getStoresByWaitingCount(boolean desc);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -14,6 +16,7 @@
import com.nowait.applicationuser.store.dto.StorePageReadDto;
import com.nowait.applicationuser.store.dto.StoreReadDto;
import com.nowait.applicationuser.store.dto.StoreReadResponse;
import com.nowait.applicationuser.store.dto.StoreWaitingInfo;
import com.nowait.domaincorerdb.department.entity.Department;
import com.nowait.domaincorerdb.department.repository.DepartmentRepository;
import com.nowait.domaincorerdb.store.entity.Store;
Expand All @@ -32,6 +35,7 @@ public class StoreServiceImpl implements StoreService {
private final StoreRepository storeRepository;
private final StoreImageRepository storeImageRepository;
private final DepartmentRepository departmentRepository;
private final StringRedisTemplate redisTemplate;


@Override
Expand Down Expand Up @@ -188,4 +192,30 @@ public List<StorePageReadDto> searchStoresByName(String name) {
})
.toList();
}

// 주점 대기 리스트 반환 (많은 순/적은 순)
@Transactional(readOnly = true)
public List<StoreWaitingInfo> getStoresByWaitingCount(boolean desc) {
// 1. 모든 waiting:{storeId} key 조회 (패턴 탐색)
Set<String> keys = redisTemplate.keys("waiting:*");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Redis KEYS 명령어 사용에 대한 성능 우려사항이 있습니다.

Redis KEYS 명령어는 모든 키를 스캔하므로 운영 환경에서 성능 문제를 일으킬 수 있습니다.

SCAN 명령어를 사용하거나, 별도의 인덱스 구조를 고려해보세요:

-Set<String> keys = redisTemplate.keys("waiting:*");
+// SCAN을 사용한 개선 방안
+Set<String> keys = new HashSet<>();
+ScanOptions options = ScanOptions.scanOptions().match("waiting:*").build();
+try (Cursor<String> cursor = redisTemplate.scan(options)) {
+    cursor.forEachRemaining(keys::add);
+}
📝 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
Set<String> keys = redisTemplate.keys("waiting:*");
// SCAN을 사용한 개선 방안
Set<String> keys = new HashSet<>();
ScanOptions options = ScanOptions.scanOptions().match("waiting:*").build();
try (Cursor<String> cursor = redisTemplate.scan(options)) {
cursor.forEachRemaining(keys::add);
}
🤖 Prompt for AI Agents
In
nowait-app-user-api/src/main/java/com/nowait/applicationuser/store/service/StoreServiceImpl.java
at line 200, replace the use of redisTemplate.keys("waiting:*") with a Redis
SCAN command implementation to avoid performance issues caused by the KEYS
command scanning all keys. Implement a cursor-based iteration using SCAN to
retrieve matching keys incrementally, or consider maintaining a separate index
structure for these keys to improve efficiency in production environments.

if (keys == null) return List.of();

List<StoreWaitingInfo> result = keys.stream()
.filter(key -> key.startsWith("waiting:") && !key.startsWith("waiting:party:"))
.filter(key -> "zset".equals(redisTemplate.type(key).code()))
.map(key -> {
Long count = redisTemplate.opsForZSet().zCard(key);
String storeId = key.replace("waiting:", "");
String storeName = storeRepository.findById(Long.valueOf(storeId))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Long 파싱에서 예외 처리가 누락되었습니다.

storeId를 Long으로 파싱할 때 NumberFormatException이 발생할 수 있습니다.

예외 처리를 추가하세요:

-String storeName = storeRepository.findById(Long.valueOf(storeId))
+String storeName;
+try {
+    storeName = storeRepository.findById(Long.valueOf(storeId))
+        .map(Store::getName)
+        .orElse("UNKNOWN");
+} catch (NumberFormatException e) {
+    storeName = "INVALID_STORE_ID";
+}
📝 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
String storeName = storeRepository.findById(Long.valueOf(storeId))
String storeName;
try {
storeName = storeRepository.findById(Long.valueOf(storeId))
.map(Store::getName)
.orElse("UNKNOWN");
} catch (NumberFormatException e) {
storeName = "INVALID_STORE_ID";
}
🤖 Prompt for AI Agents
In
nowait-app-user-api/src/main/java/com/nowait/applicationuser/store/service/StoreServiceImpl.java
at line 209, the code parses storeId to Long without handling potential
NumberFormatException. Add a try-catch block around the Long.valueOf(storeId)
parsing to catch NumberFormatException and handle it appropriately, such as
logging the error and returning a meaningful response or throwing a custom
exception.

.map(Store::getName)
.orElse("UNKNOWN");
return new StoreWaitingInfo(storeId, storeName, count != null ? count : 0);
})
.sorted((a, b) -> desc ?
b.getWaitingCount().compareTo(a.getWaitingCount()) :
a.getWaitingCount().compareTo(b.getWaitingCount()))
.toList();

return result;
}
}