Repository navigation
[Feat/#146] 사물함 상태 일괄 변경 관리자 API 추가 - #148
Open
sangrae2325 wants to merge 4 commits into
Open
sangrae2325 wants to merge 4 commits into
sangrae2325 wants to merge 4 commits into
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
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 |
github-actions
Bot
requested review from
jjunh33,
leegain1,
tnals0924 and
xeoxxn
October 19, 2026 04:16
sangrae2325
added this pull request to stack #131
October 19, 2026 04:19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#️⃣연관된 이슈
🎯 해결하려는 문제가 무엇인가요?
운영진 콘솔에서 구역 안의 사물함 여러 개를 골라 물리 상태를 한 번에 바꾸는 관리자 API 1개를 추가합니다.
#132(구역 조회)에 이어지는 사물함 관리자 API의 세 번째 작업입니다.
❓ 왜 해결해야 하나요?
사물함이 고장 나도 상태를 바꿀 방법이 DB 직접 수정뿐입니다.
LockerRepository에 사물함 쓰기 경로가 아예 없습니다 — 회차는 #119에서 뚫었지만 사물함은 조회만 있습니다.상태를
DISABLED로 내리면Locker.isSelectable이 false가 되어 학생 화면의 선택 가능 수와 칸 표시에서 빠집니다. 그게 이 기능의 목적입니다.⭐ 어떻게 해결했나요?
커밋 4개로 나눴고 각각 단독으로 컴파일됩니다.
1. 도메인 —
Locker에changeStatus를 더합니다. 바뀐 값이 있으면true를 돌려줍니다. 36칸 구역에서 두 칸만 바꿔도 전체를 저장하지 않으려고 서비스가 이 값으로 거릅니다.2. 저장소 —
saveLockers(여러 건 저장)와findByLockerIds를 추가합니다. 빈 목록이 들어오면 쿼리를 타지 않습니다. 회차 조회는 기존findPublishedPeriodsByIds를 그대로 씁니다.3. 서비스 —
AdminLockerService.changeLockerStatus입니다.검증을 전부 먼저 하고 바꿉니다. "하나라도 안 되면 전체를 안 바꾼다"를
@Transactional에만 기대지 않았습니다 — 예외로 롤백하는 것보다 사전 검증이 의도가 분명하고 실패 사유도 정확해집니다.이용 중 검사는
DISABLED일 때만 합니다.AVAILABLE로 되돌리는 건 막을 이유가 없고 쿼리 2개를 아낍니다.4. API — 기존
AdminLockerSectionController에@PatchMapping("/{sectionId}/lockers/status")를 더합니다. 관리자 "구역 관리" 탭 한 화면이 쓰는 API가 전부/sections/{sectionId}아래라 컨트롤러를 탭 단위로 맞췄습니다. 조회 컨트롤러에 쓰기가 섞이는 건AdminNoticeController·AdminLockerPeriodController선례가 있습니다.조회는
LockerService, 변경은AdminLockerService로 서비스 2개를 주입받습니다. "운영진 전용 동작은 Admin 서비스에 둔다"는 팀 규칙 그대로입니다.🧩 이 PR의 한계 & 트레이드오프
@DynamicUpdate가 아니라LockerJpaEntity.from(domain)+ merge로 전체 행을 저장해서 다른 컬럼까지 덮어씁니다. 다만 사물함은 상태 말고 바뀌는 값이 없고 운영진 전용이라 감수했습니다lockerIds에 중복이 와도 막지 않습니다. 저장은changeStatus가 두 번째에false를 돌려줘서 한 번만 되고, 응답에만 같은 항목이 두 번 담깁니다. 칸 그리드에서 선택 집합을 보내는 화면에선 일어나지 않아 요청 DTO에distinct를 두지 않았습니다LOCKER_NOT_IN_SECTION(400)입니다. 구역 조회 결과에 없다는 사실만으로는 둘을 가를 수 없어서, 가르려면 조회를 한 번 더 해야 합니다DISABLED변경은 쿼리가 2개 더 듭니다(신청 조회 → 회차 조회). 한 번에 바꾸는 칸이 수십 개 수준이라 묶음 조회 2개로 끝냈습니다AGENTS.md원칙에 따랐습니다⛓️ 기존 기능에 미치는 영향
LockerService를 하나도 고치지 않았습니다lockers.status컬럼이 이미 있습니다DISABLED로 내리면 학생 화면의 선택 가능 수와 칸 표시에서 빠집니다 — 의도한 동작입니다LockerErrorCode에 2개(LOCKER_NOT_IN_SECTION,LOCKER_IN_USE)가 늘지만 새 경로에서만 던집니다🔀 Edge Case & 실패 시나리오
lockerIds가 빈 배열INVALID_INPUT(400) + "사물함을 하나 이상 선택해 주세요."lockerStatus가 enum에 없는 값INVALID_INPUT(400) — Jackson이 못 읽어HttpMessageNotReadableExceptionLOCKER_NOT_IN_SECTION(400), 아무것도 안 바뀜DISABLED로LOCKER_IN_USE(409), 아무것도 안 바뀜DISABLED로AVAILABLE로is_deleted = false로 걸러LOCKER_NOT_IN_SECTION📋 검토한 대안과 선택 이유
architecture.md:74도infrastructure:*가 비즈니스 규칙을 갖지 않는다고 합니다. 저장소는 신청·회차를 읽어 오기만 합니다. (EventRepositoryImpl에 SQLCASE로 상태를 계산하는 선례가 있지만, 그건 그 값으로 목록을 거르느라 쿼리에서 해야 하는 경우라 여기엔 안 맞습니다)!period.isUsageEnded(today)로: 같은 판정에 이름이 두 개 생겨서, 내 신청 내역 화면이 쓰는LockerApplicationStatus.from(period, today)를 그대로 재사용했습니다. "배정 중"의 기준이 나중에 바뀌어도 한 곳만 고치면 됩니다findPeriodsByIds를 만들었다가 지웠습니다. 게시를 내리는 기능이 없고(AdminLockerService에 공개 토글이 없습니다), 신청은 게시된 회차에만 들어와서 기존findPublishedPeriodsByIds와 결과가 같습니다. 비슷한 이름의 포트를 늘리지 않았습니다LOCKER_NOT_IN_SECTION을 404로: "없는 사물함"으로 보면 404지만, 구역과 사물함의 조합이 틀린 요청이라 400으로 뒀습니다LOCKER_NOT_FOUND를 따로 두기: 1단계에서 만들었다가 지웠습니다. 위 이유로 던질 곳이 없어 죽은 코드가 됩니다. 사물함 등록·삭제가 붙을 때 필요하면 그때 넣습니다AdminLockerStatusController): 화면 단위로 묶는 쪽이/periods·/applications와 나란히 가서 기존 컨트롤러에 넣었습니다lockerStatus를String으로 받고from()으로 변환(AdminFeeController방식): enum을 그대로 받는NoticeCreateRequest쪽을 따랐습니다. 잘못된 값은 어차피 400INVALID_INPUT입니다ApiResponse<Void>로: 화면이 누른 칸을 다시 그려야 해서 바뀐 뒤 상태를 돌려줍니다PUT: 전체 교체가 아니라 상태 한 필드만 바꿔서PATCH입니다💬 리뷰 포인트
[r]이미 끝난 회차에만 배정된 칸은DISABLED로 바꿀 수 있게 했습니다. 이용 중 판정을LockerApplicationStatus.from(period, today) == ASSIGNED로 두어 내 신청 내역 화면과 기준을 한 곳으로 묶었습니다. 사용 종료일 당일까지는 사용 중입니다(isUsageEnded가today.isAfter(usageEndAt)). 운영 기준이 이게 맞는지 봐주세요[r]응답에 이미 그 상태였던 칸도 담습니다. 저장은 안 하고 반환만 합니다. 화면이 "실제로 바뀐 것"만 필요하다면 거르는 쪽으로 바꾸겠습니다[c]없는 사물함과 다른 구역 사물함을LOCKER_NOT_IN_SECTION하나로 묶었습니다. 운영진이 원인을 알기 어려우면 나눠야 할지[c]응답 레코드 이름이AdminLockerStatusChangeResponse입니다. 이 패키지 응답 4개가 전부Admin접두사를 써서 맞췄는데, 요청은 접두사 없는LockerStatusChangeRequest라 짝이 안 맞습니다[a]응답에lockerNumber를 넣었습니다(명세대로). 요청이lockerId로 들어오고 화면도 번호를 이미 알아서 빼도 됩니다