perf: 렌더링 성능 최적화 + 환적 Python 이관 + 중국어선감시 통합 #158

병합
htlee perf/rendering-optimization 에서 develop 로 9 commits 를 머지했습니다 2026-03-23 13:16:25 +09:00

9 커밋

작성자 SHA1 메시지 날짜
e06a35cd1e docs: 릴리즈 노트 업데이트 2026-03-23 13:15:34 +09:00
1e9d5cd935 fix: 헤더 레이아웃 정리 — 이란 mode-toggle 좌측 배치 + Flag 빈값 표기 수정
- #dashboard-header-slot: flex + justify-content:center 기본 중앙 배치
- 이란 mode-toggle-left: position:absolute left:0 → 탭 오른쪽 배치
- 한국 필터 탭: 중앙 배치 유지
- 감시 목록 Flag 빈값: '??' → '-'

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:14:33 +09:00
c515975185 fix: 헤더 1행 배치 + 비허가 어구 2개 이상만 탐지 + 중국 어구그룹 감시 배지
- 헤더 mode-toggle: flex-wrap:nowrap + overflow-x:auto → 1행 가로 스크롤
- 비허가 어구 그룹: 어구 2개 이상일 때만 그룹 탐지/폴리곤 생성 (1개는 제외)
  → 조업구역내 어구 + 선단 현황은 현행 유지
- cnFishing 배지: '중국 어구그룹 감시 N개' (어구그룹 수=고유 모선명 수)
  → 어구 패턴 매칭 선박만 집계 (중국 어선 단독은 제외)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:03:03 +09:00
0da477c53c feat: 중국어선감시 KoreaFilters 통합 + 필터 배지 클릭 선박목록/CSV 다운로드
- cnFishing을 KoreaFilters 인터페이스에 통합 (koreaLayers → koreaFilters)
  → 다른 필터 탭과 동일한 선박 비활성화/상단 배지/카운트 동작
- 상단 필터 배지 클릭 → 대상 선박 목록 패널 (MMSI/이름/국적/유형/속도)
  → 선박 클릭 시 flyTo, 200척까지 표시
- CSV 다운로드: BOM 포함 UTF-8, 필터별 파일명 (e.g. cnFishing_2026-03-23.csv)
- cnFishingSuspects Set 추가 (useKoreaFilters 반환값)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:55:52 +09:00
18b827ced0 fix: 한국 필터 토글 시 선박 표시 복원 + 필터별 개별 탐지 카운트
- anyKoreaFilterOn 시 filteredShips(필터 결과) 전달, 비활성 시 allShips(전체) 전달
- 상단 배너: 합산 "N척 탐지" → 필터별 개별 카운트 (불법어선 3척, 다크베셀 5척 등)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:46:23 +09:00
459a0e3d6e perf: LIVE 모드 매초 선박 재계산 제거 — currentTime 의존성 완전 분리
- liveShips: baseShipsKorea 변경(5분 polling) 시에만 계산. currentTime 의존성 없음.
- replayShips: REPLAY 모드에서만 currentTime으로 위치 보간.
- LIVE 모드: 매초 useMemo 실행 자체가 발생하지 않음.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:40:32 +09:00
2a2e4e3590 perf: LIVE 모드 매초 선박 재계산 제거 — 동일 참조 반환으로 하위 useMemo 연쇄 차단
- LIVE 모드: enrichedShipsRef 동일 참조 반환
  → currentTime 매초 변경 시에도 visibleShips/filteredShips/shipGeoJson 재실행 안 함
- mtCategory/natGroup: baseShipsKorea 변경 시 1회 새 배열 생성 (useState 불변성 준수)
- REPLAY 모드: propagateShips로 위치 보간 유지 (mtCategory는 spread로 상속)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:37:58 +09:00
d9ba1b0e1a feat: 환적탐지 Python 이관 — O(n²) 프론트엔드 근접탐지 → 서버사이드 공간인덱스
- prediction/algorithms/transshipment.py 신규: 그리드 공간인덱스 O(n log n) 환적 쌍 탐지
  → 후보 필터(sog<2, tanker/cargo/fishing, 외국해안 제외) + 110m 근접 + 60분 지속
- prediction/scheduler.py: 8단계 환적탐지 사이클 추가, pair_history 영속화
- prediction/models/result.py: is_transship_suspect, transship_pair_mmsi, transship_duration_min
- prediction/db/kcgdb.py: UPSERT 쿼리에 3개 컬럼 추가
- database/migration/008_transshipment.sql: ALTER TABLE 3개 컬럼 추가
- backend VesselAnalysisResult + VesselAnalysisDto: TransshipInfo 중첩 DTO 추가
- frontend types.ts: algorithms.transship 타입 추가
- frontend useKoreaFilters.ts: O(n²) 65줄 → analysisMap 소비 8줄
  → currentTime 매초 의존성 제거, proximityStartRef 제거

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:29:44 +09:00
13427f32bb perf: 렌더링 성능 최적화 — deck.gl updateTriggers + 선박 토글 MapLibre filter 전환
- deck.gl updateTriggers 적용: 정적 레이어(4개 sub-hook) + 분석 레이어 + KoreaMap 인라인 레이어
  → 줌 변경 시 accessor 재평가 최소화
- 선박 카테고리/국적 토글: JS-level 배열 필터링 → MapLibre GPU-side filter 표현식
  → 토글 시 13K GeoJSON 재생성 + GPU 재업로드 제거
- Ship.mtCategory/natGroup 사전 계산: propagateShips 후 1회 계산, 이후 Set.has() O(1)
  → getMarineTrafficCategory() 13K×N회 호출 제거
- onPick useCallback 안정화: 매 렌더마다 28개 정적 레이어 불필요 재생성 방지
- SVG 데이터 URI 모듈 레벨 캐싱: 함수 호출 간 캐시 유지
- useAnalysisDeckLayers 데이터/스타일 분리: 줌 변경 시 ships 필터링 스킵

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:24:36 +09:00