42 KiB
WF1~WF3 레이아웃 재설계 및 파일 업로드 프로세스 개선 계획서
작성일: 2026-07-10 (업데이트)
상태: 상세 설계 단계
범위: B03_FileInput (파일 업로드 비동기 처리), 대시보드 워크플로우 상태 관리, B04_wf1_Surface~B06_wf3_ProfileCross 공통 레이아웃 템플릿 (0_old 기반)
1. 개요 및 개선 배경
1.1 현재 문제점
-
B03 파일 업로드
- 업로드 시작 후 완료될 때까지 UI 로딩 오버레이 활성화 상태 유지 → 사용자 동작 불가
- 페이지 리프레시 시 업로드 진행상황 소실
- 백엔드는 비동기 처리 중인데 프론트엔드는 동기 대기
-
B01 대시보드 워크플로우 상태
- 파일 업로드 완료 후 WF1 분석 완료되어도 워크플로우 버튼이 활성화되지 않음
- 대시보드의 프로젝트 상태 변경 로직 미동기화
-
B04_wf1_Surface, B05_wf2_Route, B06_wf3_ProfileCross 레이아웃
- 현재 3단 레이아웃(상단+좌측+우측)이 협소함
- 좌측 폼 영역이 항상 표시되어 우측 작업 영역을 제한
- 3D 조작, 경로 설계, 종단/횡단 작업 같은 실무에는 넓은 공간 필수
- 현재 B04 페이지는 카드형 제목만 표시 (불완전)
-
0_old 프로그램 기반 구현
- 0_old/frontend/src에 PointCloudViewer.tsx, TerrainModelViewer.tsx, RouteDesignStage.tsx, LongitudinalProfile.tsx, CrossSectionGrid.tsx 등 완성된 컴포넌트 있음
- 0_old/utils에 필터 적용(CSF, PMF, RANSAC, grid_min_z), 경로 계산(dijkstra, ridge_valley), 종횡단 생성 로직 있음
- 0_old/backend/app에 분석 엔진 있음 (분석 결과를
storage/projects/{projectId}/processed/에 JSON/NPZ 형식으로 저장) - 현재 프로젝트와 통합: 레이아웃(데스크톱 IDE 스타일)과 테마(Wiza 디자인)는 새로 작성, 콘텐츠와 3D 렌더링은 0_old 참고/재사용
2. 세부 개선 사항
2.1 B03_FileInput 업로드 비동기 처리 개선
2.1.1 현재 상태 (코드 분석)
- 파일 선택/드래그 → 유효성 검증 → 청크 업로드 반복
uploadOneFile()함수 내 루프에서 모든 청크 업로드 완료 대기showLoadingOverlay()/hideLoadingOverlay()호출로 UI 블로킹- 백엔드
pollWF1Analysis()함수로 분석 상태 폴링 (5초 주기, 최대 30분)
2.1.2 개선 계획
2.1.2.1 파일 업로드 진행 상태 UI 표시 (로딩 오버레이 제거)
- 로딩 오버레이 제거 → 사용자는 자유롭게 다른 페이지 이동 가능
- 대신 지속적인 업로드 상태 표시:
- 각 파일 카드에 진행률 바 및 상태 배지 표시 (이미 구현됨)
- 우상단 토스트: "파일 업로드 중... (60% 완료)" 지속 표시
- 분석 시작 후 토스트 업데이트: "WF1 분석 중... (30% 진행률)"
2.1.2.2 업로드 세션 정보 localStorage에 지속 저장 + 분석 진행률 함께 저장
- 현재: 업로드 완료 시
localStorage.removeItem(storageKey)실행 → 페이지 리프레시 시 정보 소실 - 개선: 업로드 완료 후에도 세션 정보 유지 (별도 키:
b03_project_state_${projectId}) - 저장 형식:
{ "projectId": "uuid", "uploadedAt": 1720599600000, "files": [ { "slot": "las_laz", "fileName": "data.las", "fileSize": 1024000000, "status": "completed" } ], "analysisStatus": "in_progress", // pending | in_progress | completed | failed "analysisProgress": 30, "lastCheckedAt": 1720599630000 } - 페이지 리로드 후 복구 로직:
- localStorage에서 저장된 정보 로드
- 파일 카드들을 "완료" 상태로 표시
- 분석이 진행 중이면 토스트 메시지 "WF1 분석이 계속 진행 중입니다..." 표시
- 백그라운드에서 분석 진행률 폴링 재개
2.1.2.3 분석 진행 상태 추적 메커니즘
-
0_old의 구조 분석:
- 0_old/backend/app/analyzer.py의
analyze_project()함수는 분석을 동기로 실행 - 결과를
storage/projects/{projectId}/processed/analysis.json에 저장 - 프론트엔드는
/api/projects/{projectId}/analysis로 분석 결과를 조회
- 0_old/backend/app/analyzer.py의
-
개선 방식 (⚠️ 신규 API 생성 금지 — 기존 API 확장):
- 기존 API 활용:
GET /api/projects/{project_id}/surface/status가 이미 존재함 (B04_wf1_Surface_Router.pyget_wf1_analysis_status(), 프론트 클라이언트는 B03_FileInput_Api_Fetch.tscheckWF1AnalysisStatus()) - 기존 구현의 한계 (개선 대상):
- 현재는
surface_models테이블의 모델 카운트만으로 completed/in_progress 판정 - 분석이 실패해도 영원히 in_progress 로 표시됨 (failed 상태 판별 불가)
- 진행률(%) 정보 없음
- 현재는
- 확장 계획: 기존 엔드포인트 응답에 필드 추가 (경로 변경 없음)
{ "project_id": "uuid", "status": "in_progress", // pending | in_progress | completed | failed "model_count": 0, "progress_percent": 30, "current_stage": "filter_csf", "message": "CSF 필터 적용 중" } - 진행률 기록 위치: 분석 실행 측(B03_FileInput_Engine_Analyze.py)이 진행 단계마다 진행률을 기록하고, status API가 이를 읽어 응답. 기록 방식은 기존
common_util_workflow.py의 workflow.json 메커니즘(backend.md §5, 원자적 쓰기)을 우선 검토하고, 부적합 시 프로젝트 저장소 루트(storage/{회사slug}/{사용자slug}/{projectId}/B04_wf1_Surface/) 하위에 진행률 JSON 파일 저장.storage/{projectId}/...같은 축약 경로는 실제 구조와 다르므로 사용 금지. - 폴링 주기: 기존 B03 코드의 5초 유지 (backend.md §5.3은 workflow 폴링 3초를 규정하므로, 코더는 구현 시 두 값을 config_frontend 상수로 통일할 것)
- 사용자 이탈 대응: 페이지 복귀 시 localStorage 복구 + status API 재폴링으로 진행률 재표시
- 기존 API 활용:
2.1.2.4 프로젝트 상태 DB 업데이트 (대시보드 워크플로우 버튼 활성화)
- 현재: 파일 업로드 → 분석 완료 자동 이동만 처리
- 개선:
- B03_FileInput_Engine_Analyze.py에서 각 분석 단계마다
projects.status업데이트:- 업로드 완료:
status = 'WF1_ANALYZING' - 분석 완료:
status = 'WF1_COMPLETE'
- 업로드 완료:
- DB 업데이트 로직:
await db.execute( "UPDATE projects SET status = %s, updated_at = NOW() WHERE id = %s", ('WF1_COMPLETE', project_id) ) - 대시보드 워크플로우 테이블에서 프로젝트별
status필드를 읽어 버튼 활성화/비활성화 결정
- B03_FileInput_Engine_Analyze.py에서 각 분석 단계마다
2.1.3 구현 파일 수정
- B03_FileInput_UI_Page.ts
startChunkedUpload()함수: 로딩 오버레이 제거uploadOneFile()함수: 백그라운드 진행 표시로 전환- 세션 저장 로직 개선 (완료 후 분석 상태 포함)
- 페이지 리로드 시
detectPausedUploads()함수에서 세션 상태 복구
- B03_FileInput_Api_Fetch.ts
- 분석 진행률 조회 API 추가:
async function getWF1AnalysisProgress(projectId: string)
- 분석 진행률 조회 API 추가:
- B03_FileInput_Engine_Analyze.py
- 분석 완료 후
projects.status업데이트 - 이메일 발송 후 대시보드 반영 시간 ~5초 이내
- 분석 완료 후
2.2 B01 대시보드 워크플로우 버튼 — 활성화 및 프로젝트 컨텍스트 전달
2.2.1 현재 상태 (코드 검증 완료 — 기존 계획서 v1의 오류 정정)
버튼 활성화 메커니즘은 이미 존재함:
B01_Dashboard_Repository.py_stage_from_status()(line 20):projects.status문자열에서 stage 번호 계산- 예: status에 "WF1" 포함 → stage 2, "FILE_UPLOADED" → stage 1, "NEW" → stage 0
B01_Dashboard_UI_Page.tsworkflow()(line 370): stage 기반으로 B03~B09 버튼 활성/비활성 렌더링enabled = index + 1 <= Math.max(activeStage, 1)→ B03은 항상 활성
따라서 "버튼이 활성화되지 않는" 실제 원인은 UI가 아니라:
- 백엔드가 분석 완료 후
projects.status를 갱신하지 않음 → §2.1.2.4에서 해결 (WF1_ANALYZING→WF1_COMPLETE) - 대시보드가 열려 있는 동안 상태 변화를 다시 가져오지 않음 (새로고침해야 반영)
추가 발견 — 토큰 매칭의 허점:
_stage_from_status()는 부분 문자열 매칭이므로WF1_ANALYZING과WF1_COMPLETE가 모두 "WF1" 토큰에 걸려 stage 2가 됨- 즉 분석이 진행 중(ANALYZING)이어도 B04 버튼이 열림 →
_COMPLETE접미사까지 확인하도록 수정 필요 (ANALYZING은 직전 단계까지만 활성)
2.2.2 🐞 버그: 워크플로우 버튼으로 진입 시 "현재 프로젝트가 선택되지 않았습니다" 표시
증상: 대시보드에서 기존 프로젝트의 B03 버튼 클릭 → 파일 입력 페이지 하단에
"현재 프로젝트가 선택되지 않았습니다. 프로젝트를 먼저 생성하거나 선택하세요." (ui_template_locale.ts:531 B03_File_Error_Project)
원인 (검증 완료):
- B03~B06 페이지는 모두
localStorage.getItem(CURRENT_PROJECT_ID_KEY)("frd_current_project_id") 로 프로젝트를 식별- B03:
B03_FileInput_UI_Page.ts:182→ 값이 비어 있으면validateSlots()가 line 395에서 위 에러 메시지 반환
- B03:
- 이 키를 설정하는 곳은 B02 프로젝트 등록 페이지 단 한 곳 (
B02_ProjRegister_UI_Page.ts:154, 신규 생성 직후) - 대시보드 워크플로우 버튼의 클릭 핸들러(
B01_Dashboard_UI_Page.ts:391)는navigateTo(route)만 호출하고 프로젝트 ID를 저장하지 않음 - 심지어
workflow(activeStage: number)함수는 stage 숫자만 받아서 프로젝트 ID가 함수 스코프에 아예 없음 (호출부 line 362는 행별project객체를 갖고 있음) - 결과: 신규 생성 직후가 아닌 경로(기존 프로젝트 진입, localStorage 삭제, 다른 브라우저)에서는 항상 에러
수정 계획:
workflow()시그니처 변경:workflow(activeStage: number)→workflow(project: ProjectItem)(또는projectId추가 인자)- 버튼 클릭 핸들러에서 이동 전 프로젝트 ID 저장:
button.addEventListener("click", () => { localStorage.setItem(CURRENT_PROJECT_ID_KEY, project.id); navigateTo(route); }); - B03/B04/B05/B06은 수정 불필요 (이미 localStorage에서 읽는 구조이므로 진입 시 자연 해결)
- 참고: backend.md §5.1의 다중 브라우저 원칙상 localStorage는 브라우저별 격리 — 대시보드 버튼이 유일한 진입점이므로 클릭 시점 저장이 올바른 위치. (장기적으로 라우트 해시에 projectId를 포함하는 방식도 가능하나 라우터 전면 수정이 필요하므로 이번 범위에서 제외)
2.2.3 구현 파일 수정
- B01_Dashboard_UI_Page.ts
workflow()함수: 프로젝트 ID를 받아 클릭 시CURRENT_PROJECT_ID_KEY저장 (§2.2.2)- 분석 진행 중인 프로젝트가 있을 때만 목록 재조회 폴링 (5초) — 상태 변화 자동 반영
- B01_Dashboard_Repository.py
_stage_from_status():_COMPLETE접미사 구분 로직 추가 (ANALYZING 상태에서 다음 단계 버튼 미개방)
- 신규 API 불필요 — 기존 프로젝트 목록 API 재사용 (workflow_stage 필드 이미 포함)
2.3 WF1~WF6 공통 레이아웃 템플릿 설계
2.3.1 목표
- 오프라인 프로그램 스타일 인터페이스 (AutoCAD, QGIS 같은 데스크톱 프로그램의 레이아웃)
- 헤더 숨김/표시 토글 기능
- 좌측 패널 (메뉴 + 설정) = 오버레이 구조로 토글 가능
- 우측 대형 캔버스/뷰 영역 (3D 렌더링, 도면, 테이블 등)
2.3.2 레이아웃 구조
┌─────────────────────────────────────────────────────────┐
│ [≡] 로고 | Aislo 프로젝트명 | WF 진행률 | 설정 | 언어 | 로그아웃 │ ← 헤더 (숨기기 가능)
└─────────────────────────────────────────────────────────┘
│ │
│ [▶] ◄── 드롭다운 화살표 (헤더 숨김 시 표시) │
│ │
│ ┌─────────────┐ ┌──────────────────────────────────────┐ │
│ │ 메뉴패널 │ │ │ │
│ │ (토글) │ │ 메인 작업 영역 │ │
│ │ │ │ (3D 뷰어, 표, 그래프 등) │ │
│ │ WF1: 지표면 │ │ │ │
│ │ - 필터 설정 │ │ [← 이 영역이 전체 브라우저 크기의│ │
│ │ - 모델 선택 │ │ 좌우상하 8% 정도 여유만 남기고 │ │
│ │ - 실행 │ │ 전부 사용] │ │
│ │ │ │ │ │
│ │ WF2: 경로 │ │ │ │
│ │ - 경로 매개 │ │ │ │
│ │ ... │ │ │ │
│ └─────────────┘ └──────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
2.3.3 상세 스펙
2.3.3.1 헤더 (createWorkflowShell 확장)
- 현재: 페이지 타이틀 + 스텝바 표시
- 개선:
- 좌상단:
[≡]메뉴 토글 버튼 추가 (아이콘) - 중앙: 프로젝트명 + 현재 WF 단계 표시
- 우상단: 기존대로 (설정, 언어, 로그아웃)
- 숨기기 기능: 헤더 전체를 슬라이드업 (CSS 애니메이션)
- 헤더 숨김 상태: 중앙에
[▶]화살표 표시 → 클릭하면 드롭다운 메뉴 표시
- 좌상단:
2.3.3.2 좌측 메뉴 패널 (오버레이 구조)
- 고정 너비: 240px (닫힌 상태 시 0px)
- 오버레이 Z-index: 1000
- 콘텐츠:
- WF1: 필터 선택 (grid_min_z, csf, pmf, ransac)
- WF1: 모델 방식 선택 (tin, dtm, nurbs, implicit, meshfree)
- WF1: 강제 재계산 체크박스
- WF1: 실행 버튼
- (다른 WF는 각자 필요한 설정)
- 토글 방식:
- 헤더의
[≡]클릭 → 패널 슬라이드인/아웃 (CSS 트랜지션) - 또는 패널 바깥 클릭 → 패널 닫기
- 헤더의
- 스타일: 디자인 가이드
.agent/design.md준수- ⚠️ frontend.md §1 규칙: CSS에 hex 코드 직접 입력 금지. 아래 hex는 참고용이며, 실제 코드는 반드시
ui_template/ui_template_theme.css에 선언된 CSS 변수만 참조할 것. design.md의 토큰이 theme.css에 없으면 theme.css에 변수를 먼저 추가한 뒤 사용 - 배경: paper 계열 (참고: #f6f7fa)
- 텍스트: charcoal 계열 (참고: #333333)
- 섹션 타이틀: Inter 500 14px
- 섹션 간 구분: mist 계열 1px 보더 (참고: #e6e2e3)
- 폼 요소: 기존
createInputField,createButton재사용. 체크박스 공통 컴포넌트는 현재 없음 (frontend.md §2.1 목록에 부재) — B04 기존 코드의buildCheckboxGroup()패턴을ui_template_elements.ts로 승격하여 공통화 권장
- ⚠️ frontend.md §1 규칙: CSS에 hex 코드 직접 입력 금지. 아래 hex는 참고용이며, 실제 코드는 반드시
2.3.3.3 메인 작업 영역 (우측)
- 전체 브라우저 크기에서 좌우상하 8% 여유 남기고 차지
- 배경:
--color-canvas(#ffffff) - 콘텐츠별 렌더링:
- WF1: 3D 포인트클라우드 뷰어 (0_old의 PointCloudViewer.tsx 참고)
- WF1: 모델 카드 그리드 (선택 가능)
- WF2: 경로 설계 맵/캔버스
- WF3: 종단면/횡단면 2D 뷰어
- (다른 WF는 각자 콘텐츠)
- 반응형 레이아웃: 메뉴 토글 시 우측 영역 자동 너비 조정
2.3.4 레이아웃 템플릿 구현 파일
- ui_template/ui_template_workflow_layout.ts (신규)
- 함수:
createWorkflowLayout(options: WorkflowLayoutOptions) - 옵션:
interface WorkflowLayoutOptions { title: string; // 페이지 타이틀 steps: string[]; // 워크플로우 단계들 activeStep: number; // 현재 단계 인덱스 leftPanel: HTMLElement; // 좌측 설정 패널 mainContent: HTMLElement; // 우측 메인 콘텐츠 onHeaderToggle?: (isVisible: boolean) => void; // 헤더 토글 콜백 onMenuToggle?: (isOpen: boolean) => void; // 메뉴 토글 콜백 } - 반환: 완성된 DOM 구조 + 토글 컨트롤 함수
- 내부 스타일: 별도 CSS 파일
ui_template/ui_template_workflow_layout.css에서 관리
- 함수:
2.4 B04_wf1_Surface, B05_wf2_Route, B06_wf3_ProfileCross 페이지 재구현 (0_old 기반)
2.4.1 0_old 프로그램 분석
데이터 흐름 (0_old):
- LAS 파일 업로드 →
storage/projects/{projectId}/raw/저장 analyze_project(projectId)실행:- LAS 데이터를 컴퓨터가 읽기 좋은 형태로 변환 (NumPy arrays, JSON)
storage/projects/{projectId}/processed/에 저장:las-points-sample.json— 샘플링된 포인트 (3D 뷰어용)analysis.json— 메타데이터 (bounds, CRS, point_count 등)
- 필터 선택 (grid_min_z, csf, pmf, ransac) → 지면 포인트 추출
storage/projects/{projectId}/processed/ground-stats.json저장
- 모델 방식 선택 (tin, dtm, nurbs, implicit, meshfree) → 지표면 생성
- 각 모델별 결과:
storage/projects/{projectId}/processed/{model_type}.json
- 각 모델별 결과:
- 프론트엔드:
- PointCloudViewer.tsx: 3D 포인트클라우드 렌더링 (WebGL/THREE.js)
- TerrainModelViewer.tsx: 지표면 모델 3D 렌더링
구현 요소:
- 0_old/frontend/src:
PointCloudViewer.tsx— 포인트클라우드 3D 뷰어TerrainModelViewer.tsx— 지표면 모델 뷰어RouteDesignStage.tsx— WF2 경로 설계 (Dijkstra, Ridge-Valley 알고리즘)LongitudinalProfile.tsx— WF3 종단면 2D 그래프CrossSectionGrid.tsx— WF3 횡단면 2D 그래프sectionTypes.ts— 종횡단 데이터 타입
- 0_old/utils:
filter_*.py(CSF, PMF, RANSAC, grid_min_z) — 지면 필터terrain_model_converter.py— 지표면 모델 생성section_generator.py— 종횡단 생성route_solver*.py— 경로 계산
2.4.2 현재 프로젝트에서의 재사용 방식
레이아웃: 새 작성 (데스크톱 IDE 스타일 + Wiza 테마) 콘텐츠 & 3D 렌더링: 0_old 코드 참고/재사용 데이터: 백엔드에서 동일한 구조로 저장
⚠️ 필수 제약 1 — React → Vanilla TS 전환:
- 0_old 프론트엔드는 React 19 + JSX(.tsx) + lucide-react 아이콘 기반
- 현재 프로젝트는 React 미사용 (package.json에 react 없음 — three, maplibre-gl만 존재). 순수 TypeScript DOM 조작 방식 (
document.createElement,createButton등) - 따라서 0_old 컴포넌트는 절대 그대로 복사 불가. 다음 규칙으로 재작성:
- React 훅(
useState,useEffect,useRef) → 클로저 변수 + 명시적 렌더 함수로 변환 (B03/B04 기존 페이지 코드의 패턴 참고) - JSX →
document.createElement+append방식 lucide-react아이콘 → 사용 불가. 인라인 SVG 문자열 또는 유니코드 기호로 대체 (B03의icon: "●"패턴 참고)- THREE.js 씬 구성 로직(카메라, OrbitControls, BufferGeometry 등)은 React와 무관하므로 거의 그대로 재사용 가능 — 0_old에서 가장 가치 있는 부분
- React 훅(
- 0_old의 API 호출부(
fetch(API_BASE...))는 현재 프로젝트의Api_Fetch.ts패턴(credentials: "include", 타임아웃, 오류 변환)으로 교체
⚠️ 필수 제약 2 — 백엔드 엔진은 이미 이식 완료:
- 0_old/utils의 필터·모델 로직은 이미 B04_wf1_Surface_Engine_*.py 로 이식되어 존재함 (Filter_Grid/CSF/PMF/RANSAC, ModelBuild, Smooth, Contour, Pipeline, Structurize 모두 존재 확인됨)
- 코더는 백엔드 분석 로직을 재이식하지 말 것. 필요한 백엔드 작업은:
/surface/status응답 확장 (진행률)/surface/point-cloud,/surface/ground-stats신규 엔드포인트 (기존 Engine 산출물을 읽어 반환)projects.status갱신 로직
- WF2/WF3 백엔드(route_solver, section_generator)는 아직 미이식 → Phase 5/6에서 0_old/utils 참고해 이식
⚠️ 필수 제약 3 — 700줄 제한 (CLAUDE.md):
- PointCloudViewer 등 대형 컴포넌트 이식 시 700줄 초과 가능성 높음
- 사전에 파일 분할 설계: 예)
B04_wf1_Surface_UI_Viewer.ts(3D 씬),B04_wf1_Surface_UI_ViewerControls.ts(조작 패널) 분리 후 structure.md 갱신
진행 방식:
- 0_old의 각 컴포넌트를 위 제약에 따라 vanilla TS로 재작성 (파일명 규칙:
[폴더명]_[기능].ts) - 백엔드는 기존 B04 Engine 재사용 + API 확장만 수행
- 레이아웃 템플릿만 새로 작성 (모든 WF에서 재사용)
2.4.3 B04_wf1_Surface 재구현 계획
사용자 흐름:
[좌측 메뉴] [우측 메인 영역]
┌────────────────┐ ┌──────────────────────┐
│ WF1 지표면 │ │ 1. 포인트클라우드 │
│ ───────────── │ ──────→ │ 3D 뷰어 │
│ 필터 선택: │ │ 2. 필터 적용 후 │
│ ☑ grid_min_z │ │ 지표면 모델 선택 │
│ ☑ CSF │ │ (카드: TIN, DTM..│
│ ☑ PMF │ │ 3. 모델 상세 뷰 │
│ ☑ RANSAC │ │ (해상도, 파일크기│
│ │ │ │
│ 모델 선택: │ │ [▼] 다음 단계 진행 │
│ ☑ TIN │ │ │
│ ☑ DTM │ └──────────────────────┘
│ ☑ NURBS │
│ ☑ Implicit │
│ ☑ Meshfree │
│ │
│ [분석 실행] │
│ (또는 진행률) │
└────────────────┘
구현:
-
좌측 메뉴 패널:
- 필터 체크박스 (0_old: grid_min_z, csf, pmf, ransac)
- 모델 선택 체크박스 (0_old: tin, dtm, nurbs, implicit, meshfree)
- "강제 재계산" 체크박스
- "분석 실행" 버튼 (또는 진행률 표시)
-
우측 메인 영역 (탭 또는 스테이지 표시):
- 탭 1: 포인트클라우드 뷰어
- 0_old의 PointCloudViewer.tsx 재사용
- 밀도 조절, 포인트 크기, 축 표시/숨기기 기능
- 탭 2: 필터 결과 선택
- 각 필터별 포인트 통계 표시
- 선택한 필터에 대해 "분석 실행"
- 탭 3: 지표면 모델 선택
- 모델 카드 그리드:
- 모델 이름 (TIN, DTM, ...)
- 상태 배지 (완료/진행 중)
- 선택 버튼
- 선택한 모델의 상세 정보:
- 해상도, 생성 시간, 파일 크기
- 3D 미리보기 (TerrainModelViewer.tsx)
- 모델 카드 그리드:
- 탭 4: 분석 진행 중 (선택사항)
- 진행률 바, 현재 단계, ETA
- 탭 1: 포인트클라우드 뷰어
-
API & 백엔드 (§4 표 참조 — 기존 API 재사용 우선):
POST /surface/analyze— ✅ 기존 (분석 실행: 필터 + 모델)GET /surface/models— ✅ 기존 (모델 목록)GET /surface/status— ✅ 기존, 진행률 필드 확장GET /surface/point-cloud— 🆕 신규 (포인트클라우드 샘플)GET /surface/ground-stats— 🆕 신규 (필터별 통계)
-
UX 개선 (기존 B04의 문제 해결):
- 현재 B04는 사용자가
input_file_id를 숫자로 직접 입력해야 함 → 자동화: 페이지 진입 시 프로젝트의 input_files 목록을 조회해 LAS 파일을 자동 선택 (사용자 직접 입력 제거) - B03 업로드 직후 백엔드가 자동으로 분석을 실행하므로(B03_FileInput_Engine_Analyze.py), B04의 "분석 실행" 버튼은 재분석(force) 용도임을 UI에 명시 (예: 버튼명 "재분석 실행")
- 현재 B04는 사용자가
2.4.4 B05_wf2_Route 재구현 계획
사용자 흐름:
[좌측 메뉴] [우측 메인 영역]
┌────────────────┐ ┌──────────────────────┐
│ WF2 경로 설계 │ │ 지표면 3D 뷰 │
│ ───────────── │ ──────→ │ + 경로 선 그려짐 │
│ 시작점(B점) │ │ │
│ 끝점(E점) │ │ [마우스: 경로점 │
│ 중간점(C점) │ │ 클릭하여 추가] │
│ 도움점(A점) │ │ │
│ 피해회피점(F점) │ [▼] 다음 단계 진행 │
│ │ └──────────────────────┘
│ 알고리즘: │
│ ○ Dijkstra │
│ ○ Ridge-Valley
│ │
│ 임도 등급: │
│ ○ 간선임도 │
│ ○ 지선임도 │
│ ○ 작업임도 │
│ │
│ 최소 곡선반경: │
│ [______] m │
│ │
│ 포장 여부: │
│ ☐ 포장 │
│ │
│ [경로 계산] │
└────────────────┘
구현:
- 0_old의 RouteDesignStage.tsx 참고
- 좌측: 매개변수 입력 (알고리즘, 등급, 곡선반경, 포장)
- 우측: 3D Canvas
- 지표면 모델 렌더링 (TerrainModelViewer)
- 사용자가 클릭하여 경로점 추가
- 계산된 경로 선 표시
2.4.5 B06_wf3_ProfileCross 재구현 계획
사용자 흐름:
[좌측 메뉴] [우측 메인 영역]
┌────────────────┐ ┌──────────────────────┐
│ WF3 종횡단 │ │ 1. 종단면 2D 그래프 │
│ ───────────── │ ──────→ │ (거리 vs 고도) │
│ 기준점 간격: │ │ │
│ [50] m │ │ [▼] 기준점 선택 │
│ │ │ │
│ 횡단면 너비: │ │ 2. 횡단면 2D 그래프 │
│ [20] m │ │ (오프셋 vs 고도) │
│ │ │ │
│ 샘플 간격: │ │ [▼] 다음 단계 진행 │
│ [1] m │ └──────────────────────┘
│ │
│ 연직 과장: │
│ [1.0] x │
│ │
│ 엔드포인트 │
│ 포함: │
│ ☐ 포함 │
│ │
│ [생성] │
└────────────────┘
구현:
- 0_old의 LongitudinalProfile.tsx, CrossSectionGrid.tsx 참고
- 좌측: 종횡단 매개변수 입력
- 우측:
- 탭 1: 종단면 2D 그래프 (LongitudinalProfile.tsx)
- 탭 2: 횡단면 2D 그래프 (CrossSectionGrid.tsx)
- 기준점 선택 → 해당 종/횡단면 표시
2.4.6 공통 레이아웃 템플릿
모든 WF(B04~B06)이 공유하는 레이아웃:
- 헤더: 숨김/표시 토글, 프로젝트명, WF 단계
- 좌측 메뉴: 매개변수 입력 (각 WF별로 상이)
- 우측 메인: 3D 뷰어 또는 2D 그래프 (각 WF별로 상이)
- 스타일: Wiza 테마 준수 (색상, 타입, 간격)
3. 데이터베이스 변경사항
3.1 projects 테이블 상태 값 확장
- 기존:
NEW,FILE_UPLOADED,WF1_ANALYZING,WF1_COMPLETE, ... - 추가 사항: 상태 변경 타이밍
FILE_UPLOADED→WF1_ANALYZING(분석 시작 시)WF1_ANALYZING→WF1_COMPLETE(분석 완료 시)- 각 단계 완료 후 이메일 발송 (기존)
3.2 업로드 세션 저장소 (클라이언트 localStorage 사용)
- DB 변경 없음 (localStorage에 JSON 저장)
- 키 이름 (§2.1.2.2와 동일 — 단일 키로 통일):
b03_project_state_${projectId} - 값 형식은 §2.1.2.2 참조 (files, analysisStatus, analysisProgress, lastCheckedAt)
- 주의: localStorage는 브라우저별 격리(backend.md §5.1)이므로 표시 복구 용도로만 사용. 진실의 원천(source of truth)은 항상 서버(status API + DB
projects.status)이며, 페이지 진입 시 서버 값으로 localStorage를 덮어쓴다.
4. API 엔드포인트 추가/수정
4.0 기존 API 현황 (⚠️ 코더는 신규 생성 전 반드시 확인 — 중복 생성 금지)
| 엔드포인트 | 메서드 | 상태 | 위치 |
|---|---|---|---|
/api/projects/{id}/surface/analyze |
POST | ✅ 존재 (분석 실행 + DB 기록) | B04_wf1_Surface_Router.py |
/api/projects/{id}/surface/models |
GET | ✅ 존재 (모델 목록) | B04_wf1_Surface_Router.py |
/api/projects/{id}/surface/status |
GET | ✅ 존재 (확장 필요 — §2.1.2.3) | B04_wf1_Surface_Router.py |
/api/projects/{id}/upload-sessions, /chunks, /finalize, /upload-status/{sid} |
POST/GET | ✅ 존재 (청크 업로드) | B03_FileInput_Router.py |
4.1 신규 API (네이밍은 기존 /surface/ 컨벤션 준수, /wf1/ 접두사 사용 금지)
| 엔드포인트 | 메서드 | 설명 | 백엔드 파일 |
|---|---|---|---|
/api/projects/{id}/surface/point-cloud |
GET | 포인트클라우드 샘플 (3D 뷰어용, 0_old las-points-sample.json 방식) |
B04_wf1_Surface_Router.py |
/api/projects/{id}/surface/ground-stats |
GET | 필터별 지면 통계 | B04_wf1_Surface_Router.py |
| WF2/WF3 API | - | B05/B06 구현 시 동일 패턴으로 설계 (예: /route/..., /sections/...) |
B05/B06 Router |
4.2 수정 API
| 엔드포인트 | 변경사항 |
|---|---|
GET /api/projects/{id}/surface/status |
응답에 progress_percent, current_stage, message 추가 + failed 상태 판별 (§2.1.2.3) |
| 대시보드 프로젝트 목록 API | 응답에 각 프로젝트의 status 필드 포함 여부 확인 후 필요 시 추가 (projects 테이블에 status 열 존재함) |
5. 프론트엔드 컴포넌트 신규 작성
5.1 WorkflowLayout 템플릿
- 파일:
ui_template/ui_template_workflow_layout.ts - 파일:
ui_template/ui_template_workflow_layout.css - 함수 시그니처:
export function createWorkflowLayout(options: WorkflowLayoutOptions): HTMLElement
5.2 PointCloudViewer 컴포넌트 (0_old 기반 개조)
- 파일:
B04_wf1_Surface_UI_Viewer.ts(700줄 제한 대비 별도 파일 — §2.4.2 제약 3) - 의존성 (확인 완료):
three@^0.185.0— ✅ 현재 package.json에 설치됨 (0_old와 동일 버전)maplibre-gl@^5.24.0— ✅ 설치됨geotiff— ❌ 미설치 (0_old에는 있음). TIF 래스터를 프론트에서 직접 파싱할 경우에만 추가 필요. 백엔드에서 PNG 프리뷰로 변환해 전달하면 불필요 — 백엔드 변환 방식 권장 (0_old도preview.png생성 방식 사용)lucide-react— ❌ 사용 불가 (React 전용). 인라인 SVG/유니코드로 대체 (§2.4.2 제약 1)
- 주의: React 훅 → vanilla TS 변환 필수 (§2.4.2 제약 1), 테마 변수 사용, 디자인 가이드 준수
5.3 모델 카드 프리뷰 컴포넌트
- 파일:
ui_template/ui_template_elements.ts에 추가 - 함수:
createSurfaceModelCard(model: SurfaceModelSummary, isSelected: boolean, onSelect: () => void)
6. 구현 순서 및 의존성
Phase 별 구현 계획
Phase 1: 공통 인프라 (1~2일)
- B03_FileInput_UI_Page.ts: 로딩 오버레이 제거 → 토스트 + localStorage로 전환
- B03_FileInput_Api_Fetch.ts:
getWF1AnalysisProgress()API 추가 - localStorage 저장/복구 로직 구현
- 백엔드: 분석 진행률 파일(
.wf1_progress) 작성 로직
Phase 2: 대시보드 연동 (1일)
- 🐞 워크플로우 버튼 클릭 시
CURRENT_PROJECT_ID_KEY저장 버그 수정 (§2.2.2 — 최우선, 소규모) _stage_from_status(): ANALYZING/COMPLETE 구분 로직 (§2.2.1)- 분석 진행 중 프로젝트 존재 시 목록 재조회 폴링 (5초 주기)
Phase 3: WorkflowLayout 템플릿 (1~2일)
ui_template/ui_template_workflow_layout.ts/css새로 작성- 헤더 토글, 메뉴 오버레이 토글 기능
- Wiza 테마 색상/타이포그래피 준수
Phase 4: B04_wf1_Surface 이식 (2~3일)
- 0_old/PointCloudViewer.tsx → B04 컴포넌트 이식 (테마 적용)
- 0_old/TerrainModelViewer.tsx 이식
- B04_wf1_Surface_UI_Page.ts: 새 레이아웃 + 탭 구조
- API:
/wf1/analysis,/wf1/point-cloud,/wf1/ground-stats,/wf1/progress - 백엔드: 기존 분석 로직 + 진행률 추적
Phase 5: B05_wf2_Route 이식 (2~3일)
- 0_old/RouteDesignStage.tsx 이식
- B05_wf2_Route_UI_Page.ts: 새 레이아웃 + 3D Canvas
- API:
/wf2/surface-bounds,/wf2/calculate-route,/wf2/progress - 백엔드: 경로 계산 로직 (Dijkstra, Ridge-Valley)
Phase 6: B06_wf3_ProfileCross 이식 (2~3일)
- 0_old/LongitudinalProfile.tsx, CrossSectionGrid.tsx 이식
- B06_wf3_ProfileCross_UI_Page.ts: 새 레이아웃 + 2D 그래프 탭
- API:
/wf3/section-generation,/wf3/progress - 백엔드: 종횡단 생성 로직
Phase 7: WF4~WF6 준비 (선택사항, 현재는 미구현)
- 레이아웃 템플릿만 적용
- 콘텐츠는 향후 구현
7. 테스트 및 검증 계획
7.1 B03 파일 업로드
- 큰 파일 업로드 시 로딩 오버레이 없음 확인
- 업로드 중 다른 페이지 이동 가능 확인
- 페이지 리프레시 후 업로드 상태 복구 확인
- 분석 진행률 업데이트 확인
7.2 대시보드 워크플로우
- 분석 완료 후 WF1 버튼 활성화 확인
- 이메일 도착 후 대시보드 상태 갱신 확인
- 워크플로우 상태 폴링 작동 확인
- 기존 프로젝트의 B03 버튼 클릭 → "프로젝트가 선택되지 않았습니다" 에러 없이 진입 확인 (§2.2.2)
- localStorage 비운 상태(시크릿 창)에서 워크플로우 버튼 진입 확인
- 프로젝트 2개 이상일 때 각 행의 버튼이 해당 프로젝트로 진입하는지 확인 (ID 교차 오염 없음)
WF1_ANALYZING상태에서 B04 버튼이 열리지 않는지 확인 (§2.2.1 토큰 매칭 수정)
7.3 WF1 레이아웃
- 헤더 숨김/표시 토글 작동 확인
- 메뉴 패널 오버레이 슬라이드 작동 확인
- 3D 포인트클라우드 렌더링 확인 (성능)
- 모델 카드 선택/상세 뷰 작동 확인
- 진행률 폴링 업데이트 확인
- input_file_id 자동 선택 확인 (수동 입력 제거 — §2.4.3)
- 분석 실패 시 failed 상태 표시 확인 (§2.1.2.3 status API 확장)
7.3.1 WF2 경로 설계 (Phase 5)
- 지표면 3D 뷰 위 경로점(BP/EP/CP/AP/FP) 클릭 추가 확인
- Dijkstra / Ridge-Valley 알고리즘 선택 및 경로 계산 확인
- 임도 등급·곡선반경·경사 한계 매개변수 반영 확인
7.3.2 WF3 종횡단 (Phase 6)
- 종단면 그래프 렌더링 + 기준점 선택 연동 확인
- 횡단면 그리드 렌더링 확인
- 기준점 간격/횡단 너비/연직 과장 매개변수 반영 확인
7.4 반응형 및 성능
- 다양한 브라우저 윈도우 크기에서 레이아웃 정렬 확인
- 포인트클라우드 대용량 렌더링 성능 (프레임률, 메모리)
- 모바일 환경에서 오버레이 레이아웃 작동 확인 (선택사항)
8. 위험 요소 및 제약사항
8.1 위험 요소
- 포인트클라우드 렌더링 성능: 수억 개 포인트 샘플링/렌더링 시 프레임률 저하
- 대책: 밀도 조절 기능, 초기 샘플링 제한
- 대역폭: 포인트클라우드 데이터 전송 시간
- 대책: 압축, 샘플링, 청크 다운로드
- 폴링 주기: 분석 진행률 폴링이 너무 빈번하면 서버 부하 증가
- 대책: 5초 주기 유지
8.2 제약사항
- 디자인 가이드 준수:
.agent/design.md에 정의된 색상, 타이포그래피, 간격 엄격히 준수 - 레이아웃 재사용: WF1~WF6이 동일 템플릿 사용하므로 템플릿 설계 철저히
- 백엔드 의존성: 포인트클라우드 데이터, 진행률 API를 백엔드에서 제공해야 함
9. 주요 고려사항
9.1 대역폭 & 성능
- 포인트클라우드 샘플링: 0_old는 최대 1000만 개 포인트 샘플링 후 JSON으로 전송
- 현재 프로젝트에서도 동일 방식 적용
- 필요시 바이너리 포맷(protobuf) 검토
- 3D 렌더링: THREE.js 사용 (0_old와 동일)
- 성능 최적화: LOD(Level of Detail), 프러스텀 컬링 필요
- 모바일: 포인트 수 감소, 해상도 낮춤
9.2 브라우저 호환성
- Chrome/Edge/Firefox 최신 버전
- 모바일 사파리: 제한적 지원 (대역폭, 성능)
- WebGL 지원 필수
9.3 0_old 코드 이식 시 주의사항
- 좌표계: CRS(EPSG:5178 등) 변환 로직 유지
- 단위: 미터 기준 (높이, 거리, 반경 등)
- 파일 포맷: JSON 저장 방식 통일 (MariaDB와 JSON 호환)
9.4 반응형 레이아웃
- 좌우측 너비 동적 조정
- 좌측 메뉴 토글 시 우측 캔버스 자동 확장
- 모바일: 전체 화면 사용 (좌측 메뉴는 오버레이만 표시)
10. 저장소 구조 정정 (코드베이스 검증)
10.0 계획서 §10.3 저장소 구조는 0_old 기반이며, 현재 프로젝트와 다름
0_old 구조 (analyzer.py line 19):
storage/projects/{projectId}/
├── raw/ → 원본 파일
└── processed/ → 변환·분석 결과
현재 프로젝트 실제 구조 (config_system.py line 240, 260, 247-256):
storage/{company_slug}/{user_slug}/{projectId}/
├── B03_FileInput/ → 원본 입력 (LAS/TIF/PRJ/TFW)
├── B04_wf1_Surface/ → WF1 변환·분석 결과
├── B05_wf2_Route/ → WF2 경로 설계 결과
├── B06_wf3_ProfileCross/ → WF3 종횡단 결과
├── B07_wf4_DesignDetail/ → WF4 구조물
├── B08_wf5_Quantity/ → WF5 수량
└── B09_wf6_Estimation/ → WF6 최종 산출물
수정 대상 (코더는 아래 구조 사용):
- 계획서 §4 "신규 API" 설명의 저장 경로 모두 현재 구조로 읽고 사용
storage/{projectId}/...축약 표기는 사용 금지 — 전체 경로는storage/{company}/{user}/{projectId}/[B0N_]/...- 각 WF의 결과는 각각의 워크플로우 폴더 아래에만 저장 (§3 CLAUDE.md "단계별 루트 강제")
- 예: WF1 분석 결과 →
B04_wf1_Surface/아래만 (프로젝트 루트의result_*.json같은 축약 방식 금지)
- 예: WF1 분석 결과 →
11. 0_old 프로그램 구조 참고
10.1 프론트엔드 컴포넌트
0_old/frontend/src/
├── PointCloudViewer.tsx → B04 포인트클라우드 뷰어 참고
├── TerrainModelViewer.tsx → B04/B05 지표면 렌더링 참고
├── RouteDesignStage.tsx → B05 경로 설계 참고
├── LongitudinalProfile.tsx → B06 종단면 2D 그래프 참고
├── CrossSectionGrid.tsx → B06 횡단면 2D 그래프 참고
├── sectionTypes.ts → B06 데이터 타입 참고
├── WorkflowBar.tsx → 워크플로우 상태 표시 참고
├── pointCloudUtils.ts → 포인트 데이터 처리 유틸
└── MapViewerFrame → 줌/팬닝 뷰어 프레임 참고
10.2 백엔드 분석 엔진
0_old/backend/app/
├── analyzer.py → 분석 오케스트레이터
└── classifier.py → 포인트 분류
0_old/utils/
├── filter_grid_min_z.py → Grid Min-Z 필터
├── filter_csf.py → CSF(가상 천) 필터
├── filter_pmf.py → PMF(형태학) 필터
├── filter_ransac.py → RANSAC 필터
├── terrain_model_converter.py → TIN/DTM/NURBS/Implicit/Meshfree 생성
├── section_generator.py → 종횡단 생성
├── route_solver.py → Dijkstra 경로 계산
└── route_solver_ridgevalley.py → Ridge-Valley 경로 계산
10.3 저장소 구조
storage/projects/{projectId}/
├── raw/ → 원본 LAS/TIF/PRJ/TFW 파일
└── processed/
├── analysis.json → 메타데이터 (bounds, CRS 등)
├── las-points-sample.json → 샘플링된 포인트 (3D 뷰어용)
├── ground-stats.json → 필터별 지면 통계
├── tin.json → TIN 모델 (삼각형 메시)
├── dtm.json → DTM 모델 (격자)
├── nurbs.json → NURBS 모델
├── implicit.json → Implicit 모델
├── meshfree.json → Meshfree 모델
├── route.json → 계산된 경로 (경로점, 곡선 등)
└── sections.json → 종횡단 데이터 (LongitudinalSection[], CrossSection[])
11. 질의응답 정리
사용자 피드백 적용:
- ✅ 진행률 추적: localStorage + 폴링 으로 페이지 이탈 후에도 복구 가능
- ✅ 데이터 구조: LAS → JSON 변환 후 저장, 프론트는 저장된 데이터만 조회
- ✅ 모바일 대응: 전체 화면 사용으로 자동 반응형
- ✅ THREE.js: 프로젝트에 설치됨, 0_old와 동일 방식 사용
- ✅ WF4~WF6: 현재는 기능 없음 (향후 구현)
- ✅ 0_old 참고: 콘텐츠/렌더링은 0_old, 레이아웃/테마는 현재 프로젝트 기준
계획서 최종 검토일: 2026-07-10
버전: 2.0 (0_old 분석 기반)
상태: 완료 (코딩 팀 진행 대기)