- CoordDebugTool: Ctrl+Click 다중 좌표 표시 (DD/DMS, WGS84) - import.meta.env.DEV 가드로 프로덕션 빌드에서 코드 제거 - CLAUDE.md: 디버그 도구 가이드 섹션 추가
12 KiB
12 KiB
프로젝트 개요
- 이름: 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
cd frontend
npm install
npm run dev # 개발서버 (포트 5173)
npm run build # 프로덕션 빌드
npm run lint # ESLint 검증
Backend
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
cd prediction
pip install -r requirements.txt # shapely, scikit-learn, apscheduler 등
uvicorn main:app --host 0.0.0.0 --port 8001
Database
# 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에 정의된 절차를 순서대로 엄격히 따라야 한다.
특히 다음 단계를 절대 건너뛰지 말 것:
- Step 0.5 해시 비교: 서버 해시와 로컬 해시를 실제로 bash 실행하여 비교.
불일치 시
/sync-team-workflow자동 실행 후 원래 작업 계속. - AskUserQuestion 사용자 확인: 커밋 메시지, MR 타겟, 릴리즈 노트 초안을 반드시 사용자에게 보여주고 승인/수정/취소를 물어야 한다. 자의적으로 진행하지 말 것.
- 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 가드로만 연결:
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