Repository navigation
[Feat/#185] 아카이빙 목록·상세 조회 관리자 API 추가 - #188
Open
sangrae2325 wants to merge 5 commits into
Open
sangrae2325 wants to merge 5 commits into
sangrae2325 wants to merge 5 commits into
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
github-actions
Bot
requested review from
jjunh33,
leegain1,
tnals0924 and
xeoxxn
October 29, 2026 05:17
sangrae2325
force-pushed
the
feat/#185-admin-archive-queries
branch
from
October 29, 2026 08:24
975a488 to
424643b
Compare
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.
#️⃣연관된 이슈
main기준 단독 PR입니다. 사물함 스택([Feat/#119] 사물함 운영 회차 관리자 API 추가 #129~[Feat/#178] 사물함 구역 배치·사진 수정 관리자 API 추가 #184)과 기능이 겹치지 않아 쌓지 않았습니다🎯 해결하려는 문제가 무엇인가요?
운영진 콘솔에서 아카이빙을 찾고 열어볼 수 있게 조회 API 2개를 추가하고, 그에 필요한 슬랑제 노출 여부·소프트 삭제 컬럼을 넣습니다.
슬랑제는 소프트웨어융합대학 연말 행사입니다. 전용 페이지를 따로 만들어 아카이빙에 등록된 것 중 고른 것만 노출하는데, 이번 작업은 노출 여부를 저장하고 운영진이 목록에서 보고 걸러내는 것까지입니다.
❓ 왜 해결해야 하나요?
archives테이블과archive도메인은 #40에서 학생 앱 조회용으로만 만들어졌습니다.ArchiveService에 쓰기가 하나도 없고AdminArchiveService도 없으며, 관리자 화면이 쓰는 값이 테이블에 빠져 있습니다.is_deleted가 없다⭐ 어떻게 해결했나요?
커밋 5개로 나눴고 각각 단독으로 컴파일됩니다.
1. 스키마(V27) —
is_exposed·is_deleted를 넣습니다. 운영 중인 행이 있어 둘 다DEFAULT를 줍니다.인덱스는 두지 않습니다. 아카이빙이 연간 수십 건 규모라 목록이 테이블을 통째로 읽어도 되고, 제목 검색이
LIKE '%...%'라 어차피 인덱스를 타지 못합니다.컬럼 이름에 "슬랑제"를 넣지 않았습니다. 아카이빙이 노출될 곳은 슬랑제 페이지뿐이라
is_exposed로 충분하고, 어디에 노출되는지는 마이그레이션 주석과 도메인 javadoc이 설명합니다.소프트 삭제는
BaseSoftDeleteEntity가 들고 도메인에는 넣지 않습니다 —Notice·Event도메인도 삭제 플래그를 들고 있지 않습니다. 반면 노출 여부는 운영진이 목록에서 보고 켜고 끄는 값이라 도메인에 둡니다.2. 기존 앱 조회에 삭제 필터 — 목록·연도 목록·상세 세 군데입니다. 연도 목록(
findAllYearsDesc)은 목록과 별개 쿼리라 놓치면 지운 아카이빙의 연도가 필터 버튼에 남습니다.3~4. 저장소·서비스 — 제목 부분 일치 + 노출 여부 + 등록일 최신순 페이징.
AdminArchiveService를 새로 만들어 학생용ArchiveService와 나눕니다.나누는 기준은 "조회가 실제로 다른가"입니다. 목록은 정렬 기준이 달라(등록일 vs 활동 시작일) 쿼리가 다르지만, 상세는 한 글자도 안 달라서 운영진도
ArchiveService를 그대로 씁니다.coding-style.md2-7절의 공지와 같은 모양입니다.5. API 계층 — 컨트롤러가 목록은
AdminArchiveService, 상세는ArchiveService를 부릅니다.쿼리 파라미터를 record로 감쌌습니다
Boolean을@RequestParam으로 직접 받으면?isExposed=abc에 500이 납니다.MethodArgumentTypeMismatchException은TypeMismatchException자식이라GlobalExceptionHandler의IllegalArgumentException핸들러에 걸리지 않고 catch-all로 빠집니다.@Valid @ModelAttribute로 받으면 바인딩 실패가MethodArgumentNotValidException으로 나와 400INVALID_INPUT이 됩니다(ModelAttributeMethodProcessor가 그 예외를 던지는 것을 확인했습니다).LockerPeriodParams·ArchiveListParams가 같은 이유로 record를 쓰고 있습니다.🧩 이 PR의 한계 & 트레이드오프
is_deleted를 1로 만들 방법이 없어, 필터가 동작하는지 보려면 DB를 직접 고쳐야 합니다LIKE '%...%'는 인덱스를 타지 못합니다. 아카이빙이 연간 수십 건 규모라 그대로 뒀고, 커지면 전문 검색을 따로 봅니다created_at최신순이라(is_deleted, created_at)을 넣을까 했는데, 아카이빙이 연간 수십 건 규모라 테이블을 통째로 읽어도 되고 제목 검색이LIKE '%...%'라 어차피 인덱스를 못 탑니다. 행이 늘면 다시 봅니다@ModelAttribute가 둘입니다(ArchiveSearchParams·PageParams). 저장소에 선례가 없는 모양인데, 필터를 한 덩어리로 묶는 쪽이 읽기 좋다고 봤습니다GET /{archiveId}에 숫자가 아닌 값을 넣으면 500입니다.@PathVariable Long도 같은MethodArgumentTypeMismatchException을 내는데 핸들러가 없습니다. 저장소 전체 공통 문제라(/v1/admin/notices/{noticeId}등)common-api의GlobalExceptionHandler를 건드려야 해서 이 PR 범위에서 뺐습니다. 후속 이슈로 보면 좋겠습니다AGENTS.md원칙에 따랐습니다⛓️ 기존 기능에 미치는 영향
is_deleted = 0만 붙고, 지금은 삭제된 행이 없어 결과가 같습니다Archive에createdAt이 올라옵니다.created_at은 V2부터 있던 컬럼인데 도메인에 없었습니다. 운영진 목록이 이 값으로 정렬하고 화면에도 보여줍니다(Notice도메인도createdAt을 들고 있습니다)ArchiveDetail에exposed·createdAt이 늘어납니다. 운영진만 쓰고 학생 앱 응답은 담지 않습니다admin-api에core:domain:event의존이 생깁니다. 운영진 콘솔의 첫 event 기능입니다. 사물함 스택([Feat/#119] 사물함 운영 회차 관리자 API 추가 #129)도 같은 줄을 추가하므로 나중에 머지하는 쪽에서 한 줄 충돌이 납니다ArchiveErrorCode·기존 에러 코드는 그대로입니다🔀 Edge Case & 실패 시나리오
keyword에%나_LikePatterns.escape+ 쿼리의ESCAPE '!'keyword가 공백뿐escape가 null로 바꾼다)isExposed=abcINVALID_INPUT(400)isExposed생략page가 음수 /size가 101INVALID_INPUT(400) —PageParams의@Min/@MaxARCHIVE_NOT_FOUND(404)ARCHIVE_NOT_FOUND(404) — 없는 것과 같게 본다images가 빈 배열📋 검토한 대안과 선택 이유
AdminArchiveService에 두기: 처음엔 그렇게 썼다가 접었습니다. 내용이 학생 앱과 한 글자도 다르지 않아 복사본이 생깁니다.coding-style.md2-7절이 공지를 예로 "상세 조회는 운영진도 공용"이라고 적고 있어 그대로 맞췄습니다AdminArchiveSummary)을 두기: 만들었다가 지웠습니다.Archive의 필드를 그대로 베끼기만 하고 계산이 없어서,AdminNoticeController가PageResult<Notice>를 받아 매핑하는 것과 같이 도메인 객체를 그대로 넘깁니다images[0]과 중복되고, 학생 앱 상세(ArchiveDetailResponse)와 모양도 달라집니다thumbnail_file_id컬럼을 만들기: 대표를 사진과 별개 파일로 두는 방식인데, 지금처럼 "첫 장이 대표"면 컬럼이 필요 없고 관리자 화면의 대표 선택은 사진 순서로 처리됩니다departmentName을CouncilDepartmentenum으로 묶기: 화면 예시("대외협력국·학생복지국·문화기획국")가 enum의 8개 부서명(회장단·집행부·총무부·기획부·홍보부·미디어부·복지부·소통부)과 맞지 않아 자유 문자열로 뒀습니다💬 리뷰 포인트
[c]V27 번호와 머지 순서를 봐주세요.main이 V19까지인데 사물함 스택이 V20·V21·V26, 행사 스택이 V20V22, #140이 V22, #167이 V23V25를 들고 있습니다.outOfOrder가 꺼져 있어서 이 PR이 그 스택들보다 먼저 머지되면 뒤에 올라오는 낮은 번호를 Flyway가 거부합니다. 뒤로 미루거나 번호를 다시 잡아야 합니다[c]학생 앱 조회 세 곳에 붙인is_deleted = 0이 빠진 데가 없는지 봐주세요. 연도 목록이 별개 쿼리라 놓치기 쉬운 자리였습니다[a]쿼리 파라미터를ArchiveSearchParams로 감싼 것 —@RequestParam두 개로 두면isExposed=abc에 500이 납니다.keyword까지 같이 묶었는데, 공지처럼keyword만@RequestParam으로 두는 쪽이 나으면 바꾸겠습니다