- prediction: dark_vessel 의심 점수화(8패턴 0~100), transshipment 베테랑 재설계
- prediction: vessel_store/scheduler/config 개선, monitoring_zones 데이터 추가
- prediction: signal_api 신규, diagnostic-snapshot 스크립트 추가
- frontend: 지도 레이어 구조 정리 (BaseMap, useMapLayers, static layers)
- frontend: NoticeManagement CRUD 권한 가드 추가 (admin:notices C/U/D)
- frontend: EventList CRUD 권한 가드 추가 (enforcement:event-list U, enforcement:enforcement-history C)
- frontend: 지도 페이지 6개 + Dashboard 등 4개 페이지 소폭 개선
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
VesselDetail:
- iran proxy → prediction 직접 API 전환 (getAnalysisLatest/getAnalysisHistory)
- dark 패턴 시각화: dark_tier Badge, 의심점수 바, dark_patterns 태그, 7일 반복 횟수
- 환적 의심 분석 섹션 추가 (transship_tier, transship_score)
- 24h AIS 수신 이력 타임라인 그래프 (시간대별 수신/소실 막대)
- 단속 이력 탭 신설 (GET /api/enforcement/records?vesselMmsi)
- 지도 중심좌표를 분석 결과의 lat/lon으로 자동 설정
- 위험도 점수 표시 0~100 직접 사용 (iran proxy의 0~1 변환 제거)
DarkVesselDetection:
- iran proxy → getDarkVessels() 직접 API 전환
- derivePattern() 제거 → features.dark_tier/dark_suspicion_score/dark_patterns 직접 표시
- tier 기반 KPI 카드 (CRITICAL/HIGH/WATCH) + 클릭 필터
- 의심 점수 내림차순 정렬 (가장 의심스러운 순)
- tier별 필터 셀렉트 추가
- 지도 범례: tier 기반 색상
enforcement.ts: getEnforcementRecords에 vesselMmsi 파라미터 추가
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- EventList 인라인 액션 버튼 4종 추가 (확인/선박상세/단속등록/오탐)
- 확인(ACK): NEW 상태 이벤트만 활성, ackEvent API 연동
- 선박 상세: /vessel/{mmsi} 네비게이션
- 단속 등록: createEnforcementRecord API → 이벤트 RESOLVED 자동 전환
- 오탐 처리: updateEventStatus(FALSE_POSITIVE) 연동
- MMSI → VesselDetail 링크 3개 화면 적용
- EventList: MMSI 컬럼 클릭 → /vessel/{mmsi}
- DarkVesselDetection: MMSI 컬럼 클릭 → /vessel/{mmsi}
- EnforcementHistory: 대상 선박 컬럼 클릭 → /vessel/{mmsi}
- PredictionEvent 타입에 features 필드 추가 (dark_tier, transship_score 등)
- analysisApi.ts 서비스 신규 생성 (직접 조회 API 5개 연동)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
이슈: "Select element must have an accessible name" — 스크린 리더가 용도를
인지할 수 없어 WCAG 2.1 Level A 위반.
수정:
- Select 공통 컴포넌트 타입을 union으로 강제
- aria-label | aria-labelledby | title 중 하나는 TypeScript 컴파일 타임에 필수
- 누락 시 tsc 단계에서 즉시 실패 → 회귀 방지
- 네이티브 <select> 5곳 aria-label 추가:
- admin/SystemConfig: 대분류 필터
- detection/RealVesselAnalysis: 해역 필터
- detection/RealGearGroups: 그룹 유형 필터
- detection/ChinaFishing: 관심영역 선택
- detection/GearIdentification: SelectField에 label prop 추가
- 쇼케이스 FormSection Select 샘플에 aria-label 추가
이제 모든 Select 사용처가 접근 이름을 가지며,
향후 신규 Select 사용 시 tsc가 누락을 차단함.
- 모든 feature 페이지의 Badge className 패턴을 intent/size prop으로 변환
- 컬러풀 액션 버튼 (bg-*-500/600/700 + text-heading) -> text-on-vivid
- 검색/필터 버튼 배경 bg-blue-400 + text-on-bright (밝은 배경 위 검정)
- ROLE_COLORS 4곳 중복 제거 (MainLayout/UserRoleAssignDialog/
PermissionsPanel/AccessControl) -> getRoleBadgeStyle 공통 호출
- PermissionsPanel 역할 생성/수정에 ColorPicker 통합
- MainLayout: PagePagination + scroll page state 제거 (데이터 페이지네이션 혼동)
- Dashboard RiskBar 단위 버그 수정 (0~100 정수 처리)
- ReportManagement, TransferDetection p-5 space-y-4 padding 복구
- EnforcementHistory 그리드 minmax 적용으로 컬럼 잘림 해소
- timeline 시간 formatDateTime 적용 (ISO T 구분자 처리)
- 각 feature 페이지가 공통 카탈로그 API (getXxxIntent/Label/Classes) 사용
## 시간 표시 KST 통일
- shared/utils/dateFormat.ts 공통 유틸 신규 (formatDateTime/formatDate/formatTime/toDateParam)
- 14개 파일에서 인라인 toLocaleString → 공통 유틸 교체
## i18n 'group.parentInference' 사이드바 미번역 수정
- ko/en common.json의 'group' 키 중복 정의를 병합
(95행 두번째 group 객체가 35행을 덮어써서 parentInference 누락)
## Dashboard/MonitoringDashboard/Statistics 더미→실 API
- 백엔드 GET /api/stats/hourly 신규 (PredictionStatsHourly 엔티티/리포지토리)
- Dashboard: HOURLY_DETECTION/VESSEL_TYPE/AREA_RISK 하드코딩 제거 →
getHourlyStats(24) + getDailyStats(today) 결과로 useMemo 변환
- MonitoringDashboard: TREND Math.random() 제거 → getHourlyStats 기반
위험도 가중평균 + 경보 카운트
- Statistics: KPI_DATA 하드코딩 제거 → getKpiMetrics() 결과를 표 행으로
## Store mock 의존성 제거
- eventStore.alerts/MOCK_ALERTS 제거 (MobileService는 events에서 직접 추출)
- enforcementStore.plans 제거 (EnforcementPlan은 이미 직접 API 호출)
- transferStore + MOCK_TRANSFERS 완전 제거
(ChinaFishing/TransferDetection은 RealTransshipSuspects 컴포넌트 사용)
- mock/events.ts, mock/enforcement.ts, mock/transfers.ts 파일 삭제
## RiskMap 랜덤 격자 제거
- generateGrid() Math.random() 제거 → 빈 배열 + 'AI 분석 데이터 수집 중' 안내
- MTIS 외부 통계 5개 탭에 [MTIS 외부 통계] 배지 추가
## 12개 mock 화면에 '데모 데이터' 노란색 배지 추가
- patrol/PatrolRoute, FleetOptimization
- admin/AdminPanel, DataHub, NoticeManagement, SystemConfig
- ai-operations/AIModelManagement, MLOpsPage
- field-ops/ShipAgent
- statistics/ReportManagement, ExternalService
- surveillance/MapControl
## 백엔드 NUMERIC precision 동기화
- PredictionKpi.deltaPct: 5,2 → 12,2
- PredictionStatsDaily/Monthly.aiAccuracyPct: 5,2 → 12,2
- (V015 마이그레이션과 동기화)
44 files changed, +346 / -787
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
탐지 화면 3개:
- GearDetection: gearStore 더미 → fetchGroups() API (GEAR_IN/OUT_ZONE)
- DarkVesselDetection: vesselStore 더미 → fetchVesselAnalysis() + filterDarkVessels()
- 패턴 자동 분류 (완전차단/장기소실/MMSI변조/간헐송출)
- ChinaFishing: inline 더미 → fetchVesselAnalysis() + mmsi 412* 필터
- 센서 카운터 동적 계산, 위험도 분포 도넛 차트
함정/단속계획:
- patrol.ts: 스텁 → GET /api/patrol-ships 실제 호출
- patrolStore: API 기반 (routes/scenarios는 mock 유지)
- EnforcementPlan: GET /api/enforcement/plans 연결
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 6: iran 백엔드 실연결 + 화면 연동
- application.yml: app.iran-backend.base-url=https://kcg.gc-si.dev
- IranBackendClient: RestClient 확장 (Accept JSON header, getAs<T>)
- VesselAnalysisProxyController: HYBRID 합성 로직 추가
- GET /api/vessel-analysis: stats + 7423건 분석 결과 통과
- GET /api/vessel-analysis/groups: 476건 그룹 + 자체 DB resolution 합성
- GET /api/vessel-analysis/groups/{key}/detail
- GET /api/vessel-analysis/groups/{key}/correlations
- 권한: detection / detection:gear-detection (READ)
- 프론트 services/vesselAnalysisApi.ts: 타입 + 필터 헬퍼
(filterDarkVessels, filterSpoofingVessels, filterTransshipSuspects)
- features/detection/RealGearGroups.tsx: 어구/선단 그룹 실시간 표시
(FLEET/GEAR_IN_ZONE/GEAR_OUT_ZONE 필터, 통계 5종, 운영자 결정 합성 표시)
- features/detection/RealVesselAnalysis.tsx: 분석 결과 모드별 렌더
- mode='dark' / 'spoofing' / 'transship' / 'all'
- 위험도순 정렬 + 6개 통계 카드 + 해역/Dark/Spoofing/전재 표시
- 화면 연동:
- GearDetection → RealGearGroups 추가
- DarkVesselDetection → RealDarkVessels + RealSpoofingVessels
- ChinaFishing(dashboard) → RealAllVessels
- TransferDetection → RealTransshipSuspects
Phase 7: 시스템 상태 대시보드
- features/monitoring/SystemStatusPanel.tsx
- 3개 서비스 카드: KCG Backend / iran 백엔드 / Prediction
- 위험도 분포 (CRITICAL/HIGH/MEDIUM/LOW) 4개 박스
- 30초 자동 폴링
- MonitoringDashboard 최상단에 SystemStatusPanel 추가
Phase 8: AI 채팅 기반 (SSE는 Phase 9 인증 후)
- 프론트 services/chatApi.ts: sendChatMessage (graceful fallback)
- 백엔드 PredictionProxyController.chat 추가
- POST /api/prediction/chat
- 권한: ai-operations:ai-assistant (READ)
- 현재 stub 응답 (iran chat 인증 토큰 필요)
- AIAssistant 페이지에 백엔드 호출 통합
(handleSend → sendChatMessage → 응답 표시 + graceful 메시지)
검증:
- 백엔드 컴파일/기동 성공 (Started in 5.2s)
- iran 프록시: 471개 그룹, 7423건 분석 결과 정상 통과
- 프론트 빌드 통과 (502ms)
- E2E 시나리오:
- admin 로그인 → /api/vessel-analysis/groups → 476건 + serviceAvailable=true
- /api/prediction/chat → stub 응답 (Phase 9 안내)
설계 원칙:
- iran 백엔드 미연결 시 graceful degradation (serviceAvailable=false + 빈 데이터)
- HYBRID 합성: prediction 후보 + 자체 DB의 운영자 결정을 백엔드에서 조합
- 향후 iran 인증 토큰 통과 후 SSE 채팅 활성화
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 1: 모노레포 디렉토리 구조 구축
- 기존 React 프로젝트를 frontend/ 디렉토리로 이동 (git mv)
- backend/ 디렉토리 생성 (Phase 2에서 Spring Boot 초기화)
- database/migration/ 디렉토리 생성 (Phase 2에서 Flyway 마이그레이션)
- 루트 .gitignore에 frontend/, backend/ 경로 반영
- 루트 CLAUDE.md를 모노레포 가이드로 갱신
- Makefile 추가 (dev/build/lint 통합 명령)
- frontend/vite.config.ts에 /api → :8080 백엔드 proxy 설정
- .githooks/pre-commit을 모노레포 구조에 맞게 갱신
(frontend/ 변경 시 frontend/ 내부에서 검증)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>