kcg-monitoring/CLAUDE.md
htlee 433141a3e8 feat: AI 분석 통계 서버사이드 전환 + 어구/선단 UI 개선
- Backend: /api/vessel-analysis 응답에 stats 집계 필드 추가
- Backend: GroupPolygonService.getGearStats() 어구 SQL 집계
- Frontend: 클라이언트 사이드 stats/gearStats 계산 로직 완전 제거
- Frontend: 가상 선박 마커, 어구 겹침 팝업, 패널 아코디언
- Frontend: cnFishingSuspects에 모선 포함
- Python: vessel_store COG bearing 계산 (마지막 2점 기반)

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

214 lines
11 KiB
Markdown
Raw Blame 히스토리

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 프로젝트 개요
- **이름**: KCG 모니터링 대시보드 (kcg-monitoring)
- **구조**: 모노레포 (Frontend + Backend + Prediction)
- **도메인**: https://kcg.gc-si.dev
- **Gitea**: https://gitea.gc-si.dev/gc/kcg-monitoring
## 기술 스택
| 패키지 | 스택 | 비고 |
|--------|------|------|
| **Frontend** | React 19 + TypeScript 5.9 + Vite 7 + Tailwind CSS 4 | i18n(ko/en), 테마(dark/light), MapLibre GL + deck.gl GPU |
| **Backend** | Spring Boot 3.2.5 + Java 21 + PostgreSQL + PostGIS | Google OAuth + JWT, Caffeine 캐시 |
| **Prediction** | FastAPI + Python 3.9 + Shapely + APScheduler | 5분 주기 해양 분석 파이프라인 |
| **DB** | PostgreSQL 16 + PostGIS (211.208.115.83:5432/kcgdb, 스키마: kcg) | |
| **궤적 DB** | PostgreSQL (snpdb, 211.208.115.83:5432/snpdb, 스키마: signal) | LineStringM 궤적 |
| **CI/CD** | Gitea Actions → nginx + systemd | main merge 시 자동 배포 |
## 빌드 및 실행
### Frontend
```bash
cd frontend
npm install
npm run dev # 개발서버 (포트 5173)
npm run build # 프로덕션 빌드
npm run lint # ESLint 검증
```
### Backend
```bash
cd backend
sdk use java 21.0.9-amzn # JDK 21 필수
mvn spring-boot:run -Dspring-boot.run.profiles=local # 개발서버 (포트 8080)
mvn compile # 컴파일 검증
mvn package # JAR 빌드 (target/kcg.jar)
```
### Prediction
```bash
cd prediction
pip install -r requirements.txt # shapely, scikit-learn, apscheduler 등
uvicorn main:app --host 0.0.0.0 --port 8001
```
### Database
```bash
# kcgdb (분석 결과)
psql -h 211.208.115.83 -U kcg_app -d kcgdb -f database/migration/009_group_polygons.sql
# snpdb (궤적 원본) — 읽기 전용, 별도 관리
```
## 프로젝트 구조
```
frontend/ # React 19 + Vite 7 + Tailwind CSS 4 + deck.gl
├── src/
│ ├── App.tsx # 인증가드 → SharedFilterProvider → FontScaleProvider
│ ├── contexts/ # SharedFilterContext, FontScaleContext
│ ├── styles/
│ │ ├── tokens.css # 테마 토큰 (dark/light), Tailwind @theme
│ │ ├── fonts.ts # FONT_MONO/FONT_SANS 상수 (@fontsource-variable)
│ │ └── tailwind.css
│ ├── components/
│ │ ├── common/ # LayerPanel, EventLog, FontScalePanel, ReplayControls
│ │ ├── layers/ # DeckGLOverlay, ShipLayer, AircraftLayer, SatelliteLayer
│ │ ├── iran/ # IranDashboard, ReplayMap, SatelliteMap, GlobeMap
│ │ │ # createIranOil/Airport/MEFacility/MEEnergyHazard Layers
│ │ ├── korea/ # KoreaDashboard, KoreaMap + 25개 레이어/패널
│ │ │ # FleetClusterLayer (API GeoJSON 렌더링)
│ │ │ # AnalysisStatsPanel, FieldAnalysisModal
│ │ └── auth/ # LoginPage
│ ├── hooks/
│ │ ├── useReplay, useMonitor, useAuth, useTheme
│ │ ├── useIranData (더미↔API 토글), useKoreaData, useKoreaFilters
│ │ ├── useVesselAnalysis (5분 폴링, mmsi별 분석 DTO)
│ │ ├── useGroupPolygons (5분 폴링, 선단/어구 폴리곤)
│ │ ├── useStaticDeckLayers (4개 서브훅 조합)
│ │ ├── useAnalysisDeckLayers (위험도/다크/스푸핑 마커)
│ │ ├── useFontScale, useLocalStorage, usePoll
│ │ └── layers/ # createPort/Navigation/Military/FacilityLayers
│ ├── services/ # API 클라이언트 (ships, aircraft, osint, vesselAnalysis 등)
│ ├── data/ # 정적 데이터 (공항, 유전, 샘플, 어업수역 GeoJSON)
│ └── i18n/ # i18next (ko/en)
├── package.json
└── vite.config.ts # Vite + 프록시 (/api/kcg → backend)
backend/ # Spring Boot 3.2 + Java 21
├── src/main/java/gc/mda/kcg/
│ ├── auth/ # Google OAuth + JWT (AuthFilter: 인증 예외 경로 관리)
│ ├── config/ # CORS, Security, CacheConfig (Caffeine)
│ ├── domain/
│ │ ├── analysis/ # VesselAnalysisController/Service/Dto/Repository
│ │ ├── fleet/ # FleetCompanyController, GroupPolygonController/Service/Dto
│ │ ├── event/ # EventController/Service (이란 리플레이)
│ │ ├── aircraft/ # AircraftController/Service (시점 조회)
│ │ └── osint/ # OsintController/Service (시점 조회)
│ └── collector/ # GDELT, GoogleNews, CENTCOM (placeholder)
└── pom.xml
prediction/ # FastAPI + Python 3.9 + APScheduler
├── main.py # FastAPI app + 스케줄러 초기화
├── scheduler.py # 5분 주기 분석 사이클 (7단계 파이프라인 + 폴리곤 생성)
├── fleet_tracker.py # 등록 선단 매칭 + 어구 정체성 추적
├── config.py # Settings (snpdb/kcgdb 접속정보)
├── cache/
│ └── vessel_store.py # 인메모리 AIS 캐시 (14K선박, 24h 윈도우)
├── algorithms/
│ ├── polygon_builder.py # Shapely 폴리곤 생성 (선단/어구 그룹)
│ ├── fleet.py # 선단 패턴 탐지 (PT/FC/PS)
│ ├── transshipment.py # 환적 탐지 (그리드 O(n log n))
│ ├── location.py # 특정어업수역 판정 (Point-in-Polygon)
│ └── ... # dark_vessel, spoofing, risk, fishing_pattern
├── pipeline/ # 7단계 분석 파이프라인
├── models/ # AnalysisResult
├── db/
│ ├── snpdb.py # 궤적 DB (읽기 전용)
│ └── kcgdb.py # 분석 결과 DB (UPSERT + 폴리곤 저장)
├── data/zones/ # 특정어업수역 GeoJSON (EPSG:3857)
└── requirements.txt # shapely, scikit-learn, apscheduler, pandas, numpy
database/ # PostgreSQL 마이그레이션
├── init.sql
└── migration/
├── 001_initial_schema.sql # events, news, osint, users
├── 002_aircraft_positions.sql # PostGIS 활성화
├── 005_vessel_analysis.sql # vessel_analysis_results
├── 007_fleet_registry.sql # fleet_companies, fleet_vessels, gear_identity_log
├── 008_transshipment.sql # 환적 탐지 칼럼 추가
└── 009_group_polygons.sql # group_polygon_snapshots (PostGIS Polygon)
deploy/ # systemd + nginx 배포 설정
.gitea/workflows/deploy.yml # CI/CD (main merge → 자동 빌드/배포)
```
## 주요 기능
### 한국 현황 대시보드
- **선박 모니터링**: 13K+ AIS 선박, MapLibre GPU-side filter, 카테고리/국적 토글
- **감시 탭**: 불법어선, 환적, 다크베셀, 해저케이블, 독도감시, 중국어선감시
- **선단/어구 폴리곤**: Python 서버사이드 생성 (Shapely + PostGIS) → API GeoJSON 렌더링
- FLEET 15개, GEAR_IN_ZONE 57개, GEAR_OUT_ZONE 45개 (5분 주기 갱신, 7일 히스토리)
- 가상 선박 마커 (ship-triangle + COG 회전 + zoom interpolate)
- 겹침 해결: queryRenderedFeatures → 다중 선택 팝업 + 호버 하이라이트
- **AI 분석**: Python 7단계 파이프라인, 위험도/다크베셀/스푸핑 deck.gl 오버레이
- **현장분석**: FieldAnalysisModal (어구/선단 분석 대시보드)
- **시설 레이어**: deck.gl IconLayer(SVG) + TextLayer, 줌 스케일 연동
### 이란 상황 대시보드
- **공습 리플레이**: 실데이터 Backend DB 기반 (더미↔API 토글)
- **유전/공항/군사시설**: deck.gl SVG 아이콘, 사막 대비 고채도 팔레트
- **센서 그래프**: 지진, 기압, 소음/방사선
- **위성지도/평면/3D Globe**: 3개 맵 모드
### 공통
- **웹폰트**: @fontsource-variable Inter, Noto Sans KR, Fira Code 자체 호스팅
- **글꼴 크기 커스텀**: FontScalePanel (시설/선박/분석/지역 4그룹 × 0.5~2.0x)
- **LayerPanel**: 공통 트리 구조 (LayerTreeRenderer 재귀, 부모 캐스케이드)
- **인증**: Google OAuth + DEV LOGIN
- **localStorage**: 13개+ UI 상태 영속화
## 팀 스킬 사용 지침
### 중요: 스킬 실행 시 반드시 따라야 할 규칙
**`/push`, `/mr`, `/release` 스킬은 SKILL.md에 정의된 절차를 순서대로 엄격히 따라야 한다.**
특히 다음 단계를 절대 건너뛰지 말 것:
1. **Step 0.5 해시 비교**: 서버 해시와 로컬 해시를 실제로 bash 실행하여 비교.
불일치 시 `/sync-team-workflow` 자동 실행 후 원래 작업 계속.
2. **AskUserQuestion 사용자 확인**: 커밋 메시지, MR 타겟, 릴리즈 노트 초안을
반드시 사용자에게 보여주고 승인/수정/취소를 물어야 한다.
자의적으로 진행하지 말 것.
3. **API 응답 검증**: MR 생성, 봇 승인, 머지 API 호출 후 반드시 상태를 확인.
실패 시 사용자에게 알리고 중단.
### 스킬 목록
- `/push` — 커밋 + 푸시 (해시 비교 → 커밋 메시지 확인 → 푸시)
- `/mr` — 커밋 + 푸시 + MR 생성 (릴리즈 노트 갱신 포함)
- `/release` — develop → main 릴리즈 MR (릴리즈 노트 날짜 전환)
- `/version` — VERSION-HISTORY.md 생성
- `/create-mr` — MR 생성만 (세부 옵션)
- `/fix-issue` — 이슈 기반 작업 브랜치 생성
### 환경변수
- `GITEA_TOKEN`: `.claude/settings.local.json``env`에 설정 (gitignored)
- `CLAUDE_BOT_TOKEN`: `.claude/settings.json``env`에 설정 (gitignored by .claude/ rule)
## 배포
| 서버 | 역할 | 경로/설정 |
|------|------|----------|
| **rocky-211** (192.168.1.20) | Frontend + Backend | `/devdata/services/kcg/` |
| | Frontend | nginx 정적 파일 (`/deploy/kcg/`) |
| | Backend | systemd `kcg-backend` (JDK 21, 2~4GB 힙) |
| | CI/CD | act runner Docker (node:24) |
| **redis-211** (192.168.1.18:32023) | Prediction | `/home/apps/kcg-prediction/` |
| | | systemd `kcg-prediction` (uvicorn 8001, venv) |
| **도메인** | | https://kcg.gc-si.dev |
| **nginx** | | `/etc/nginx/conf.d/kcg.conf` (SSL + SPA + API 프록시) |
| **DB** | kcgdb | 211.208.115.83:5432/kcgdb (유저: kcg_app, pw: Kcg2026monitor) |
| **DB** | snpdb | 211.208.115.83:5432/snpdb (유저: snp, pw: snp#8932, 읽기 전용) |
## 팀 규칙
- 코드 스타일: `.claude/rules/code-style.md`
- 네이밍: `.claude/rules/naming.md`
- 테스트: `.claude/rules/testing.md`
- Git 워크플로우: `.claude/rules/git-workflow.md`
- 팀 정책: `.claude/rules/team-policy.md`
- 릴리즈 노트 가이드: `.claude/rules/release-notes-guide.md`
- 서브에이전트 정책: `.claude/rules/subagent-policy.md`