o2o-infinith-demo/src/types/discovery.ts
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

126 lines
3.2 KiB
TypeScript

/**
* INFINITH AI Discovery AEO/GEO 채점 타입
*
* 설계 원칙
* - 기준표(rubric)와 결과(result)를 분리한다. 결과는 criterionId → level 매핑만 가진다.
* - 미검증(unverified) 항목은 0점이 아니라 분모에서 제외한다.
* - 모든 항목에 근거 등급(evidenceGrade)과 통제 가능성(control)을 붙인다.
*/
/** 0 = 없음/치명, 1 = 미흡, 2 = 양호, 3 = 우수 */
export type CriterionLevel = 0 | 1 | 2 | 3;
/** 근거 등급 (ado2-aeo-geo 정직성 규약) */
export type EvidenceGrade = 'measured' | 'academic' | 'vendor' | 'estimate';
/** 업체가 통제할 수 있는 정도 */
export type ControlLevel = 'direct' | 'influence' | 'none';
/** 자동 채점 가능 여부 */
export type EvidenceMethod = 'auto' | 'semi' | 'manual';
export type CategoryId =
| 'access'
| 'entity'
| 'content'
| 'surface'
| 'measure'
| 'hygiene';
export interface RubricLevelSpec {
level: CriterionLevel;
label: string;
}
export interface RubricCriterion {
id: string;
category: CategoryId;
name: string;
/** 왜 AI 답변 노출에 영향을 주는가 */
rationale: string;
/** 배점 (카테고리 합 = 카테고리 weight) */
weight: number;
evidenceGrade: EvidenceGrade;
control: ControlLevel;
method: EvidenceMethod;
/** 어떻게 확인하는가 (자동화 시 구현 스펙) */
howToCheck: string;
levels: RubricLevelSpec[];
}
export interface RubricCategory {
id: CategoryId;
code: string;
name: string;
nameEn: string;
description: string;
/** 100점 만점 중 배점 */
weight: number;
}
export interface Rubric {
version: string;
updatedAt: string;
categories: RubricCategory[];
criteria: RubricCriterion[];
}
/** 개별 항목 채점 결과 */
export interface CriterionResult {
criterionId: string;
/** 'unverified' → 분모 제외 */
level: CriterionLevel | 'unverified';
/** 실측 근거 (한 줄) */
evidence: string;
/** 실측 원문·URL 등 */
source?: string;
}
export type ActionPriority = 'P0' | 'P1' | 'P2';
export interface ActionItem {
priority: ActionPriority;
title: string;
detail: string;
/** 연결된 기준 항목 */
criterionIds: string[];
/** 예상 소요 */
effort: '1일' | '1주' | '2~4주' | '지속';
}
export interface DiscoveryResult {
id: string;
clinicName: string;
url: string;
industry: string;
auditedAt: string;
rubricVersion: string;
/** 측정 조건 명시 (정직성 규약) */
conditions: string[];
results: CriterionResult[];
/** AI가 지금 이 업체를 어떻게 읽는지. 핵심 발견 */
keyFindings: { title: string; detail: string; severity: 'critical' | 'warning' | 'good' }[];
actions: ActionItem[];
/** 하지 않을 것 + 이유 */
notDoing: { item: string; reason: string }[];
}
/** 집계 결과 */
export interface CategoryScore {
category: RubricCategory;
earned: number;
possible: number; // 검증된 항목의 배점 합
weight: number; // 원래 배점
pct: number; // 0~100
verifiedCount: number;
totalCount: number;
}
export interface OverallScore {
score: number; // 0~100 (검증 항목 기준 정규화)
earned: number;
possible: number;
categories: CategoryScore[];
grade: 'A' | 'B' | 'C' | 'D';
}