kcg-ai-monitoring/frontend/src/lib/i18n/locales/ko/detection.json
htlee cbfed23823 feat(detection): 환적 의심 전용 탐지 페이지 신설 (Phase 0-3)
docs/prediction-analysis.md §7 P1 권고의 "UI 미노출 탐지" 해소 중 두 번째.
prediction algorithms/transshipment.py 5단계 필터 파이프라인 결과를 전체 목록·
집계·상세 수준으로 조회하는 READ 전용 대시보드.

### 배경
기존 features/vessel/TransferDetection.tsx 는 선박 상세 수준(특정 MMSI 의 환적
이력)이고, 환적 의심 선박 전체 목록을 보려면 ChinaFishing 의 탭 중 하나를 거쳐야
했다. /api/analysis/transship 엔드포인트는 이미 존재하나 전용 페이지가 없었음.

### 변경
- frontend/src/features/detection/TransshipmentDetection.tsx 신설 (405 라인)
  - PageContainer + PageHeader(ArrowLeftRight) + KPI 5장
    (Total / Transship tier CRITICAL/HIGH/MEDIUM / Risk CRITICAL)
  - DataTable 8컬럼 (analyzedAt / mmsi / pairMmsi / duration / tier / risk / zone)
  - features.transship_tier 읽어 Badge 로 심각도 표시
  - 필터: hours(1/6/12/24/48) / riskLevel / mmsi 검색
  - 상세 패널: 분석 피처 JSON 원본 + 좌표 + transship_score
  - 기존 analysisApi.getTransshipSuspects 재사용 — backend 변경 없음
- index.ts + componentRegistry.ts 등록
- detection.json (ko/en) transshipment.* 네임스페이스 추가 (각 44키)
- common.json (ko/en) nav.transshipment 추가
- V033__menu_transshipment_detection.sql
  - auth_perm_tree(detection:transshipment, nav_sort=910)
  - ADMIN 5 ops + OPERATOR/ANALYST/FIELD/VIEWER READ

### 권한 주의
/api/analysis/transship 의 @RequirePermission 은 현재 detection:dark-vessel.
이 메뉴 READ 만으로는 API 호출 불가. 현행 운영자 역할(OPERATOR/ANALYST/FIELD)
은 dark-vessel READ 도 보유하므로 실용 동작.
향후 VesselAnalysisController.listTransshipSuspects 의 @RequirePermission 을
detection:transshipment 로 교체하는 권한 일관화는 별도 MR (후속).

### 검증
- npx tsc --noEmit 통과
- pre-commit tsc + ESLint 통과 예정
- Flyway V033 자동 적용 (백엔드 재배포 필요)
2026-04-20 05:51:06 +09:00

195 lines
6.1 KiB
JSON

{
"darkVessel": {
"title": "Dark Vessel 탐지",
"desc": "SFR-09 | AIS 조작·위장·Dark Vessel 등 불법 패턴 탐지·분류·라벨링"
},
"gearDetection": {
"title": "어망·어구 탐지",
"desc": "SFR-10 | 불법 어구 위치·허가 현황·위험도 모니터링"
},
"chinaFishing": {
"title": "중국어선 분석",
"desc": "SFR-09/10 | 통합센서 기반 중국어선 조업 패턴·환적·어구 분석"
},
"gearId": {
"title": "어구 식별 분석",
"desc": "SFR-10 | AI 기반 어구 원산지·유형 자동 식별 및 판정"
},
"transshipment": {
"title": "환적 의심 탐지",
"desc": "prediction 5단계 필터 파이프라인(이종 쌍 → 감시영역 → RENDEZVOUS 90분+ → 점수 50+ → 밀집 방폭) 통과 선박 목록. features.transship_tier 기반 심각도 분류",
"refresh": "새로고침",
"stats": {
"title": "현황 요약",
"total": "전체",
"tierCritical": "환적 CRITICAL",
"tierHigh": "환적 HIGH",
"tierMedium": "환적 MEDIUM",
"riskCritical": "종합위험 CRITICAL"
},
"list": {
"title": "환적 의심 선박",
"empty": "최근 {{hours}}시간 내 환적 의심 선박이 없습니다."
},
"columns": {
"analyzedAt": "분석 시각",
"mmsi": "MMSI",
"pairMmsi": "상대 MMSI",
"durationMin": "지속(분)",
"tier": "환적 tier",
"riskScore": "위험도",
"riskLevel": "종합 위험",
"zone": "수역"
},
"filters": {
"hours": "조회 기간",
"level": "위험도",
"mmsi": "MMSI 검색",
"hoursValue": "최근 {{h}}시간",
"allLevel": "전체 위험도"
},
"detail": {
"title": "환적 의심 상세",
"location": "좌표",
"features": "분석 피처 원본",
"transshipScore": "환적 점수",
"close": "닫기"
},
"error": {
"loadFailed": "환적 의심 목록을 불러오지 못했습니다."
}
},
"illegalPattern": {
"title": "불법 조업 이벤트",
"desc": "수역-어구 위반 / 영해 침범 / 특정수역 진입 등 불법 조업 의심 이벤트 통합 조회 (READ 전용 — 처리 액션은 이벤트 목록에서)",
"refresh": "새로고침",
"stats": {
"title": "심각도 분포",
"total": "전체"
},
"byCategory": {
"title": "카테고리별 건수"
},
"category": {
"GEAR_ILLEGAL": "어구 위반",
"EEZ_INTRUSION": "영해/접속수역 침범",
"ZONE_DEPARTURE": "특정수역 진입"
},
"categoryDesc": {
"GEAR_ILLEGAL": "G-01/G-05/G-06 수역·어구 불일치, 고정어구 drift, 쌍끌이 공조",
"EEZ_INTRUSION": "영해(CRITICAL) / 접속수역 + 고위험 위반",
"ZONE_DEPARTURE": "관심 수역(ZONE_I~IV) 진입 + 위험도 40+"
},
"list": {
"title": "이벤트 목록",
"empty": "조건에 맞는 불법 조업 이벤트가 없습니다."
},
"columns": {
"occurredAt": "발생 시각",
"level": "심각도",
"category": "카테고리",
"title": "제목",
"mmsi": "MMSI",
"zone": "수역",
"status": "상태"
},
"filters": {
"category": "카테고리",
"level": "심각도",
"mmsi": "MMSI 검색",
"limit": "최대",
"allCategory": "전체 카테고리",
"allLevel": "전체 심각도"
},
"status": {
"NEW": "신규",
"ACKED": "확인",
"RESOLVED": "처리완료",
"FALSE_ALARM": "오탐"
},
"detail": {
"title": "이벤트 상세",
"vesselName": "선박명",
"location": "좌표",
"features": "추가 정보",
"close": "닫기",
"openEventList": "이벤트 목록에서 열기"
},
"error": {
"loadFailed": "이벤트를 불러오지 못했습니다."
}
},
"gearCollision": {
"title": "어구 정체성 충돌 탐지",
"desc": "동일 어구 이름이 서로 다른 MMSI 로 같은 사이클에 동시 송출되는 공존 패턴 — 어구 복제/스푸핑 의심",
"stats": {
"title": "현황 요약",
"total": "전체",
"open": "미검토",
"reviewed": "검토됨",
"confirmed": "불법 확정",
"falsePositive": "오탐"
},
"list": {
"title": "충돌 이력",
"empty": "최근 {{hours}}시간 내 감지된 충돌이 없습니다.",
"refresh": "새로고침"
},
"columns": {
"name": "어구명",
"mmsiPair": "MMSI 쌍",
"parentName": "추정 모선",
"coexistenceCount": "공존 횟수",
"maxDistance": "최대 거리(km)",
"severity": "심각도",
"status": "상태",
"lastSeen": "마지막 감지",
"actions": "액션"
},
"filters": {
"status": "상태",
"severity": "심각도",
"name": "어구명 검색",
"hours": "조회 기간(시간)",
"allStatus": "전체 상태",
"allSeverity": "전체 심각도"
},
"detail": {
"title": "공존 상세",
"evidence": "관측 이력",
"trajectoryCompare": "궤적 비교",
"firstSeenAt": "최초 감지",
"lastSeenAt": "마지막 감지",
"swapCount": "교체 누적"
},
"resolve": {
"title": "운영자 분류",
"reviewed": "검토 완료",
"confirmedIllegal": "불법으로 확정",
"falsePositive": "오탐으로 분류",
"reopen": "재오픈",
"note": "판정 메모",
"notePlaceholder": "분류 사유·추가 증거 등을 기록하세요",
"submit": "저장",
"cancel": "취소",
"confirmPrompt": "선택한 분류로 상태를 갱신합니다. 계속할까요?"
},
"status": {
"open": "미검토",
"reviewed": "검토됨",
"confirmedIllegal": "불법 확정",
"falsePositive": "오탐"
},
"severity": {
"CRITICAL": "매우 심각",
"HIGH": "심각",
"MEDIUM": "주의",
"LOW": "경미"
},
"error": {
"loadFailed": "충돌 목록을 불러오지 못했습니다",
"resolveFailed": "분류 저장에 실패했습니다"
}
}
}