KCG AI 기반 불법조업 탐지·차단 플랫폼 프론트엔드. React 19 + TypeScript 5.9 + Vite 8 + MapLibre + deck.gl + Zustand + Tailwind CSS. SFR 20개 전체 UI 구현 완료, 백엔드 연동 대기. - npm + Nexus 프록시 레지스트리 설정 - 팀 워크플로우 v1.6.1 부트스트랩 파일 배치 - .githooks (commit-msg, post-checkout) - package.json name: kcg-ai-monitoring v0.1.0 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
8.5 KiB
8.5 KiB
KCG AI Monitoring - 다음 단계 리팩토링 TODO
프론트엔드 UI 스캐폴딩 + 기반 인프라(상태관리, 지도 GPU, mock 데이터, CVA) 완료 상태. 백엔드 연동 및 운영 품질 확보를 위해 남은 항목을 순차적으로 진행한다.
1. ✅ 상태관리 도입 (Zustand 5.0) — COMPLETED
zustand 5.0.12 설치, src/stores/에 8개 독립 스토어 구현 완료.
vesselStore— 선박 목록, 선택, 필터patrolStore— 순찰 경로/함정eventStore— 탐지/경보 이벤트kpiStore— KPI 메트릭, 추세transferStore— 전재(환적)gearStore— 어구 탐지enforcementStore— 단속 이력settingsStore— theme/language + localStorage 동기화, 지도 타일 자동 전환
AuthContext는 유지 (인증은 Context API가 적합, 마이그레이션 불필요로 결정)
2. API 서비스 계층 (Axios 1.14) — 구조 완성, 실제 연동 대기
현재 상태
src/services/에 7개 서비스 모듈 구현 (api, vessel, event, patrol, kpi, ws, index)api.ts: fetch 래퍼 (apiGet,apiPost) — 향후 Axios 교체 예정- 각 서비스가
data/mock/모듈에서 mock 데이터 반환 (실제 HTTP 호출 0건) ws.ts: STOMP WebSocket 스텁 존재, 미구현
남은 작업
axios1.14 설치 →api.ts의 fetch 래퍼를 Axios 인스턴스로 교체- Axios 인터셉터:
- Request: Authorization 헤더 자동 주입
- Response: 401 → 로그인 리다이렉트, 500 → 에러 토스트
@tanstack/react-query5.x 설치 → TanStack Query Provider 추가- 각 서비스의 mock 반환을 실제 API 호출로 교체
- 로딩 스켈레톤, 에러 바운더리 공통 컴포넌트
3. 실시간 인프라 (STOMP.js + SockJS) — 스텁 구조만 존재
현재 상태
services/ws.ts에connectWs스텁 함수 존재 (인터페이스 정의 완료)- STOMP.js, SockJS 미설치 — 실제 WebSocket 연결 없음
useStoreLayerSynchook으로 store→지도 실시간 파이프라인 준비 완료
남은 작업
@stomp/stompjs+sockjs-client설치ws.ts스텁을 실제 STOMP 클라이언트로 구현- 구독 채널 설계:
/topic/ais-positions— 실시간 AIS 위치/topic/alerts— 경보/이벤트/topic/detections— 탐지 결과/user/queue/notifications— 개인 알림
- 재연결 로직 (지수 백오프)
- store →
useStoreLayerSync→ 지도 마커 실시간 업데이트 연결 eventStore와 연동하여 알림 배너/뱃지 카운트 업데이트
4. ✅ 고급 지도 레이어 (deck.gl 9.2) — COMPLETED
deck.gl 9.2.11 + @deck.gl/mapbox 설치, MapLibre + deck.gl 인터리브 아키텍처 구현 완료.
- BaseMap:
forwardRef+memo,MapboxOverlay를useImperativeHandle로 외부 노출 - useMapLayers: RAF 배치 레이어 업데이트, React 리렌더 0회
- useStoreLayerSync: Zustand store.subscribe → RAF → overlay.setProps (React 우회)
- STATIC_LAYERS: EEZ + NLL PathLayer 싱글턴 (GPU 1회 업로드)
- createMarkerLayer: ScatterplotLayer + transitions 보간 + DataFilterExtension
- createRadiusLayer: 반경 원 표시용 ScatterplotLayer
- 레거시 GeoJSON 레이어(
boundaries.ts)는 하위 호환으로 유지
성능 목표 40만척+ GPU 렌더링 달성. TripsLayer/HexagonLayer/IconLayer는 실데이터 확보 후 추가 예정.
5. ✅ 더미 데이터 통합 — COMPLETED
src/data/mock/에 7개 공유 mock 모듈 구현 완료. TypeScript 인터페이스 정의 포함.
data/mock/
├── vessels.ts # VesselData — 선박 목록 (한국, 중국, 경비함)
├── events.ts # EventRecord, AlertRecord — 탐지/단속 이벤트
├── transfers.ts # 전재(환적) 데이터
├── patrols.ts # PatrolShip — 순찰 경로/함정
├── gear.ts # 어구 탐지 데이터
├── kpi.ts # KpiMetric, MonthlyTrend, ViolationType
└── enforcement.ts # 단속 이력 데이터
services/계층이 mock 모듈을 import하여 반환 → 향후 API 교체 시 서비스만 수정- 인터페이스가 API 응답 타입 계약 역할 수행
6. i18n 실적용 — 구조 완성, 내부 텍스트 미적용
현재 상태
- 10 네임스페이스 리소스 완비: common, dashboard, detection, patrol, enforcement, statistics, ai, fieldOps, admin, auth
- ko/en 각 10파일 (총 20 JSON)
settingsStore.toggleLanguage()+localStorage동기화 구현 완료- 적용 완료: MainLayout 사이드바 메뉴명, 24개 페이지 제목, LoginPage
- 미적용: 각 페이지 내부 텍스트 (카드 레이블, 테이블 헤더, 상태 텍스트 등) — 대부분 한국어 하드코딩 잔존
남은 작업
- 각 feature 페이지 내부 텍스트를
useTranslation('namespace')+t()로 교체 - 날짜/숫자 포맷 로컬라이즈 (
Intl.DateTimeFormat,Intl.NumberFormat) - 누락 키 감지 자동화 (i18next missing key handler 또는 lint 규칙)
7. ✅ Tailwind 공통 스타일 모듈화 (CVA) — COMPLETED
class-variance-authority 0.7.1 설치, src/lib/theme/variants.ts에 3개 CVA 변형 구현 완료.
- cardVariants: default / elevated / inner / transparent — CSS 변수 기반 테마 반응
- badgeVariants: 8 intent (critical~cyan) x 4 size (xs~lg) — 150회+ 반복 패턴 통합
- statusDotVariants: 4 status (online/warning/danger/offline) x 3 size (sm/md/lg)
shared/components/ui/card.tsx,badge.tsx에 CVA 적용 완료- CSS 변수(
surface-raised,surface-overlay,border) 참조로 Dark/Light 자동 반응
8. 코드 스플리팅 — 미착수
현재 상태
- 단일 번들 ~3.2MB (모든 feature + deck.gl + MapLibre + ECharts 포함)
React.lazy미적용, 모든 31개 페이지가 동기 import- 초기 로딩 시 사용하지 않는 페이지 코드까지 전부 다운로드
필요한 이유
- 초기 로딩 성능 개선 (FCP, LCP)
- 현장 모바일 환경 (LTE/3G)에서의 사용성 확보
- 번들 캐싱 효율 향상 (변경된 chunk만 재다운로드)
구현 계획
React.lazy+Suspense로 feature 단위 동적 임포트:const Dashboard = lazy(() => import('@features/dashboard/Dashboard')); const RiskMap = lazy(() => import('@features/risk-assessment/RiskMap'));App.tsx라우트 전체를 lazy 컴포넌트로 교체- 로딩 폴백 컴포넌트 (스켈레톤 또는 스피너) 공통화
- Vite
build.rollupOptions.output.manualChunks설정:manualChunks: { 'vendor-react': ['react', 'react-dom', 'react-router-dom'], 'vendor-map': ['maplibre-gl', 'deck.gl', '@deck.gl/mapbox'], 'vendor-chart': ['echarts'], } - 목표: 초기 번들 < 300KB (gzip), 각 feature chunk < 100KB
vite-plugin-compression으로 gzip/brotli 사전 압축 검토
9. Light 테마 하드코딩 정리
현재 상태
- Dark/Light 테마 전환 구조 완성 (CSS 변수 +
.light클래스 + settingsStore) - 시맨틱 변수(
surface-raised,text-heading등) + CVA 변형은 정상 작동 - 문제: 일부 alert/status 색상이 Tailwind 하드코딩 (
bg-red-500/20,text-red-400,border-red-500/30등)- Dark에서는 자연스러우나, Light 전환 시 대비/가독성 부족
구현 계획
- 하드코딩 alert 색상을 CSS 변수 또는 CVA intent로 교체
badgeVariants의 intent 색상도 CSS 변수 기반으로 전환 검토- Light 모드 전용 대비 테스트 (WCAG AA 기준)
우선순위 및 의존관계
✅ 완료 ─────────────────────────────────────
[1. Zustand] [4. deck.gl] [5. mock 데이터] [7. CVA]
진행 중 / 남은 작업 ──────────────────────────
[6. i18n 내부 텍스트] ──┐
├──▶ [2. API 실제 연동] ──▶ [3. 실시간 STOMP]
[9. Light 테마 정리] ───┘
[8. 코드 스플리팅] ← 독립 작업, 언제든 착수 가능 (~3.2MB → 목표 <300KB)
권장 진행 순서
- Phase A (품질): i18n 내부 텍스트 적용 (6) + Light 테마 하드코딩 정리 (9) + 코드 스플리팅 (8)
- Phase B (연동): Axios 설치 + API 실제 연동 (2)
- Phase C (실시간): STOMP.js + SockJS 실시간 인프라 (3)