Files
tasteby/docs/design/545-hide-foreign-reservation-buttons
joungmin 6754976e72 [Architect] #545 예약버튼 국내 게이트 설계서 소급 작성
- Developer 구현(5d62866) 이후 설계서 게이트 위반 보완
- isKoreaRestaurant() 적용 범위/근거를 구현과 일치하도록 문서화

Refs #545
2026-07-19 09:09:50 +09:00
..

설계서: 해외 식당 예약 버튼(테이블링/캐치테이블) 숨김 (#545)

상태: Approved 작성: [AI] Architect (소급 작성 — Developer 구현 후 게이트 보완) · 최종수정: 2026-07-19 추적성 — Redmine: #545 · 관련 ADR: 없음 · 구현 파일: frontend/src/components/RestaurantDetail.tsx · 테스트: 육안 확인(QA 잔여)

1. 목적 (Why)

해외 식당 상세에 국내 전용 예약 서비스(테이블링/캐치테이블) 버튼이 노출되는 버그를 막는다. 테이블링/캐치테이블은 국내 식당만 지원하므로, 해외 식당에서는 두 버튼을 숨겨야 한다.

2. 범위 (Scope)

  • 포함: RestaurantDetail.tsx의 테이블링/캐치테이블 예약 버튼 2종에 국내 판정 게이트 적용.
  • 제외 (out of scope): 백엔드 예약 URL 검색/벌크 수집이 해외 식당을 제외하도록 하는 것 (#545 후속, 별도 이슈로 분리 가능).

3. 인수조건 (Acceptance Criteria)

  • 해외 식당(좌표가 한국 bbox 밖) 상세에서 테이블링/캐치테이블 버튼이 보이지 않는다.
  • 국내 식당 상세에서는 기존과 동일하게 두 버튼이 보인다 (URL 존재 시).
  • tsc 타입체크 통과.
  • 육안 QA 확인 (해외/국내 식당 각 1건 이상, 대표 발견 케이스 포함).

4. 컨텍스트 & 제약

  • 의존성: Restaurant.latitude/longitude, Restaurant.region (좌표 없는 구 데이터 fallback).
  • 제약: 기존 지도 링크 분기(151행)에 이미 쓰이던 isKoreaRestaurant() 판정 기준과 동일하게 유지해야 함(판정 기준 이원화 방지).
  • 가정: tabling_url/catchtable_url"NONE"이 아니고 값이 있어도, 해외 식당이면 노출하지 않는다.

5. 아키텍처 개요

  • 변경 파일: frontend/src/components/RestaurantDetail.tsx 1개.
  • 데이터 흐름: restaurant prop → isKoreaRestaurant(restaurant) 순수 판정 → JSX 렌더 게이트.
  • I/O 없음, 순수 함수 기반 조건부 렌더링만 추가.
Restaurant (좌표/region)
       │
       ▼
isKoreaRestaurant(r) ──false──▶ 테이블링/캐치테이블 버튼 미렌더
       │
      true
       │
       ▼
기존 로직: url 존재 && != "NONE" → 버튼 렌더

6. 데이터 모델

  • 입력: Restaurant { latitude?, longitude?, region?, tabling_url?, catchtable_url? } (기존 타입, 변경 없음).
  • 출력: 없음 (렌더 분기만).
  • 경계 검증: isKoreaRestaurant() 내부에서 이미 null/undefined 가드 처리(좌표 없으면 region 첫 토큰 fallback).

7. 함수 명세 (Function Specs)

함수 책임(1줄) 시그니처 입력 출력 에러/실패 복잡?
isKoreaRestaurant 좌표/region 기반 국내 식당 판정 (기존 함수, 변경 없음 — 적용 범위만 확대) (r: Restaurant) => boolean Restaurant boolean 없음 (순수 함수) 단순

신규 함수 없음. 기존 isKoreaRestaurant()(30행, 지도 링크 분기용으로 이미 존재)를 예약 버튼 2곳에도 동일 적용.

8. 흐름 / 알고리즘

  1. isKoreaRestaurant(restaurant) 평가 (좌표 우선, KR bbox 3338.7°N / 124132°E; 좌표 없으면 region 첫 토큰이 "한국"인지로 fallback).
  2. true일 때만 기존 조건(tabling_url/catchtable_url 존재 && !== "NONE")을 이어서 평가.
  3. 최종 true일 때만 버튼 렌더.

9. 엣지케이스 & 에러 처리

  • 좌표와 region 모두 없는 구 데이터 → isKoreaRestaurant!r.region 조건으로 true 반환(국내로 간주, 기존 동작 유지 — 회귀 아님).
  • 좌표가 KR bbox 경계값에 걸치는 경우(제주/울릉도 등) → 기존 지도 링크 판정과 동일 로직이므로 별도 리스크 없음(기존에 검증된 임계값 재사용).

10. 테스트 계획

  • 수동 QA: 해외 식당(예: 일본/방콕 소재) 상세 진입 → 테이블링/캐치테이블 버튼 미노출 확인.
  • 수동 QA: 국내 식당 상세 진입 → 기존과 동일하게 버튼 노출 확인 (url 존재 시).
  • npm run build / tsc 통과 (완료).
  • 자동화 테스트: 없음 (컴포넌트 스냅샷/RTL 테스트 미비 — #543 커버리지 이슈에서 다룸).

11. 리스크 & 대안 검토

  • 대안: 백엔드에서 해외 식당의 tabling_url/catchtable_url을 애초에 null로 채우지 않는 방법도 있으나, 프론트 게이트가 더 즉각적이고 기존 판정 로직 재사용 가능 → 채택.
  • 되돌리기 어려운 결정 없음. ADR 불필요.

12. 미해결 질문 (Open Questions)

  • 백엔드 예약 URL 수집/검색 단계에서 해외 식당을 원천 제외할지 여부는 별도 이슈로 분리할 가치가 있음 (설명에 "후속(옵션)"으로 명시됨).