Skip to content

feat: 탐색 탭에서 이미 팔로우한 회원의 Collection을 제외한다 - #205

Merged
ghkim1632 merged 5 commits into
devfrom
feat/S15P11A705-398-ai-탐색-탭-팔로잉-사용자-책-제외-필터링-적용
Aug 7, 2026

Hidden character warning

The head ref may contain hidden characters: "feat/S15P11A705-398-ai-\ud0d0\uc0c9-\ud0ed-\ud314\ub85c\uc789-\uc0ac\uc6a9\uc790-\ucc45-\uc81c\uc678-\ud544\ud130\ub9c1-\uc801\uc6a9"
Merged

feat: 탐색 탭에서 이미 팔로우한 회원의 Collection을 제외한다#205
ghkim1632 merged 5 commits into
devfrom
feat/S15P11A705-398-ai-탐색-탭-팔로잉-사용자-책-제외-필터링-적용

Conversation

@ghkim1632

Copy link
Copy Markdown
Contributor

요약

탐색(GET /v1/feed/collections) 탭에서 이미 팔로우 중인 회원의 Collection이 후보에서 제외되도록 한다. 이 저장소가 참조하는 AI 파트 소유 명세(feed-scoring.md)는 반대로 "팔로우 = 최고 가중치 신호"로 설계돼 있어, 상충 사실을 명세 쪽에 마킹하고 결정 배경은 BD-51에 남겼다.

Jira (필수)

  • 키 또는 URL: S15P11A705-398

변경 사항

  • FeedCandidateRepository: RECENT_SQL·SAMPLE_FROM_PIVOT_SQL·SAMPLE_WRAPPED_SQL의 WHERE 절에 core.follow 기준 NOT EXISTS를 추가해 이미 팔로우한 회원의 Collection을 제외
  • FeedService#collectCandidates: 탐색 후보 병합에서 findFollowed 채널 호출 제거 (FOLLOWED_SQL/findFollowed 자체는 남김 — AI 파트 소유 자산이며 별도 테스트로 검증됨)
  • FeedCandidateChannelTests: 실패 테스트를 먼저 추가(C10, RED 확인 후 구현)
  • FeedKeywordDisplayOrderTests: "팔로우해서 강제 상위 노출"시키던 픽스처 트릭이 이제 정반대 효과를 내 커서를 끝까지 순회하는 방식으로 교체
  • docs/ai/spec/feed-scoring.md·feed-recommendation.md: 이 결정과 상충하는 자리에 마킹만 남기고 AI 파트 소유 값(w_follow 등)은 임의로 고치지 않음
  • docs/backend/decisions/BD-51, worklog 항목 추가

테스트 / 검증

  • ./gradlew clean check --no-daemon
    • RED: FeedCandidateChannelTests.exploreChannelsExcludeFollowedMembersCollections 추가 직후 실행 → recentIds 단언 실패([8L, 7L, 6L, 1L]에 제외돼야 할 7L이 포함) 확인
    • GREEN: SQL 수정 후 같은 테스트·feed 도메인 전체(100개) 반복 통과, FeedChannelPlanTestsNOT EXISTS 추가 후에도 ix_collection_feed 인덱스 정렬 순서(Presorted Key) 유지 확인
    • Regression: 전체 654개 테스트 중 646개 통과. 남은 10개(OpenAPI 문서화·인증 계약·Flyway 테스트)는 매번 동일하게 PSQLException(Postgres 연결 거부)로 실패하지만 개별 실행 시 전부 통과 — 이 변경과 무관한, 로컬 Docker의 대량 동시 컨테이너 자원 한계로 판단
  • DB 변경 시 PostgreSQL 통합 테스트 — FeedCandidateChannelTests(Testcontainers), FeedChannelPlanTests(EXPLAIN 계획 검증)
  • 되돌리기 어려운 결정을 포함하면 docs/backend/decisions/에 BD 추가 또는 기존 BD 링크 — BD-51

배경

현재 코드는 버그가 아니라 AI 파트 소유 명세(feed-scoring.md)가 "팔로우가 사용자가 명시적으로 표현한 유일한 관심 신호"라는 근거로 최고 가중치(w_follow=0.500)를 주고 우선 노출하도록 설계한 그대로였다. 제품 요구사항(탐색 탭은 신규 발견이 목적)이 이 설계를 뒤집기에, CLAUDE.md 9번 규칙(코드-문서 충돌은 정본을 임의로 고치지 않고 마킹만 남긴다)의 정신을 따라 AI 파트 소유 값·구조(wFollow, followLimit, FOLLOWED_SQL, findFollowed)는 코드에서 지우지 않고, 탐색 파이프라인이 그 채널을 부르지 않고 남은 채널에서 명시적으로 제외하는 방식으로 구현했다. 상세 트레이드오프는 BD-51 참조.

리뷰 포인트

  1. AI 파트 소유 명세와 정면 상충하는 제품 결정이라, 명세 문서 쪽 갱신 여부는 AI 파트 판단이 필요하다 (마킹만 남겨둔 상태).
  2. wFollow·followLimit 설정값과 FOLLOWED_SQL/findFollowed 코드를 지우지 않고 "안 부르는" 방식으로 무력화했다 — 되돌리기 쉽게 하려는 선택인데, 당장은 안 읽히는 설정처럼 보일 수 있어 동의 여부 확인 필요.

미결 / 후속

  • 팔로우한 회원의 새 책을 볼 수 있는 별도 "팔로잉" 피드 화면은 이 PR 범위에 없다. 필요해지면 FOLLOWED_SQL/findFollowed를 그 화면의 데이터 소스로 재사용할 수 있다.

ghkim1632 and others added 5 commits August 7, 2026 16:59
탐색(GET /v1/feed/collections) 후보에서 findFollowed 채널을 더 이상 합류시키지
않고, 최신·무작위 채널의 WHERE 절에 core.follow 기준 NOT EXISTS를 추가해 이미
팔로우한 회원의 Collection을 직접 제외한다.

이 저장소가 참조하는 AI 파트 소유 명세(feed-scoring.md)는 반대로 "팔로우 =
최고 가중치 신호"로 설계돼 있어(w_follow=0.500, 최우선 채널), 그 설계를 뒤집는
결정이다. 명세의 값·구조(wFollow, findFollowed/FOLLOWED_SQL)는 AI 파트 소유라
지우지 않고, 상충 사실만 feed-scoring.md·feed-recommendation.md에 마킹했다.
근거와 감수한 것은 BD-51에 정리했다.

FeedCandidateChannelTests에 실패 테스트(C10)를 먼저 추가해 RED를 확인한 뒤
구현했고, FeedChannelPlanTests로 NOT EXISTS 추가 후에도 ix_collection_feed의
정렬 순서(Presorted Key)가 유지되는지 확인했다. FeedKeywordDisplayOrderTests가
"팔로우해서 강제 노출"시키던 픽스처 트릭은 이제 역효과를 내므로, 커서를 끝까지
순회해 대상 Collection을 찾는 방식으로 바꿨다.

주: 이 브랜치는 원래 feat/S15P11A705-366-image-upload-limit에서 갈라져 나왔다.
그 브랜치에 함께 있던 미완성 Feed Interest Profile 작업(FeedProfileService 등)은
이 변경과 무관해 커밋에 포함하지 않았다.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@ghkim1632
ghkim1632 merged commit e0a4979 into dev Aug 7, 2026
2 checks passed
@ghkim1632
ghkim1632 deleted the feat/S15P11A705-398-ai-탐색-탭-팔로잉-사용자-책-제외-필터링-적용 branch August 7, 2026 09:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant