- 채점 기준표: 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>
126 lines
3.2 KiB
TypeScript
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';
|
|
}
|