From 7103dc5c4297cfa658d772a1a2ca2cfc956282ce Mon Sep 17 00:00:00 2001 From: htlee Date: Tue, 31 Mar 2026 14:07:29 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20CI/CD=20=EC=9B=8C=ED=81=AC=ED=94=8C?= =?UTF-8?q?=EB=A1=9C=EC=9A=B0=20=EA=B0=9C=EC=84=A0=20=EB=B0=8F=20ESLint=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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) --- .claude/settings.json | 37 ++++++++ .claude/workflow-version.json | 3 +- .gitea/workflows/deploy.yml | 5 + .node-version | 1 + .sdkmanrc | 1 + CLAUDE.md | 92 +++++++++++++++++++ .../vesselLayer/hooks/useVesselDeckLayer.ts | 3 - .../wing-gis-web/src/hooks/useAisPolling.ts | 5 +- 8 files changed, 142 insertions(+), 5 deletions(-) create mode 100644 .node-version create mode 100644 .sdkmanrc create mode 100644 CLAUDE.md diff --git a/.claude/settings.json b/.claude/settings.json index 322e437..5ac3c35 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -47,5 +47,42 @@ "Read(./**/.env.*)", "Read(./**/secrets/**)" ] + }, + "hooks": { + "SessionStart": [ + { + "matcher": "compact", + "hooks": [ + { + "type": "command", + "command": "bash .claude/scripts/on-post-compact.sh", + "timeout": 10 + } + ] + } + ], + "PreCompact": [ + { + "hooks": [ + { + "type": "command", + "command": "bash .claude/scripts/on-pre-compact.sh", + "timeout": 30 + } + ] + } + ], + "PostToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { + "type": "command", + "command": "bash .claude/scripts/on-commit.sh", + "timeout": 15 + } + ] + } + ] } } diff --git a/.claude/workflow-version.json b/.claude/workflow-version.json index 5d39e62..9072246 100644 --- a/.claude/workflow-version.json +++ b/.claude/workflow-version.json @@ -2,5 +2,6 @@ "applied_global_version": "1.6.1", "applied_date": "2026-03-31", "project_type": "react-ts", - "custom_pre_commit": true + "custom_pre_commit": true, + "gitea_url": "https://gitea.gc-si.dev" } diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 6396240..bf71652 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -27,12 +27,17 @@ jobs: working-directory: frontend/wing-gis-web run: npm ci + - name: Lint + working-directory: frontend/wing-gis-web + run: npm run lint + - name: Build working-directory: frontend/wing-gis-web run: npm run build - name: Deploy to server run: | + mkdir -p /deploy/wing-gis rm -rf /deploy/wing-gis/* cp -r frontend/wing-gis-web/dist/* /deploy/wing-gis/ echo "Deployed at $(date '+%Y-%m-%d %H:%M:%S')" diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..a45fd52 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +24 diff --git a/.sdkmanrc b/.sdkmanrc new file mode 100644 index 0000000..8bea3c1 --- /dev/null +++ b/.sdkmanrc @@ -0,0 +1 @@ +java=21.0.9-amzn diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..382a7eb --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,92 @@ +# WING-GIS - 해양경찰청 통합 GIS 위치정보시스템 + +모노레포 구조: React 19 TypeScript 프론트엔드 + Spring Boot 3.3 Java 21 백엔드 (MSA) +해양 GIS 시스템으로 선박 물표 추적(AIS/V-Pass/VTS 등 7개 소스), S-100 전자해도, 공간분석 기능 제공. + +상세 아키텍처: [ARCHITECTURE.md](ARCHITECTURE.md) 참조 + +## 기술 스택 + +### Frontend +- React 19 + TypeScript 5.9 + Vite 8 +- MapLibre GL JS 5.18 + deck.gl 9.2 (해양 지도 렌더링) +- Zustand 5 (상태 관리), Ant Design 6 (UI), STOMP.js (WebSocket) +- ENC: Martin 타일 서버 연동, S-52 day/dusk/night 테마 + +### Backend +- Spring Boot 3.3.6 + Java 21 + Gradle 9.3.1 +- PostgreSQL 16/PostGIS 3.4, Hibernate Spatial +- Redis (캐시), Kafka (선박 스트리밍), Keycloak (SSO) +- MapStruct (DTO 매핑), SpringDoc OpenAPI 2.3 (API 문서) + +### Infrastructure +- Docker Compose (PostgreSQL, Redis, Kafka, MinIO, pg_tileserv, Keycloak) +- npm 레지스트리: https://nexus.gc-si.dev/repository/npm-public/ + +## 빌드 명령어 + +### Frontend +```bash +cd frontend/wing-gis-web +npm install +npm run build +``` + +### Backend (wing-gis-map 서비스) +```bash +cd services/wing-gis-map +./gradlew build +``` + +## 개발 서버 +```bash +cd frontend/wing-gis-web +npm run dev # http://localhost:5174 +``` + +## 테스트 +```bash +# Frontend (테스트 러너 미설정) +# Backend +cd services/wing-gis-map && ./gradlew test +``` + +## Lint +```bash +# Frontend (ESLint 9, flat config) +cd frontend/wing-gis-web && npm run lint +# Prettier: 미설정 +# Backend: checkstyle/spotless 미설정 +``` + +## 디렉토리 구조 +``` +wing-gis/ +├── frontend/wing-gis-web/ # React SPA +│ └── src/ +│ ├── components/ # layout, map, vessel UI +│ ├── features/ # vesselLayer, nauticalChart +│ ├── hooks/ # useStore, useMap, useDeckLayers, useVesselStream +│ ├── lib/map/ # mapCore, MaplibreDeckCustomLayer +│ ├── services/ # api.ts, vesselApi.ts +│ ├── types/ # ais.ts, vessel.ts, layer.ts +│ └── utils/ # coordinate, s52Colors, vesselIcon +├── services/ # Spring Boot MSA (10개) +│ ├── wing-gis-map/ # GIS API (구현 완료) +│ ├── wing-gis-vessel/ # 선박/신호 (stub) +│ ├── wing-gis-gateway/ # API Gateway (stub) +│ ├── wing-gis-auth/ # 인증 (stub) +│ ├── wing-gis-layer/ # 레이어 관리 (stub) +│ ├── wing-gis-analysis/ # 분석 (stub) +│ ├── wing-gis-integration/ # 연계 (stub) +│ ├── wing-gis-admin/ # 관리 (stub) +│ └── wing-gis-mcp/ # MCP Agent (stub) +├── infra/ # Docker Compose, K8s, SQL +├── docs/ # 문서 +└── .claude/ # Claude Code 설정 +``` + +## 팀 컨벤션 +- `.claude/rules/` 팀 코딩 표준 참조 (`/sync-team-workflow`로 다운로드) +- 커밋 메시지: Conventional Commits (한국어), `.githooks/commit-msg`로 검증 +- 커밋 전 lint 검증 필수 diff --git a/frontend/wing-gis-web/src/features/vesselLayer/hooks/useVesselDeckLayer.ts b/frontend/wing-gis-web/src/features/vesselLayer/hooks/useVesselDeckLayer.ts index f8a4720..5aff949 100644 --- a/frontend/wing-gis-web/src/features/vesselLayer/hooks/useVesselDeckLayer.ts +++ b/frontend/wing-gis-web/src/features/vesselLayer/hooks/useVesselDeckLayer.ts @@ -50,9 +50,6 @@ export function useVesselDeckLayer( const renderer = aisRendererRef.current; if (renderer) { renderer.setData(features); - } else { - // Renderer not ready yet, set directly - setRenderedAis(features); } }, [aisTargets]); diff --git a/frontend/wing-gis-web/src/hooks/useAisPolling.ts b/frontend/wing-gis-web/src/hooks/useAisPolling.ts index 2d42fe3..5a9cdca 100644 --- a/frontend/wing-gis-web/src/hooks/useAisPolling.ts +++ b/frontend/wing-gis-web/src/hooks/useAisPolling.ts @@ -11,7 +11,10 @@ const RETENTION_MS = 120 * 60 * 1000; export function useAisPolling() { const setAisTargets = useStore((s) => s.setAisTargets); const storeRef = useRef(useStore.getState); - storeRef.current = useStore.getState; + + useEffect(() => { + storeRef.current = useStore.getState; + }); useEffect(() => { const ac = new AbortController(); -- 2.45.2