Commit Graph

60 Commits

Author SHA1 Message Date
Haewon Kam
890da0ecdf feat(discovery): 진단 리포트에서 개선 제안(Action Plan) 단계 분리
증거(진단)와 처방(할 일)을 한 페이지에 두면 스크롤이 너무 길어져
둘 다 읽기 힘들다는 지적에 따라 단계를 나눴다.

- /actions/:id 신규: Action Plan(P0~P2) + What We Don't Sell + 빌드 제안
  (ActionPlanSection·IntegritySection 신규 컴포넌트, Tag는 두 페이지가
  같이 써서 공용 컴포넌트로 뺌)
- /discovery/🆔 위 섹션 제거, 진단(점수·근거·Scorecard·Rubric)만 남김.
  페이지 맨 아래 중복으로 박혀 있던 확인 항목 패널(ClinicInputsPanel)도
  제거 — /supporters/:id 전용 단계가 이미 있어 두 번 보여줄 필요가 없었다
- 진단 데이터가 없는 병원이 /actions/:id 로 오면 /discovery/:id 로 되돌림
- ClinicNav: 5단계로 확장(진단 리포트→개선 제안→사이트 빌드→사진 확인→
  확인 항목), 다음 단계 플로팅 버튼 추가(기존엔 이전 단계만 있었다)
- App.tsx: 라우트 전환 시 스크롤을 맨 위로 되돌림. 스크롤을 내린 채
  다음 단계를 누르면 새 페이지가 같은 위치(짧으면 빈 하단)에서 시작하던
  문제 수정. 인앱 해시 앵커(#breakdown)가 있으면 건드리지 않음
- 사이트 빌드/확인 항목 화면의 미리보기 버튼을 "초안 사이트 열기"로
  통일(공개 후에는 "공개본 사이트 열기")

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 10:27:12 +09:00
Haewon Kam
f38c0f3bda feat(front): 진단 요약과 보완 계획을 보여 준 뒤 빌드하게 한다
버튼만 두면 무엇에 동의하는지 모른 채 누르게 된다. 진단을 요약하고, 이 빌드가 무엇을
보완하는지 말한 뒤 누르게 한다.

처음 만든 판은 실행 항목을 카테고리로 갈라 "이 빌드로 채워지는 항목 5건"이라고 했는데
그 5건이 깨진 JSON-LD 수정·GBP 전화번호 등록·H1 재설계처럼 전부 병원 홈페이지 몫이었다.
카테고리는 무엇에 관한 문제인지를 말할 뿐 누가 고치는지를 말하지 않는다. 지키지 못할
약속이라 프레임을 바꿨다.

빌드는 홈페이지를 한 줄도 고치지 않는다. AI가 인용할 새 표면을 하나 더 만들어 약한
카테고리(콘텐츠·엔티티·표면)를 우회 보완할 뿐이다. 화면도 그렇게 말한다.
"이 빌드가 대신할 수 없는 것"으로 실행 항목이 그대로 병원 몫임을 밝힌다.

- 다크 섹션 위 주 버튼을 .btn-on-dark 로 뺀다. 기본 CTA 그라디언트(#4F1DA1→#021341)는
  끝 색이 배경(#0A1128)과 거의 같아 버튼으로 읽히지 않았다. 밝은 보라와 글로우로 떼어 놓는다.
- 문구에서 "결과"를 뺀다. 빌드가 끝나도 사진 확인과 확인 항목이 남아 최종이 아니고,
  누른 적 없는 사람에게 "결과 보기"부터 보이는 것도 맞지 않는다.
- 이전 단계로 가는 플로팅 버튼을 왼쪽 아래에 고정한다. 오른쪽 아래는 주 행동 자리이고,
  좁은 화면에서는 상단 절차 메뉴가 가로 스크롤 안으로 밀린다. 첫 단계에서는 띄우지 않는다.
- 떠 있던 승인 바와 BuildSiteCta 는 이 섹션과 역할이 겹쳐 지운다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 17:25:50 +09:00
Haewon Kam
14c4b82155 refactor(design): 요청문과 설명문을 텍스트 역할 토큰으로 가른다
"한 장씩 봐 주세요" 같은 요청문이 읽고 넘어가는 설명문과 같은 무게로 놓여 있어
지나치기 쉬웠다. 역할별 토큰과 클래스를 두고 화면에 적용한다.

  .ui-ask   요청문. 사람이 무엇을 해야 하는지 말하는 문장 (17px·600·인디고)
  .ui-ask-block  문단으로 서는 요청문. 왼쪽 규칙선으로 설명과 구분한다
  .ui-body  설명 본문 (16px·slate-600)
  .ui-note  보조·출처 (14px·slate-400)

크기는 기존 화면을 세어 맞췄다. text-base 167회·text-sm 58회가 지배적이라
body 를 16px, note 를 14px 로 두면 치환해도 크기가 변하지 않고 역할과 색만 정리된다.

한글 줄바꿈: word-break keep-all 로 어절을 지키고, 긴 URL·영문 토큰만
overflow-wrap anywhere 로 자른다. text-wrap 으로 마지막 줄에 한 어절만 남는 것을
줄이고, 62ch 로 줄 길이를 묶는다. 제목에도 keep-all 과 balance 를 건다.

다크 섹션은 .on-dark 로 값을 뒤집고, 그 안의 흰 카드는 .on-light 로 되돌린다.
이걸 두지 않으면 흰 글씨가 흰 배경에 얹혀 보이지 않는다(디자인 시스템 기록된 실수).

사진 확인 화면의 썸네일 줄이 누를 수 있는 것으로 안 읽혀 같이 고친다. 72px 카드,
호버 반응, 순번 배지, 현재 위치 표시, 안 정한 것 아래 띠, 범례, 이전·다음 이동을 둔다.
상태가 안 보이는 것이 크기보다 큰 문제였다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 16:56:52 +09:00
Haewon Kam
be1ea72fcc feat(front): 진단 리포트에서 사이트 빌드로 이어지는 화면
예전 전략마케팅 툴은 분석 진행 화면에서 단계를 보여 주고 리포트로 넘어갔다.
지금 버전은 진단과 사이트 빌드가 서로 모르는 상태로 떨어져 있어, 진단을 읽은 병원이
다음에 무엇을 하는지 알 수 없었다. 진단 → 빌드 → 사진 확인 → 확인 항목을 한 줄로 잇는다.

- /build/:id 를 추가한다. 예전 /report/loading 의 단계 UX(스피너·체크·진행바)를 잇되,
  진행 상황을 프런트가 만들지 않고 supporter_builds 를 폴링해 워커가 쓴 값을 읽는다.
  프런트가 파이프라인을 돌리지 않으므로 창을 닫아도 빌드는 계속되고, 재개 로직이 필요 없다.
- 워커 17단계를 고객이 읽을 수 있는 5묶음으로 접는다(src/lib/buildPhases.ts). 진행률은
  묶음이 아니라 끝난 워커 단계 수로 세어 한 묶음 안에서도 바가 움직인다.
- 경고로 끝난 단계는 완료 화면에 "확인 대기로 발행된 부분"으로 남긴다. 자동으로 못 채운
  값을 감추지 않는다. 멈춤은 발행 게이트와 실행 실패를 구분해 문구를 나눈다.
- 진단 리포트의 Action Plan 뒤에 빌드 구간을 둔다. 무엇을 만들어 주는지와 버튼만 둔다.
  버튼은 supporter_builds 에 queued 를 넣고 폴러가 집어 간다.
- 상단 메뉴를 경로로 가른다. 병원 작업 경로에서는 마케팅 메뉴 대신 4단계 절차를 띄운다.
  Pricing·Use Cases 는 사진을 고르는 중인 병원에게 방해다.
- 진단 데이터가 없는 병원(빌드만 한 곳)은 막다른 길 대신 빌드·사진 확인으로 잇는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 16:56:34 +09:00
Haewon Kam
5cf28d9eef feat(front): 병원이 사이트에 실을 사진을 한 장씩 고르는 화면
싣기 어려운 사진(환자·전후 비교·시술 장면·효과 주장 그래픽)은 파일명이나
설명문으로 걸러지지 않아 사람이 눈으로 봐야 한다. 그 과정이 제품 밖에 있어
빌드마다 검토서를 따로 만들어 보냈다.

/images/:clinicId 를 추가한다. supporter_builds.report.images 를 읽어 미리보기
사이트의 사진을 한 장씩 보여 주고, 사용·제외를 supporter_inputs(key=image_review)
에 쌓는다. 워커가 apply_inputs 에서 읽어 다음 빌드에 반영한다.

- 첫 화면 대표 → 사이트에 실림 → 아직 안 쓰임 순으로 정렬한다. 중간에 그만둬도
  실제로 노출되는 사진은 다 보게 된다
- 판정 기준은 법 조항이 아니라 눈으로 확인할 수 있는 질문으로 적는다
- 중간 저장한다. 같은 key 는 최신 행이 유효값이라 다시 들어오면 이어서 본다
- 사진 파일은 preview_url 에서 불러온다. 배포 전 빌드는 안내 문구로 빠진다

대상이 병원 담당자라 제작 과정과 내부 규칙은 화면에 쓰지 않는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 16:04:25 +09:00
Haewon Kam
bfde7f61b2 feat(landing): 히어로 문구를 'AI에게 병원을 묻습니다'로
특정 서비스명(ChatGPT와 Perplexity) 대신 AI로 바꿨다. webforai.kr 공유 이미지의
같은 문장도 함께 바꿨다. 아직 배포하지 않았다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 16:55:59 +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
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
ee8c06f53b feat(supporters): haewon 결정 반영 — 채널 인기 전체 탭 제거, 단가 상한 $10 기본, 큐 폴러(poll.mjs)+launchd, /supporters/:id 페이지, URL 신청→빌드 큐, 수집기 UA·슬래시 수정, 기획 목록 일반화(원진 6편)
WIP: 원진성형외과 회귀는 글 생성 단계에서 네트워크 끊김(fetch failed)으로 중단. 다음 세션에 --from generate 로 재실행.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 18:54:01 +09:00
Haewon Kam
7e515b70ae feat(supporters): 승인 UI·입력 반영·워커 — §7-5 ClinicInputsPanel + supporter_builds/inputs 마이그레이션 + apply_inputs, §12-2 상단 고지·개설자 승인·색인 빌드 필터, §7-6 워커 E2E(뷰성형외과 URL → 5편 → 게이트 0오류)
- 게이트: DISCLOSURE_TOP_MISSING, APPROVED_*, UNAPPROVED_IN_INDEXABLE_BUILD, PRESS_VOICE 규칙화, 픽스처 추가 (16/16)
- 생성기: --site 옵션, 병원 확인 답변(clinicAnswers) 근거 [A]
- default_briefs.mjs 첫 배치 자동 기획, workers/supporters-build/run.mjs
- 랜딩: SAMPLE REPORT 라벨 "실제 사례"로 (haewon 지시)
- v2 §11-6·§11-7 기록, E2E 리포트

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 17:07:06 +09:00
Haewon Kam
76ec63bc1e feat(discovery): 기준표 v2.0 정식 채택 — 배지·헤더·랜딩 카피·비교 엑셀·덱 v2.0
- aeoGeoRubricV2 status active/2.0, 결과 rubricVersion 2.0. 리포트 헤더는 AEO·GEO 링 2개가 주, v1.0 종합은 보조 표기
- 랜딩: Hero 카피, ABMR 칩(AEO/GEO 목표), SampleReport(두 링 + 축별 8항목 바), Roadmap 제목, HowItWorks를 v2 계산값에서 파생. 발견 칩 수치 v1.1 스냅샷으로 정정
- 비교 엑셀 v2: scripts/build_supporters_v2_compare.ts(점수 계산 TS 단일 원본) → build_supporters_audit_v2_xlsx.py. 공식 AEO 42/GEO 56 · 서포터즈 noindex 상한 40(G1) · 색인 허용 AEO 94/GEO 77
- 덱 v2.0: build_viewclinic_deck_v2_0.py (17장, 표지 배지 v2.0, KPI AEO/GEO, 스코어카드 2장, Method v2.0) + 표준캔버스 + PDF. v1.0·v1.1 파일은 그대로
- docs/AEO_GEO_RUBRIC.md에 v2.0 채택 주석, AEO_GEO_RUBRIC_v2.md 재생성, 리포트 페이지 PDF 재출력

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 15:25:00 +09:00
Haewon Kam
c02de9ea51 feat(discovery): AEO/GEO 분리 채점 기준표 v2.0 초안 + 리포트 패널
- src/data/aeoGeoRubricV2.ts: AEO 답변 준비도 8항목·GEO 출처 준비도 8항목(각 100), 게이트 2종(크롤러 접근·본문 렌더링 → 상한 40), 부가 지표 11개
- v1.0 36항목을 v2 항목에 1:1 매핑(중복 0·미매핑 0, 스크립트 검사). 항목 점수 = v1 실측 레벨 가중 평균, 사람 판정(v2Results) 우선, 미검증은 분모 제외
- src/lib/discoveryScoreV2.ts 집계, src/components/discovery/AeoGeoV2Panel.tsx 리포트 패널(헤더 아래)
- 뷰성형외과 재채점: v1 54/C → AEO 42/C · GEO 56/C (사람 판정 4개는 수집기 원문 근거 초안). 태하: 게이트 G1(A2) 실패로 40 상한
- docs/AEO_GEO_RUBRIC_v2.md는 scripts/gen_rubric_v2_doc.ts로 코드에서 생성
- tsconfig exclude에 supporters·templates·evidence 추가 (Astro 하위 프로젝트가 루트 tsc에 잡히던 문제)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 15:12:35 +09:00
Haewon Kam
13a8fca775 chore(reports): docs/reports를 고객·단계별 폴더로 분류
- viewclinic/01_readiness_report (진단 덱 v1.0·v2_표준캔버스·v1.1 + 빌더) / 02_poc_proposal (POC 정본·v3 + 빌더) / 03_question_bank (QB 120문항·실측·엑셀) / 04_supporters (GEO 계획·콘텐츠 기획·감사 엑셀)
- taeha/ (태하 리포트 + 빌더), ibk/ (기업은행 블로그 감사), landing/ (랜딩 시안·스크린샷·HTML 내보내기)
- README.md에 구조·정본/파생본·빌드 명령 안내
- 경로 참조 갱신: 핸드오버 문서 4개, QB 스크립트 3개, 빌더 docstring, discovery 페이지 주석
- 이전에 삭제된 POC v2_표준캔버스 2파일 삭제 반영

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 13:03:53 +09:00
Haewon Kam
3ba8fc839d feat: /discovery CTA 'URL 입력으로 시작하기' — URL 입력 진단 신청 모달 + discovery_leads 저장
- 히어로·하단 CTA 버튼명 변경(무료 AEO/GEO 진단 받기 → URL 입력으로 시작하기), mailto 직행 제거
- DiscoveryLeadModal: URL(필수)·연락처(필수)·상호(선택) → Supabase discovery_leads insert
- RLS anon insert 전용(조회 불가), 저장 실패 시 o2oteam@o2o.kr mailto 폴백 (정직성 규약)
- 마이그레이션 20260831_discovery_leads.sql (적용은 supabase login 후 db push 필요)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgWoJZAvvzMxTpWeenZSia
2026-08-31 16:58:38 +09:00
Haewon Kam
18740ca800 feat: AI Discovery 랜딩 /discovery 구현 (시안 ai_discovery_landing.html 기준)
- 신규 라우트 /discovery → DiscoveryLandingPage, 기존 /discovery/:id 리포트와 공존
- 섹션 9종: Hero(ABMR 루프 + AI 답변 목업) / Why Now / How It Works / Sample Report / 8주 로드맵 / 정직성 스트립 / 최종 CTA
- ABMR 루프는 Solution.tsx 다이어그램 구조 복제, AGDP → ABMR 워딩 교체
- 점수·등급·카테고리 %·항목 수 전부 scoreDiscovery 계산값 파생, JSX 수치 하드코딩 없음
  (nextGradeTarget·scorePctColor 헬퍼를 discoveryScore에 추가)
- ScoreRing에 valueClassName·subLabel 옵션 prop 추가 (하위 호환)
- AI 답변 목업 "AEO / GEO 구축 후 목표 상태 예시" 라벨 유지, 연락처 o2oteam@o2o.kr 단일
- 시안 HTML·핸드오버 문서·POC 덱 산출물 포함

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgWoJZAvvzMxTpWeenZSia
2026-08-31 16:17:25 +09:00
Haewon Kam
85d72e4cfb fix: npm run lint(tsc --noEmit) 실제 0 에러 달성 — 기존 93건 정리
- tsconfig에 supabase 제외 (Deno 런타임 코드를 프론트 tsc+DOM lib로 검사하던 오류 79건)
- src/vite-env.d.ts 추가 (import.meta.env 타입 6건)
- @types/react 부재 환경의 JSX key 시임 4건 (ColorSwatchCard·WorkflowCard·EnvKeyRow·ApiCard)
- transformPlan latestPosts 타입 캐스트, transformReport unknown 경유 캐스트, MultiChannelInput trim 가드
- Office 임시 잠금 파일(~$*.pptx) 삭제 반영

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgWoJZAvvzMxTpWeenZSia
2026-08-31 16:17:12 +09:00
Haewon Kam
ef4d8218e9 feat: AI Discovery AEO/GEO 채점 기준표 v1.0 + /discovery/:id 리포트 (뷰성형외과 44점)
- 채점 기준표: 6 카테고리 36 항목 100점, 항목별 근거등급/통제/채점방식/howToCheck
- 집계: 미검증 항목 분모 제외, llms.txt 항목 제외
- 뷰성형외과 실측 결과 + 핵심 발견 5 + 액션 7 + 하지 않을 것 5
- DiscoveryReportPage: INFINITH 디자인 토큰, 본문 +2pt, 판정 배지/우선순위 +4pt 볼드, keep-all
- SeverityBadge className prop 추가
- Badge.tsx 복원 (PricingPage import 누락으로 빌드 깨져 있던 것)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 10:26:29 +09:00
Haewon Kam
dc8a1db3f2 feat: 뷰성형외과 미팅 대비 — 데이터 갱신(2026-04-28) + URL 7분할 + 가격 개편
- mockReport.ts (view-clinic): 8채널 실측 갱신
  · YouTube · 강남언니 · 네이버 플레이스 · 네이버 블로그 → Firecrawl
  · Instagram (KR · EN) · Facebook (KR · EN) → Apify
  · createdAt 2026-04-13 → 2026-04-28
- mockPlan.ts (view-clinic): KPI 베이스라인 동기화 + scheduledDate 5월로 이동
- MultiChannelInput: 단일 textarea → 7-필드 분할 (홈페이지 · YT · IG · FB · 네이버플레이스 · 블로그 · 강남언니), 채널별 실시간 검증 아이콘
- PricingPage / FeatureComparisonTable: 49만/149만/399만 → 9만/29만/99만, 월 리포트 수 1회/4회/10회, 경쟁사 추적 1/3/5

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 11:25:45 +09:00
Haewon Kam
938ebacbf9 feat: PART III 랜딩 피봇 — 다채널 URL 입력 + Strategic Planner 포지셔닝
- MultiChannelInput: URL 뭉치 붙여넣기 → classifyUrls로 7개 채널 자동 분류
  (homepage·YouTube·Instagram·Facebook·네이버플레이스·블로그·강남언니)
  · "Analyze" pill 버튼 복원 + variant별 색 분기 (hero=dark brand,
    cta=#fff3eb→#e4cfff→#f5f9ff warm 3-stop)
  · placeholder 중앙 정렬 + "한 줄씩" 규칙 제거 (유연 파싱 노출)

- Navbar: Free Report CTA 제거 → Login + 문의하기 (contact@o2o.kr) duo
- LoginPage: 계약 고객용 스캐폴딩 페이지 신규 추가
- PricingPage: 계약 기반 영업 반영, FAQ에서 해지·환불 항목 제거
  (세부 정책 미확정 → 후속 추가)

- Landing 카피 Strategic Planner 포지셔닝 피봇:
  · Hero sub: "10분 진단 → 12개월 전략 설계"
  · Solution AGDP: Audit / Generation / Direction / Planning 재해석
  · Modules: Intelligence + Planning Available, 나머지 Coming Soon 정직화
  · TargetAudience: 전략 파트너 / 전략 자문 + Partner Program 신청 waitlist
  · Problems: 콘텐츠 소진 / 경쟁사 분석 부재 / 데이터 부족 3축
  · UseCases: 진단·전략·KPI(Medical) · 수주·자문·포트폴리오(Agency)

- discover-channels Edge Function: manualChannels 수용 — 사용자 붙여넣은
  URL이 Firecrawl 스크래핑보다 우선, naverPlace/gangnamUnni 직접 주입

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-17 09:01:41 +09:00
Haewon Kam
dc6e2f0504 fix: Production Workflow 카드 크기·위치 균일화
- Flexbox + items-center → CSS Grid 전환 (모든 컬럼 동일 너비)
- 카드 h-full + flex flex-col 로 높이 균등 (description 길이 무관)
- description flex-1 + 태그 mt-auto 로 하단 칩 정렬 통일
- 화살표 absolute -right-3 분리 (카드 너비에 영향 없음)
- step 수 4·5·6·7·8 모두 grid-cols 명시 (Tailwind purge 안전)

7개 데모 (view/banobagi/grand/wonjin/ts/irum/o2o) 모두 적용
- step 4: irum  / step 5: view  / step 6: 나머지 5개

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 14:22:20 +09:00
Haewon Kam
105e8288e0 fix: Facebook 페이지 URL 중복 prepend + YouTube linkedUrl 상대경로 버그
- FacebookAudit: 'facebook.com/...' 형식 데이터에 'https://www.facebook.com/' 가
  중복 prepend 되어 'https://www.facebook.com/facebook.com/...' 깨진 URL 생성
- YouTubeAudit: linkedUrls 의 url 이 protocol 없이 그대로 href 에 들어가
  상대 경로로 인식되던 버그
- 6개 병원 (view/banobagi/grand/wonjin/ts/irum) 모두 영향

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 09:06:13 +09:00
Haewon Kam
99d72f81d6 fix: Instagram 핸들 클릭 시 항상 인스타그램 프로필로 이동
profileLink (병원 홈페이지 도메인) 이 우선되어 핸들 클릭 시
인스타그램이 아닌 홈페이지로 이동하던 버그 수정.
5개 병원 (banobagi/grand/wonjin/ts/irum) 모두 영향.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 08:59:49 +09:00
Haewon Kam
f2441de0bf fix: 리포트 '마케팅 기획' 버튼 → 브랜딩 가이드 섹션으로 이동
- KPIDashboard의 CTA 버튼이 /plan/:id 로만 이동 → 스크롤 위치 불확정
- 수정: /plan/:id#branding-guide 로 해시 포함 이동
- MarketingPlanPage에 useEffect 추가: location.hash 감지 시
  sticky Navbar(80px) + ReportNav(48px) = 128px 오프셋 적용하여
  해당 섹션 상단이 nav 바로 아래에 정렬되도록 scrollTo

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 16:48:44 +09:00
Haewon Kam
d816bb2d13 fix: 콘텐츠 캘린더 뿌연 현상 근본 해결 — isDragging bug fix
세션 내내 추적하던 'opacity 20-30% 흐림' 인상의 진짜 원인:
  const isDragging = draggedEntry?.entry.id === entry.id;
→ mock entry에 id가 없어 undefined === undefined → true
→ 모든 entry에 opacity-40 상시 적용됨

수정:
- isDragging: 오브젝트 참조 비교로 전환 (id 의존 제거)
- entry 배경/border: 더 진한 파스텔로 대비 강화
  (#F3F0FF → #EDE5FF, border #D5CDF5 → #B8A8E8 등)
- entry 제목: text-slate-700 → font-medium text-[#0A1128]
- 아이콘 opacity-60 제거 (100% 불투명)
- shadow-sm + hover:shadow-lg
- 섹션 dark 테마 복원 (Dark/White 섹션 교차 규칙 유지)
- 일자 셀 bg-slate-50/50 제거, 빈 셀 border 불투명화

6개 병원 데모(view-clinic/banobagi/grand/wonjin/ts/irum) 모두
ContentCalendar 컴포넌트를 공유하므로 한 번에 반영.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 16:40:43 +09:00
Haewon Kam
281efac932 fix: 콘텐츠 캘린더 뿌연 레이어 제거 — 셀 배경 제거 + entry shadow 강화
- 일자 셀 bg-slate-50/50(50% 투명) 제거 → entry 카드가 주간 카드 위 직접 노출
- 빈 셀 border-slate-200/60 → border-slate-200 (불투명)
- entry 카드에 contentTypeColors.shadow 추가 → 색상별 soft glow로 떠있는 느낌
- dark 테마 유지 (ChannelStrategy와 동일한 dark 섹션 + 흰 카드 패턴)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 16:23:09 +09:00
Haewon Kam
6b3b950ad0 fix: 플랜 페이지 전체 섹션 투명 현상 완전 해결 — initial opacity:0 전수 제거
- PlanHeader: motion.div/h1/p의 initial opacity:0 → plain HTML로 교체
  (배경 blob 애니메이션은 opacity 무관하여 유지)
- RepurposingProposal: 카드 motion.div → plain div, 확장 accordion도 plain div
- ChannelStrategy, ContentStrategy, AssetCollection, PlanCTA,
  BrandingGuide, WorkflowTracker, StrategyAdjustmentSection:
  initial={{ opacity: 0, ... }} 라인 전수 제거
- 이 환경의 framer-motion이 animate prop 완료 실패 → opacity:0에서 멈춤

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 16:06:21 +09:00
Haewon Kam
eaf215ea6d fix: 콘텐츠 캘린더 흐림 현상 근본 해결 — nav backdrop-blur 제거
- Navbar/ReportNav의 backdrop-blur-lg가 스크롤 시 섹션을 덮는
  GPU 합성 블러 레이어를 만들어 콘텐츠 캘린더가 흐려 보임
- bg-white/95 단색으로 교체 (시각적 차이 미미, 블러 부작용 제거)
- 이전 커밋(5f7d58c, aac1367)의 motion/whileInView 제거는
  원인이 아니었음 — 조상 nav의 backdrop-filter가 진범

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-14 15:59:10 +09:00
Haewon Kam
aac1367808 fix: 콘텐츠 캘린더 흐림 현상 완전 해결 — motion 제거
framer-motion animate가 프로덕션 빌드에서 완료되지 않는 문제로
SectionWrapper/ContentCalendar의 opacity:0 initial 상태가 유지됨.
motion.div/motion.button/motion.section을 일반 태그로 교체하고
모든 opacity 진입 애니메이션 제거.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 15:42:31 +09:00
Haewon Kam
5f7d58c490 fix: 콘텐츠 캘린더 흐림 현상 수정 — whileInView 제거
SectionWrapper의 motion.section이 opacity:0 initial 상태에서
framer-motion animate가 발동하지 않아 전체 섹션이 투명하게 보이는
문제를 수정. SectionWrapper를 일반 <section>으로 교체하고,
plan 컴포넌트들의 whileInView/viewport 애니메이션 제거.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-14 15:33:34 +09:00
Haewon Kam
c0c37b84de fix: naverBlog RSS 전환 + naverPlace DB-first 패턴 + 핵심문제진단 JSON 렌더링 버그 수정
- collect-channel-data: naverBlog 실시간 검색 제거 → verified handle 기반 RSS 직접 fetch
- collect-channel-data: naverPlace DB-first 패턴 (verified_channels에 저장된 데이터 우선 사용, 없을 때만 URL도메인 매칭 검색 후 DB에 저장)
- transformReport: ch.issues 배열 항목이 {issue, severity} 객체일 때 JSON.stringify 대신 .issue 문자열 추출
- ProblemDiagnosis: Lucide 아이콘 제거 → FilledIcons(ShieldFilled, FileTextFilled, LinkExternalFilled), 항목 구분자 ' ' → ' — '

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 17:17:22 +09:00
Haewon Kam
2027ae9b64 feat: 마케팅 플랜 Phase 1~3 완성
- ContentCalendar: 드래그앤드롭(주차 내 요일 간 이동) + 엔트리 추가 버튼 + iCal Export
- BrandingGuide: 색상 팔레트 인라인 편집(스와치 클릭 → hex 팝오버) + DO/DON'T 2컬럼
- WorkflowTracker: 콘텐츠 제작 파이프라인(기획→AI초안→검토→승인→배포), 동영상/이미지+텍스트 분류
- RepurposingProposal: YouTube 인기 영상 리퍼포징 제안 아코디언 섹션
- AssetDetailModal: 에셋 카드 클릭 시 상세 모달
- 디자인 시스템 감사: Lucide 라인 아이콘 제거, 원색(pink/indigo/purple) 제거, 이모지 UI 제거
- "My Assets" → "나의 소재" 일관성 변경
- FilledIcons: DownloadFilled, RocketFilled 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 16:44:21 +09:00
Haewon Kam
9c4d10609f feat: 스크린샷 리포트 반영 + 영구 저장 인프라 강화
- transformReport: channel_data.screenshots → report.screenshots 자동 매핑
- transformReport: youtubeAudit/instagramAudit/facebookAudit diagnosis에 evidenceIds 자동 연결 (채널별 스크린샷 → 진단 항목 연결)
- collect-channel-data: 스크린샷 아카이브를 병렬→순차로 변경 (rate-limit 방지), 실패 시 상세 로그
- scripts/archive-screenshots.py: 기존 GCS 임시 URL → Supabase Storage 일괄 재아카이브 스크립트 추가
- TypeScript 기존 에러 3개 수정 (SectionErrorBoundary, ClinicSnapshot, reviewCount 유니언 타입)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 14:43:25 +09:00
Haewon Kam
2d1937944a fix: 리포트 데이터 정확도 개선 + 강남언니·인스타그램 스크래핑 데이터 반영
- ClinicSnapshot: 내부 관리용 배지(Registry 검증·분점·등급) 병원 리포트에서 제거
- transformReport: Facebook 리뷰수 파싱 ("Not yet rated (3 Reviews)" 정규식 추출)
- transformReport: 네이버 플레이스 KPI 목표가 현재값보다 낮은 오류 수정 (동적 계산)
- transformReport: 네이버 블로그 방문자 "0(미운영)" → "검색 노출 N건 (방문자 비공개)"
- transformReport: 웹사이트+SNS 유입 "0%" → "측정 불가 (트래킹 미설치)"
- clinic_registry_working.csv: gangnam_unni_badges, gangnam_unni_procedures 컬럼 추가 (60개 병원)
- clinic_registry_working.csv: instagram_followers, instagram_posts 컬럼 추가 (64개 병원)
- INFINITH_Outbound_List.csv: 인스타그램 팔로워·게시물수 컬럼 추가 (64개 병원)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 14:18:31 +09:00
Haewon Kam
ae87953fa0 feat: Registry-verified badge + registryData data flow + V3 error recording
- ClinicSnapshot.tsx: 'Registry 검증' badge (ShieldCheck icon), district/branches/brandGroup pills, external links (강남언니/네이버플레이스/구글맵) when source=registry
- report.ts: add source and registryData fields to ClinicSnapshot type
- transformReport.ts: ApiMetadata now accepts source/registryData; passes to clinicSnapshot
- useReport.ts: DB load path extracts scrape_data.source + scrape_data.registryData → transformApiReport
- V3 dual-write error recording: discover-channels, collect-channel-data, generate-report now write error_message + error status to analysis_runs on catch instead of silently swallowing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:01:19 +09:00
Haewon Kam
d5f7f24e0a feat: clinic registry DB + pipeline audit P0 fixes
## Clinic Registry
- data/clinic-registry/clinic_registry_working.csv — 91개 병원 채널 마스터 DB
- data/clinic-registry/INFINITH_Outbound_List.csv — BD팀 아웃바운드 리스트 (17컬럼)
- data/clinic-registry/update_csv.py — 안전 CSV 업데이트 스크립트 (빈 필드만 채움)
- data/clinic-registry/extract_place_ids.py — 네이버 플레이스 ID 추출기
- scripts/import-registry.ts — CSV → Supabase clinic_registry 테이블 임포트
- supabase/migrations/20260406_clinic_registry.sql — clinic_registry 테이블 스키마

## Pipeline P0 Bug Fixes (전수 감사 후)
- fix(collect-channel-data): 강남언니 rating 0-10 스케일 오변환 제거
  - 기존: rating ≤ 5이면 ×2 → 4.8/10을 9.6/10으로 잘못 변환
  - 수정: Firecrawl 프롬프트가 이미 0-10 지시 → rawValue 직접 신뢰
- fix(generate-report): Perplexity 단일 fetch → fetchWithRetry 교체
  - maxRetries:2, backoffMs:[5000,15000], timeoutMs:90s
  - 기존: 타임아웃/429 시 리포트 생성 전체 실패
  - 수정: 자동 재시도로 일시적 API 오류 극복

## Docs
- docs/PIPELINE_IMPROVEMENT_PLAN.md — Sprint 0/1/2 완료 표시 + 전수 감사 결과 추가
- docs/REGISTRY_FUNCTIONAL_SPECS.md, DB_SCHEMA_V3.md 외 기획 문서 다수 추가

## New Components & Features
- supabase/functions/generate-content-plan, adjust-strategy — 콘텐츠 플랜/전략 조정
- src/components/plan/EditEntryModal, StrategyAdjustmentSection — 플랜 편집 UI
- supabase/functions/_shared/dataQuality, foundingYearExtractor, urlClassifier — 데이터 품질 유틸

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 09:33:25 +09:00
Haewon Kam
ec991057e6 feat: add API Dashboard + filled icons + pipeline improvements
- Add /api-dashboard page with API connection status, env var checker,
  pipeline flow diagram, and cost estimator
- Add 15 new filled SVG icons (Shield, Database, Server, Bolt, Eye,
  Copy, Check, Cross, Warning, Refresh, Flow, Coin, LinkExternal etc.)
- Follow INFINITH design system: no emoji, no line icons, semantic
  status colors, diagonal shadows, brand gradients, font-serif headings
- Improve Vision Analysis with base64 encoding fix
- Add SectionErrorBoundary for graceful section-level error handling
- Add Google Places API utility (prepared for future migration)
- Fix Edge Function auth headers and report generation pipeline

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 14:59:31 +09:00
Haewon Kam
d1157da39c fix: restore button active state + inject gangnamunni Vision data into report
- Hero button: gray when empty, accent gradient when URL entered
- generate-report: force-inject gangnamUnniStats from Vision Analysis
  into channelAnalysis (score, rating, reviews, doctors)
- Add gangnamunni Vision data to prompt context

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 11:53:33 +09:00
Haewon Kam
79950925a1 fix: add Authorization header to all Edge Function calls + fix Vision Analysis
- All fetch calls to Supabase Edge Functions now include
  Authorization: Bearer <anon_key> (was missing → 401 errors)
- Fix Firecrawl screenshot API: remove invalid screenshotOptions,
  use "screenshot@fullPage" format (v2 API compatibility)
- Fix screenshot response handling: v2 returns URL not base64,
  now downloads and converts to base64 for Gemini Vision
- Add about page to Vision Analysis capture targets
- Add retry utility, channel error tracking, pipeline resume,
  enrichment retry, EmptyState improvements (Sprint 2-3)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 10:08:03 +09:00
Haewon Kam
a02c83155e fix: remove duplicate Facebook link at bottom — now only on page name
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 16:28:46 +09:00
Haewon Kam
4928d24ace feat: consistent ExternalLink on all channel names — Facebook + OtherChannels
Facebook pageName now links to facebook.com/{url} with ExternalLink icon.
OtherChannels: moved ExternalLink from right-end to inline with channel
name, matching the Instagram/YouTube pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 16:23:29 +09:00
Haewon Kam
2a35108149 fix: '의료진 3명' → '전문의 3명' — staffCount는 강남언니 등록 의사 수
staffCount is the number of registered doctors from 강남언니, not total
staff. Label changed from 의료진(medical staff) to 전문의(specialists)
to accurately reflect the data source. Diagnosis message also updated.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 16:21:10 +09:00
Haewon Kam
66b4826f55 feat: add clickable source links to all report sections
YouTubeAudit: handle links to youtube.com/@{handle} with ExternalLink icon
InstagramAudit: handle links to instagram.com/{handle} with ExternalLink icon
ClinicSnapshot: domain is now clickable link, phone is tel: link
OtherChannels: Google Maps generates search URL, Naver Blog links to
  first blog post or search results (previously empty string)
transformReport: fills missing URL fields for Google Maps and Naver Blog

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 11:02:35 +09:00
Haewon Kam
c6b39e3706 revert: restore Hero, Modules, CSS to exact original version (922ec8f)
Reverts to the original design with full-color button (no disabled
opacity), original background gradients, and original blob decorations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:07:18 +09:00
Haewon Kam
46b911d4c0 fix: remove opacity-50 from Analyze button — always show full color
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:05:50 +09:00
Haewon Kam
0d72750982 revert: restore Hero, Modules, CSS to original state
All layout changes (blob modifications, overflow-x/clip, scrollbar-gutter)
reverted to the original version that was working correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:56:58 +09:00
Haewon Kam
0f517473e0 fix: remove asymmetric blobs from Hero, use centered gradient
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:48:15 +09:00
Haewon Kam
7154e76bc4 fix: balance Hero blob sizes and opacity for symmetric layout
Reduced blob size (w-64→w-48), lowered opacity (30%→20%), used
percentage positioning (left-10→left-[10%]), and wrapped in
overflow-clip container. Eliminates visual weight asymmetry.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:45:28 +09:00
Haewon Kam
2b7494305a fix: contain all overflowing blobs within viewport
- Modules.tsx: wrap blobs in overflow-clip container, use max-w instead
  of min-w to prevent viewport overflow
- index.css: add #root { overflow-x:clip; max-width:100vw } as final
  safety net — no child element can expand beyond viewport

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:42:35 +09:00
Haewon Kam
7557ef774c feat: Pipeline V2 — 3-phase analysis with verified channel discovery
Restructured the entire analysis pipeline from AI-guessing social
handles to deterministic 3-phase discovery + collection + generation.

Phase 1 (discover-channels): 3-source channel discovery
  - Firecrawl scrape: extract social links from HTML
  - Perplexity search: find handles via web search
  - URL regex parsing: deterministic link extraction
  - Handle verification: HEAD requests + YouTube API
  - DB: creates row with verified_channels + scrape_data

Phase 2 (collect-channel-data): 9 parallel data collectors
  - Instagram (Apify), YouTube (Data API v3), Facebook (Apify)
  - 강남언니 (Firecrawl), Naver Blog + Place (Naver API)
  - Google Maps (Apify), Market analysis (Perplexity 4x parallel)
  - DB: stores ALL raw data in channel_data column

Phase 3 (generate-report): AI report from real data
  - Reads channel_data + analysis_data from DB
  - Builds channel summary with real metrics
  - AI generates report using only verified data
  - V1 backwards compatibility preserved (url-based flow)

Supporting changes:
  - DB migration: status, verified_channels, channel_data columns
  - _shared/extractSocialLinks.ts: regex-based social link parser
  - _shared/verifyHandles.ts: multi-platform handle verifier
  - AnalysisLoadingPage: real 3-phase progress + channel panel
  - useReport: channel_data column support + V2 enrichment merge
  - 강남언니 rating: auto-correct 5→10 scale + search fallback
  - KPIDashboard: navigate() instead of <a href>
  - Loading text: 20-30초 → 1-2분

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 21:49:13 +09:00