fix(backend): 영업시간 해석 오류와 행사 날짜 500 수정, 함께 가기용 trusted 조건 추가 #4

Merged
ttipo merged 3 commits from fix/place-hours-and-nearby into main 2026-11-05 01:21:11 +09:00
Owner

무엇을 · 왜

2026-11-04 전체 회귀 점검(실제 데이터 API 846회 · 에뮬레이터)에서 찾은 백엔드 결함을 고친다.

  • 영업시간 해석 오류 — 영업 중인데 '영업 종료'
    • 관광공사 원문 107곳이 줄바꿈 없이 붙어 온다("- 11:0021:00- 준비시간 16:0017:00- 마지막 주문 20:20").
    • 파서가 이를 한 구간으로 보고 영업시간까지 준비시간·마지막 주문으로 읽었다.
    • 그래서 39곳이 영업 중인 낮에 '영업 종료'로 보였고, 41곳은 요일 시간이 통째로 비었다.
    • 시각·닫는 괄호 뒤의 '- ' 와 대괄호 머리말 앞에서 구간을 나눈다.
    • 시설 머리말("[칠성시장] … [칠성야시장] …")마다 시간표를 만들어 요일별로 합친다.
      나누기만 하면 뒤 시설의 요일 시간이 앞 시설을 지워 일부 시간대가 빠졌다(칠성시장 일요일 낮 등).
    • '휴게시간'은 쉬는 시간으로, '점심시간'은 2시간 이하일 때만 쉬는 시간으로 읽는다.
    • 요일 사이 '/' 는 나열로 읽고, 0분 구간("13:00~13:00")은 버린다.
    • 개발 DB 는 reparse-hours 로 다시 해석했다(107곳 바뀜, API 재호출 없음).
    • 결과: '영업 종료' 오표시 39곳 → 1곳(원문 자체가 틀린 곳), 요일 시간이 빈 곳 41곳 → 0곳.
    • 바뀌는 107곳은 반영 전에 전후를 하나씩 대조했다.
  • 행사 목록 500
    • from=2030-13-01 처럼 없는 시작일에 to 를 생략하면 500(SYS_001)이 났다.
    • 날짜 계산을 shared/utils/iso-date.ts 로 옮기고 VAL_001(400)로 응답한다.
  • 장소 목록 trusted 조건(선택)
    • 관광공사 장소와 운영자 확인 장소만 주고, '추천 안 함' 판정은 뺀다.
    • 장소 상세 '함께 가기 좋은 곳'이 쓴다(앱 수정은 별도 PR).
    • 앱이 가까운 30곳을 받아 거르면 도심에서는 모두 상가라 칸이 비었다.
      관광공사 장소 상세 860곳 중 30곳은 칸이 사라지고 186곳은 덜 보였다(봉산서원 0곳 → 6곳).

남긴 것(원본 데이터 문제·한계)

  • 원문이 틀린 곳(팔공산 닭갈비 "준비시간(주말) 05:00~16:30")은 그대로다.
  • 원본 좌표가 틀린 곳: 오천서원(주소 대구·좌표 포항), 대구올레 팔공산 3·4·5코스(사무실 주소로 등록).
  • 쉬는 시간은 시설·요일 구분 없이 하루 전체에 적용한다.

확인 방법

cd backend
npm run lint && npm run test
# e2e 는 DB 가 필요하다 — 개발 컨테이너 안에서
docker exec wandergo-backend npx jest --config ./test/jest-e2e.json test/place.e2e-spec.ts test/festival.e2e-spec.ts
# 파서를 바꿨으므로 저장된 영업시간을 다시 해석한다(키 불필요)
docker exec -w /app wandergo-backend npm run place:sync -- reparse-hours
  • 린트 Warning 0, 단위 테스트 227개 통과(새로 19개 — 영업시간 실제 원문 10건, 날짜 계산 9건)
  • e2e(장소·행사) 34개 통과 — trusted(관광공사 · 확인 안 된 상가 · 확인한 상가 · 추천 안 함 2곳), 끝을 생략한 없는 날짜 3가지
  • 실제 개발 데이터 API 점검 113항목 중 112 통과 — 실패 1건은 원본 좌표가 틀린 오천서원(이 PR 범위 밖)
  • 저장된 영업시간 1,114곳 = 지금 파서 결과(차이 0)

영향 범위

  • backend
  • frontend
  • flutter
  • docker / 인프라
  • 규칙 문서(.claude/)

공유 계약: GET /api/places 에 선택 조건 trusted 를 추가했다(필드 추가와 같은 호환 변경, 기존 호출은 그대로).
앱은 다음 PR(fix/flutter-nearby-a11y-images)에서 쓴다. 이 PR 이 먼저 배포되어야 한다 — 모르는 조건은 VAL_001(400)이다.
에러 코드·응답 포맷 변경 없음. 설계 문서 docs/design/place-db.md 에 파서 변경과 trusted 를 적었다.

체크리스트

  • 린트/분석 통과 (Warning 0) · 변경 영역 테스트 통과
  • 주석 한국어, 매직 넘버·하드코딩 문자열 없음
  • 사용자 노출 실패는 모두 에러 코드와 함께 처리 (BusinessException('VAL_001'))
  • 에러 코드를 바꿨다면 npm run sync:error-codes 실행 후 생성 파일까지 커밋 — 해당 없음(생성 파일 차이 없음 확인)
  • 민감정보 미커밋
  • 로그에 비밀번호·토큰·요청 본문 전체가 남지 않음

🤖 Generated with Claude Code

## 무엇을 · 왜 2026-11-04 전체 회귀 점검(실제 데이터 API 846회 · 에뮬레이터)에서 찾은 백엔드 결함을 고친다. - **영업시간 해석 오류 — 영업 중인데 '영업 종료'** - 관광공사 원문 107곳이 줄바꿈 없이 붙어 온다("- 11:00~21:00- 준비시간 16:00~17:00- 마지막 주문 20:20"). - 파서가 이를 한 구간으로 보고 영업시간까지 준비시간·마지막 주문으로 읽었다. - 그래서 39곳이 영업 중인 낮에 '영업 종료'로 보였고, 41곳은 요일 시간이 통째로 비었다. - 시각·닫는 괄호 뒤의 '- ' 와 대괄호 머리말 앞에서 구간을 나눈다. - 시설 머리말("[칠성시장] … [칠성야시장] …")마다 시간표를 만들어 요일별로 합친다. 나누기만 하면 뒤 시설의 요일 시간이 앞 시설을 지워 일부 시간대가 빠졌다(칠성시장 일요일 낮 등). - '휴게시간'은 쉬는 시간으로, '점심시간'은 2시간 이하일 때만 쉬는 시간으로 읽는다. - 요일 사이 '/' 는 나열로 읽고, 0분 구간("13:00~13:00")은 버린다. - 개발 DB 는 `reparse-hours` 로 다시 해석했다(107곳 바뀜, API 재호출 없음). - 결과: '영업 종료' 오표시 39곳 → 1곳(원문 자체가 틀린 곳), 요일 시간이 빈 곳 41곳 → 0곳. - 바뀌는 107곳은 반영 전에 전후를 하나씩 대조했다. - **행사 목록 500** - `from=2030-13-01` 처럼 없는 시작일에 `to` 를 생략하면 500(SYS_001)이 났다. - 날짜 계산을 `shared/utils/iso-date.ts` 로 옮기고 VAL_001(400)로 응답한다. - **장소 목록 `trusted` 조건(선택)** - 관광공사 장소와 운영자 확인 장소만 주고, '추천 안 함' 판정은 뺀다. - 장소 상세 '함께 가기 좋은 곳'이 쓴다(앱 수정은 별도 PR). - 앱이 가까운 30곳을 받아 거르면 도심에서는 모두 상가라 칸이 비었다. 관광공사 장소 상세 860곳 중 30곳은 칸이 사라지고 186곳은 덜 보였다(봉산서원 0곳 → 6곳). 남긴 것(원본 데이터 문제·한계) - 원문이 틀린 곳(팔공산 닭갈비 "준비시간(주말) 05:00~16:30")은 그대로다. - 원본 좌표가 틀린 곳: 오천서원(주소 대구·좌표 포항), 대구올레 팔공산 3·4·5코스(사무실 주소로 등록). - 쉬는 시간은 시설·요일 구분 없이 하루 전체에 적용한다. ## 확인 방법 ```bash cd backend npm run lint && npm run test # e2e 는 DB 가 필요하다 — 개발 컨테이너 안에서 docker exec wandergo-backend npx jest --config ./test/jest-e2e.json test/place.e2e-spec.ts test/festival.e2e-spec.ts # 파서를 바꿨으므로 저장된 영업시간을 다시 해석한다(키 불필요) docker exec -w /app wandergo-backend npm run place:sync -- reparse-hours ``` - 린트 Warning 0, 단위 테스트 227개 통과(새로 19개 — 영업시간 실제 원문 10건, 날짜 계산 9건) - e2e(장소·행사) 34개 통과 — trusted(관광공사 · 확인 안 된 상가 · 확인한 상가 · 추천 안 함 2곳), 끝을 생략한 없는 날짜 3가지 - 실제 개발 데이터 API 점검 113항목 중 112 통과 — 실패 1건은 원본 좌표가 틀린 오천서원(이 PR 범위 밖) - 저장된 영업시간 1,114곳 = 지금 파서 결과(차이 0) ## 영향 범위 - [x] backend - [ ] frontend - [ ] flutter - [ ] docker / 인프라 - [ ] 규칙 문서(.claude/) > 공유 계약: `GET /api/places` 에 선택 조건 `trusted` 를 추가했다(필드 추가와 같은 호환 변경, 기존 호출은 그대로). > 앱은 다음 PR(`fix/flutter-nearby-a11y-images`)에서 쓴다. 이 PR 이 먼저 배포되어야 한다 — 모르는 조건은 VAL_001(400)이다. > 에러 코드·응답 포맷 변경 없음. 설계 문서 `docs/design/place-db.md` 에 파서 변경과 `trusted` 를 적었다. ## 체크리스트 - [x] 린트/분석 통과 (Warning 0) · 변경 영역 테스트 통과 - [x] 주석 한국어, 매직 넘버·하드코딩 문자열 없음 - [x] 사용자 노출 실패는 모두 에러 코드와 함께 처리 (`BusinessException('VAL_001')`) - [x] 에러 코드를 바꿨다면 `npm run sync:error-codes` 실행 후 생성 파일까지 커밋 — 해당 없음(생성 파일 차이 없음 확인) - [x] 민감정보 미커밋 - [x] 로그에 비밀번호·토큰·요청 본문 전체가 남지 않음 🤖 Generated with [Claude Code](https://claude.com/claude-code)
ttipo added 3 commits 2026-11-05 00:04:38 +09:00
관광공사 원문 107곳이 "- 11:00~21:00- 준비시간 16:00~17:00- 마지막 주문 20:20" 처럼
줄바꿈 없이 붙어 온다. 맨 앞 글머리표만 지우던 파서는 이를 한 구간으로 보고 영업시간까지
준비시간·마지막 주문으로 읽었다. 그래서 39곳이 영업 중인 낮에 '영업 종료'로 보였고
41곳은 요일 시간이 통째로 비었다(2026-11-04 회귀 점검).

- 시각·닫는 괄호 뒤의 '- '(다음이 숫자가 아닌 말)와 대괄호 머리말 앞에서 구간을 나눈다
- 시설 머리말("[칠성시장] … [칠성야시장] …")마다 시간표를 따로 만들고 요일별로 합친다.
  나누기만 하면 뒤 시설의 요일 시간이 앞 시설 시간을 지워 일부 시간대가 빠졌다
- '휴게시간'은 쉬는 시간, '점심시간'은 2시간 이하일 때만 쉬는 시간으로 읽는다(식당의 점심 영업과 구분)
- 요일 사이의 '/' 는 나열로 읽고, 0분 구간("13:00~13:00")은 24시간으로 읽지 않고 버린다

개발 DB 는 reparse-hours 로 다시 해석했다(107곳 바뀜, 공공데이터 API 재호출 없음).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
from=2030-13-01 처럼 없는 시작일에 to 를 생략하면 끝 날짜를 계산하다 RangeError 가 나서
VAL_001(400) 대신 SYS_001(500)이 나갔다. from=9999-12-31 은 DB 가 읽지 못하는 끝 날짜를 만들었다.
날짜 계산을 shared/utils/iso-date.ts 순수 함수로 옮기고, 없는 날짜와 네 자리 연도를 넘는 결과는
null 로 알려 VAL_001 로 응답한다. 앱은 항상 두 날짜를 보내므로 사용자에게는 보이지 않았다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat(backend): 장소 목록에 관광공사·확인 장소만 받는 trusted 조건 추가
CI / Backend (lint · test · e2e · build) (pull_request) Successful in 11m54s
CI / 에러 코드 SSOT 동기화 검사 (pull_request) Successful in 11m0s
CI / Frontend (lint · type-check · test) (pull_request) Successful in 11m5s
CI / Frontend (lint · type-check · test) (push) Has been cancelled
CI / 에러 코드 SSOT 동기화 검사 (push) Has been cancelled
CI / Backend (lint · test · e2e · build) (push) Has been cancelled
4bd2a9b4ad
장소 상세 '함께 가기 좋은 곳'은 확인 안 된 상가정보 매장을 빼야 한다(2026-11-02 합의).
앱이 가까운 30곳을 받아 거르면 도심처럼 상가가 빽빽한 곳은 받은 곳이 모두 상가라 칸이 비었다.
관광공사 장소 상세 860곳 중 30곳은 칸이 사라지고 186곳은 덜 보였다(봉산서원은 1.5km 안에
관광공사 장소가 53곳인데 0곳).

trusted=true 면 관광공사 장소와 운영자가 확인한 장소만 주고 '추천 안 함' 판정도 뺀다.
선택 조건이라 기존 호출은 그대로다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ttipo merged commit 4bd2a9b4ad into main 2026-11-05 01:21:11 +09:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ttipo/wandergo#4