/** * INFINITH AI Discovery AEO/GEO 채점 기준표 v1.0 * * 근거 기반: ado2-aeo-geo 스킬 (2026-08-26 한국 실측 · Princeton GEO · C-SEO Bench) * * 배점 철학 * - "차단되면 절대 인용될 수 없다"는 논쟁의 여지가 없다 → A(접근성)·B(엔티티) 배점이 높다 * - GEO 콘텐츠 전술의 효과는 학술적으로 논쟁 중 → C는 배점이 크지만 "좋은 콘텐츠 원칙"으로만 설명한다 * - llms.txt는 항목에서 제외한다 (Google 공식 효과 0, 채택률 0.13%) * - 병의원 업종은 강남언니(ai-input=yes)가 AI 인용을 장악 → D(표면)에서 최고 배점 */ import type { Rubric } from '../types/discovery'; const L = (l0: string, l1: string, l2: string, l3: string) => [ { level: 0 as const, label: l0 }, { level: 1 as const, label: l1 }, { level: 2 as const, label: l2 }, { level: 3 as const, label: l3 }, ]; export const AEO_GEO_RUBRIC: Rubric = { version: '1.0', updatedAt: '2026-08-28', categories: [ { id: 'access', code: 'A', name: 'AI 크롤러 접근성', nameEn: 'Access & Crawlability', description: 'AI 검색엔진이 사이트를 읽을 수 있는가. 크롤러 접근이 막히면 나머지 항목은 전부 무효다.', weight: 20, }, { id: 'entity', code: 'B', name: '엔티티 식별·구조화', nameEn: 'Entity & Structured Data', description: 'AI가 "이 병원이 누구인지"를 기계적으로 확정할 수 있는가. NAP 일관성과 스키마 위생.', weight: 20, }, { id: 'content', code: 'C', name: '답변 인용 가능 콘텐츠', nameEn: 'Answer-Ready Content', description: '패시지 단위로 잘라내도 자기완결적인 사실 덩어리가 있는가. 정의문·FAQ·수치·표·의료진 근거.', weight: 25, }, { id: 'surface', code: 'D', name: 'AI 인용 표면 확보', nameEn: 'Off-site Surfaces', description: '실제로 AI가 인용하는 외부 표면(강남언니·GBP·오픈웹)에 존재하는가. 네이버 자산은 글로벌 AI에 기여도 0.', weight: 20, }, { id: 'measure', code: 'E', name: 'AI 가시성 측정 인프라', nameEn: 'Measurement', description: '개선을 증명할 수 있는가. 소유 신호(크롤러 로그·GA4 AI 유입) 계측 여부.', weight: 10, }, { id: 'hygiene', code: 'F', name: '기술 위생', nameEn: 'Technical Hygiene', description: '이미지 대체텍스트·CMS 보안·페이지 무게·모바일. 보조 지표.', weight: 5, }, ], criteria: [ // ───────────── A. 접근성 (20) ───────────── { id: 'A1', category: 'access', name: '검색용 AI 봇 허용', rationale: 'OAI-SearchBot·PerplexityBot·Claude-SearchBot·bingbot·Googlebot이 막히면 인용 자체가 불가능. 학습봇(GPTBot·ClaudeBot)과 구분해 평가.', weight: 5, evidenceGrade: 'measured', control: 'direct', method: 'auto', howToCheck: 'robots.txt 파싱 + 각 UA로 실제 GET 200 확인 (crawler_audit.py)', levels: L('검색봇 2개 이상 차단', '검색봇 1개 차단', '모두 허용, 학습봇 일부 차단', '검색봇 전부 허용 + 200 응답'), }, { id: 'A2', category: 'access', name: 'CDN/WAF AI 차단 없음', rationale: 'Cloudflare는 2025-07부터 신규 도메인에 AI 크롤러 기본 차단. 업체가 인지하지 못한 채 AI 검색에서 사라지는 주원인.', weight: 3, evidenceGrade: 'measured', control: 'direct', method: 'auto', howToCheck: '응답 헤더(server/cf-ray) + AI UA 요청 시 403/challenge 여부', levels: L('AI UA 403/챌린지', '일부 UA 차단', 'CDN 사용, 차단 없음', 'CDN 차단 없음 확인'), }, { id: 'A3', category: 'access', name: '서버 렌더링 본문', rationale: 'AI 크롤러는 JS를 실행하지 않거나 지연시킨다. 초기 HTML에 본문이 없으면 빈 페이지로 읽힌다.', weight: 3, evidenceGrade: 'measured', control: 'direct', method: 'auto', howToCheck: 'JS 미실행 HTML의 텍스트 길이 / 렌더 후 텍스트 길이 비율', levels: L('본문 전무 (SPA 빈 셸)', '30% 미만', '30~80%', '80% 이상 (SSR/정적)'), }, { id: 'A4', category: 'access', name: 'HTTPS·리다이렉트 정합', rationale: 'http/www 변형이 하나의 정본 URL로 301 수렴해야 엔티티가 분산되지 않는다.', weight: 2, evidenceGrade: 'measured', control: 'direct', method: 'auto', howToCheck: 'http://, http://www, https:// 4변형 → 최종 URL 동일 여부', levels: L('HTTPS 없음', '변형 간 200 중복', '일부 302', '전부 301로 정본 수렴'), }, { id: 'A5', category: 'access', name: 'sitemap.xml 제공', rationale: '크롤러 발견 경로. robots.txt에 선언되어야 한다.', weight: 3, evidenceGrade: 'measured', control: 'direct', method: 'auto', howToCheck: 'robots.txt Sitemap: 선언 + 200 + lastmod 존재', levels: L('없음', '있으나 robots 미선언', '선언·200', '선언·200·lastmod 최신'), }, { id: 'A6', category: 'access', name: 'Bing 색인 (ChatGPT 검색 경로)', rationale: 'ChatGPT 검색은 Bing 인덱스에 상당 부분 의존. Bing Webmaster + IndexNow 등록 여부.', weight: 3, evidenceGrade: 'vendor', control: 'direct', method: 'manual', howToCheck: 'Bing Webmaster Tools 등록 확인 (오너 접근 필요) 또는 site: 검색 결과 수', levels: L('Bing 미색인', '일부 색인', '색인됨', '색인 + IndexNow 연동'), }, { id: 'A7', category: 'access', name: '응답 속도·크롤 예산', rationale: 'TTFB가 느리거나 HTML이 비대하면 크롤러가 페이지를 덜 가져간다.', weight: 1, evidenceGrade: 'estimate', control: 'direct', method: 'auto', howToCheck: 'TTFB < 0.5s, HTML < 300KB', levels: L('TTFB > 2s', 'TTFB > 1s 또는 HTML > 1MB', 'TTFB < 0.5s, HTML > 300KB', 'TTFB < 0.5s, HTML < 300KB'), }, // ───────────── B. 엔티티 (20) ───────────── { id: 'B1', category: 'entity', name: 'JSON-LD 문법 유효성', rationale: '문법이 깨진 JSON-LD는 파서가 통째로 버린다. 있는데 무효인 것은 없는 것과 같다.', weight: 3, evidenceGrade: 'measured', control: 'direct', method: 'auto', howToCheck: '모든 ld+json 블록 JSON.parse 성공 여부', levels: L('전부 무효 또는 없음', '일부 무효', '전부 유효', '전부 유효 + @graph 연결'), }, { id: 'B2', category: 'entity', name: '업종 엔티티 스키마 (MedicalClinic / LegalService / LocalBusiness)', rationale: '엔티티 식별을 돕는 위생 조치. 인과 증거는 없으나 name·address·telephone·openingHours·전문분야(medicalSpecialty / areaServed)를 기계가 읽게 한다.', weight: 5, evidenceGrade: 'academic', control: 'direct', method: 'auto', howToCheck: '@type MedicalClinic|LegalService|LocalBusiness 존재 + 필수 속성 4개', levels: L('없음', 'Organization만', '업종 타입 + 주소·전화', '+ openingHours·전문분야·geo'), }, { id: 'B3', category: 'entity', name: '전문가 스키마 (Physician / Attorney)', rationale: '"누가 담당하나"는 병의원·로펌 질의의 핵심. 의사·변호사 이름과 자격·경력을 구조화하면 E-E-A-T 엔티티가 된다.', weight: 3, evidenceGrade: 'academic', control: 'direct', method: 'auto', howToCheck: '@type Physician|Attorney + name·전문분야·worksFor', levels: L('없음', '이름만', '전문분야 포함', '자격·소속·sameAs 포함'), }, { id: 'B4', category: 'entity', name: 'NAP 사이트 내 일관성', rationale: '같은 사이트 안에서 주소 표기가 다르면 외부 표면과 대조할 기준이 없다. 한 글자까지 동일해야 한다.', weight: 3, evidenceGrade: 'measured', control: 'direct', method: 'auto', howToCheck: '주소·전화 정규식 추출 → 고유 표기 수', levels: L('주소/전화 미표기', '3개 이상 표기 변형', '2개 변형', '단일 표기'), }, { id: 'B5', category: 'entity', name: 'sameAs 연결', rationale: 'Organization.sameAs로 YouTube·Instagram·강남언니·GBP를 연결해야 AI가 흩어진 언급을 한 엔티티로 묶는다.', weight: 2, evidenceGrade: 'academic', control: 'direct', method: 'auto', howToCheck: 'Organization.sameAs 배열 길이', levels: L('비어 있음', '1~2개', '3~4개', '5개 이상 (SNS + 버티컬 + 지도)'), }, { id: 'B6', category: 'entity', name: 'canonical·중복 제거', rationale: '같은 내용이 여러 URL이면 인용 신호가 분산된다.', weight: 2, evidenceGrade: 'measured', control: 'direct', method: 'auto', howToCheck: 'rel=canonical 존재 + self-referencing', levels: L('없음', '있으나 불일치', '있음', '있음 + 파라미터 정리'), }, { id: 'B7', category: 'entity', name: '다국어 hreflang', rationale: '외국인 환자 질의(영·중·일)는 별도 엔진 표면. 언어 버전이 있다면 hreflang으로 연결해야 한다.', weight: 2, evidenceGrade: 'vendor', control: 'direct', method: 'auto', howToCheck: 'link hreflang 태그 수', levels: L('다국어 페이지 있으나 미연결', '단일 언어', '2개 언어 연결', '3개 이상 연결'), }, // ───────────── C. 콘텐츠 (25) ───────────── { id: 'C1', category: 'content', name: '정의문형 첫 문단', rationale: 'Google AI Mode의 query fan-out은 패시지 단위로 검색한다. "○○은 강남 신논현에 있는 가슴성형 전문 성형외과다"처럼 답을 먼저 써야 청크가 자기완결적이 된다.', weight: 4, evidenceGrade: 'academic', control: 'direct', method: 'semi', howToCheck: '메인·시술 페이지 첫 200자에 [상호+지역+전문분야] 정의문 존재', levels: L('없음 (슬로건·이미지만)', '슬로건형', '일부 페이지에 정의문', '전 핵심 페이지 정의문'), }, { id: 'C2', category: 'content', name: 'FAQ 섹션', rationale: '실제 질문 형태 그대로의 H2/H3 + 답변은 답변엔진이 가장 잘 가져가는 구조. FAQPage 스키마와 결합.', weight: 4, evidenceGrade: 'academic', control: 'direct', method: 'auto', howToCheck: 'FAQ/Q&A 섹션 탐지 + FAQPage 스키마', levels: L('없음', '게시판형 Q&A만', 'FAQ 섹션 존재', 'FAQ + FAQPage 스키마 + 시술별'), }, { id: 'C3', category: 'content', name: '제목 계층 의미성', rationale: 'H1은 페이지당 1개, 주제를 서술해야 한다. "VIEW SELFIE" 같은 라벨형 H1은 AI에게 아무 정보도 주지 않는다.', weight: 3, evidenceGrade: 'measured', control: 'direct', method: 'auto', howToCheck: 'H1 개수 = 1, H1/H2 텍스트가 명사구 서술형인지, 중복 H2 비율', levels: L('H1 없음 또는 5개 이상', 'H1 다수·라벨형', 'H1 1개, H2 일부 라벨형', 'H1 1개 서술형, H2 논리 계층'), }, { id: 'C4', category: 'content', name: '구체 수치 (가격·시간·회복)', rationale: '가격대·수술시간·회복기간·재수술률 같은 수치는 인용되는 콘텐츠의 공통 특징. (Princeton GEO 정합, 단 C-SEO Bench 반박 있음 → 효과 보장 아님)', weight: 4, evidenceGrade: 'academic', control: 'direct', method: 'semi', howToCheck: '시술 페이지에서 원/분/일/% 단위 수치 밀도', levels: L('수치 없음', '마케팅 문구 속 수치만', '시술별 일부 수치', '시술별 가격대·시간·회복 표기'), }, { id: 'C5', category: 'content', name: '표·비교 구조', rationale: 'AI가 인용하는 콘텐츠는 구조화·표 중심 (인블로그 조사). 보형물 비교표·시술 비교표가 대표 예.', weight: 2, evidenceGrade: 'vendor', control: 'direct', method: 'auto', howToCheck: '