wing-gis/frontend/wing-gis-web
htlee 7103dc5c42 fix: CI/CD 워크플로우 개선 및 ESLint 에러 수정
- deploy.yml: mkdir -p 추가로 배포 디렉토리 미존재 시 실패 방지
- deploy.yml: lint 단계 추가로 빌드 전 코드 품질 검증
- useVesselDeckLayer: useEffect 내 직접 setState 호출 제거
- useAisPolling: 렌더 중 ref 업데이트를 useEffect 내부로 이동
- CLAUDE.md, .sdkmanrc, .node-version 등 팀 워크플로우 초기 구성

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:07:29 +09:00
..
public chore: 팀 워크플로우 기반 초기 프로젝트 구성 2026-03-31 12:36:38 +09:00
src fix: CI/CD 워크플로우 개선 및 ESLint 에러 수정 2026-03-31 14:07:29 +09:00
.gitignore chore: 팀 워크플로우 기반 초기 프로젝트 구성 2026-03-31 12:36:38 +09:00
.npmrc chore: 팀 워크플로우 기반 초기 프로젝트 구성 2026-03-31 12:36:38 +09:00
eslint.config.js chore: 팀 워크플로우 기반 초기 프로젝트 구성 2026-03-31 12:36:38 +09:00
index.html chore: 팀 워크플로우 기반 초기 프로젝트 구성 2026-03-31 12:36:38 +09:00
package-lock.json chore: 팀 워크플로우 기반 초기 프로젝트 구성 2026-03-31 12:36:38 +09:00
package.json chore: 팀 워크플로우 기반 초기 프로젝트 구성 2026-03-31 12:36:38 +09:00
README.md chore: 팀 워크플로우 기반 초기 프로젝트 구성 2026-03-31 12:36:38 +09:00
tsconfig.app.json chore: 팀 워크플로우 기반 초기 프로젝트 구성 2026-03-31 12:36:38 +09:00
tsconfig.json chore: 팀 워크플로우 기반 초기 프로젝트 구성 2026-03-31 12:36:38 +09:00
tsconfig.node.json chore: 팀 워크플로우 기반 초기 프로젝트 구성 2026-03-31 12:36:38 +09:00
vite.config.ts chore: 팀 워크플로우 기반 초기 프로젝트 구성 2026-03-31 12:36:38 +09:00

WING-GIS Web Frontend

해양경찰청 통합 GIS 위치정보시스템 프론트엔드

기술 스택

분류 기술 버전 용도
Framework React 19.x SPA UI
Language TypeScript 5.9 타입 안전성
Build Vite 8.x 빌드 + HMR
Map Engine MapLibre GL JS 5.18 ENC 전자해도 렌더링
Map Overlay deck.gl (MapboxOverlay) 9.2 선박 아이콘 WebGL 렌더링
State Zustand 5.x 경량 상태 관리
HTTP Axios / fetch - REST API 통신
WebSocket STOMP.js 7.x 실시간 물표 수신 (예정)

시작하기

# 의존성 설치
yarn install

# 개발 서버 (http://localhost:5174)
yarn dev

# 프로덕션 빌드
yarn build

# 빌드 결과물 프리뷰
yarn preview

프로젝트 구조

src/
├── App.tsx                          # 루트 컴포넌트 (레이아웃 + AIS 폴링)
├── main.tsx                         # 엔트리 포인트
├── App.css                          # 디자인 토큰 (CSS 변수)
│
├── components/
│   ├── layout/                      # 5-패널 레이아웃
│   │   ├── TitleBar.tsx             # 상단 헤더 (로고, 네비, 시계, 사용자)
│   │   ├── SubToolbar.tsx           # 컨텍스트별 도구 모음
│   │   ├── Sidebar.tsx              # 좌측 (검색, 레이어 트리)
│   │   ├── RightPanel.tsx           # 우측 (물표현황/경보/해양정보)
│   │   └── BottomBar.tsx            # 하단 상태바
│   ├── map/                         # 지도 오버레이 컴포넌트
│   │   ├── MapViewML.tsx            # MapLibre + deck.gl 통합 컨테이너
│   │   ├── MapTools.tsx             # 지도 도구 (확대/축소/초기화)
│   │   ├── BaseMapSelector.tsx      # 배경지도 탭
│   │   ├── ScaleBar.tsx             # 축척바
│   │   ├── MapLegend.tsx            # 물표 범례 (실시간 AIS 카운트)
│   │   └── CoordStatusBar.tsx       # 좌표/줌 상태바
│   └── vessel/                      # 선박 관련 UI
│       ├── VesselPopup.tsx          # 선박 미니 팝업
│       ├── VesselSearch.tsx         # 선박 통합 검색
│       └── VesselSignalToggle.tsx   # 신호 소스 ON/OFF 토글
│
├── features/
│   ├── vesselLayer/                 # 선박 렌더링 파이프라인
│   │   ├── hooks/
│   │   │   └── useVesselDeckLayer.ts  # deck.gl 레이어 통합 훅
│   │   └── lib/
│   │       ├── aisAdapter.ts        # AisTarget → AisFeature 변환
│   │       ├── aisDeckLayers.ts     # AIS deck.gl IconLayer 빌더
│   │       ├── aisIcons.ts          # SignalKindCode별 SVG 아이콘 (8종)
│   │       ├── shipTooltip.ts       # 호버 툴팁 HTML 생성
│   │       ├── ShipBatchRenderer.ts # 뷰포트 컬링 + 밀도 제어
│   │       ├── vesselAdapter.ts     # 비AIS 소스 어댑터
│   │       ├── vesselDeckLayers.ts  # 비AIS deck.gl 레이어
│   │       └── vesselIcons.ts       # 비AIS 소스별 SVG 아이콘
│   ├── nauticalChart/               # ENC 전자해도 오버레이
│   │   ├── hooks/
│   │   │   └── useNauticalChartOverlay.ts
│   │   ├── lib/
│   │   │   ├── fetchNauticalStyle.ts  # gcnautical.com 스타일 fetch
│   │   │   └── nauticalLayerManager.ts  # 레이어 주입/제거/S-52 테마
│   │   ├── model/
│   │   │   └── types.ts             # S52Theme, NauticalChartSettings
│   │   └── ui/
│   │       └── NauticalChartToggle.tsx  # ENC on/off + 주간/황혼/야간
│   └── shipImage/                   # 선박 사진
│       ├── api/
│       │   └── shipImageApi.ts      # 이미지 API + 썸네일/고화질 URL
│       └── ui/
│           └── ShipImageModal.tsx    # 사진 뷰어 모달
│
├── hooks/
│   ├── useMap.ts                    # MapLibre 맵 + MapboxOverlay 초기화
│   ├── useDeckLayers.ts             # deck.gl 레이어 + 콜백 전달
│   ├── useStore.ts                  # Zustand 글로벌 스토어
│   ├── useAisPolling.ts             # AIS REST 폴링 (60분 초기, 1분 간격)
│   └── useVesselStream.ts           # STOMP WebSocket (예정)
│
├── services/
│   ├── aisApi.ts                    # AIS recent-positions API
│   ├── api.ts                       # Axios 인스턴스
│   └── vesselApi.ts                 # 물표 CRUD API
│
├── types/
│   ├── ais.ts                       # SignalKindCode, AisTarget, DTO
│   ├── vessel.ts                    # Vessel, VesselSource, 색상/형태 맵
│   └── layer.ts                     # LayerGroup, S100_PRODUCTS
│
├── utils/
│   ├── coordinate.ts                # DMS 변환, 축척 계산
│   ├── s52Colors.ts                 # S-52 수심 색상 팔레트
│   └── vesselIcon.ts                # 범용 SVG 아이콘 생성
│
├── lib/map/
│   ├── mapCore.ts                   # kickRepaint, onMapStyleReady
│   ├── mapConstants.ts              # 기본 좌표, 줌, OSM 폴백 스타일
│   └── MaplibreDeckCustomLayer.ts   # Globe 모드용 (현재 미사용)
│
├── context/
│   └── MapContext.tsx               # mapRef, overlayRef 전달
│
└── data/
    └── mockVessels.ts               # 비AIS 더미 선박 데이터

핵심 데이터 흐름

AIS 선박 위치

API: GET /signal-batch/api/v2/vessels/recent-positions?minutes=N
  │
  ▼
useAisPolling (60분 초기 → 60초 간격 2분 데이터 → 2시간 프루닝)
  │
  ▼
Zustand Store: aisTargets (Map<mmsi, AisTarget>)
  │
  ▼
useVesselDeckLayer → ShipBatchRenderer (뷰포트 컬링 + 밀도 제어)
  │
  ▼
deck.gl IconLayer (signalKindCode별 색상 아이콘)
  │
  ├── 호버 → getTooltip (이름, MMSI, SOG/COG, 사진 썸네일)
  └── 클릭 → ShipImageModal (사진 있는 선박만)

ENC 전자해도

gcnautical.com/styles/nautical.json → fetchEncStyle (폰트 패칭)
  │
  ▼
MapLibre map.setStyle() (초기 로드 시 OSM → ENC 전환)
  │
  ├── ENC 토글 → useNauticalChartOverlay (레이어 주입/제거)
  └── S-52 테마 → applyS52Theme (주간/황혼/야간 색상)

선박 아이콘 체계

AIS 선박 (SignalKindCode 기반, 실시간 데이터)

코드 종류 색상 형태
000020 어선 #00C853 (녹색) 항해: 화살표 32x48 / 정박: 원 16x16
000021 경비함정 #FF5722 (주황)
000022 여객선 #2196F3 (파랑)
000023 화물선 #9C27B0 (보라)
000024 유조선 #F44336 (빨강)
000025 관공선 #FF9800 (오렌지)
000027 일반 #607D8B (회색)
000028 부이 #795548 (갈색) 폴+몸체 32x44 (회전 없음)

비AIS 소스 (VesselSource 기반, 더미 데이터)

소스 색상 형태
V-Pass #1a8a3a 삼각형
E-NAV #8833cc 삼각형
VTS #cc6600 사각형
VTS-RADAR #cc3300 다이아몬드
AIR-AIS #0099aa 비행기
VHF-DSC #d63030 삼각형 (점멸)

환경 변수

변수 기본값 설명
VITE_API_BASE http://localhost:8080 백엔드 API 기본 URL
VITE_WS_URL http://localhost:8080/ws/vessels WebSocket 엔드포인트

Vite 프록시 (개발 환경)

경로 타겟 용도
/api http://localhost:8080 백엔드 API
/signal-batch https://wing.gc-si.dev AIS 선박 위치 API
/shipimg https://wing.gc-si.dev 선박 사진 정적 파일
/martin http://192.168.1.18:3030 Martin ENC 타일 서버