- GET /api/admin/restaurants/duplicates/place-id (어드민 전용) - 그룹별 식당 목록 + video/review/memo 카운트 동봉 - Mapper: findDuplicatePlaceIdRows + Service 그룹핑 - 정리/병합 + UNIQUE 제약은 데이터 위험 분리 위해 후속 PR로 Refs: #359 (조회 단계 완료) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
48 lines
2.2 KiB
Markdown
48 lines
2.2 KiB
Markdown
# 설계서: google_place_id 중복 조회 API (#359 1단계)
|
|
|
|
> **상태**: Approved
|
|
> **작성**: [AI] Architect · **최종수정**: 2026-06-15
|
|
> **추적성** — Redmine: #359 · 1단계(조회 전용, 위험 0). 2단계(자동 병합) / 3단계(UNIQUE)는 별도 PR.
|
|
> · 구현 파일: `backend-java/src/main/resources/mybatis/mapper/RestaurantMapper.xml`, `backend-java/src/main/java/com/tasteby/mapper/RestaurantMapper.java`, `backend-java/src/main/java/com/tasteby/service/RestaurantService.java`, `backend-java/src/main/java/com/tasteby/controller/AdminRestaurantController.java`
|
|
> · 테스트: 본 범위 밖 (수동 — admin token으로 호출).
|
|
|
|
## 1. 목적 (Why)
|
|
|
|
같은 `google_place_id`에 다중 식당이 매핑된 경우 운영자가 어떤 것을 유지/병합할지 결정 필요. 본 단계는 **조회만** — 그룹과 후보 식당을 메타데이터(연결된 영상/리뷰/메모 수)와 함께 보여줘 의사결정 자료 제공.
|
|
|
|
## 2. 범위
|
|
|
|
- 포함: `GET /api/admin/restaurants/duplicates/place-id` — 운영자만, 그룹별 식당 + 카운트 동봉.
|
|
- 제외 (별도 PR): 병합/삭제, UNIQUE constraint.
|
|
|
|
## 3. 인수조건
|
|
|
|
- [ ] requireAdmin 보호.
|
|
- [ ] 응답 구조: `[{ google_place_id, items: [{ id, name, address, created_at, video_count, review_count, memo_count, hidden }] }]`.
|
|
- [ ] 그룹은 `COUNT(*) > 1` 만 반환.
|
|
|
|
## 4. SQL
|
|
|
|
```sql
|
|
SELECT r.id, r.google_place_id, r.name, r.address,
|
|
TO_CHAR(r.created_at, 'YYYY-MM-DD"T"HH24:MI:SS') AS created_at,
|
|
r.hidden,
|
|
(SELECT COUNT(*) FROM video_restaurants vr WHERE vr.restaurant_id = r.id) AS video_count,
|
|
(SELECT COUNT(*) FROM reviews rv WHERE rv.restaurant_id = r.id) AS review_count,
|
|
(SELECT COUNT(*) FROM memos mm WHERE mm.restaurant_id = r.id) AS memo_count
|
|
FROM restaurants r
|
|
WHERE r.google_place_id IN (
|
|
SELECT google_place_id FROM restaurants
|
|
WHERE google_place_id IS NOT NULL
|
|
GROUP BY google_place_id HAVING COUNT(*) > 1
|
|
)
|
|
ORDER BY r.google_place_id, r.created_at
|
|
```
|
|
|
|
Service 계층에서 google_place_id로 그룹핑하여 응답 구조 변환.
|
|
|
|
## 5. 엣지케이스
|
|
|
|
- 중복 0건 → 빈 배열.
|
|
- 누군가가 google_place_id를 동시에 변경 중 → 다음 호출에서 반영 (캐시 X).
|