# 0_old vs 현재 프로젝트 혼선 지점 분석 (Critical for Coders) **작성일:** 2026-07-10 **목적:** 0_old 코드 참고 시 발생할 수 있는 통합 오류 사전 차단 --- ## 1. 데이터 구조 & 저장소 경로 차이 ### 1.1 저장소 경로 구조 | 항목 | 0_old | 현재 프로젝트 | |------|-------|------------| | **기본 경로** | `storage/projects/{projectId}/` | `storage/{company_slug}/{user_slug}/{projectId}/` | | **원본 입력** | `input/` (명확하지 않음) | `B03_FileInput/input/` | | **처리 결과** | `processed/` (모든 것을 한곳에) | `B04_wf1_Surface/processed/` (분산) | | **지표면 모델** | `processed/` 내 JSON | `B04_wf1_Surface/models/` | | **경로 데이터** | `route_design/` | `B05_wf2_Route/route/` | | **종횡단면** | `sections/` | `B06_wf3_ProfileCross/` | **코더 주의:** - 0_old의 경로를 그대로 현재 코드에 복사하면 **파일을 찾을 수 없음** - 항상 `config_system.py`의 `PROJECT_STORAGE_STAGE_DIRS` 확인 - 경로 변환은 `common_util_storage.py`의 `resolve_stored_project_path()` 사용 **예시 오류:** ```python # ❌ 0_old 방식 path = f"storage/projects/{projectId}/processed/tin.json" # ✅ 현재 방식 from common_util.common_util_storage import resolve_stored_project_path stored_path = await get_project_storage_relative_path(connection, projectId) project_root = Path(resolve_stored_project_path(stored_path)) path = project_root / "B04_wf1_Surface" / "models" / "tin.json" ``` --- ## 2. API 엔드포인트 & 요청/응답 구조 ### 2.1 0_old API 엔드포인트 | 메서드 | 경로 | 목적 | |--------|------|------| | GET | `/api/projects/{projectId}/analysis` | 분석 결과 조회 | | GET | `/api/projects/{projectId}/las-points` | LAS 포인트 샘플 조회 | | GET | `/api/projects/{projectId}/all-points` | 모든 포인트 조회 | | GET | `/api/projects/{projectId}/ground-points` | 지면 포인트만 조회 | | POST | `/api/projects/{projectId}/analyze-ground` | 분석 실행 (동기) | | GET | `/api/projects/{projectId}/terrain-models` | 지표면 모델 목록 | | POST | `/api/projects/{projectId}/route/solve` | 경로 계산 | | POST | `/api/projects/{projectId}/sections/generate` | 종횡단면 생성 | ### 2.2 현재 프로젝트 API 엔드포인트 | 메서드 | 경로 | 목적 | |--------|------|------| | POST | `/api/projects/{projectId}/surface/analyze` | 분석 실행 (비동기, **상태 저장**) | | GET | `/api/projects/{projectId}/surface/status` | 분석 상태 및 진행률 조회 | | GET | `/api/projects/{projectId}/surface/models` | 지표면 모델 목록 | | GET | `/api/projects/{projectId}/surface/point-cloud` | 포인트 샘플 조회 | | GET | `/api/projects/{projectId}/surface/ground-stats` | 지면 필터 통계 | | POST | `/api/projects/{projectId}/files` | 파일 업로드 (다중) | | POST | `/api/projects/{projectId}/upload-sessions` | 청크 업로드 세션 시작 | | POST | `/api/projects/{projectId}/chunks` | 청크 업로드 | | POST | `/api/projects/{projectId}/finalize` | 업로드 완료 | **코더 주의:** - 0_old의 `/api/projects/{projectId}/analyze-ground` 는 **현재에 없음** - 현재는 `/api/projects/{projectId}/surface/analyze` + `/api/projects/{projectId}/surface/status` 조합 - 0_old 코드 마이그레이션 시 **비동기 처리 방식 변경 필수** --- ## 3. 프론트엔드 기술 스택 차이 ### 3.1 라이브러리 버전 | 라이브러리 | 0_old | 현재 프로젝트 | 비고 | |-----------|-------|------------|------| | React | 19.2.7 | **없음** | **critical diff** | | React-DOM | 19.2.7 | **없음** | **critical diff** | | lucide-react | 1.23.0 | **없음** | 아이콘 라이브러리 | | THREE.js | 0.185.0 | 0.185.0 | ✅ 동일 | | MapLibre-GL | 5.24.0 | **없음** | 지도 렌더러 | | TypeScript | 6.0.3 | 5.x (확인 필요) | 버전 차이 가능성 | **코더 주의:** - 0_old의 모든 `.tsx` 컴포넌트는 **React 훅 기반** - 현재 프로젝트는 **바닐라 TypeScript + DOM 조작** - 0_old 컴포넌트를 현재 프로젝트에 복사하면 **즉시 오류** (React 불가) ### 3.2 필수 변환 규칙 (0_old → 현재) #### React 훅 → 클로저 + 렌더 함수 ```typescript // ❌ 0_old (React 훅) function PointCloudViewer({ projectId }: { projectId: string }) { const [scale, setScale] = useState(1.0); useEffect(() => { /* initialization */ }, [projectId]); return
...
; } // ✅ 현재 (바닐라 TS) function createPointCloudViewer(projectId: string): HTMLElement { let scale = 1.0; const container = document.createElement('div'); const initialize = async () => { /* initialization */ }; initialize(); return container; } ``` #### JSX → `createElement` (또는 템플릿 리터럴) ```typescript // ❌ 0_old (JSX) // ✅ 현재 (DOM 직접 생성) const button = document.createElement('button'); button.textContent = 'Click me'; button.addEventListener('click', handleClick); ``` #### lucide-react 아이콘 → 인라인 SVG / 유니코드 ```typescript // ❌ 0_old (lucide-react) import { FileUp } from 'lucide-react'; // ✅ 현재 (유니코드 또는 SVG) const icon = document.createElement('span'); icon.textContent = '📤'; // 또는 인라인 SVG ``` --- ## 4. 분석 엔진 & 백엔드 알고리즘 ### 4.1 0_old 분석 프로세스 **`0_old/backend/app/analyzer.py`:** - `analyze_project()` — 동기식 전체 분석 실행 - LAS 로드 및 메타데이터 추출 - 포인트 클라우드 필터 적용 (CSF, PMF, RANSAC, grid_min_z) - 지표면 모델 생성 (TIN, DTM, NURBS, implicit, meshfree 등) - 결과를 `storage/projects/{projectId}/processed/analysis.json` 에 저장 **결과 저장 형식:** ```json { "timestamp": "2025-07-10T...", "project_files": { /* file metadata */ }, "point_cloud_summary": { "total": 1000000, ... }, "ground_filter_results": { "csf": { ... }, "pmf": { ... }, ... }, "terrain_models": { "tin": { "model_file": "...", "contours": [...] }, "dtm": { ... } } } ``` ### 4.2 현재 프로젝트 분석 프로세스 **`B04_wf1_Surface/B04_wf1_Surface_Engine.py`:** - `run_surface_analysis()` — 동기식이지만, 라우터에서 `asyncio.to_thread()` 로 실행 - 결과를 여러 개의 DB 테이블에 저장: - `processed_point_clouds` 테이블 - `surface_models` 테이블 - `terrain_layers` 테이블 - 파일 경로도 함께 DB에 저장 (`model_file_path`, `layer_file_path` 등) **코더 주의:** - 0_old는 JSON 파일 중심, 현재는 **DB + 파일 경로 이원화** - 분석 결과 조회 시: - 0_old: `storage/projects/{projectId}/processed/analysis.json` 직접 읽기 - 현재: `surface_models` 테이블 쿼리 + 필요한 파일을 경로로 로드 --- ## 5. 프론트엔드 상태 관리 & LocalStorage ### 5.1 0_old 상태 관리 **`main.tsx`에서 `useState` 사용:** - `projectId` — 현재 프로젝트 ID - `stage` — 현재 워크플로우 단계 - `analysisResult` — 분석 결과 캐시 - `selectedRoute` — 선택된 경로 - 등등 **localStorage 미사용** (또는 매우 제한적) ### 5.2 현재 프로젝트 상태 관리 **`config_frontend.ts`:** ```typescript const CURRENT_PROJECT_ID_KEY = "frd_current_project_id"; ``` **localStorage 의존성:** - 프로젝트 ID는 반드시 localStorage에 저장 - 페이지 네비게이션 시 projectId 복구 - 청크 업로드 세션 정보도 localStorage 유지 **코더 주의:** - 0_old 코드를 현재 프로젝트에 옮길 때, localStorage 복구 로직 추가 필수 - 특히 B04, B05, B06 페이지는 모두 `CURRENT_PROJECT_ID_KEY` 의존 --- ## 6. 3D 렌더링 (THREE.js) — 유사성 ### 6.1 공통점 **0_old와 현재 모두 THREE.js 0.185.0 사용:** - `PointCloudViewer.tsx` → 포인트 클라우드 렌더링 - `TerrainModelViewer.tsx` → 지표면 모델 렌더링 - OrbitControls 사용 (카메라 조작) **코더에게 좋은 소식:** - THREE.js 부분은 상대적으로 간단한 변환 가능 - 렌더 루프, 조명, 카메라 로직은 큰 변경 불필요 - DOM 생성 부분만 수정하면 대부분 재사용 가능 **예시:** ```typescript // ❌ 0_old (JSX) ... // ✅ 현재 (THREE.js 직접) const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, width/height, 0.1, 10000); camera.position.set(100, 100, 100); const renderer = new THREE.WebGLRenderer(); renderer.render(scene, camera); ``` --- ## 7. 필터 알고리즘 (Python) — 재사용 가능 ### 7.1 0_old 필터 유틸리티 **`0_old/utils/` 디렉토리:** - `filter_csf.py` — Cloth Simulation Filter - `filter_pmf.py` — Progressive Morphological Filter - `filter_ransac.py` — RANSAC-기반 필터 - `filter_grid_min_z.py` — Grid Min-Z 필터 **현재 프로젝트에서 이 필터들을 사용하는가?** - ✅ 네, `B04_wf1_Surface_Engine.py`에서 참고 - 동일한 필터 알고리즘 재구현 가능 **코더 주의:** - 필터 알고리즘은 그대로 복사 가능 (Python 코드) - 하지만 **경로, DB 저장 방식은 변경 필수** --- ## 8. 라우팅 & 네비게이션 차이 ### 8.1 0_old 라우팅 **`main.tsx`에서 React Router 미사용, 수동 state 관리:** ```typescript if (stage === "TERRAIN_ANALYSIS") { return ; } else if (stage === "ROUTE_DESIGN") { return ; } // ... ``` ### 8.2 현재 프로젝트 라우팅 **`A00_Common/A00_Common_UI_Navigator.ts`에서 수동 SPA 라우팅:** ```typescript function navigateTo(route: string): void { window.location.hash = route; // ... } ``` **코더 주의:** - 0_old 코드를 현재에 적용할 때, `navigateTo()` 사용 필수 - localStorage 저장 + 네비게이션 순서 엄격 준수 (§2.2.2 참고) --- ## 9. 체크리스트 for Coders 0_old 코드를 현재 프로젝트에 통합할 때 반드시 확인: ### 파일 경로 - [ ] `storage/projects/...` → `storage/{company}/{user}/{projectId}/B0N_...` 변환 - [ ] 하드코딩된 경로 제거 - [ ] `resolve_stored_project_path()` 및 `PROJECT_STORAGE_STAGE_DIRS` 사용 ### API 호출 - [ ] 엔드포인트 변경 (`/analyze-ground` → `/surface/analyze`) - [ ] 비동기 처리 추가 (폴링 로직) - [ ] 요청/응답 포맷 확인 ### 프론트엔드 컴포넌트 - [ ] React 훅 → 클로저 + 렌더 함수 변환 - [ ] JSX → `createElement` 또는 템플릿 리터럴 변환 - [ ] lucide-react 아이콘 → 유니코드/인라인 SVG 변환 - [ ] localStorage 의존성 추가 (`CURRENT_PROJECT_ID_KEY`) ### 상태 관리 - [ ] `useState` 호출 제거 - [ ] localStorage에 상태 저장 확인 - [ ] 페이지 리로드 후 복구 로직 확인 ### THREE.js 렌더링 - [ ] 캔버스 생성 부분 확인 - [ ] 렌더 루프 설정 확인 - [ ] 이벤트 리스너(resize, click 등) 추가 ### DB 저장 - [ ] JSON 파일 저장에서 DB 테이블 저장으로 변경 - [ ] 파일 경로를 DB에 함께 저장 - [ ] 트랜잭션 처리 확인 --- ## 10. 예시: 0_old PointCloudViewer 변환 ### 0_old (React + JSX) ```typescript // 0_old/frontend/src/PointCloudViewer.tsx (간략) export function PointCloudViewer({ projectId }: { projectId: string }) { const [scale, setScale] = useState(1.0); const canvasRef = useRef(null); useEffect(() => { const canvas = canvasRef.current; const renderer = new THREE.WebGLRenderer({ canvas }); // 렌더링 설정 }, [projectId]); return ; } ``` ### 현재 프로젝트 (바닐라 TS) ```typescript // B04_wf1_Surface/B04_wf1_Surface_UI_PointCloud.ts (신규) export function createPointCloudViewer(projectId: string): HTMLElement { let scale = 1.0; const canvas = document.createElement('canvas'); const initialize = async () => { const renderer = new THREE.WebGLRenderer({ canvas }); // 렌더링 설정 const response = await fetch(`/api/projects/${projectId}/surface/point-cloud`); const data = await response.json(); // 포인트 클라우드 렌더 }; initialize(); return canvas; } ``` --- ## 11. 결론 | 영역 | 재사용 난이도 | 주의사항 | |------|-----------|---------| | **경로 구조** | 높음 | 전체 매핑 필요 | | **API 엔드포인트** | 높음 | 비동기 처리 방식 변경 | | **프론트엔드 컴포넌트** | 높음 | React → TS 변환 필수 | | **필터 알고리즘** | 낮음 | 경로 변수만 수정 | | **THREE.js 렌더링** | 낮음 | JSX → DOM 생성만 수정 | | **DB 저장 로직** | 높음 | 완전 재작성 | **최종 권장사항:** 1. 0_old는 **알고리즘 참고용**으로만 사용 2. 경로, API, 컴포넌트 구조는 **현재 프로젝트 표준 준수** 3. 통합 전 **단위 테스트** 작성 (경로 매핑, API 응답 검증)