wing-gis/ARCHITECTURE.md
htlee b9d924e81e chore: 팀 워크플로우 기반 초기 프로젝트 구성
WING-GIS 해양경찰 통합 GIS 위치정보시스템.
모노레포: frontend(React 19 + MapLibre + deck.gl) + services(Spring Boot + Gradle).

- npm + Nexus 프록시 레지스트리 설정
- 팀 워크플로우 v1.6.1 부트스트랩 파일 배치
- .githooks (commit-msg, post-checkout)
- custom_pre_commit: true (모노레포 pre-commit 별도 관리)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 12:36:38 +09:00

739 lines
36 KiB
Markdown

# WING-GIS Architecture Design
## 해양경찰청 통합 GIS 위치정보시스템
---
## 1. System Overview
```
WING-GIS System Architecture
============================
[Browser / ECDIS / Mobile]
|
v
+-----------------+ +------------------+ +------------------+
| React 19 SPA | | Nginx / Gateway | | Keycloak SSO |
| MapLibre+deck.gl|<--->| (API Gateway) |<--->| (INR-04 Auth) |
| (wing-gis-web) | | | | |
+-----------------+ +------------------+ +------------------+
|
+--------------+--------------+
| | |
+-----v----+ +-----v----+ +------v-----+
| GIS API | | Vessel | | Analysis |
| Service | | Signal | | Service |
| (SFR-01~ | | Service | | (SFR-09) |
| SFR-04) | | (SFR-05~ | +------+-----+
+-----+----+ | SFR-08) | |
| +-----+----+ |
| | |
+-----v--------------v--------------v-----+
| PostgreSQL + PostGIS |
| (wing_gis_db / wing_vessel_db) |
+-----------------------------------------+
| |
+-----v----+ +-----v-----------+
| Redis | | Kafka / RabbitMQ|
| (Cache) | | (Signal Stream) |
+----------+ +-----------------+
```
---
## 2. Technology Stack
### Frontend (구현 완료)
| Category | Technology | Version | Purpose |
|----------|-----------|---------|---------|
| Framework | React | 19.x | SPA UI |
| Language | TypeScript | 5.9 | Type safety |
| Map Engine | **MapLibre GL JS** | 5.18 | ENC 전자해도 렌더링 |
| Map Overlay | **deck.gl (MapboxOverlay)** | 9.2 | 선박 아이콘 WebGL 렌더링 |
| State | Zustand | 5.x | 경량 상태 관리 |
| UI Library | Ant Design | 6.x | 해경 UI 컴포넌트 (일부 사용) |
| API Client | Axios + fetch | - | 서버 통신 |
| WebSocket | STOMP.js | 7.x | 실시간 물표 수신 (예정) |
| Build | Vite | 8.x | 빌드 도구 |
| Chart | ECharts | 6.x | 통계/분석 차트 (예정) |
| ENC Tiles | gcnautical.com | - | S-57 전자해도 벡터 타일 |
### Backend
| Category | Technology | Version | Purpose |
|----------|-----------|---------|---------|
| Framework | Spring Boot | 3.3.x | MSA 서비스 |
| Language | Java | 21 (LTS) | 백엔드 로직 |
| ORM | JPA/Hibernate + QueryDSL | - | DB 접근 |
| GIS | GeoTools | 31.x | S-57/S-101 파싱 |
| API Docs | SpringDoc (OpenAPI 3) | - | INR-05 API 명세 |
| Security | Spring Security + Keycloak | - | SSO/GPKI (INR-04) |
| Message | Kafka / RabbitMQ | - | 물표 스트리밍 |
| Cache | Redis | 7.x | 물표 캐시 |
| Container | Docker + K8s | - | ECR-01 MSA 인프라 |
### Database
| Category | Technology | Purpose |
|----------|-----------|---------|
| Main DB | PostgreSQL 16 + PostGIS 3.4 | 공간데이터 저장 |
| Tile Cache | pg_tileserv / Martin | 벡터 타일 서빙 |
| Time Series | TimescaleDB (확장) | 물표 이력/항적 |
| File Storage | MinIO (S3 호환) | SHP/GeoJSON 업로드 |
---
## 3. MSA Service Decomposition (ECR-01)
```
wing-gis/
├── services/
│ ├── wing-gis-gateway/ # API Gateway (Spring Cloud Gateway)
│ ├── wing-gis-auth/ # 인증/권한 (INR-04: SSO, GPKI)
│ ├── wing-gis-map/ # 통합 GIS 서비스 (SFR-01~04)
│ ├── wing-gis-vessel/ # 물표/선박 신호 (SFR-05~06, SFR-08)
│ ├── wing-gis-layer/ # 레이어 관리 (SFR-07)
│ ├── wing-gis-analysis/ # 분석 서비스 (SFR-09)
│ ├── wing-gis-integration/ # 통합연계모듈 (SFR-06, SFR-10)
│ ├── wing-gis-admin/ # 관리도구
│ └── wing-gis-mcp/ # MCP 에이전트 (INR-06: LLM 연계)
├── frontend/
│ └── wing-gis-web/ # React SPA
├── infra/
│ ├── docker-compose.yml # 개발환경
│ ├── k8s/ # 운영환경 K8s 매니페스트
│ └── sql/ # DB 초기화 스크립트
└── docs/
└── api/ # API 명세서
```
---
## 4. Frontend Structure (React) — 현재 구현 상태
```
wing-gis-web/src/
├── App.tsx # 루트 (레이아웃 + useAisPolling)
├── main.tsx # 엔트리 포인트
├── App.css # 디자인 토큰 (CSS 변수)
├── components/
│ ├── layout/ # ✅ 5-패널 레이아웃
│ │ ├── TitleBar.tsx # 상단 헤더
│ │ ├── SubToolbar.tsx # 컨텍스트별 도구 모음
│ │ ├── Sidebar.tsx # 좌측 (검색, 레이어 트리)
│ │ ├── RightPanel.tsx # 우측 (물표현황 실데이터/경보/해양정보)
│ │ └── BottomBar.tsx # 하단 상태바
│ ├── map/ # ✅ MapLibre GL JS + deck.gl 기반
│ │ ├── MapViewML.tsx # 맵 컨테이너 + deck.gl 콜백 (툴팁/클릭)
│ │ ├── MapTools.tsx # 확대/축소/초기화
│ │ ├── BaseMapSelector.tsx # 배경지도 탭
│ │ ├── ScaleBar.tsx # 축척바
│ │ ├── MapLegend.tsx # 물표 범례 (실시간 AIS 카운트)
│ │ └── CoordStatusBar.tsx # 좌표/줌 상태바
│ └── vessel/ # ✅ 선박 UI
│ ├── VesselPopup.tsx # 선박 미니 팝업
│ ├── VesselSearch.tsx # 선박 통합 검색 (SFR-08)
│ └── VesselSignalToggle.tsx # 신호 소스 ON/OFF 토글
├── features/
│ ├── vesselLayer/ # ✅ AIS 실시간 + 비AIS 더미 렌더링
│ │ ├── hooks/
│ │ │ └── useVesselDeckLayer.ts # AIS+비AIS deck.gl 레이어 통합
│ │ └── lib/
│ │ ├── aisAdapter.ts # AisTarget → AisFeature 변환
│ │ ├── aisDeckLayers.ts # AIS IconLayer + halo + overlay
│ │ ├── aisIcons.ts # SignalKindCode별 SVG 아이콘 8종
│ │ ├── shipTooltip.ts # 호버 툴팁 HTML (사진 썸네일 포함)
│ │ ├── ShipBatchRenderer.ts # 뷰포트 컬링 + 밀도 제어 (제네릭)
│ │ ├── vesselAdapter.ts # 비AIS Vessel → VesselFeature
│ │ ├── vesselDeckLayers.ts # 비AIS deck.gl 레이어
│ │ └── vesselIcons.ts # 비AIS VesselSource별 아이콘
│ ├── nauticalChart/ # ✅ ENC 전자해도 오버레이
│ │ ├── hooks/useNauticalChartOverlay.ts
│ │ ├── lib/fetchNauticalStyle.ts # gcnautical.com 스타일 fetch
│ │ ├── lib/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 레이어 + getTooltip/onClick
│ ├── useStore.ts # ✅ Zustand (vessels, aisTargets, signalState...)
│ ├── useAisPolling.ts # ✅ AIS REST 폴링 (60분→1분→2시간 프루닝)
│ └── useVesselStream.ts # ⏳ STOMP WebSocket (백엔드 연동 시)
├── services/
│ ├── aisApi.ts # ✅ /signal-batch/api/v2/vessels/recent-positions
│ ├── api.ts # Axios 인스턴스
│ └── vesselApi.ts # 물표 CRUD API
├── types/
│ ├── ais.ts # ✅ SignalKindCode 8종, AisTarget, DTO, 색상맵
│ ├── vessel.ts # Vessel, VesselSource 7종
│ └── 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 더미 데이터
```
### 구현 상태 범례
- ✅ 구현 완료 (실동작)
- ⏳ 코드 준비됨, 백엔드 연동 대기
### 미구현 (향후 개발)
- `components/layer/` — LayerTree, LayerUpload, LayerStyle (SLD 편집)
- `components/analysis/` — AnalysisTabs, BufferAnalysis, HeatmapAnalysis
- `components/admin/` — UserManage, IntegrationStatus, AuditLog
- `components/common/` — LoginModal (SSO/GPKI), NotificationBell
- `hooks/useAuth.ts`, `hooks/useLayer.ts`
- `services/layerApi.ts`, `services/analysisApi.ts`, `services/authApi.ts`
- `types/s100.ts`, `types/auth.ts`
- React Router 라우팅
---
## 5. Backend Structure (Spring Boot)
```
wing-gis-map/ # 대표 서비스 구조
├── src/main/java/kr/go/kcg/wingis/
│ ├── WingGisMapApplication.java
│ ├── config/
│ │ ├── SecurityConfig.java
│ │ ├── CorsConfig.java
│ │ ├── WebSocketConfig.java
│ │ └── PostgisConfig.java
│ ├── domain/
│ │ ├── vessel/
│ │ │ ├── Vessel.java # Entity
│ │ │ ├── VesselTrack.java # 항적 Entity
│ │ │ ├── VesselRepository.java
│ │ │ ├── VesselService.java
│ │ │ └── VesselController.java
│ │ ├── layer/
│ │ │ ├── Layer.java
│ │ │ ├── LayerGroup.java
│ │ │ ├── S100Layer.java # S-100 전용
│ │ │ ├── LayerRepository.java
│ │ │ ├── LayerService.java
│ │ │ └── LayerController.java
│ │ ├── chart/
│ │ │ ├── ChartDataset.java # S-101 ENC 데이터셋
│ │ │ ├── ChartFeature.java # 해도 피처
│ │ │ └── ChartService.java
│ │ ├── boundary/
│ │ │ ├── Boundary.java # EEZ/NLL/관할구역
│ │ │ └── BoundaryService.java
│ │ ├── analysis/
│ │ │ ├── AnalysisResult.java
│ │ │ ├── AnalysisService.java
│ │ │ └── AnalysisController.java
│ │ └── user/
│ │ ├── User.java
│ │ └── UserService.java
│ ├── integration/ # SFR-06 통합연계모듈
│ │ ├── ais/
│ │ │ ├── AisReceiver.java # AIS 수신기
│ │ │ └── AisDecoder.java # NMEA 디코더
│ │ ├── vpass/
│ │ │ └── VPassClient.java
│ │ ├── vts/
│ │ │ └── VtsRadarClient.java
│ │ ├── lrit/
│ │ │ └── LritClient.java
│ │ └── DataFusionEngine.java # 물표 융합 엔진
│ ├── dto/
│ │ ├── VesselDto.java
│ │ ├── LayerDto.java
│ │ └── SearchDto.java
│ └── exception/
│ └── GlobalExceptionHandler.java
├── src/main/resources/
│ ├── application.yml
│ ├── application-dev.yml
│ └── application-prod.yml
├── build.gradle
└── Dockerfile
```
---
## 6. Database Schema (PostgreSQL + PostGIS)
### Core Tables
```sql
-- 물표/선박
CREATE TABLE vessel (
id BIGSERIAL PRIMARY KEY,
mmsi VARCHAR(20) UNIQUE,
imo VARCHAR(20),
name VARCHAR(100),
callsign VARCHAR(20),
ship_type VARCHAR(50),
flag VARCHAR(5),
gt DECIMAL,
dwt DECIMAL,
loa DECIMAL,
beam DECIMAL,
draft DECIMAL,
status VARCHAR(30),
source VARCHAR(20), -- AIS/V-Pass/VTS/RADAR/E-NAV/VHF-DSC
position GEOMETRY(Point, 4326),
sog DECIMAL,
cog DECIMAL,
heading DECIMAL,
nav_status VARCHAR(30),
destination VARCHAR(100),
eta TIMESTAMP,
last_updated TIMESTAMP DEFAULT NOW(),
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_vessel_position ON vessel USING GIST(position);
CREATE INDEX idx_vessel_mmsi ON vessel(mmsi);
CREATE INDEX idx_vessel_source ON vessel(source);
-- 항적 (TimescaleDB hypertable 권장)
CREATE TABLE vessel_track (
id BIGSERIAL,
vessel_id BIGINT REFERENCES vessel(id),
position GEOMETRY(Point, 4326),
sog DECIMAL,
cog DECIMAL,
heading DECIMAL,
recorded_at TIMESTAMP NOT NULL,
PRIMARY KEY (id, recorded_at)
);
CREATE INDEX idx_track_vessel ON vessel_track(vessel_id, recorded_at DESC);
CREATE INDEX idx_track_position ON vessel_track USING GIST(position);
-- 레이어
CREATE TABLE layer_group (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
parent_id INTEGER REFERENCES layer_group(id),
sort_order INTEGER DEFAULT 0,
icon VARCHAR(10),
is_system BOOLEAN DEFAULT FALSE
);
CREATE TABLE layer (
id BIGSERIAL PRIMARY KEY,
group_id INTEGER REFERENCES layer_group(id),
name VARCHAR(200),
layer_type VARCHAR(30), -- VECTOR/RASTER/WMS/S100
s100_product VARCHAR(10), -- S-101/S-102/S-104/S-111/S-122/S-124/S-127/S-412
geometry_type VARCHAR(20), -- POINT/LINE/POLYGON
srid INTEGER DEFAULT 4326,
style_sld TEXT,
min_scale INTEGER,
max_scale INTEGER,
is_visible BOOLEAN DEFAULT TRUE,
is_default_on BOOLEAN DEFAULT FALSE,
feature_count INTEGER DEFAULT 0,
source_url VARCHAR(500),
created_by BIGINT,
created_at TIMESTAMP DEFAULT NOW()
);
-- S-100 전자해도 데이터셋
CREATE TABLE chart_dataset (
id BIGSERIAL PRIMARY KEY,
cell_name VARCHAR(20), -- KR4G3A40
product VARCHAR(10), -- S-101, S-102, ...
edition INTEGER,
update_num INTEGER,
scale INTEGER,
status VARCHAR(20), -- CURRENT/SUPERSEDED/NEW
coverage GEOMETRY(Polygon, 4326),
fc_version VARCHAR(20),
pc_version VARCHAR(20),
feature_count INTEGER,
file_path VARCHAR(500),
issued_date DATE,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_chart_coverage ON chart_dataset USING GIST(coverage);
-- 해도 피처
CREATE TABLE chart_feature (
id BIGSERIAL PRIMARY KEY,
dataset_id BIGINT REFERENCES chart_dataset(id),
feature_type VARCHAR(50), -- Lighthouse/DepthArea/Buoy/...
feature_name_ko VARCHAR(200),
feature_name_en VARCHAR(200),
geometry GEOMETRY(Geometry, 4326),
attributes JSONB, -- S-101 속성 (유연한 구조)
scamin INTEGER,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_feature_geom ON chart_feature USING GIST(geometry);
CREATE INDEX idx_feature_type ON chart_feature(feature_type);
CREATE INDEX idx_feature_attrs ON chart_feature USING GIN(attributes);
-- 경계/관할구역
CREATE TABLE boundary (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
boundary_type VARCHAR(30), -- EEZ/NLL/TERRITORIAL/JURISDICTION
geometry GEOMETRY(MultiPolygon, 4326),
organization VARCHAR(100),
attributes JSONB
);
CREATE INDEX idx_boundary_geom ON boundary USING GIST(geometry);
-- 분석 결과
CREATE TABLE analysis_result (
id BIGSERIAL PRIMARY KEY,
analysis_type VARCHAR(50), -- ILLEGAL_FISHING/TRANSSHIP/DARK_VESSEL/...
name VARCHAR(200),
geometry GEOMETRY(Geometry, 4326),
result_data JSONB,
confidence DECIMAL,
status VARCHAR(20),
created_by BIGINT,
created_at TIMESTAMP DEFAULT NOW(),
expires_at TIMESTAMP
);
-- 사용자
CREATE TABLE app_user (
id BIGSERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
name VARCHAR(50),
department VARCHAR(100),
organization VARCHAR(100), -- 지방청/해양경찰서
role VARCHAR(30), -- ADMIN/OPERATOR/VIEWER
jurisdiction_id INTEGER REFERENCES boundary(id),
sso_id VARCHAR(100),
gpki_dn VARCHAR(500),
is_active BOOLEAN DEFAULT TRUE,
last_login TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW()
);
-- 경보/알림
CREATE TABLE alert (
id BIGSERIAL PRIMARY KEY,
alert_type VARCHAR(30), -- SOS/ZONE_VIOLATION/SIGNAL_LOST/...
severity VARCHAR(10), -- CRITICAL/WARNING/INFO
title VARCHAR(200),
description TEXT,
vessel_id BIGINT REFERENCES vessel(id),
position GEOMETRY(Point, 4326),
is_acknowledged BOOLEAN DEFAULT FALSE,
acknowledged_by BIGINT REFERENCES app_user(id),
created_at TIMESTAMP DEFAULT NOW()
);
-- 감사 로그
CREATE TABLE audit_log (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT REFERENCES app_user(id),
action VARCHAR(50),
target_type VARCHAR(50),
target_id VARCHAR(50),
detail JSONB,
ip_address VARCHAR(45),
created_at TIMESTAMP DEFAULT NOW()
);
```
---
## 7. API Endpoints (RESTful)
### Vessel API (SFR-05, SFR-08)
```
GET /api/v1/vessels # 물표 목록 (필터/페이징)
GET /api/v1/vessels/{mmsi} # 물표 상세
GET /api/v1/vessels/{mmsi}/tracks # 항적 조회
GET /api/v1/vessels/search?q= # 통합 검색 (SFR-08)
GET /api/v1/vessels/bbox?bbox= # 영역 내 물표
WS /ws/vessels # 실시간 물표 스트림
```
### Layer API (SFR-03, SFR-07)
```
GET /api/v1/layers # 레이어 트리
POST /api/v1/layers/upload # 레이어 업로드
PUT /api/v1/layers/{id}/style # SLD 스타일 변경
GET /api/v1/layers/{id}/features # 피처 조회
DELETE /api/v1/layers/{id} # 레이어 삭제
```
### Chart API (SFR-04)
```
GET /api/v1/charts # S-100 데이터셋 목록
GET /api/v1/charts/{cellName}/features # 해도 피처
GET /api/v1/charts/tile/{z}/{x}/{y} # 벡터 타일
```
### Analysis API (SFR-09)
```
POST /api/v1/analysis/buffer # 버퍼 분석
POST /api/v1/analysis/heatmap # 히트맵
POST /api/v1/analysis/upload # 결과 업로드
GET /api/v1/analysis/results # 결과 목록
```
### Auth API (INR-04)
```
POST /api/v1/auth/login # 로그인
POST /api/v1/auth/sso # SSO 인증
POST /api/v1/auth/gpki # GPKI 인증
GET /api/v1/auth/me # 현재 사용자
POST /api/v1/auth/logout # 로그아웃
```
---
## 8. S-100 Product Specification Support Matrix
### 8.1 Specification Inventory
본 사업에서 지원하는 IHO S-100 기반 제품 규격과 보유 문서 현황:
| S-100 Product | Version | Full Name | PS | FC | PC | DCEG | Validation | Sample |
|---------------|---------|-----------|:--:|:--:|:--:|:----:|:----------:|:------:|
| **S-100** | Ed.5.2.1 (Dec 2025) | Universal Hydrographic Data Model | PDF | - | Lua/XSLT | - | S-158-100 v1.0.0 | - |
| **S-101** | Ed.2.0.0 | Electronic Navigational Chart (ENC) | PDF | XML 2.0.0 | ZIP 2.0.0 | PDF 2.0.0 | S-158-101 v1.1.0 | - |
| **S-102** | Ed.3.0.0 | Bathymetric Surface | PDF | XML 3.0.0 | ZIP 3.0.0 | - | S-158-102 v1.0.0 | - |
| **S-104** | Ed.2.0.0 | Water Level Information | PDF | XML 2.0.0 | - | - | - | - |
| **S-111** | Ed.2.0.0 | Surface Currents | PDF | XML 2.0.0 | ZIP 2.0.0 | - | - | - |
| **S-122** | Ed.1.0.0 | Marine Protected Areas (MPA) | ZIP | XML 1.0.0 | - | - | - | ZIP |
| **S-123** | Ed.1.0.0 | Marine Radio Services (MRS) | ZIP | XML 1.0.0 | - | - | - | ZIP |
| **S-124** | Ed.2.0.0 | Navigational Warnings | PDF | XML 2.0.0 | ZIP 2.0.0 | PDF 2.0.0 | - | - |
| **S-127** | Ed.1.0.0 | Marine Traffic Management | PDF | ZIP 1.0.0 | - | - | - | ZIP |
> 참조 경로: `/Documents/GIS/S-100 Specifications/{S-1xx}/`
### 8.2 Service-to-Product Mapping
각 백엔드 서비스가 담당하는 S-100 제품과 구체적 활용 범위:
```
┌─────────────────────────────────────────────────────────────────────────┐
│ wing-gis-map (GIS API) │
│ │
│ S-101 ENC Ed.2.0.0 ─── 전자해도 렌더링, 피처 조회, Edition 관리 │
│ ├─ FC 2.0.0 ── FeatureType 정의 (DepthArea, Lighthouse, Buoy...) │
│ ├─ PC 2.0.0 ── S-52 Portrayal 렌더링 규칙 │
│ ├─ DCEG 2.0.0 ── 피처 속성 검증 (Data Capture Encoding Guide) │
│ └─ S-158-101 ── 데이터 품질 검증 (Validation Checks) │
│ │
│ S-102 Bathymetric Ed.3.0.0 ─── 수심 격자 데이터 표출 │
│ ├─ FC 3.0.0 ── BAG 수심 피처 정의 │
│ └─ PC 3.0.0 ── 수심 음영/등심선 색상 팔레트 │
│ │
│ S-104 Water Level Ed.2.0.0 ─── 실시간 조석/수위 오버레이 │
│ └─ FC 2.0.0 ── 조석 관측점/예측 격자 피처 정의 │
│ │
│ S-111 Surface Currents Ed.2.0.0 ─── 해류 벡터/격자 오버레이 │
│ ├─ FC 2.0.0 ── 해류 벡터 피처 정의 │
│ └─ PC 2.0.0 ── 해류 화살표/색상 렌더링 규칙 │
│ │
│ S-122 MPA Ed.1.0.0 ─── 해양보호구역 경계 표출 │
│ └─ FC 1.0.0 ── 보호구역 등급/경계 피처 정의 │
│ │
│ S-123 MRS Ed.1.0.0 ─── 해양무선 커버리지 표출 │
│ └─ FC 1.0.0 ── VHF/MF/HF 무선 범위 피처 정의 │
│ │
│ S-124 Nav Warnings Ed.2.0.0 ─── 항행경보 구역 실시간 표출 │
│ ├─ FC 2.0.0 ── 경보 구역/유형 피처 정의 │
│ ├─ PC 2.0.0 ── 경보 심볼/색상 렌더링 │
│ └─ DCEG 2.0.0 ── 경보 데이터 입력 검증 │
│ │
│ S-127 MTM Ed.1.0.0 ─── TSS/VTS 구역 표출 │
│ └─ FC 1.0.0 ── 통항분리대/VTS 관할 피처 정의 │
│ │
│ S-100 Ed.5.2.1 ─── 공통 데이터 모델 / Exchange Set / 인코딩 │
│ ├─ Part 5 (FC) ── Feature Catalogue 구조 파싱 │
│ ├─ Part 9/9a (Portrayal/Lua) ── 렌더링 엔진 │
│ ├─ Part 10a/10b/10c ── 인코딩 (8211/GML/HDF5) │
│ ├─ Part 15 ── 암호화/서명 (Encryption optional, Signing mandatory) │
│ ├─ Part 16/16a ── Interoperability / Harmonised Portrayal │
│ └─ Part 17 ── Discovery Metadata (Exchange Catalogue) │
├─────────────────────────────────────────────────────────────────────────┤
│ wing-gis-vessel (Vessel Signal) │
│ │
│ S-124 ─── 조난 경보 연동 (VHF-DSC → S-124 Nav Warning 자동 생성) │
│ S-127 ─── VTS 관제 구역 내 선박 연계 │
├─────────────────────────────────────────────────────────────────────────┤
│ wing-gis-integration (통합연계모듈) │
│ │
│ S-100 Part 10b (GML) ─── 물표 데이터 GML 인코딩 변환 │
│ S-100 Part 14 ─── Online Communication Exchange 프로토콜 │
│ S-100 Part 17 ─── Exchange Catalogue 메타데이터 관리 │
│ S-100 Part 15 ─── 데이터 서명/검증 (Digital Signature) │
├─────────────────────────────────────────────────────────────────────────┤
│ wing-gis-analysis (분석 서비스) │
│ │
│ S-102 ─── 수심 격자 기반 해저 지형 분석 │
│ S-104 ─── 조석 데이터 기반 수위 예측 분석 │
│ S-111 ─── 해류 데이터 기반 표류 예측 분석 │
├─────────────────────────────────────────────────────────────────────────┤
│ wing-gis-layer (레이어 관리) │
│ │
│ S-100 Part 5 ─── Feature Catalogue XML 파싱/관리 │
│ S-100 Part 9 ─── Portrayal Catalogue 관리 (SLD 변환) │
│ S-100 Part 11 ─── Product Specification 메타 관리 │
│ S-158 ─── Validation Checks 실행 엔진 │
└─────────────────────────────────────────────────────────────────────────┘
```
### 8.3 Feature Catalogue Integration
FC(Feature Catalogue) XML을 파싱하여 DB에 자동 로드하는 구조:
```
S-100 Specifications/S-101/101_Feature_Catalogue_2.0.0.xml
┌──────────────┐ ┌──────────────────────────────┐
│ FC Parser │────▶│ chart_feature_type (DB) │
│ (GeoTools/ │ │ ├─ feature_type: Lighthouse │
│ JAXB) │ │ ├─ attributes: JSONB │
│ │ │ ├─ geometry_type: Point │
└──────────────┘ │ └─ product: S-101 │
└──────────────────────────────┘
```
| FC File | Product | Feature Types | DB Table |
|---------|---------|---------------|----------|
| `101_FC_2.0.0.xml` | S-101 | DepthArea, DepthContour, Lighthouse, Buoy, Rock, Wreck, FairwaySystem, AnchorageArea, RestrictedArea, Coastline, LandArea, ... (~180 types) | `chart_feature` |
| `102_FC_3.0.0.xml` | S-102 | BathymetricDataset, TrackingList, QualityOfBathymetricData | `chart_feature` |
| `104_FC_2.0.0.xml` | S-104 | WaterLevelTrend, WaterLevelTimeSeries, TidalStation | `chart_feature` |
| `111_FC_2.0.0.xml` | S-111 | SurfaceCurrentDataset, SurfaceCurrentTimeSeries | `chart_feature` |
| `122_FC_1.0.0.xml` | S-122 | MarineProtectedArea | `boundary` |
| `123_FC_1.0.0.xml` | S-123 | RadioServiceArea, RadioStation | `chart_feature` |
| `124_FC_2.0.0.xml` | S-124 | NavigationalWarningPart, NavigationalWarningFeaturePart | `alert` / `chart_feature` |
| `S-127_FC_1.0.0` | S-127 | TrafficSeparationScheme, VTSArea, ReportingPoint | `boundary` |
### 8.4 Portrayal Catalogue Integration
PC(Portrayal Catalogue)를 활용한 S-52 기반 렌더링 규칙:
| PC File | Product | 렌더링 대상 | Frontend 적용 |
|---------|---------|-----------|-------------|
| `101_PC_2.0.0` | S-101 | 해도 심볼/색상/선형 | OpenLayers Style + Lua 엔진 |
| `102_PC_3.0.0` | S-102 | 수심 음영/등심선 | Raster 타일 색상 팔레트 |
| `111_PC_2.0.0` | S-111 | 해류 벡터 화살표 | SVG 벡터 오버레이 |
| `124_PC_2.0.0` | S-124 | 항행경보 구역 심볼 | 경보 폴리곤 스타일 |
| S-100 BPC (Lua) | 공통 | Lua 기반 Portrayal 스크립팅 | Part 9a Lua 인터프리터 |
### 8.5 Validation Integration (S-158)
S-158 기반 데이터 품질 검증:
| Validation File | 대상 | 검증 내용 | 서비스 |
|----------------|------|---------|--------|
| `S-158-100_v1.0.0` | S-100 공통 | Exchange Set 구조, 메타데이터, 인코딩 규칙 | wing-gis-integration |
| `S-158-101_v1.1.0` | S-101 ENC | 피처 속성 완전성, 토폴로지, SCAMIN, 좌표 정밀도 | wing-gis-map |
| `S-158-102_v1.0.0` | S-102 수심 | BAG 격자 무결성, 수심 범위 검증 | wing-gis-map |
### 8.6 Data Encoding Support (S-100 Part 10)
| Encoding | S-100 Part | 지원 제품 | 라이브러리 |
|----------|-----------|---------|-----------|
| ISO/IEC 8211 | Part 10a | S-101 (레거시 S-57 호환) | GeoTools S-57 Driver |
| GML 3.2 | Part 10b | S-122, S-123, S-124, S-127 | JAXB + GML Parser |
| HDF5 | Part 10c | S-102, S-104, S-111 (격자 데이터) | JHdf5 / HDF5 Java |
### 8.7 S-100 Ed.5.2.1 Key Changes Applied
본 시스템에 반영된 S-100 Ed.5.2.1 (December 2025) 주요 변경사항:
| Part | 변경 내용 | 시스템 반영 |
|------|---------|-----------|
| Part 1 | URI Derived Type에 fileURI 추가, MRN 형식 변경 | 메타데이터 URI 처리 |
| Part 5 | FC InformationType/FeatureType 상속 관계 정정 | FC XML 파서 |
| Part 10b | GML 파일 확장자 .GML 필수, xlink:title 명시 | GML 인코딩 모듈 |
| Part 10c | HDF5 featureAttributeTableKey 컬럼명 변경, timePoint optional | HDF5 리더 |
| Part 11 | Product Specification 참조를 IHO GI Registry로 변경 | PS 메타 관리 |
| Part 14 | ISO/IEC 80000-13:2025 추가 | 온라인 교환 |
| **Part 15** | **암호화 optional, 서명 mandatory**, schemeAdministrator [1] 필수 | **S-63 Encryptor** |
| Part 16a | Harmonised Portrayal URL 변경 | 렌더링 엔진 |
| Part 17 | editionNumber → PositiveInteger, boundingPolygon 좌표 순서 CRS 기준 | Exchange Catalogue |
| Part 18 | URL 정규화 참조 변경 | 다국어 지원 |
---
## 9. RFP Requirement Mapping (80 Requirements)
| RFP ID | 요구사항 | 서비스 | 상태 | 비고 |
|--------|---------|--------|:----:|------|
| SFR-01 | 통합 GIS 서비스 | wing-gis-map + MapViewML | ✅ | MapLibre GL JS |
| SFR-02 | 서비스 제공 방식 | React SPA (WEB) | ✅ | Vite 8 |
| SFR-03 | 전자해도+공간정보 통합조회 | nauticalChart 피처 | ✅ | gcnautical.com ENC |
| SFR-04 | S-100 차세대 전자해도 | fetchEncStyle + S-52 테마 | ✅ | 주간/황혼/야간 |
| SFR-05 | 물표정보 연계+융합 | useAisPolling + deck.gl | ✅ | AIS 실시간, 비AIS 더미 |
| SFR-06 | 통합연계모듈 | wing-gis-integration | ⏳ | Kafka 스트림 |
| SFR-07 | 관할 기반+사용자 레이어 | wing-gis-layer | ⏳ | 업로드/SLD |
| SFR-08 | 선박 통합 검색 | VesselSearch | ⚠️ | UI 구현, 백엔드 미연동 |
| SFR-09 | 외부 분석결과 시각화 | wing-gis-analysis | ⏳ | GeoJSON/SHP |
| SFR-10 | 7개 시스템 통합 | wing-gis-integration | ⏳ | 7종 어댑터 |
| PER-03 | 동시접속 3,000명 | K8s HPA + Redis | ⏳ | Scale-out |
| ECR-01 | MSA 아키텍처 | Docker + K8s | ⚠️ | Docker Compose 완료, K8s 미구현 |
| INR-04 | SSO/GPKI | wing-gis-auth + Keycloak | ⏳ | |
| INR-05 | API 서비스 | SpringDoc OpenAPI | ⏳ | |
| INR-06 | MCP 에이전트 | wing-gis-mcp | ⏳ | LLM 연계 |
| DAR-01~12 | 데이터 요구사항 | PostgreSQL + PostGIS | ⚠️ | 스키마 완료, 데이터 미적재 |
> ✅ 구현 완료 · ⚠️ 부분 구현 · ⏳ 미착수
---
## 10. Development Phases
### Phase 1: 기반 구축 (M+0 ~ M+2) — 완료
- [x] 프로젝트 구조 설계 (ARCHITECTURE.md)
- [x] React 프로젝트 초기화 (Vite 8 + TypeScript 5.9)
- [x] PostgreSQL + PostGIS 스키마 생성 (001_init_schema.sql)
- [x] Docker Compose 개발환경 (7개 서비스)
- [x] **MapLibre GL JS 기반 지도** (OpenLayers → MapLibre 전환 완료)
- [x] **deck.gl MapboxOverlay 통합** (선박 WebGL 렌더링)
- [x] **ENC 전자해도** (gcnautical.com 벡터 타일, S-52 테마)
- [x] 레이아웃 5-패널 구조 (TitleBar/SubToolbar/Sidebar/RightPanel/BottomBar)
- [x] Zustand 상태 관리 (vessels, aisTargets, signalState, nauticalChartSettings)
### Phase 2: 핵심 기능 (M+2 ~ M+4) — 진행 중
- [x] **AIS 실시간 물표** (REST 폴링 60분 초기 → 1분 간격 → 2시간 프루닝)
- [x] **SignalKindCode 기반 아이콘** (8종 색상/형태, 항해/정박 구분)
- [x] **호버 툴팁** (이름, MMSI, SOG/COG, 사진 썸네일)
- [x] **선박 사진 모달** (고화질 뷰어, 네비게이션, 캐러셀)
- [x] **물표현황 실데이터** (AIS 카운트, 관할 내 선박 분류)
- [x] 선박 통합 검색 UI (SFR-08, 백엔드 미연동)
- [ ] EEZ/NLL/관할구역 경계 레이어
- [ ] 사용자 인증 (SSO/GPKI)
### Phase 3: 통합 (M+4 ~ M+6)
- [ ] 7개 시스템 연계 어댑터 (V-Pass/E-NAV/VTS/VTS-RADAR/AIR-AIS/VHF-DSC/LRIT)
- [ ] STOMP WebSocket 실시간 물표 스트리밍
- [ ] 통합연계모듈 (수집/정제/융합/배포)
- [ ] 공간분석 기능 (버퍼/히트맵/통계)
- [ ] 레이어 업로드/SLD 편집
- [ ] MCP 에이전트 (LLM 연계)
### Phase 4: 안정화 (M+6 ~ M+7)
- [ ] 성능 최적화 (ShipBatchRenderer 밀도 컬링 고도화, 3,000명 동시접속)
- [ ] 보안 감사 로그
- [ ] 운영 전환 + 교육