# 프로젝트 개요 - **이름**: 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`