尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证반려동물과 보호자 모두를 위한 맞춤형 맵 / 커뮤니티 서비스
翻译准备中
正在加载完整 README。 以下为已保存的摘录。
"우리 아이랑 여기 갈 수 있을까?"에 답해 주는 반려동물 동반 여행 서비스입니다. 한국관광공사는 반려동물 동반 조건을 "5kg 이하 동반 가능(이동장 이용 필수)" 같은 문장으로 제공하는데, 멍냥맵은 이 문장을 읽어서 우리 아이의 몸무게, 맹견 여부, 준비물과 비교한 뒤 🟢 입장 가능, 🟡 조건부, 🔴 불가로 알려줍니다. 현장에 갔다가 입장을 거절당하는 일을 줄이는 게 목표입니다. 2026 관광데이터 활용 공모전 웹·앱 구현 부문, 지정과제 6번 출품작입니다. 배포 주소: https://meongnyangmap.vercel.app (출처: ⓒ한국관광공사) 같은 롯데월드타워라도 7kg 강아지는 조건부(소형견 조건은 맞지만 이동장이 없음), 28kg 강아지는 불가로 나옵니다. 판정 근거는 모두 관광공사 원문에서 가져옵니다. 처음에는 반려동물과 갈 수 있는 카페·식당 지도를 만들려고 했습니다. 그런데 데이터가 이 기획을 받쳐줄지 몰라서, 코드를 짜기 전에 API를 438번 직접 호출해 봤습니다(8월 29일, 오류 0건). 그래서 "어디에 있는지"를 보여주는 지도가 아니라, "우리 아이가 갈 수 있는지"를 알려주는 서비스로 방향을 바꿨습니다.查看完整 README ↗
"우리 아이랑 여기 갈 수 있을까?"에 답해 주는 반려동물 동반 여행 서비스입니다. 한국관광공사는 반려동물 동반 조건을 "5kg 이하 동반 가능(이동장 이용 필수)" 같은 문장으로 제공하는데, 멍냥맵은 이 문장을 읽어서 우리 아이의 몸무게, 맹견 여부, 준비물과 비교한 뒤 🟢 입장 가능, 🟡 조건부, 🔴 불가로 알려줍니다. 현장에 갔다가 입장을 거절당하는 일을 줄이는 게 목표입니다.
2026 관광데이터 활용 공모전 웹·앱 구현 부문, 지정과제 6번 출품작입니다.
배포 주소: https://meongnyangmap.vercel.app (출처: ⓒ한국관광공사)
같은 롯데월드타워라도 7kg 강아지는 조건부(소형견 조건은 맞지만 이동장이 없음), 28kg 강아지는 불가로 나옵니다. 판정 근거는 모두 관광공사 원문에서 가져옵니다.
| 항목 | 내용 |
|---|---|
| 데이터 | 전국 9,682곳, 동반 조건 9,690건, 캠핑장 3,118곳. 매일 새벽 3시에 자동으로 다시 받습니다 |
| 판정 로직 | 문장으로 된 조건을 읽는 파서와 판정기. 판정·영업시간 파서 테스트 146개 전부 통과 (대부분 실제 원문에서 뽑은 케이스) |
| 관광공사 API | 4개 서비스, 11개 오퍼레이션. 실제로 호출하는 것만 아래에 적었습니다 |
| 개발 | 2026년 8월 29일 시작, Claude와 함께 작업 (작업 방식) |
처음에는 반려동물과 갈 수 있는 카페·식당 지도를 만들려고 했습니다. 그런데 데이터가 이 기획을 받쳐줄지 몰라서, 코드를 짜기 전에 API를 438번 직접 호출해 봤습니다(8월 29일, 오류 0건).
| 확인한 것 | 그래서 한 것 |
|---|---|
| 전체 9,693건 중 8,647건(89%)이 쇼핑이었습니다. 열어 보니 약국, 안경원, 의원 같은 일반 쇼핑 데이터였고 동반 조건은 거의 비어 있었습니다 | 쇼핑은 기본 목록에서 뺐습니다 (필터를 켜면 보입니다) |
| 음식점은 72건뿐이었고, 그중 조건이 적힌 곳은 30% 남짓이었습니다 | 카페·식당 지도는 이 데이터로 만들기 어렵다고 보고 접었습니다 |
| 조건이 "5kg 이하 동반 가능(이동장 이용 필수)"처럼 문장으로 들어옵니다 | 과제에서 말하는 헛걸음이 바로 이 모호함 때문이라고 보고, 판정을 서비스의 중심에 두었습니다 |
그래서 "어디에 있는지"를 보여주는 지도가 아니라, "우리 아이가 갈 수 있는지"를 알려주는 서비스로 방향을 바꿨습니다.
제가 올린 커밋 126개 중 124개는 Claude와 같이 작성했습니다(2026-09-25 기준). 역할은 이렇게 나눴습니다.
| 제가 정한 것 | AI에게 맡긴 것 |
|---|---|
| 무엇을 만들지. 위 실측 결과를 보고 카페 지도를 접은 결정 | 실측 스크립트 작성과 결과 집계 |
| 되돌리기 어려운 규칙 4개 (CLAUDE.md) | 규칙 안에서의 구현, 리팩터링, 문서 정리 |
| 판정이 틀렸을 때 어느 쪽 피해를 더 무겁게 볼지 | 실제 데이터에서 테스트 케이스 추출, 기대값 교차 계산 |
| 예시 프로필을 없애는 것 같은 제품 판단 (5e8e71f) | 보안, 정확성, 규칙 준수 관점의 코드 리뷰 |
CLAUDE.md에는 코드만 봐서는 알 수 없고, 어기면 되돌리기 어려운 것 네 가지만 적었습니다.
판정 테스트의 기대값(초기 133건)은 Claude 세션 두 개를 서로 모르게 띄워서 각자 계산하게 하고, 둘이 같은 답을 낸 것만 썼습니다(tests/README.md의 '두 명의 검증자'). 한쪽은 정규식과 분기를 직접 따라가게 했고, 다른 쪽은 이 값이 틀리면 누가 헛걸음을 하게 되는지를 따져보게 했습니다. 의견이 갈린 11건은 테스트에 넣지 않았습니다.
사진·리뷰 기능을 붙인 뒤 보안, 정확성, 규칙 준수 관점으로 에이전트 18개를 나눠 리뷰를 돌렸고, 기능 테스트로는 드러나지 않던 문제가 나왔습니다(0d029dc).
| 문제 | 발견 경로 | 수정 |
|---|---|---|
대문자 8KG를 못 읽어서 28kg 개가 8kg 제한 숙소에 🟢로 나옴 | 실제 데이터 149종으로 만든 테스트 | 148종을 표로 정리하고 정규식 보강 (3eb5c3b) |
'불가(보조견만 가능)'이 🟡로 통과하고, '맹견 동반 불가'는 일반견까지 🔴로 막음 | 같은 테스트 | 같은 커밋 |
| 일일 한도 초과 응답이 JSON으로도 오는데 XML만 검사해서, 모든 장소가 "조건 정보 없음"으로 보임 | 한도에 걸린 날의 화면 | 두 형식 모두 오류로 처리. 0건이던 실패가 78건으로 드러남 (5b94006) |
| 8개씩 동시에 호출하면 오류 대신 정상 응답에 빈 결과가 옴 (서울 78건 전부) | 지역별 건수 대조 | 동시 호출 4개로. 서울 78/78, 부산 39/39, 경기 125/125 확인 (9ca0171) |
| "10kg 미만"을 "이하"로 읽어서 딱 10kg인 아이가 🟢로 나옴 | 전체 데이터를 다시 받는 과정 | 다시 받으면서 8,731건에 경계 정보가 채워져 해결 (4bd5a13) |
| 파서를 고친 뒤 첫 수집에서 141곳이 "조건 바뀜"으로 잘못 찍힘 (원문은 그대로) | 이전 스냅샷과 원문 대조 | 파싱 결과가 아니라 원문끼리 비교 (75ad3af) |
| 원천 데이터의 '사고 위험 요소' 545곳 중 394곳이 엉뚱한 내용 | "⚠ 사고 위험 요소: 전 견종 동반 가능"이라는 화면 문구 | 필드 이름이 아니라 내용을 보고 표시 문구를 고름 (03dc3ca) |
| 호출 기록 저장이 실패하면 재전송량이 계속 불어남 (1,200회 호출에 POST 701회) | 리뷰 후 재현 | 500행 단위 전송과 재시도 간격 추가. 같은 조건에서 POST 3회 (2fd84d6) |
속도도 재 보고 고쳤습니다. 목록을 서버에서 걸러 보내도록 바꿔서 서울 기본 화면은 1,008KB에서 24KB로, 전국 검색은 3MB에서 12KB로 줄었습니다(c133162).
detailPetTour2가 주는 조건은 코드가 아니라 문장입니다.
acmpyTypeCd "일부구역 동반가능"
acmpyPsblCpam "5kg 이하 동반 가능(이동장 이용 필수)"
acmpyNeedMtr "목줄 착용,반려동물 유모차 탑승,이동장(켄넬)사용"
parseRules()가 이 문장을 구조화하고, judge()가 프로필과 비교해서 세 가지 중 하나로 답합니다(lib/petTour.ts).
lib/cpamMap.ts). 표에 없는 값이나 나중에 새로 생긴 값은 정규식이 처리합니다.판정이 틀리는 경우는 두 가지이고, 피해 크기가 다릅니다.
🔴 못 가는데 '입장 가능' → 헛걸음. 이 서비스가 막으려던 일이 그대로 생깁니다
🟡 갈 수 있는데 '불가' → 기회 손실. 사용자는 틀렸다는 걸 알 방법이 없습니다
첫 번째 오류를 최대한 줄이려면 같은 입력에는 항상 같은 답이 나와야 하고, 판정 근거를 원문 한 줄까지 보여줄 수 있어야 했습니다. 그래서 LLM은 원문을 분석해서 규칙과 테스트를 만드는 데 쓰고, 실제 판정은 규칙이 하도록 했습니다. 판정 로직을 고치면 146개 테스트부터 통과시키고, 테스트 이름에는 어느 쪽 피해인지를 적어 두었습니다.
| 판정 | 화면 |
|---|---|
ok | ○ 입장 가능 |
cond | ✓ 조건부 가능 (무엇을 준비해야 하는지 함께 표시) |
no | 목록에서 숨김 (숫자로만 알려줌) |
npm install
npm run dev
.env.local 이 필요하다. 아래 환경변수 참고.
| 명령 | 하는 일 |
|---|---|
npm run dev | 개발 서버 |
npm run build | 프로덕션 빌드 |
npm test | 판정 로직 테스트 146개 |
npm run collect | 데이터 수집 → data/*.json (GitHub Actions 가 매일 03:00 KST 자동 실행) |
전체 구조는 ARCHITECTURE.md 에 있다. 작업 규칙은 CLAUDE.md.
lib/
kto.ts 한국관광공사 OpenAPI 클라이언트 (서버 전용)
petTour.ts 자연어 조건 파서 + 판정 엔진 ← 서비스의 핵심
cpamMap.ts 동반가능동물 148종 원문 → 조건 매핑표
camping.ts 캠핑장 판정 (animalCmgCl 기반)
curate.ts 핫플레이스 선별 + 지역 방문자 순위
catalog.ts 전국 장소 목록 (파일 우선, 사흘 넘으면 실시간)
pets.ts 판정 기준이 되는 반려동물 프로필
app/
page.tsx 멍냥맵 지도 (필터 / 목록 / 지도 / 상세 패널)
hotplace/ 핫플레이스 · 캠핑 (중메뉴)
community/ 커뮤니티 (Supabase)
api/ 서버 라우트: 아래 표 참고
data/ 배치가 받아둔 스냅샷. 빌드에 포함된다
tests/ 판정 로직 테스트 (케이스는 실측값에서 뽑음)
scripts/
collect.mts 일 배치: data/*.json 을 채운다
seed.mts Supabase 적재용. 현재 서비스 경로와 무관한 보조 스크립트
실제로 호출하는 것만 적는다. 주최측이 인증키로 호출 내역을 검증한다.
app/api/)| 오퍼레이션 | 서비스 | 어디서 | 캐시 |
|---|---|---|---|
ldongCode2 | KorPetTourService2 | /api/regions: 시도·시군구 | 1시간 |
lclsSystmCode2 | KorPetTourService2 | /api/categories: 분류체계 이름표 | 24시간 |
petTourSyncList2 | KorPetTourService2 | /api/places: 파일이 사흘 넘었을 때만 | 6시간 |
detailPetTour2 | KorPetTourService2 | /api/pet-rules: 파일에 없는 장소만 | 30분 |
detailCommon2 detailIntro2 detailInfo2 detailImage2 | KorPetTourService2 | /api/detail: 파일에 없는 장소만 | 24시간 |
전량 수집이 끝난 뒤로 detailPetTour2 와 detail* 은 평소 호출이 없다. 파일에서 나온다.
scripts/collect.mts)| 오퍼레이션 | 서비스 | 받는 것 |
|---|---|---|
petTourSyncList2 | KorPetTourService2 | 전국 장소 (1콜) |
detailPetTour2 | KorPetTourService2 | 동반 조건 (새 장소만) |
detailCommon2 detailIntro2 detailInfo2 detailImage2 | KorPetTourService2 | 상세 (새 장소만, 곳당 4콜) |
basedList | GoCamping | 캠핑장 (1콜) |
locgoRegnVisitrDDList | DataLabService | 시군구별 방문자 수 30일치 |
tatsCnctrRatedList | TatsCnctrRateService | 관광지 집중률 (향후 30일 예측) |
areaBasedList2 · searchKeyword2 · locationBasedList2 · areaCode2 · categoryCode2 는
현재 서비스 경로에서 호출하지 않는다. (areaCode2 · categoryCode2 는 scripts/seed.mts
에만 남아 있고, 이 스크립트는 화면·배치와 무관한 보조 도구다.)
locationBasedList2 는 좌표를 서버로 보내야 해서 일부러 쓰지 않는다 (CLAUDE.md 1번).
data/ 는 배치가 받아둔 스냅샷이고 빌드에 포함된다. 배포 후에는 서버에서 고칠 수 없어,
GitHub Actions 가 매일 새로 받아 커밋하고 그 커밋이 재배포를 부른다.
배치가 사흘 넘게 멈추면 lib/catalog.ts 가 실시간 조회로 넘어간다.
2026-09-25 스냅샷 기준 (매일 조금씩 바뀐다):
| 파일 | 건수 | 내용 |
|---|---|---|
places.json | 9,682 | 전국 장소 |
petRules.json | 9,690 | 동반 조건 (조건 있는 곳 9,684) |
details.json | 9,691 | 영업시간·휴무·전화·소개글·사진 |
camping.json | 3,118 | 캠핑장 (반려동물 가능 1,131) |
visitors.json | 269 | 시군구 방문자 순위 |
crowd.json | 399 | 관광지 집중률 예측 |
.env.local 은 git 에 올라가지 않는다.
| 이름 | 쓰임 |
|---|---|
KTO_SERVICE_KEY | 한국관광공사 OpenAPI 인증키(인코딩키). 서버 전용 |
NEXT_PUBLIC_KAKAO_MAP_KEY | 카카오맵 JavaScript 키. 브라우저로 나간다 |
SUPABASE_URL / SUPABASE_SERVICE_ROLE_KEY | 커뮤니티. RLS 우회 키라 서버 전용 |
KTO_MOBILE_APP 은 선택 (기본값 MeongNyangPass).
배포 환경(Vercel)은 대시보드의 Environment Variables 에 같은 값을 넣어야 한다.
GitHub Actions 는 KTO_SERVICE_KEY 를 리포지토리 시크릿으로 읽는다.
feature/kim: 자세한 것은 CLAUDE.md