- CoordDebugTool: Ctrl+Click 다중 좌표 표시 (DD/DMS, WGS84) - import.meta.env.DEV 가드로 프로덕션 빌드에서 코드 제거 - CLAUDE.md: 디버그 도구 가이드 섹션 추가
243 lines
12 KiB
Markdown
243 lines
12 KiB
Markdown
# 프로젝트 개요
|
||
|
||
- **이름**: 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, 읽기 전용) |
|
||
|
||
## 디버그 도구 가이드
|
||
|
||
### 원칙
|
||
- 디버그/개발 전용 기능은 `import.meta.env.DEV` 가드로 감싸서 **프로덕션 빌드에서 코드 자체가 제거**되도록 구현
|
||
- Vite production 빌드 시 `import.meta.env.DEV = false` → dead code elimination → 번들 미포함
|
||
- 무거운 DB 조회, 통계 계산 등도 DEV 가드 안이면 프로덕션에 영향 없음
|
||
|
||
### 파일 구조
|
||
- 디버그 컴포넌트: `frontend/src/components/{도메인}/debug/` 디렉토리에 분리
|
||
- 메인 컴포넌트에서는 import + DEV 가드로만 연결:
|
||
```tsx
|
||
import { DebugTool } from './debug/DebugTool';
|
||
const debug = import.meta.env.DEV ? useDebugHook() : null;
|
||
// JSX:
|
||
{debug && <DebugTool ... />}
|
||
```
|
||
|
||
### 기존 디버그 도구
|
||
| 도구 | 위치 | 기능 |
|
||
|------|------|------|
|
||
| CoordDebugTool | `korea/debug/CoordDebugTool.tsx` | Ctrl+Click 좌표 표시 (DD/DMS, 다중 포인트) |
|
||
|
||
### 디버그 도구 분류 기준
|
||
다음에 해당하면 디버그 도구로 분류하고, 불확실하면 사용자에게 확인:
|
||
- 개발/검증 목적의 좌표/데이터 표시 도구
|
||
- 프로덕션 사용자에게 불필요한 진단 정보
|
||
- 임시 데이터 시각화, 성능 프로파일링
|
||
- 특정 조건에서만 활성화되는 테스트 기능
|
||
|
||
## 팀 규칙
|
||
|
||
- 코드 스타일: `.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`
|