Repository navigation
feat: 휴지통 목록 API (#54) - #55
Conversation
chjpooh2002
left a comment
There was a problem hiding this comment.
수고하셨습니다~ 리뷰 내용 한 번 확인 부탁드려요!
| private List<Template> findPageWithOneMore(TrashListQuery query) { | ||
| Limit limit = Limit.of(query.size() + 1); | ||
| if (query.cursor() == null || query.cursor().isEmpty()) { | ||
| return templateRepository.findTrashFirstPage(query.userId(), limit); |
There was a problem hiding this comment.
휴지통 목록은 본문을 내보내지 않는데 엔티티를 통째로 읽어서, 최대 51개 행의 본문을 매번 복호화하고 있습니다. 비용도 있지만, 복호화가 실패하는 행이 하나라도 생기면 본문을 보여주지도 않는 휴지통 목록 전체가 500이 될 거 같아요! 필요한 컬럼만 고르는 조회(repository/dto의 행 객체)로 바꾸는 걸 고려하면 어떨까 싶습니다!
There was a problem hiding this comment.
아 맞네여 휴지통 목록은 본문을 안보여주니까, 말씀 주신 부분 맞습니다 감사합니당 😄
제안 해 주신 repository/dto로 가면 좋을것 같은 생각이여서 해당 부분 반영 하겠습니다 !
| * 같은 초 안에서도 순서가 갈리므로 시각은 DATETIME(6)과 같은 마이크로초까지 넣는다. | ||
| * 해석할 때 자릿수를 고정해 DB가 받지 못하는 연도(+12026)가 쿼리까지 가지 않게 한다. | ||
| */ | ||
| public record TrashCursor(LocalDateTime deletedAt, Long id) { |
There was a problem hiding this comment.
support는 "다른 도메인이 써도 되는 순수 규칙" 자리인데, 커서는 이 API의 페이지 처리 방식이라 다른 도메인이 쓸 일이 없어 보입니다. service 쪽으로 옮기는 게 컨벤션 의도에 맞을 것 같아요!
TrashRetention은 정리 배치와 같이 쓰니 support에 두는 게 맞다고 봅니다!
| template.getTitle().getValue(), | ||
| template.getShortcut().getValue(), | ||
| template.getDeletedAt(), | ||
| TrashRetention.purgeAt(template.getDeletedAt()) |
There was a problem hiding this comment.
예정 시각이 지났는데 배치가 아직 안 돈 항목이 "과거의 삭제 예정 시각"을 달고 그대로 보이는데, 화면에서 이걸 어떻게 표시할지 기획/프론트랑 한 번 얘기해봐야 될 거 같은데 어떻게 생각하시나요?!
There was a problem hiding this comment.
좋습니당 피그마 보니까 삭제 시점을 노출하는 것으로 되어있기는 한데, 요게 어떤식으로 노출이 되는지 잘 모르기도 하구
몇 시간에서 최대 하루 정도 더 보일 뿐이여서 해당 부분 얘기 나누면 좋을 부분같아여
서버에서 안보이게 막기에는 조큼 귀찮아질것 같긴 합니다아 .. ㅋㅎㅋㅎ
관련 이슈
작업 내용
명세 15번
GET /api/v1/trash/templates를 구현했습니다. 16·17·18번이 이어서 쓸TrashController,TrashSuccessCode,TrashErrorCode도 여기서 만듭니다.커밋별로 보기
TemplateRepository메서드 3개,TrashQueryService,TrashCursor,TrashErrorCode, 결과 객체TrashController,TrashSuccessCode, 응답 객체TrashRetention으로 분리TrashCursor를service패키지로 이동 (이 API만 쓰는 페이지 처리라 패키지 안으로 감춤)TrashTemplateRow로 조회해 본문을 읽지 않도록 변경동작 규칙
deleted_at내림차순, 동률은id내림차순size생략 또는 비어 있음cursor생략 또는 비어 있음size0 이하 또는 51 이상, 해석할 수 없는 커서TRASH400_1sizeCOMMON400_1hasNext: false,nextCursor: nulltotalCountpurgeAtdeleted_at + 30일. 지난 항목도 배치가 지우기 전까지 그대로 보여 줌커서는 마지막 항목의
(deletedAt, id)를 이어 붙여 Base64 URL로 인코딩합니다. 응답 시각은 초까지만 나가지만 커서에는 마이크로초까지 넣어서, 같은 초 안의 항목이 페이지 경계에 걸려도 건너뛰지 않습니다.명세와 달라진 점
size(예:99999999999)는 명세의TRASH400_1이 아니라COMMON400_1입니다. 범위 검사 전에 숫자 변환에서 실패하기 때문입니다. 이 동작은 테스트로 고정했습니다테스트
TrashControllerTest(테스트컨테이너 MySQL)id내림차순, 필드 순서,+09:00,no-store,purgeAt,totalCountsize기본값, 경계 1·50, 0·51·-1TRASH400_1, 숫자가 아닌 값COMMON400_1, 빈 파라미터TRASH400_1, 0000년·9999년 커서도 500 없음, 토큰 없음COMMON401_1200TrashTemplateRepositoryTest: 정렬, 커서 조건, 마이크로초 비교, 본인 휴지통만 읽고 세기TrashQueryServiceTest(모키토): 첫·다음 페이지 분기,size + 1조회, 커서 생성, 잘못된 커서면 DB를 읽지 않음TrashCursorTest: 왕복 변환, URL 안전 문자, 서버가 만든 형식이 아닌 값 거절TrashRetentionTest: 삭제 시각의 30일 뒤TrashErrorCodeTest: 결과 코드와 문구확인 체크리스트
./gradlew build통과global공통 코드 변경 없음리뷰어에게
EXPLAIN에서 세 쿼리 모두idx_templates_user_deleted를 탔습니다. 목록 두 쿼리는 파일 정렬 없는 역방향 스캔이고, 개수는 커버링 인덱스입니다Row를 썼습니다 (CLAUDE.md 규칙의 예외):Row는 성능 문제가 확인됐을 때만 쓰는 규칙이지만, 이번에는 장애 격리 때문입니다. 엔티티로 읽으면 내보내지도 않는 본문을 복호화해서, 복호화에 실패한 행 하나가 목록 전체를500으로 만듭니다. 테스트로 재현한 뒤 고쳤습니다support/TrashRetention에 뒀습니다. feat: 내 템플릿 상세 조회 API (#49) #50·#53이 수정 중인Template을 피했고, 상태 없는 순수 규칙이라 정리 배치도 같은 곳을 쓰면 됩니다deleted_at을 비웠습니다. 16번이 나오면 실제 복구로 바꿀 수 있습니다🤖 Generated with Claude Code