diff --git a/CLAUDE.md b/CLAUDE.md index ffe7de2..6f311df 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -202,6 +202,35 @@ deploy/ # systemd + nginx 배포 설정 | **DB** | kcgdb | 211.208.115.83:5432/kcgdb (유저: kcg_app, pw: Kcg2026monitor) | | **DB** | snpdb | 211.208.115.83:5432/snpdb (유저: snp, pw: snp#8932, 읽기 전용) | +## 디버그 도구 가이드 + +### 원칙 +- 디버그/개발 전용 기능은 `import.meta.env.DEV` 가드로 감싸서 **프로덕션 빌드에서 코드 자체가 제거**되도록 구현 +- Vite production 빌드 시 `import.meta.env.DEV = false` → dead code elimination → 번들 미포함 +- 무거운 DB 조회, 통계 계산 등도 DEV 가드 안이면 프로덕션에 영향 없음 + +### 파일 구조 +- 디버그 컴포넌트: `frontend/src/components/{도메인}/debug/` 디렉토리에 분리 +- 메인 컴포넌트에서는 import + DEV 가드로만 연결: +```tsx +import { DebugTool } from './debug/DebugTool'; +const debug = import.meta.env.DEV ? useDebugHook() : null; +// JSX: +{debug && } +``` + +### 기존 디버그 도구 +| 도구 | 위치 | 기능 | +|------|------|------| +| CoordDebugTool | `korea/debug/CoordDebugTool.tsx` | Ctrl+Click 좌표 표시 (DD/DMS, 다중 포인트) | + +### 디버그 도구 분류 기준 +다음에 해당하면 디버그 도구로 분류하고, 불확실하면 사용자에게 확인: +- 개발/검증 목적의 좌표/데이터 표시 도구 +- 프로덕션 사용자에게 불필요한 진단 정보 +- 임시 데이터 시각화, 성능 프로파일링 +- 특정 조건에서만 활성화되는 테스트 기능 + ## 팀 규칙 - 코드 스타일: `.claude/rules/code-style.md` diff --git a/frontend/src/components/korea/KoreaMap.tsx b/frontend/src/components/korea/KoreaMap.tsx index a9ade65..9e2c0d3 100644 --- a/frontend/src/components/korea/KoreaMap.tsx +++ b/frontend/src/components/korea/KoreaMap.tsx @@ -201,6 +201,12 @@ const FILTER_I18N_KEY: Record = { cnFishing: 'filters.cnFishingMonitor', }; +// [DEBUG] 개발용 도구 — DEV에서만 동적 로드, 프로덕션 번들에서 완전 제거 +import { lazy, Suspense } from 'react'; +const DebugTools = import.meta.env.DEV + ? lazy(() => import('./debug')) + : null; + export function KoreaMap({ ships, allShips, aircraft, satellites, layers, osintFeed, currentTime, koreaFilters, transshipSuspects, cableWatchSuspects, dokdoWatchSuspects, dokdoAlerts, vesselAnalysis, groupPolygons, hiddenShipCategories, hiddenNationalities, externalFlyTo, onExternalFlyToDone, opsRoute }: Props) { const { t } = useTranslation(); const mapRef = useRef(null); @@ -609,6 +615,9 @@ export function KoreaMap({ ships, allShips, aircraft, satellites, layers, osintF > + {/* [DEBUG] 개발용 도구 — 프로덕션 번들에서 완전 제거 */} + {DebugTools && } + = 0 ? 'N' : 'S') : (dd >= 0 ? 'E' : 'W'); + const abs = Math.abs(dd); + const d = Math.floor(abs); + const mFull = (abs - d) * 60; + const m = Math.floor(mFull); + const s = ((mFull - m) * 60).toFixed(2); + return `${d}°${String(m).padStart(2, '0')}′${String(s).padStart(5, '0')}″${dir}`; +} + +interface Props { + mapRef: React.RefObject; +} + +/** + * 자체 완결형 디버그 오버레이. + * mapRef를 받아서 직접 click 이벤트를 등록/해제. + * KoreaMap의 기존 코드에 어떤 것도 섞이지 않음. + */ +export default function DevCoordDebug({ mapRef }: Props) { + const [points, setPoints] = useState([]); + + useEffect(() => { + const map = mapRef.current?.getMap(); + if (!map) return; + + const handler = (e: maplibregl.MapMouseEvent) => { + if (e.originalEvent.ctrlKey || e.originalEvent.metaKey) { + e.originalEvent.preventDefault(); + setPoints(prev => [...prev, { lat: e.lngLat.lat, lng: e.lngLat.lng, id: Date.now() }]); + } + }; + + map.on('click', handler); + return () => { map.off('click', handler); }; + }, [mapRef]); + + return ( + <> + {points.map(cp => ( +
+ +
+ + setPoints(prev => prev.filter(p => p.id !== cp.id))} + closeButton={true} + closeOnClick={false} + anchor="bottom" + offset={[0, -10]} + style={{ zIndex: 50 }} + > +
+
+ WGS84 (EPSG:4326) +
+
DD
+
{cp.lat.toFixed(6)}°N
+
{cp.lng.toFixed(6)}°E
+
DMS
+
{toDMS(cp.lat, 'lat')}
+
{toDMS(cp.lng, 'lng')}
+
+
+
+ ))} + + ); +} diff --git a/frontend/src/components/korea/debug/index.tsx b/frontend/src/components/korea/debug/index.tsx new file mode 100644 index 0000000..6e44c18 --- /dev/null +++ b/frontend/src/components/korea/debug/index.tsx @@ -0,0 +1,24 @@ +/** + * [DEBUG] 디버그 도구 허브 — 모든 개발용 도구를 조합하여 export + * + * 디버그 도구 추가/제거 시 이 파일만 수정하면 됨. + * KoreaMap에서는 이 파일만 lazy import. + * 프로덕션 빌드에서 이 파일과 하위 도구 전체가 번들에서 제거됨. + */ +import type { MapRef } from 'react-map-gl/maplibre'; +import DevCoordDebug from './DevCoordDebug'; + +interface Props { + mapRef: React.RefObject; +} + +export default function DebugTools({ mapRef }: Props) { + return ( + <> + + {/* 디버그 도구 추가 시 여기에 한 줄 추가 */} + {/* */} + {/* */} + + ); +}