[Developer] #533 언급 적은 식당 제외 필터 (min_mentions + video_count)

- backend: findAll 응답에 video_count(strong/unknown 링크수) + min_mentions 서버필터
  - Restaurant.videoCount, RestaurantMapper(xml/iface), Service, Controller(+cache key)
- frontend: Restaurant.video_count 타입 + 데스크톱 툴바 "언급"(2/3/5회+) 클라 필터
- 검증: min_mentions=2→116, =3→36 (위반 0). 빌드/tsc 통과
- 설계서 docs/design/533-min-mentions-filter/README.md

Refs #533
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
joungmin
2026-06-28 16:23:46 +09:00
parent 4760b5a284
commit 7639fd009d
9 changed files with 100 additions and 10 deletions

View File

@@ -0,0 +1,44 @@
# #533 — 언급 적은(관련도 낮은) 식당 제외 필터
## 배경 / 문제
영상에서 잠깐·우연히 언급된(=관련도 낮은) 식당까지 모두 노출되어 신호 대비 잡음이 큼.
사용자가 "언급이 충분한 식당만" 보도록 제외 필터 제공.
## 신호 정의
"의미있는 언급 수(`video_count`)" = 해당 식당의 `video_restaurants` 링크 중
**relevance ∈ ('strong','unknown')** 개수. (weak/incidental = 곁다리 언급 → 제외)
→ 기존 `findVideoLinks` 기본 노출 정책(strong/unknown)과 일관.
## 범위
- **백엔드**: 식당 목록 응답에 `video_count` 포함 + `min_mentions` 서버 필터 파라미터.
- **프론트**: `Restaurant.video_count` 타입 + 클라이언트 필터 UI(전체/2회+/3회+).
- 서버사이드 필터 일원화(현 클라 필터 패턴 통일)는 **#535**로 분리.
## 함수/변경 설계
### 백엔드
1. `domain/Restaurant.java``Integer videoCount` 필드 추가(전이 enrichment).
2. `mapper/RestaurantMapper.xml`
- `restaurantMap` resultMap: `<result property="videoCount" column="video_count"/>`
- `findAll` SELECT에 스칼라 서브쿼리 추가:
`(SELECT COUNT(*) FROM video_restaurants vrc WHERE vrc.restaurant_id = r.id AND vrc.relevance IN ('strong','unknown')) AS video_count`
- `findAll` `<where>`에 optional 필터:
`<if test="minMentions != null and minMentions > 0"> AND (위 서브쿼리) &gt;= #{minMentions} </if>`
3. `mapper/RestaurantMapper.java``@Param("minMentions") Integer minMentions` 추가.
4. `service/RestaurantService.java``findAll(..., Integer minMentions, boolean includeHidden)`로 스레드. 5-arg 오버로드는 `null, false` 전달.
5. `controller/RestaurantController.java``@RequestParam("min_mentions") Integer minMentions` + 캐시 키에 `mm=` 포함.
### 프론트
6. `lib/api.ts``Restaurant.video_count?: number | null`; `getRestaurants` 파라미터 `min_mentions?`(미래/서버필터용).
7. `app/page.tsx` — 필터 상태 `minMentions`(0/2/3) + `filteredRestaurants``(r.video_count ?? 0) >= minMentions` 가드 + UI 컨트롤 + useMemo deps 추가.
## 엣지케이스
- `video_count` 미산정(findById 등) → null. 클라 필터는 `?? 0`로 안전.
- minMentions=0(기본) → 필터 미적용(기존 동작 유지).
- DISTINCT + 스칼라 서브쿼리: r.id 단위라 결과 불변.
## 검증
- 백엔드 빌드 성공 → PM2 재시작.
- `GET /api/restaurants?min_mentions=2` 가 2회 미만 식당 제외하는지.
- 응답에 `video_count` 포함 확인.
- 프론트 토글로 목록/지도가 줄어드는지.