fix: 코스 상세·목록 응답에 shareToken 을 채운다 - #260
Conversation
- 토큰이 저장 응답에만 실려, 그 응답을 놓친 코스는 영영 공유할 수 없었다. 앱을 다시 깔거나 기기를 바꾸면 이전 코스가 전부 그랬고, 프론트는 저장 응답의 토큰을 Keychain 에 적어두고 버티고 있었다 - 소유자 단건 응답(저장·상세·여행 날짜 수정)에 싣는다. 목록·상세 모두 guestId 범위로만 조회하므로 남의 토큰이 나갈 길이 없다. 토큰이 있다고 공개되는 것도 아니다 — 링크를 넘겨야 비로소 남이 볼 수 있다 - 공유 링크로 여는 공개 조회에는 계속 싣지 않는다. 링크를 받은 사람은 수정·삭제를 못 하고 토큰은 이미 자기가 연 URL 에 있다 - 상세는 공유 행이 없으면 **그 자리에서 발급**한다. null 로 두면 #143 이전에 저장된 코스가 그대로 공유 불가로 남는다. 조회가 쓰기를 하는 셈이지만 코스당 한 번뿐이고, 경합은 이미 유니크 제약으로 흡수하고 있다 - 목록은 발급하지 않고 있는 것만 읽는다 — 페이지당 최대 100건이라 발급까지 하면 조회 한 번이 그만큼의 INSERT 가 된다. 대신 코스마다 묻지 않고 findByCourseIdIn 으로 한 번에 모은다(N+1) - 거짓이 된 문서를 함께 고쳤다: CourseResponse.shareToken 의 "저장 응답에만 실린다", GeneratedCourse javadoc, CourseStorageApi 의 목록·상세·날짜수정 설명
- 상세·목록 응답의 토큰이 저장 때와 **같은 값**인지 대조한다. "실려 있다" 만 보면 매번 새로 발급하는 회귀를 못 잡고, 그러면 먼저 뿌린 링크가 죽는다 - 남의 게스트 ID 로는 목록이 비고 상세가 404 인지 확인한다 — 이번 변경으로 토큰이 응답에 실리게 됐으니, 소유자 범위가 새면 링크까지 함께 샌다 - 공유 행이 없는 코스를 리포지토리로 직접 만들어, 상세를 열면 발급되고 두 번째 조회는 같은 토큰을 주는지 본다. 저장 API 를 거치면 항상 토큰이 붙어 이 상태는 그 길로 재현되지 않는다 - 공개 조회에 토큰이 없다는 기존 단언은 그대로 둔다 — 이번 변경이 그리로 새지 않는지가 그 테스트다
|
Warning Review limit reached
Next review available in: 49 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (11)
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 |
리뷰 (CodeRabbit 레이트리밋 대신 수동)로컬에서 검증했습니다 — 테스트 1,313건 통과 · 실패 0 · 컨벤션 훅 차단 0. 네 가지 설계 판단이 코드와 문서에 근거째 남아 있어 읽기 좋습니다. 확인한 것:
테스트가 형식적이지 않은 점이 특히 좋습니다. "토큰이 실린다" 가 아니라 저장 때와 같은 값인지 대조하고 두 번 열어도 같은지(멱등성)까지 봅니다 — 매번 새로 발급하는 회귀는 먼저 뿌린 링크를 죽이는데, 존재 확인만으로는 그걸 못 잡습니다. 아래 두 가지를 봐주세요. ① 상세 조회가 토큰 발급 실패에 통째로 500 이 된다 (중간)
return withBenefits(course, true).withShareToken(shareTokenOf(course.getId()));
이 PR 전에는 상세가 읽기 전용이라
발급 자체를 상세에서 하는 결정은 동의합니다. 실패했을 때 무엇을 포기할지만 다시 봐주세요. ② "목록은 발급하지 않는다" 계약이 테스트로 안 잠겼다 (낮음)PR 본문·port javadoc· 토큰 없는 코스를 만들고(이미 둘 다 머지를 막을 정도는 아닙니다. ①은 고치는 편이 낫다고 보고, ②는 선택입니다. |
- 토큰을 조회 경로에 실으면서 상세·날짜수정이 course_share 에 의존하게 됐다. 그전까지 그 테이블을 건드리지 않아 거기서 깨질 수 없었다 - 그대로 두면 공유 버튼 하나 때문에 코스 화면이 통째로 안 뜬다. 사용자가 잃는 것(코스 전체)이 얻는 것(링크)보다 크다 - 날짜 수정에서는 더 나쁘다. 날짜 갱신은 이미 커밋된 뒤라 여기서 던지면 바뀐 것을 안 바뀌었다고 답하게 된다 - 조용히 넘어가지는 않는다. 사유를 warn 으로 남기고, 발급 못 한 코스는 다음 상세 조회가 다시 시도한다 - 저장(save)은 그대로 둔다. 거기서 토큰이 비면 클라이언트가 링크를 못 만드는데, 그 상황은 이 변경이 만든 것이 아니라 원래 그랬다
- 본문·javadoc·@operation 세 곳이 "목록에서 발급하면 조회 한 번이 최대 100 INSERT" 라고 적어두고 정작 그걸 깨는 변경을 막는 테스트가 없었다 - null 단언만으로는 "발급은 했는데 응답에 안 실었다" 와 구분되지 않아 공유 행이 안 생겼는지까지 본다
리뷰 대응두 건 모두 반영했습니다. 테스트 1,313 → 1,314건, 실패 0. ① 상세·날짜수정이 토큰 발급 실패에 500 →
|
Situation
courseId → shareToken으로 적어두고 버티는 중이었다. 서버가 채워주면 그 저장소는 지운다.Task
토큰을 조회 응답에 싣는 것은 처음부터 "저장 응답에만" 으로 못박혀 있던 설계라(코드 주석에 "소유자에게만" 이라고 적혀 있다), 그냥 null 을 채우기 전에 그 판단이 지금도 맞는지부터 봤다. 확인한 것 넷.
guestId범위 쿼리다. 남의 코스가 섞일 길이 없다"토큰이 있다" 와 "공개됐다" 는 다르다. 링크를 넘겨야 비로소 남이 볼 수 있고, 소유자 본인에게 자기 링크를 돌려주는 것이라 노출면이 넓어지지 않는다.
Action
어디에 싣고 어디에 안 싣는가
POST /coursesGET /courses/{id}GET /coursesPATCH /courses/{id}GET /public/courses/{token}쿼리를 늘리지 않기
findByCourseIdIn을 port·adapter에 더해 목록당 조회 한 번으로 묶었다.course_id는 유니크 제약이 걸려 있어 인덱스를 그대로 탄다.allCourses)는 응답으로 나가는 길이 아니라 토큰을 아예 읽지 않는다. 읽어봐야 쿼리만 하나 더 는다.거짓이 된 문서 정정
CourseResponse.shareToken의 스키마 설명이 "저장 응답에만 실린다" 였다. 이 PR 로 거짓이 되므로 함께 고쳤다.GeneratedCoursejavadoc,CourseStorageApi의 목록·상세·날짜수정@Operation설명을 갱신했다. 목록 항목의 새 필드는@Schema로 문서화했다.검토했지만 하지 않은 것
NON_NULL적용travelDate·dDay등)가 함께 사라져 기존 계약이 깨진다Result
ShareTokenStore를 지울 수 있다. 재설치·기기 변경 후에도 저장된 코스를 공유할 수 있다.shareToken이 null 인 항목이 남을 수 있다(공유 기능 도입 이전 저장분). 상세를 한 번 열면 채워지며, 이 동작을 API 문서에 적어 뒀다.작업을 마치기 전 자문 셋
연관 이슈