Commit Graph

288 Commits

Author SHA1 Message Date
Haewon Kam
f01bc6cafc merge: feature/supporters-autobuild + feature/ai-sentiment-rubric 를 Product 1.0 한 줄기로 합침
Product 1.0 범위는 진단 + 서포터즈 초안(haewon 결정).

브랜치 확인 결과 핸드오버 §1 의 미확인 항목 두 건은 이미 해결 상태였다.
리드 CTA(DiscoveryLeadModal·discovery_leads 마이그레이션)와 AEO/GEO v2 기준표는
셋 다 main 에 있고 blob 이 동일하다. feature/discovery-url-cta 는 main 대비
ahead 0 / behind 22 인 낡은 포인터라 머지 대상에서 뺐다.

supporters/ 정본은 메인 쪽(뷰 수작업 샘플)으로 정했다(haewon 결정).
겹친 22개 파일 중 실제로 다른 것은 9개였고 전부 메인 쪽을 취했다.
layout-baseline.json 은 Base.astro 가 내는 언어 전환 링크 모양(a.lang-switch)과
짝이라 같은 쪽으로 가져왔다.

Productize 쪽에만 있던 두 가지를 정본으로 옮겼다.
- GA4 태그: site.json 의 ga4MeasurementId 가 G-형식일 때만 삽입한다.
  값이 없으면 스크립트가 아예 나가지 않는다. 키 이벤트 이름은
  data/ai_channels.json 의 conversion_events 와 맞춘다.
- 영문 법적 고지: 지원 관계·부작용 고지는 의료법 56조 대상이라 임의 번역하지 않는다.
  i18n.ts 에 병원 승인 없는 영문 번역이 들어 있어 푸터에서 쓰지 않도록 했다.
  site.json 의 sponsorNoticeEn · factSheet 의 sideEffectNoticeEn 이 채워지기 전까지
  영문 화면은 한국어 원문과 확인 대기 표기를 함께 낸다.

검증: astro build 32페이지, 게이트 41/41 통과, check.mjs 오류 0건
(경고 23건은 기존 건으로 site.sponsorNotice 미설정 18건과 원고 수치 한정 5건),
루트 tsc --noEmit 0 에러. GA4 는 임시 측정 ID 로 삽입·미삽입 양쪽을 확인하고 원복했다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 14:34:47 +09:00
Haewon Kam
6c3e2888a7 docs: AI Discovery Product 빌드 핸드오버 (제품 여정·상태, 브랜치·배포 지도, 빌드 순서, 결정 대기, 함정)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:22:58 +09:00
Haewon Kam
c044546614 docs: 서포터즈 빌드 절차 문서를 제품 핸드오버의 하위 문서로 표기
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:22:18 +09:00
Haewon Kam
99195f09f3 docs: 다음 세션 핸드오버 (Product build 절차·격리 구조·결정 대기·함정) + 오라클 핸드오버 커밋
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:14:46 +09:00
Haewon Kam
008411b929 feat(supporters): 워커 planner 단계에 관리 문장 필터 (효과 주장·홍보·정형 고지·표 조각·재수술 조언 제외) + 세부 시술명 접두
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:10:17 +09:00
Haewon Kam
5263593816 style(supporters): 태블릿·모바일 헤더 규칙 이식 (브랜드+언어 전환 한 줄, 메뉴 가로 스크롤) · 로고와 메뉴 겹침 해결
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 14:07:10 +09:00
Haewon Kam
0108fe1ff1 chore(supporters): 원진 큐레이션 기준 좌표를 네이버 지역검색 결과로 갱신
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 13:46:39 +09:00
Haewon Kam
0cc37b1b89 feat(supporters): 원진 큐레이션 장소 브리프(briefs/wonjin/planner.places.json), 플래너 추천 장소 설명을 데이터 유무에 따라 표기
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 13:11:51 +09:00
Haewon Kam
93509bf9b3 chore(supporters): 플래너 추천 장소 설명을 관광공사 데이터 유무에 따라 표기
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 13:11:25 +09:00
Haewon Kam
620b2cda59 style(supporters): 지도 출처 줄을 행 밖으로 옮겨 지도 상자와 카드 아래선을 맞춤
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 11:52:37 +09:00
Haewon Kam
94d7edec45 style(supporters): 지도 출처 줄을 행 밖으로 옮겨 지도 상자와 카드 아래선을 맞춤
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 11:51:53 +09:00
Haewon Kam
df6ad3bbd2 style(supporters): 오시는 길 지도를 카드 높이에 맞춰 늘림
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 11:49:37 +09:00
Haewon Kam
d13ac35365 style(supporters): 오시는 길 지도를 카드 높이에 맞춰 늘림 (열 비율 1.5:1, invalidateSize)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 11:48:49 +09:00
Haewon Kam
ed8f65030d feat(supporters): 오시는 길 지도·길찾기(VisitMap) 템플릿 반영, 워커 tourism 단계가 factSheet.geo 좌표 기록
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 11:38:53 +09:00
Haewon Kam
587462552b feat(supporters): 오시는 길 지도·길찾기 (VisitMap) 방문 안내와 영어 홈에 추가
- OpenStreetMap 타일 + Leaflet(cdnjs) 지도, 병원 핀, 주소 복사, 문의 전화, 네이버·카카오 길찾기(영어 화면은 구글 길찾기 추가). 벤치마크 2026-09-11
- 좌표는 factSheet.geo(운영 기록 source 는 화면에 내지 않음), 없으면 관광공사 수집 메타, 둘 다 없으면 지도 없이 주소·버튼만

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 11:38:07 +09:00
Haewon Kam
6b01cc9f7b chore(supporters): 플래너 검증·출처 줄을 Productize 템플릿과 동일하게 (관광 데이터 없을 때 건너뜀)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 11:28:05 +09:00
Haewon Kam
aa5b05227f feat(supporters): 회복 일정 플래너를 템플릿·워커에 통합 (/plan·/en/plan), /recovery·/stay 를 /plan 으로 정리
- 템플릿: Planner.astro, lib/plan.ts·tour.ts, styles/plan.css, planStrings, pages plan·en/plan·404. Base 내비 회복 일정 → /plan, 언어 짝 /plan↔/en/plan, 옛 주소 리다이렉트(vercel.json), 사이트맵
- 워커 planner 단계(recovery 다음): scripts/build_planner_data.mjs 가 업종별 기본 규칙표(scripts/template/planner/procedures.plastic|derm.json)에 병원 시술 페이지 원문(recoveryNotes)을 matchKeywords 로 붙이고, 장소는 briefs/<clinic>/planner.places.json(큐레이션) 또는 범용 기본표(관광공사 기준 좌표)로 만든다
- 브리프: viewclinic·oracle 큐레이션 장소. 빈 템플릿(관광 데이터 없음)도 빌드·검증 통과(plan.test 14건)
- 이전 세션의 미커밋 작업(피부과 수집·OCR·게이트·언어 스위치, stay 페이지 제거)도 이 커밋에 함께 들어감. docs/prd 변경은 제외

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 11:27:59 +09:00
Haewon Kam
65fb9be9c6 refactor(supporters): 플래너 히어로의 시술 목록·기준점 문구를 데이터(procedures.json 라벨, places.json origin)에서 읽음 · 병원별 이식 준비
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 11:20:06 +09:00
Haewon Kam
83b8343262 feat(supporters): 회복 일정 플래너에 한국관광공사 TourAPI 데이터 합침 + 옛 주소 리다이렉트 + 404 페이지
- src/lib/tour.ts: 사전 수집 JSON(medicalTourismKo/medicalTourism)을 추천 후보로 변환. 관광지·문화시설→관광, 쇼핑, 음식점(일반식 단계에서만), 숙박→숙소. 사우나·스파는 회복기 금지라 제외. 거리로 외출 등급(600m·3km)
- 큐레이션(places.json) 1순위, TourAPI 2순위 가점. 타임라인 추천에 이동 시간 라벨과 '관광공사' 표시
- 체류 기간과 겹치는 행사 섹션(가까운 순 6곳, 자유 외출 단계 도달일 표시), 자유 외출(L3) 날에 행사 1건 추가
- 숙소 그리드에 TourAPI 숙박 가까운 순 6곳 추가(예약 검색은 영문 이름으로)
- scripts/fetch_medical_tourism.py: Productize 브랜치의 수집 스크립트 가져옴(화면 경로 주석 갱신)
- vercel.json: /recovery·/stay·/en/recovery·/en/stay → /plan·/en/plan 영구 리다이렉트. src/pages/404.astro 사이트 스타일 404
- 테스트 14건(어댑터·우선순위·유동식 제외·축제)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 11:01:32 +09:00
Haewon Kam
f9e91d3305 chore(public): 뷰성형외과 영문 AEO/GEO 보고서 정적 배포 (reports/viewclinic/global-en-2026-09-10)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 09:51:14 +09:00
Haewon Kam
24dbe03471 docs(reports): 뷰성형외과 영문 사이트 외국인 관점 AEO/GEO 진단 보고서 2026-09-10
- 영문 60문항 질문뱅크(7군) + Perplexity/OpenAI(뉴욕) 실측 러너 scripts/run_question_bank_en.py
- 자동 채점 + 사람 보정 → v1.0 64/B · AEO 65/B · GEO 72/B (국문 54/C · 42/C · 56/C)
- HTML/PDF 보고서 빌더(Playwright), 서술 narrative_ko.json, README 폴더 안내 추가

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 09:50:33 +09:00
Haewon Kam
e47c5e2fc6 spacing(supporters): 회복 일정 페이지 간격을 전역 규격에 맞춤
- 히어로 통계 위 이중 여백 제거(섹션 머리 1.6rem만), 숫자 크기 전역 .stat b 그대로
- 다크 날짜 카드 패딩을 전역 .stat(1.5rem 1.6rem)으로, 6장을 3×2 고정
- 타임라인 행 간격 1.1rem·행 패딩 1rem 1.2rem(영상 목록 .vlist/.vitem 규격), 숙소 그리드 간격 1.25rem(.grid 규격), 범례 음수 마진 제거
- 모바일: 전역 모바일 규격과 충돌하던 히어로·섹션·카드 패딩 덮어쓰기 제거

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 17:02:29 +09:00
Haewon Kam
295401f356 en(supporters): 영어 홈에서 상담 언어·통역 문구 제거 (haewon)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 17:00:17 +09:00
Haewon Kam
c750cfd6d9 i18n(supporters): 전역 언어 전환(KO/EN)을 헤더 하나로 통일, 영어 홈 /en 신설
- 헤더 lang-switch: 현재 페이지의 상대 언어 페이지로 이동(/ ↔ /en, /plan ↔ /en/plan, 그 외는 언어 홈). 구조 기준선 갱신(haewon 승인)
- 영어 페이지에서는 메뉴·CTA·배너·뒤로가기·푸터(지원 고지·부작용 고지·링크·주소)까지 함께 전환. lib/i18n.ts, data/factSheetEn.json
- /en 영어 홈: 히어로, Start Here 카드, 병원 숫자, 오는 길(공항 경로·진료시간), 병원 사실, 원칙. 한국어 글은 번역 없이 링크만 안내
- 플래너의 페이지 내 언어 토글 제거, Step 1은 국적만. sitemap·hreflang 추가

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 16:38:41 +09:00
Haewon Kam
378ca7e7cd mobile(supporters): 회복 일정 플래너 반응형 정비 + 사이트 헤더 모바일·태블릿 대응
- 헤더(≤900px): 첫 줄 브랜드·상담 예약, 둘째 줄 메뉴 가로 스크롤. 메뉴 6개가 두 줄로 겹치던 문제를 DOM 변경 없이 CSS만으로 해결(구조 지문 유지)
- 플래너 모바일: 히어로 통계·핵심 날짜 2열, 시술 그리드 2열, 타임라인 날짜 머리 가로 배치, 숙소·예약 카드 1열, 입력 16px(iOS 확대 방지)
- 하단 고정 요약 바: 결과가 있고 결과 섹션이 화면 아래에 있을 때만 표시. 시술명, 입국→출국, 박 수, 일정표 보기 버튼
- 검증: 1280 창 안 390/768px 아이프레임 하네스로 확인 (헤드리스 크롬은 창 최소 폭 때문에 400px 직접 캡처가 부정확)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 16:20:39 +09:00
Haewon Kam
27e77add65 design(supporters): 회복 일정 플래너를 홈·영상 페이지와 같은 섹션 리듬으로 재구성
- 다크 히어로(세리프 그라디언트 제목, 언어 알약, 글래스 통계 4장) → 틴트(Step 1~3 카드 그리드) → 다크(핵심 날짜 6개 글래스 통계) → 라이트(체류 확인·회복 규칙·외출 단계 카드) → 틴트(타임라인 흰 카드) → 다크(숙소·항공·상담·저장 카드)
- 데이터 타일의 웜 그라디언트 제거(가드레일: CTA 카드 한 장에만). 전역 .kpi 규칙과 충돌하던 클래스명 교체
- 영문 세리프 제목 + 한글 부제로 위계, 날짜·박 수는 Playfair 숫자
- 빈 상태(시술·날짜 미선택) 다크 섹션 추가

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 16:10:29 +09:00
Haewon Kam
e40f9ceb94 feat(supporters): 회복 일정 플래너 /plan · /en/plan · 시술별 회복 규칙표, 큐레이션 장소, 예약 딥링크, 헤더 내비 연결
- src/pages/plan.astro, src/pages/en/plan.astro: 한국어·영어 페이지, hreflang 상호 연결
- src/components/Planner.astro: 5단계 흐름(언어·국적 → 시술·수술일 → 선호 → 일정표 → 예약·저장), 브라우저 안 계산, URL 해시 공유, ICS 저장
- src/lib/plan.ts: 입국 권장일·출국 가능 최소일·외출 등급·식사 단계·추천 점수·딥링크·ICS 순수 함수
- src/data/procedures.json: 시술 8종 규칙표. 값마다 clinic/provisional 표시, 병원 확인 전 잠정값은 화면 배지
- src/data/places.json: 신논현역 기준 큐레이션 31곳 (구글 지도·예약 사이트 검색 링크만)
- src/data/planStrings.json: UI 문자열 ko/en
- scripts/gate/plan.test.mjs: 계산·데이터 정합성 검증 11건
- Base.astro: lang·alternates prop, 내비 '회복 일정', 푸터 링크. 구조 기준선 갱신(haewon 승인)
- visit.astro: 플래너 진입 CTA 카드. sitemap에 /plan, /en/plan 추가
- 설계 근거: docs/INFINITH_Viewclinic_Supporters_Site_Design_v0.2.md §13

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-10 16:00:33 +09:00
Haewon Kam
5c08fa97ab chore(supporters): 구조 기준선 갱신 — 네비게이션 "주변 안내" 항목 승인 (haewon)
한국어 /stay 로 가는 길을 만들려고 헤더 네비에 항목 하나를 추가했고, 게이트가
LAYOUT_CHANGED 로 잡고 있었다. 언어 스위치는 EN/KO 만 오가므로 다른 페이지에서
/stay 로 갈 길이 없어 네비 항목이 필요했다. haewon 승인 후 --update-layout 으로
기준을 갱신했다.

/index.html 269 → 270 · /posts/anesthesia-choice.html 226 → 227 · /posts.html 252 → 253
경고 25건 → 23건. 남은 것은 이전부터 있던 DISCLOSURE_TOP_MISSING 18건과
NUMERIC_NO_QUALIFIER 5건이다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 14:47:53 +09:00
Haewon Kam
67f1cb8295 feat(supporters): 한국어 /stay 신설 — 언어 스위치의 짝을 맞춤
언어 스위치의 KO 가 /visit 으로 가고 있었다. 같은 내용의 한국어판이 아니라 짝이
아니었다. /stay 를 만들어 /stay ↔ /en/stay 로 잇는다.

수집 (scripts/fetch_medical_tourism.py --lang ko)
- 국문은 ContentTypeId 가 다르다(관광지 12·문화시설 14·숙박 32·쇼핑 38·음식점 39).
  다국어 코드로 부르면 엉뚱한 것이 온다.
- 국문 서비스는 KorService2 로 붙고, 국문 사진 폴백은 건너뛴다(국문이 원본이다).
- 출력은 medicalTourismKo.json.

국문이 훨씬 두껍다
  전체 123곳(영문 101) · 도보 5분 이내 13곳(영문 2) · 걸어갈 수 있는 곳 66곳(영문 25)
  설명문 146/147 · 사진 147/147
국문 관광지에는 의료관광 등록업소가 섞이지 않아 A02020500 필터가 걸리지 않는다.
영문에서 반경 5km 100건 중 92건이 병원·에이전시였던 것과 대비된다.

화면 (supporters/src/pages/stay.astro)
/en/stay 와 같은 구조에 한국어 문구를 넣었다. 이동 시간 라벨은 데이터에 영문으로
들어 있어 화면에서 만든다(도보 N분 / 차로 N분). 날씨 상태도 한국어로 옮겼고,
검색 링크는 네이버로 보낸다. 식이·회복 안내는 site.json 의 dietGuideKo /
recoveryStagesKo 를 쓰며, 없으면 병원 확인 대기로 둔다.

라우팅
- Base.astro PAIRS 에 '/stay': '/en/stay' 등록. 스위치가 서로를 가리킨다.
- 한국어 네비게이션에 "주변 안내" 추가. 스위치는 EN/KO 만 오가므로 다른 페이지에서
  /stay 로 갈 길이 없었다. 이 항목 추가로 LAYOUT_CHANGED 경고 2건이 남아 있으며
  haewon 승인 전까지 기준선을 갱신하지 않는다.
- 사이트맵에 /stay 추가.

템플릿은 같은 코드에 빈 데이터 스캐폴드를 둔다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 14:46:49 +09:00
Haewon Kam
b92f29c958 chore(supporters): 구조 기준선 갱신 — 한국어 페이지 헤더의 언어 스위치 승인 (haewon)
/en/stay 로 가는 길을 만들려고 Base.astro 에 언어 스위치를 넣으면서 한국어 페이지
헤더 구조가 바뀌었고, 게이트가 LAYOUT_CHANGED 로 잡고 있었다. haewon 승인 후
--update-layout 으로 기준을 갱신했다.

/index.html 266 → 269 · /posts/anesthesia-choice.html 223 → 226 · /posts.html 250 → 252
셋 다 늘어난 것은 div.langswitch 와 그 안의 KO/EN 링크다.

경고 26건 → 23건. 남은 것은 이전부터 있던 DISCLOSURE_TOP_MISSING 18건과
NUMERIC_NO_QUALIFIER 5건이다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 14:37:33 +09:00
Haewon Kam
2fc3f93163 fix(supporters): 동선 지도를 실제 OpenStreetMap 타일로 교체 + 핫링크 차단 대응
지도가 회색 바탕에 점만 찍혀 있어 어디인지 알 수 없었다. OSM 타일을 좌표로 직접
깔고 그 위에 핀을 얹었다. 지도 라이브러리는 부르지 않는다.
- Web Mercator 로 lat/lng → 월드 픽셀을 계산하고, 모든 지점이 여백 안에 들어오는
  가장 확대된 배율을 고른다(뷰성형외과 동선은 z=15).
- 타일은 img 가 아니라 CSS 배경으로 둔다. 장식 요소이고, 지도의 뜻은 감싸는 요소의
  aria-label 이 전한다. 스크린리더가 타일 조각을 하나씩 읽지 않는다.
- OSM 정책에 따라 "© OpenStreetMap contributors" 를 표기한다.

사진 핫링크
- 모든 사진에 referrerpolicy="no-referrer" 를 넣었다. 네이버 썸네일 CDN 이
  리퍼러를 보고 403 을 준다. 서버에서 검사할 때는 리퍼러가 없어 통과해 놓치기 쉽다.
- 사진 alt 를 채웠다. npm run build 의 접근성 게이트가 빈 alt 를 오류로 잡는다.
  로컬에서 astro build 만 돌려 게이트를 건너뛴 탓에 배포에서 처음 걸렸다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 14:01:16 +09:00
Haewon Kam
e32633e9a6 feat(supporters): /en/stay 를 참고 사이트 수준으로 다시 지음 — 설명문·이동시간·계절축제·동선·날씨
haewon 이 준 참고 사이트(스테이,머뭄)의 연동 범위에 맞춰 다시 만들었다. 앞서 만든 것은
거리순 표였고, 실제로 필요한 것은 설명문과 이동 시간이 붙은 카드, 계절로 묶은 축제,
시간표가 있는 동선이었다.

수집 (scripts/fetch_medical_tourism.py)
- detailCommon2 의 overview 를 가져온다. locationBasedList2 는 설명문을 주지 않아
  카드에 이름과 주소만 남았다. 123/125 건 확보.
- 이동 시간을 낸다. 참고 사이트 표기를 역산해 도보는 max(1, round(m/80)), 차는
  직선거리 km x 1.2 로 맞췄다(135m→2분, 566m→7분, 25km→30분). 2km 까지 도보로 보고,
  짧은 거리의 차 시간은 주차·신호 때문에 의미가 없어 최소 5분으로 둔다.
- 축제를 계절로 분류하고, 도보 시간 구간별 건수를 누적으로 집계한다.

사진 (125/125, 전부 실제로 열리는 것 확인)
목록 API 의 firstimage 만 쓰면 38건이 비었다. 폴백을 넷으로 걸었다.
  1) detailImage2 — 이미지 전용 오퍼레이션. 15건 회수(도산공원 7장이 여기 있었다)
  2) 국문 서비스 KorService2 — 영문 항목에 없어도 국문 항목에 있다. 10건
  3) 업체 공식 홈페이지 og:image — 2건
  4) Naver 이미지 검색 API — 11건
og:image 는 실제로 열어 보고 쓴다. 이미지가 아니거나 인스타 CDN 처럼 핫링크를
403 으로 막으면 화면에서 빈 칸이 되기 때문이다.
imageSource 를 항목마다 남겼다. naver 출처는 제3자 저작물이므로 내부 시연 범위이며,
공개 배포 전에는 걷어내거나 라이선스 있는 사진으로 교체해야 한다(haewon 판단).

화면 (supporters/src/pages/en/stay.astro)
- Around the clinic: 도보 시간 누적 필터, 범주별 카드, 사진 위 이동시간 배지, 설명문,
  공식 홈페이지가 있으면 링크하고 없으면 검색으로 보낸다.
- Festivals: 계절 탭.
- Shaping your days: 좌표로 그린 인라인 SVG 지도와 시간표. 외부 지도 라이브러리를
  부르지 않는다. 시각은 가정이며 화면에 그렇게 적었다.
- 오늘 날씨: Open-Meteo, 키 불필요. 빌드가 아니라 브라우저에서 받는다. 정적 빌드에
  넣으면 배포 시각의 날씨가 굳는다. 못 받으면 블록을 통째로 숨긴다.
  문구는 이 페이지의 목록에만 연결한다. 무엇을 해도 되는지는 의학 판단이라 말하지 않는다.
- 섹션 점프 바(글래스, 스티키) + IntersectionObserver 스크롤 스파이.

고친 것
- 항목마다 붙던 KO 태그를 헤더 언어 스위치 하나로 바꿨다. 짝이 있는 페이지는 서로 잇고
  없으면 그 언어의 입구로 보낸다. 영문 페이지가 늘면 PAIRS 표에 줄만 추가한다.
- .chip 클래스가 이미 있어 홈·뉴스룸·영상 페이지를 덮어쓰고 있었다. 새 스타일을
  .stay 아래로 모두 가뒀다.
- factSheet 에 영문 주소(fullEn)와 우편번호를 넣었다. 근거는 뷰성형외과 자신의
  한국관광공사 등재 항목(contentid 3364779)이며 fullEnSource 에 적었다.

템플릿은 같은 코드에 빈 데이터 스캐폴드를 둔다. 뷰성형외과 데이터가 새 병원 빌드로
새면 안 된다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 13:51:28 +09:00
Haewon Kam
a807d5dd9c refactor(supporters): 의료관광 연결을 /discovery 에서 서포터즈 사이트 /en/stay 로 옮김
붙일 자리를 잘못 잡았다. /discovery 는 INFINITH 제품의 진단 화면이고 병원마다 쓰는
범용 도구다. 외국인 환자가 보는 페이지는 병원 서포터즈 사이트다. 그쪽으로 옮겼다.

옮긴 것
- src/components/discovery/MedicalTourismPanel.tsx, src/types/medicalTourism.ts,
  src/data/medicalTourism.json 삭제. DiscoveryReportPage 원복.
- supporters/src/pages/en/stay.astro 신설. 독립 URL 과 자체 WebPage JSON-LD 를 가져
  AI 인용 단위가 된다. sitemap 에 등록하고 /visit 에서 hreflang 링크로 잇는다.
- 수집 스크립트 출력을 supporters/src/data/medicalTourism.json 으로 바꿨다.

영문 페이지 지원
- Base.astro 에 lang prop 추가(기본 ko). html lang · og:locale · 머리말 · 꼬리말이
  따라 바뀐다. 레이아웃을 하나로 유지해 한국어 페이지 동작은 그대로다.
- 의료광고 고지(지원 관계·부작용)는 규정 대상이라 임의로 번역하지 않는다. 병원이
  sponsorNoticeEn / sideEffectNoticeEn 을 확정하기 전에는 한국어 원문을 그대로 싣고
  영문 문구가 확인 대기임을 밝힌다.
- factSheet 에 nameEn / shortNameEn / shortNameEnSource 추가. 뷰성형외과 값의 근거는
  병원 자신의 영문 도메인 viewplasticsurgery.com 이며 한국관광공사 등재명도 같다.

페이지가 만들지 않는 것
- 평점·리뷰·영업시간: TourAPI 미제공이라 싣지 않는다.
- 식당의 회복 적합성: 의학 판단이라 병원이 확정한 영문 문구(site.json dietGuideEn)만
  싣는다. 확인 전에는 어떤 식당도 적합으로 표시하지 않는다고 페이지에 적는다.
- 회복 단계 일수: 병원 확정값(recoveryStagesEn). 단계는 이동 거리로만 정의한다.
- 하단에 이 페이지가 답하지 못하는 것 네 가지를 그대로 적었다.

템플릿 동기화
- templates/supporters-astro 에 같은 변경을 넣되 데이터는 빈 스캐폴드로 둔다.
  뷰성형외과 factSheet 와 관광 데이터가 새 병원 빌드에 새어 들어가면 안 된다.
  빈 데이터로 빌드해 6개 범주가 "No English listings" 로 나오는 것까지 확인했다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 11:42:46 +09:00
Haewon Kam
5d3ce40f77 feat(discovery): 의료관광 연결 섹션 — TourAPI 다국어 주변 정보 + 회복 동선
/discovery/:id 에 외국인 환자용 주변 정보를 붙였다. 숙박·음식점·웰니스·관광·문화·
쇼핑·축제 125건과 이동 반경 기준 회복 동선. 다음 뷰성형외과 미팅용 프로토타입이다.

데이터 (scripts/fetch_medical_tourism.py → src/data/medicalTourism.json)
한국관광공사 TourAPI 영문(EngService2) 사전 수집. 실시간 호출이 아닌 이유는 영문
커버리지가 얇아 필터링이 많이 필요하고, 시연 중 외부 API 상태에 화면이 종속되지
않게 하기 위해서다. 좌표는 Naver 지역검색 실측(뷰성형외과의원, 봉은사로 107).

실측으로 드러난 것과 대응
- 영문 관광지(76)의 대부분이 관광지가 아니다. 반경 5km 100건 중 92건이 분류코드
  A02020500 "Medical Tourism Sites"(categoryCode2 로 확인)이며 병원과 유치
  에이전시다. 제목 키워드로는 "하이안과", "닥파인더코리아" 를 놓쳐 코드로 걸렀다.
  거리순 상위 100건이 거의 다 여기라 페이징을 넣어야 실제 관광지가 나온다.
- 스파·찜질방(A02020300/400)은 회복 여정에 맞아 wellness 로 분리했다.
- 영문 축제는 areacode 필드가 비어 있어 areaCode 필터가 0건을 반환한다. 좌표
  거리로 걸렀다.
- TourAPI 이미지 URL 이 http 라 https 사이트에서 혼합 콘텐츠로 차단된다. 수집
  단계에서 https 로 올린다.
- 반경을 목적별로 나눴다. 회복기에 자주 가는 숙박·식사는 5km, 관광은 10km.

만들지 않은 것
- 평점·리뷰·영업시간: TourAPI 미제공이라 null 로 두고 화면에 "미연동" 으로 적었다.
  Google Places 키가 아직 비어 있다(신청 중).
- 수술 전후 식이 적합성: 의학 판단이라 병원 입력만 쓴다. ClinicInputsPanel 에
  diet_guide 항목을 더해 supporter_inputs 로 받고, 입력 전에는 "병원 확인 대기"
  로 둔다. 개별 식당의 적합 여부를 추론하지 않는다.
- 회복 단계가 며칠째인지: 병원 입력(recovery). 화면의 단계는 이동 반경으로만
  정의해 의학적 함의를 담지 않는다.
- 한계 4가지를 meta.limits 에 담아 섹션 하단 "측정 가능 범위" 에 그대로 띄운다.

FilledIcons 에 Bed·Fork·Spa·MapPin·Ticket·Bag·Theater 7종 추가(라인 아이콘·이모지
금지 규칙에 따라 채움 SVG).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 11:31:55 +09:00
Haewon Kam
b2caef9d02 docs(handover): 2026-09-09 진행분 반영 — 감성 1차 보정 완료, 남은 것은 2차 보정과 GA4 실연결
§2 각 항목에 진행 상태를 붙이고 결과 요약표를 넣었다. §4 함정에 세 줄을 더했다
(--calibration 버그 수정, 재판정 시 --out 처리, 언급 탐지를 LLM 에 맡기지 않는다).
§5 에 monthly_ai_measure.py 명령을 넣었다. §3-1 을 오늘 결과로 다시 썼다.

두 체크아웃 모두 푸시하지 않았고, 메인 체크아웃은 feature/ai-sentiment-rubric
브랜치에 있다. 문서에 적어 두었다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 10:54:52 +09:00
Haewon Kam
501d6002c6 docs(prd): 의료관광 허브 PRD v0.2 — 앵커의 병원 소개 역량 반영
2026-09-09 haewon 전달. 뷰성형외과 원장이 다른 병원 네트워크·파트너십이 많아
병원을 유치할 수 있다고 밝혔다. 명단·수·관계 단계가 확인되지 않았으므로 사실이
아니라 확인 대상으로 적었다.

- §04: "앵커의 병원 소개 역량이 큰 경우" 카드. 구조 판단(IP 귀속·중립성)은
  소개 규모와 무관하며 바뀌는 것은 소개 목표 수치와 그 대가라고 정리했다.
  앵커 계약 조항 5개(소개 목표 수치화, 성과 연동 대가, 소개 병원의 AIO2O
  직접 계약, 노출 우대 배제, 앵커 이탈 시 병원 계약 존속)와 확인 질문 4개
- §05: 의료법 27조 3항(영리 목적 환자 소개·알선·유인 금지) 확인 행. 병원 간
  상호 소개 관계를 허브로 옮길 때의 적용 여부는 변호사 확인 항목이다
- §08: 1단계 온보딩을 "최소 2~4곳, 앵커 소개 명단 확인 후 재산정" 으로.
  CEO 결정 (1)에 소개 목표·성과 연동·직접 계약 원칙·노출 우대 배제 추가
- §10: 앵커 의존 리스크(공급이 개인 관계에 붙는다), 미결 2건 추가

v0.1 은 그대로 두었다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 10:54:05 +09:00
Haewon Kam
8776a15183 feat(ga4): AI 유입 트래픽 연동 뼈대 + 리포트 "측정 가능 범위" 절
2026-09-08 작업분. GA4 에서 AI 답변엔진 유입을 채널로 갈라 보는 뼈대를 세웠다.

- data/ai_channels.json: AI 답변엔진 리퍼러 목록(채널 그룹 정의의 근거)
- scripts/ga4_ai_traffic.py: GA4 Data API 로 AI 유입을 뽑는 러너. --mock 으로 합성
  데이터 검증까지 마쳤다. 실제 속성 연결은 GCP 계정이 정해진 뒤다
- supporters/src/layouts/Base.astro + 템플릿 site.json 2곳: ga4MeasurementId 태그.
  쿠키 고지 배너 결정 전까지 미리보기에는 ID 를 넣지 않는다
- scripts/build_discovery_report.ts: Integrity 절에 "측정 가능 범위" 를 넣어
  무엇을 재고 무엇을 못 재는지 리포트가 스스로 밝히게 했다
- 원진 진단 리포트 v2.1(HTML·PDF) 재생성분

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 10:53:54 +09:00
Haewon Kam
2eb3d5cd06 feat(sentiment): 감성 판정 기준표 v0.3 — 1차 보정 반영, 결정론적 언급 탐지기, 월간 실측 체인
haewon 보정 라벨 29건으로 1차 보정을 마쳤다. sentiment 일치율이 75%로 기준선 80%에
미달해 불일치 7건에서 규칙 R1~R5를 뽑아 기준표와 판정기 프롬프트에 넣었다.

규칙 (기준표 §2)
- R1 결론 단락이 개별 항목보다 우선한다
- R2 mixed 는 긍정과 부정이 대등하게 병존할 때만
- R3 "후기 수가 많다"는 규모 서술이며 긍정 평가가 아니다
- R4 평가 축이 있는 목록에 포함되면 positive
- R5 강점 서술은 출처가 병원 홍보라도 positive

R4-a(목록에서 결론이 대상 병원을 빼면 positive 아님)와 R6(결론 없는 카탈로그는
neutral)은 시험 투입 후 철회했다. 일치율이 93%에서 89%로 떨어졌다. 하나 고치면
하나 깨진다. n=29 에서는 과적합이므로 R1~R5 에서 멈춘다.

결정론적 언급 탐지기 (기준표 §2-1, mention_kind)
sentiment 를 매기기 전에 상호 존재를 정규식으로 먼저 판정하고, 판정기가 언급이라
해도 탐지기가 없다고 하면 not_mentioned 로 덮는다. 언급 수가 모든 비율의 분모다.
- URL 을 먼저 지운다. news.nate.com/view/... 의 "view" 를 언급으로 세던 오탐 3건 제거
- "리뷰"의 "뷰" 처럼 다른 낱말의 일부인 약칭을 뺀다. G-04 오탐 제거
- 한글 상호의 음절 사이 공백을 허용한다. "뷰 성형외과" 미탐지 2건 해소
언급 84 → 83, 약한 언급 3 → 1.

수치 (뷰성형외과 240건)
감성 점수 53.6 → 58.4. 약한 언급 1건 제외 시 57.9. mixed 10 → 0.
haewon 라벨 대비 일치율 93%는 같은 표본으로 규칙을 고친 값이라 확정 근거가 아니다.
기준표 확정은 새 30건 2차 보정으로 한다. 리포트와 요약 JSON 에 confirmed=false 로 적었다.

월간 실측 체인 (scripts/monthly_ai_measure.py, 핸드오버 §2-4)
질문 뱅크 러너 → 감성 판정 → 리포트 → supporter_builds.report.sentiment 를 한 명령으로
묶었다. 보정은 사람 게이트이므로 체인에 넣지 않았다. 질문 뱅크 러너가 아직
뷰성형외과 전용이라 다른 병원으로 넓히려면 러너를 먼저 매개변수화해야 한다.

버그 수정
- --summary 를 --calibration 없이 돌리면 §7 생성에서 죽던 문제. 핸드오버가 권장하는
  명령이 그대로 터졌다(--calibration 은 haewon 라벨을 지우므로 빼야 한다)
- 결과 jsonl 의 rubric 필드와 리포트 머리말의 기준표 버전이 v0.1 로 하드코딩돼 있었다

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 10:53:32 +09:00
Haewon Kam
4e73798cce fix(supporters): collect_news 가 site.json 을 값이 바뀔 때만 다시 쓴다 (포맷만 바뀌는 diff 방지)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 14:14:42 +09:00
Haewon Kam
484601b0f5 feat(supporters): 뉴스룸 워커 단계 + 뉴스 게이트 규칙, launchd 폴러 설치
- collect_news.mjs: 네이버 뉴스 검색 다중 질의(상호·원장·의료진·주제어, 429 백오프) + 언론보도 게시판 자동 발견/clinic.json newsBoard.
  관련성 = 제목·요약에 병원 이름(v2 §8). 제목·매체·날짜·원문 링크만 저장. news_outlets.mjs 는 build_news.py 매체 표 이식
- gate: BANNED_NEWS_TITLE(전후 사진·비교, 후기, 변신)·NEGATIVE_NEWS(규제·사건, "무사고" 통과)·checkNewsItems → check.mjs·test.mjs(19/19)
- 워커 news 단계(youtube 뒤, images 앞), --news-board/--no-news, status.report.news
- 뷰 news.json: 렛미인 "변신" 기사 41건 규칙으로 제외(excludedByGate 에 목록). 회귀 1,105건(수작업 1,096, 제목 일치 1,033), 원진 1,049건
- launchd 폴러 설치(haewon 지시): PATH 에 프레임워크 python3, bootstrap/bootout 안내
- 함정: JS \W 는 한글을 지움(제목 중복 판정 붕괴), 워드프레스 article:published_time 은 게시판 생성일, 네이버 질의당 1,000건
- v3 문서 §1·§2·§3·§5·§6 갱신, 템플릿 재내보내기

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 14:14:08 +09:00
Haewon Kam
f6701c2788 docs(retro): v1.1 — haewon 기존 서비스 정의 반영, 기간 08-26부터, 타 프로젝트 사건 행 제거, 진단과 기존 리포트의 관계 한 줄
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 13:07:02 +09:00
Haewon Kam
9f5d073c5e docs(retro): 타 서비스 언급 제거 (프로젝트 격리 규칙)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 13:03:15 +09:00
Haewon Kam
7f79028415 docs(prd): 표현 수정 — 빈자리 → 공백·선점 기회 (haewon 피드백)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 12:02:13 +09:00
Haewon Kam
fa44771caa docs: Global Medical Hub PRD v0.1 (INFINITH 토큰 HTML) — 운영 구조·중립성/IP 비교, AIO2O 등록·신청 항목, 완료/부분/신규 기능 표, 로드맵·KPI·리스크. 회고 haewon 수정 반영
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 12:00:40 +09:00
Haewon Kam
c55a6ade12 docs: 핸드오버 v3(다음 세션 프롬프트·남은 일·결정 대기) + AI Discovery 회고 초안 2026-09-08
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 11:21:57 +09:00
Haewon Kam
d1b22b9872 feat(supporters): 병원별 고정값 clinic.json — 원진 유튜브 기준 채널 @wjwonjin 고정(haewon 결정), 워커 우선순위 고정값>인자>발견(영상 수)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 10:20:47 +09:00
Haewon Kam
995e1e7dfa feat(supporters): 채널 발견+엔티티 검증 — discover_channels.mjs(사이트 전수·웹검색·핸들 변형·레지스트리·플랫폼 검색, 근거 점수 3-state), 워커 discover 단계 → surfaces/sameAs, 패널·리포트 발견 채널 표, 원진 리포트 갱신
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 10:06:28 +09:00
Haewon Kam
388a4a5ea4 feat(discovery): 원진성형외과 AI Answer Readiness 리포트 v2.0 — 자동 채점+보정 결과(discovery_wonjin.ts, AEO 15/D·GEO 45/C), 독립 HTML 리포트 빌더 + Chrome PDF, docs/reports/wonjin/01_readiness_report
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 09:46:15 +09:00
Haewon Kam
dc0d233b58 feat(supporters): 홈페이지 이미지 단계 — 의료법 기준 이미지 규칙 문서, collect_images.mjs+img_process.py(법 조건부 이미지 자동 제외, 글자 이미지 검사), 워커 images 단계, 글별 히어로·갤러리 매칭. 원진 66장 반영 재배포
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 09:34:48 +09:00
Haewon Kam
eb873bc43a feat(supporters): 유튜브·로고 단계 — collect_youtube.mjs(API 집계·정보형 필터·쇼츠 판별), 워커 youtube 단계(로고·파비콘·homeVideos), 글↔영상 매칭, 카드 로고 대체, 기존 글 보존 재실행. 원진 재배포
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 09:09:00 +09:00