kcg-ai-monitoring/frontend/src/shared/constants/catalogRegistry.ts
htlee 524df19f20 feat(frontend): 선박 유형 한글 카탈로그 + 중국 선박 분석 그리드 정합성
vessel_type 카탈로그
- shared/constants/vesselTypes.ts 신규 — TRAWL/PURSE/GILLNET/LONGLINE/
  TRAP/CARGO/UNKNOWN 7종 + getVesselTypeLabel / getVesselTypeIntent
  헬퍼. 기존 alertLevels 카탈로그 패턴 답습
- catalogRegistry 에 VESSEL_TYPES 등록 — design-system 쇼케이스에 자동
  노출

RealVesselAnalysis 필터 props 확장
- Props 에 mmsiPrefix / minRiskScore / size 추가 (all·spoofing mode)
- 선박 유형 컬럼을 한글 라벨로 렌더
- RealAllVessels 편의 export 를 mmsiPrefix='412' 로 고정 + 제목을
  '중국 선박 전체 분석 결과 (실시간)' 로 변경

효과
- Tab 1 상단 그리드가 중국 선박만 표시해 페이지 성격과 일치
- 선박 유형 '저인망/선망/유자망/연승/통발/운반선/미분류' 한글 표시
- 55점 HIGH 같은 중국 선박이 상단/하단 양쪽에 일관되게 노출
2026-04-16 15:20:08 +09:00

336 lines
11 KiB
TypeScript

/**
* 분류 카탈로그 중앙 레지스트리 (Single Source of Truth)
*
* 디자인 쇼케이스의 카탈로그 섹션과 실제 프론트가 **모두 이 레지스트리를 참조**한다.
* 따라서:
* - 특정 분류의 라벨을 바꾸면 (예: '심각' → '매우 심각') 쇼케이스 + 실 페이지 동시 반영
* - 특정 분류의 intent/색상을 바꾸면 역시 자동 반영
* - 새 카탈로그를 추가하면 쇼케이스에 자동 노출 (등록만 하면 됨)
*
* 각 카탈로그는 `items: Record<Code, Meta>` 형태를 가진다 (Meta는 개별 파일의 타입 사용).
* 쇼케이스는 heterogeneous 타입을 허용하므로 CatalogEntry의 items는 Record<string, AnyMeta> 로 처리.
*/
import { ALERT_LEVELS } from './alertLevels';
import { VIOLATION_TYPES } from './violationTypes';
import { EVENT_STATUSES } from './eventStatuses';
import { ENFORCEMENT_ACTIONS } from './enforcementActions';
import { ENFORCEMENT_RESULTS } from './enforcementResults';
import { PATROL_STATUSES } from './patrolStatuses';
import { ENGINE_SEVERITIES } from './engineSeverities';
import { DEVICE_STATUSES } from './deviceStatuses';
import {
PARENT_RESOLUTION_STATUSES,
LABEL_SESSION_STATUSES,
} from './parentResolutionStatuses';
import {
MODEL_STATUSES,
QUALITY_GATE_STATUSES,
EXPERIMENT_STATUSES,
} from './modelDeploymentStatuses';
import { GEAR_GROUP_TYPES } from './gearGroupTypes';
import { DARK_VESSEL_PATTERNS } from './darkVesselPatterns';
import { USER_ACCOUNT_STATUSES } from './userAccountStatuses';
import { LOGIN_RESULTS } from './loginResultStatuses';
import { PERMIT_STATUSES, GEAR_JUDGMENTS } from './permissionStatuses';
import {
VESSEL_SURVEILLANCE_STATUSES,
VESSEL_RISK_RINGS,
} from './vesselAnalysisStatuses';
import { CONNECTION_STATUSES } from './connectionStatuses';
import { TRAINING_ZONE_TYPES } from './trainingZoneTypes';
import { MLOPS_JOB_STATUSES } from './mlopsJobStatuses';
import { THREAT_LEVELS, AGENT_PERM_TYPES, AGENT_EXEC_RESULTS } from './aiSecurityStatuses';
import { ZONE_CODES } from './zoneCodes';
import { GEAR_VIOLATION_CODES } from './gearViolationCodes';
import { VESSEL_TYPES } from './vesselTypes';
/**
* 카탈로그 공통 메타 — 쇼케이스 렌더와 UI 일관성을 위한 최소 스키마
*/
export interface CatalogEntry {
/** 안정적 ID (쇼케이스 추적 ID의 슬러그 부분) */
id: string;
/** 쇼케이스 추적 ID (TRK-CAT-*) */
showcaseId: string;
/** 쇼케이스 섹션 제목 (한글) */
titleKo: string;
/** 쇼케이스 섹션 제목 (영문) */
titleEn: string;
/** 1줄 설명 */
description: string;
/** 출처 (백엔드 enum / code_master 등) */
source?: string;
/** 카탈로그 데이터 — items의 각 meta는 { code, fallback?, intent?, classes?, ... } 구조 */
items: Record<string, unknown>;
}
/**
* 전체 카탈로그 레지스트리
*
* ⚠️ 새 카탈로그 추가 시:
* 1. shared/constants/에 파일 생성 (items record + 헬퍼 함수)
* 2. 이 레지스트리에 CatalogEntry 추가
* 3. 쇼케이스에 자동 노출 + 실 페이지에서 헬퍼 함수로 참조
*/
export const CATALOG_REGISTRY: CatalogEntry[] = [
{
id: 'alert-level',
showcaseId: 'TRK-CAT-alert-level',
titleKo: '위험도',
titleEn: 'Alert Level',
description: 'CRITICAL / HIGH / MEDIUM / LOW — 모든 이벤트/알림 배지',
source: 'backend code_master EVENT_LEVEL',
items: ALERT_LEVELS,
},
{
id: 'violation-type',
showcaseId: 'TRK-CAT-violation-type',
titleKo: '위반 유형',
titleEn: 'Violation Type',
description: '중국불법조업 / 환적의심 / EEZ침범 등',
source: 'backend ViolationType enum',
items: VIOLATION_TYPES,
},
{
id: 'vessel-type',
showcaseId: 'TRK-CAT-vessel-type',
titleKo: '선박 유형',
titleEn: 'Vessel Type',
description: 'TRAWL / PURSE / GILLNET / LONGLINE / TRAP / CARGO / UNKNOWN — prediction 분류 + fleet_vessels 매핑',
source: 'prediction AnalysisResult.vessel_type',
items: VESSEL_TYPES,
},
{
id: 'event-status',
showcaseId: 'TRK-CAT-event-status',
titleKo: '이벤트 상태',
titleEn: 'Event Status',
description: 'NEW / ACK / IN_PROGRESS / RESOLVED / FALSE_POSITIVE',
source: 'backend code_master EVENT_STATUS',
items: EVENT_STATUSES,
},
{
id: 'enforcement-action',
showcaseId: 'TRK-CAT-enforcement-action',
titleKo: '단속 조치',
titleEn: 'Enforcement Action',
description: 'CAPTURE / INSPECT / WARN / DISPERSE / TRACK / EVIDENCE',
source: 'backend code_master ENFORCEMENT_ACTION',
items: ENFORCEMENT_ACTIONS,
},
{
id: 'enforcement-result',
showcaseId: 'TRK-CAT-enforcement-result',
titleKo: '단속 결과',
titleEn: 'Enforcement Result',
description: 'PUNISHED / REFERRED / WARNED / RELEASED / FALSE_POSITIVE',
source: 'backend code_master ENFORCEMENT_RESULT',
items: ENFORCEMENT_RESULTS,
},
{
id: 'patrol-status',
showcaseId: 'TRK-CAT-patrol-status',
titleKo: '함정 상태',
titleEn: 'Patrol Status',
description: '출동 / 순찰 / 복귀 / 정박 / 정비 / 대기',
source: 'backend code_master PATROL_STATUS',
items: PATROL_STATUSES,
},
{
id: 'engine-severity',
showcaseId: 'TRK-CAT-engine-severity',
titleKo: '엔진 심각도',
titleEn: 'Engine Severity',
description: 'AI 모델/분석엔진 오류 심각도',
items: ENGINE_SEVERITIES,
},
{
id: 'device-status',
showcaseId: 'TRK-CAT-device-status',
titleKo: '함정 Agent 장치 상태',
titleEn: 'Device Status',
description: 'ONLINE / OFFLINE / SYNCING / NOT_DEPLOYED',
items: DEVICE_STATUSES,
},
{
id: 'parent-resolution',
showcaseId: 'TRK-CAT-parent-resolution',
titleKo: '모선 확정 상태',
titleEn: 'Parent Resolution Status',
description: 'PENDING / CONFIRMED / REJECTED / REVIEWING',
items: PARENT_RESOLUTION_STATUSES,
},
{
id: 'label-session',
showcaseId: 'TRK-CAT-label-session',
titleKo: '라벨 세션',
titleEn: 'Label Session Status',
description: '모선 학습 세션 상태',
items: LABEL_SESSION_STATUSES,
},
{
id: 'model-status',
showcaseId: 'TRK-CAT-model-status',
titleKo: 'AI 모델 상태',
titleEn: 'Model Status',
description: 'DEV / STAGING / CANARY / PROD / ARCHIVED',
items: MODEL_STATUSES,
},
{
id: 'quality-gate',
showcaseId: 'TRK-CAT-quality-gate',
titleKo: '품질 게이트',
titleEn: 'Quality Gate Status',
description: '모델 배포 전 품질 검증',
items: QUALITY_GATE_STATUSES,
},
{
id: 'experiment',
showcaseId: 'TRK-CAT-experiment',
titleKo: 'ML 실험',
titleEn: 'Experiment Status',
description: 'MLOps 실험 상태',
items: EXPERIMENT_STATUSES,
},
{
id: 'gear-group',
showcaseId: 'TRK-CAT-gear-group',
titleKo: '어구 그룹 유형',
titleEn: 'Gear Group Type',
description: 'FLEET / GEAR_IN_ZONE / GEAR_OUT_ZONE',
items: GEAR_GROUP_TYPES,
},
{
id: 'dark-vessel',
showcaseId: 'TRK-CAT-dark-vessel',
titleKo: '다크베셀 패턴',
titleEn: 'Dark Vessel Pattern',
description: 'AIS 끊김/스푸핑 패턴 5종',
items: DARK_VESSEL_PATTERNS,
},
{
id: 'user-account',
showcaseId: 'TRK-CAT-user-account',
titleKo: '사용자 계정 상태',
titleEn: 'User Account Status',
description: 'ACTIVE / LOCKED / INACTIVE / PENDING',
items: USER_ACCOUNT_STATUSES,
},
{
id: 'login-result',
showcaseId: 'TRK-CAT-login-result',
titleKo: '로그인 결과',
titleEn: 'Login Result',
description: 'SUCCESS / FAILED / LOCKED',
items: LOGIN_RESULTS,
},
{
id: 'permit-status',
showcaseId: 'TRK-CAT-permit-status',
titleKo: '허가 상태',
titleEn: 'Permit Status',
description: '선박 허가 유효 / 만료 / 정지',
items: PERMIT_STATUSES,
},
{
id: 'gear-judgment',
showcaseId: 'TRK-CAT-gear-judgment',
titleKo: '어구 판정',
titleEn: 'Gear Judgment',
description: '합법 / 의심 / 불법',
items: GEAR_JUDGMENTS,
},
{
id: 'vessel-surveillance',
showcaseId: 'TRK-CAT-vessel-surveillance',
titleKo: '선박 감시 상태',
titleEn: 'Vessel Surveillance Status',
description: '관심선박 추적 상태',
items: VESSEL_SURVEILLANCE_STATUSES,
},
{
id: 'vessel-risk-ring',
showcaseId: 'TRK-CAT-vessel-risk-ring',
titleKo: '선박 위험 링',
titleEn: 'Vessel Risk Ring',
description: '지도 마커 위험도 링',
items: VESSEL_RISK_RINGS,
},
{
id: 'connection',
showcaseId: 'TRK-CAT-connection',
titleKo: '연결 상태',
titleEn: 'Connection Status',
description: 'OK / WARNING / ERROR',
items: CONNECTION_STATUSES,
},
{
id: 'training-zone',
showcaseId: 'TRK-CAT-training-zone',
titleKo: '훈련 수역',
titleEn: 'Training Zone Type',
description: 'NAVY / AIRFORCE / ARMY / ADD / KCG',
items: TRAINING_ZONE_TYPES,
},
{
id: 'mlops-job-status',
showcaseId: 'TRK-CAT-mlops-job-status',
titleKo: 'MLOps Job 상태',
titleEn: 'MLOps Job Status',
description: 'running / done / fail / pending',
source: 'LGCNS MLOps 파이프라인',
items: MLOPS_JOB_STATUSES,
},
{
id: 'threat-level',
showcaseId: 'TRK-CAT-threat-level',
titleKo: 'AI 위협 수준',
titleEn: 'AI Threat Level',
description: 'HIGH / MEDIUM / LOW',
source: 'AI 보안 (SER-10)',
items: THREAT_LEVELS,
},
{
id: 'agent-perm-type',
showcaseId: 'TRK-CAT-agent-perm-type',
titleKo: 'Agent 권한 유형',
titleEn: 'Agent Permission Type',
description: 'ADMIN / DELETE / WRITE / READ / EXECUTE',
source: 'AI Agent 보안 (SER-11)',
items: AGENT_PERM_TYPES,
},
{
id: 'agent-exec-result',
showcaseId: 'TRK-CAT-agent-exec-result',
titleKo: 'Agent 실행 결과',
titleEn: 'Agent Execution Result',
description: 'BLOCKED / CONDITIONAL / ALLOWED',
source: 'AI Agent 보안 (SER-11)',
items: AGENT_EXEC_RESULTS,
},
{
id: 'zone-code',
showcaseId: 'TRK-CAT-zone-code',
titleKo: '수역 코드',
titleEn: 'Zone Codes',
description: '특정해역 I~IV / 영해 / 접속수역 / EEZ 외',
source: 'prediction/algorithms/location.py classify_zone()',
items: ZONE_CODES,
},
{
id: 'gear-violation',
showcaseId: 'TRK-CAT-gear-violation',
titleKo: '어구 위반 G코드',
titleEn: 'Gear Violation G-Codes',
description: 'G-01~G-06 어구 위반 유형 (DAR-03)',
source: 'prediction/algorithms/gear_violation.py',
items: GEAR_VIOLATION_CODES,
},
];
/** ID로 특정 카탈로그 조회 */
export function getCatalogById(id: string): CatalogEntry | undefined {
return CATALOG_REGISTRY.find((c) => c.id === id);
}