Files
Aislo/.agent/complete_and_old/plan_wf1_and_upload_improvements.md
T
2026-07-10 19:01:33 +09:00

42 KiB

WF1~WF3 레이아웃 재설계 및 파일 업로드 프로세스 개선 계획서

작성일: 2026-07-10 (업데이트)
상태: 상세 설계 단계
범위: B03_FileInput (파일 업로드 비동기 처리), 대시보드 워크플로우 상태 관리, B04_wf1_Surface~B06_wf3_ProfileCross 공통 레이아웃 템플릿 (0_old 기반)


1. 개요 및 개선 배경

1.1 현재 문제점

  1. B03 파일 업로드

    • 업로드 시작 후 완료될 때까지 UI 로딩 오버레이 활성화 상태 유지 → 사용자 동작 불가
    • 페이지 리프레시 시 업로드 진행상황 소실
    • 백엔드는 비동기 처리 중인데 프론트엔드는 동기 대기
  2. B01 대시보드 워크플로우 상태

    • 파일 업로드 완료 후 WF1 분석 완료되어도 워크플로우 버튼이 활성화되지 않음
    • 대시보드의 프로젝트 상태 변경 로직 미동기화
  3. B04_wf1_Surface, B05_wf2_Route, B06_wf3_ProfileCross 레이아웃

    • 현재 3단 레이아웃(상단+좌측+우측)이 협소함
    • 좌측 폼 영역이 항상 표시되어 우측 작업 영역을 제한
    • 3D 조작, 경로 설계, 종단/횡단 작업 같은 실무에는 넓은 공간 필수
    • 현재 B04 페이지는 카드형 제목만 표시 (불완전)
  4. 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 로 분석 결과를 조회
  • 개선 방식 (⚠️ 신규 API 생성 금지 — 기존 API 확장):

    • 기존 API 활용: GET /api/projects/{project_id}/surface/status 가 이미 존재함 (B04_wf1_Surface_Router.py get_wf1_analysis_status(), 프론트 클라이언트는 B03_FileInput_Api_Fetch.ts checkWF1AnalysisStatus())
    • 기존 구현의 한계 (개선 대상):
      • 현재는 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 재폴링으로 진행률 재표시

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 필드를 읽어 버튼 활성화/비활성화 결정

2.1.3 구현 파일 수정

  • B03_FileInput_UI_Page.ts
    • startChunkedUpload() 함수: 로딩 오버레이 제거
    • uploadOneFile() 함수: 백그라운드 진행 표시로 전환
    • 세션 저장 로직 개선 (완료 후 분석 상태 포함)
    • 페이지 리로드 시 detectPausedUploads() 함수에서 세션 상태 복구
  • B03_FileInput_Api_Fetch.ts
    • 분석 진행률 조회 API 추가: async function getWF1AnalysisProgress(projectId: string)
  • 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.ts workflow() (line 370): stage 기반으로 B03~B09 버튼 활성/비활성 렌더링
    • enabled = index + 1 <= Math.max(activeStage, 1) → B03은 항상 활성

따라서 "버튼이 활성화되지 않는" 실제 원인은 UI가 아니라:

  1. 백엔드가 분석 완료 후 projects.status를 갱신하지 않음 → §2.1.2.4에서 해결 (WF1_ANALYZINGWF1_COMPLETE)
  2. 대시보드가 열려 있는 동안 상태 변화를 다시 가져오지 않음 (새로고침해야 반영)

추가 발견 — 토큰 매칭의 허점:

  • _stage_from_status()는 부분 문자열 매칭이므로 WF1_ANALYZINGWF1_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에서 위 에러 메시지 반환
  • 이 키를 설정하는 곳은 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 삭제, 다른 브라우저)에서는 항상 에러

수정 계획:

  1. workflow() 시그니처 변경: workflow(activeStage: number)workflow(project: ProjectItem) (또는 projectId 추가 인자)
  2. 버튼 클릭 핸들러에서 이동 전 프로젝트 ID 저장:
    button.addEventListener("click", () => {
      localStorage.setItem(CURRENT_PROJECT_ID_KEY, project.id);
      navigateTo(route);
    });
    
  3. B03/B04/B05/B06은 수정 불필요 (이미 localStorage에서 읽는 구조이므로 진입 시 자연 해결)
  4. 참고: 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 로 승격하여 공통화 권장

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):

  1. LAS 파일 업로드 → storage/projects/{projectId}/raw/ 저장
  2. analyze_project(projectId) 실행:
    • LAS 데이터를 컴퓨터가 읽기 좋은 형태로 변환 (NumPy arrays, JSON)
    • storage/projects/{projectId}/processed/ 에 저장:
      • las-points-sample.json — 샘플링된 포인트 (3D 뷰어용)
      • analysis.json — 메타데이터 (bounds, CRS, point_count 등)
  3. 필터 선택 (grid_min_z, csf, pmf, ransac) → 지면 포인트 추출
    • storage/projects/{projectId}/processed/ground-stats.json 저장
  4. 모델 방식 선택 (tin, dtm, nurbs, implicit, meshfree) → 지표면 생성
    • 각 모델별 결과: storage/projects/{projectId}/processed/{model_type}.json
  5. 프론트엔드:
    • 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에서 가장 가치 있는 부분
  • 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 모두 존재 확인됨)
  • 코더는 백엔드 분석 로직을 재이식하지 말 것. 필요한 백엔드 작업은:
    1. /surface/status 응답 확장 (진행률)
    2. /surface/point-cloud, /surface/ground-stats 신규 엔드포인트 (기존 Engine 산출물을 읽어 반환)
    3. 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 갱신

진행 방식:

  1. 0_old의 각 컴포넌트를 위 제약에 따라 vanilla TS로 재작성 (파일명 규칙: [폴더명]_[기능].ts)
  2. 백엔드는 기존 B04 Engine 재사용 + API 확장만 수행
  3. 레이아웃 템플릿만 새로 작성 (모든 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     │
│                │
│ [분석 실행]    │
│ (또는 진행률)  │
└────────────────┘

구현:

  1. 좌측 메뉴 패널:

    • 필터 체크박스 (0_old: grid_min_z, csf, pmf, ransac)
    • 모델 선택 체크박스 (0_old: tin, dtm, nurbs, implicit, meshfree)
    • "강제 재계산" 체크박스
    • "분석 실행" 버튼 (또는 진행률 표시)
  2. 우측 메인 영역 (탭 또는 스테이지 표시):

    • 탭 1: 포인트클라우드 뷰어
      • 0_old의 PointCloudViewer.tsx 재사용
      • 밀도 조절, 포인트 크기, 축 표시/숨기기 기능
    • 탭 2: 필터 결과 선택
      • 각 필터별 포인트 통계 표시
      • 선택한 필터에 대해 "분석 실행"
    • 탭 3: 지표면 모델 선택
      • 모델 카드 그리드:
        • 모델 이름 (TIN, DTM, ...)
        • 상태 배지 (완료/진행 중)
        • 선택 버튼
      • 선택한 모델의 상세 정보:
        • 해상도, 생성 시간, 파일 크기
        • 3D 미리보기 (TerrainModelViewer.tsx)
    • 탭 4: 분석 진행 중 (선택사항)
      • 진행률 바, 현재 단계, ETA
  3. API & 백엔드 (§4 표 참조 — 기존 API 재사용 우선):

    • POST /surface/analyze 기존 (분석 실행: 필터 + 모델)
    • GET /surface/models 기존 (모델 목록)
    • GET /surface/status 기존, 진행률 필드 확장
    • GET /surface/point-cloud🆕 신규 (포인트클라우드 샘플)
    • GET /surface/ground-stats🆕 신규 (필터별 통계)
  4. UX 개선 (기존 B04의 문제 해결):

    • 현재 B04는 사용자가 input_file_id를 숫자로 직접 입력해야 함 → 자동화: 페이지 진입 시 프로젝트의 input_files 목록을 조회해 LAS 파일을 자동 선택 (사용자 직접 입력 제거)
    • B03 업로드 직후 백엔드가 자동으로 분석을 실행하므로(B03_FileInput_Engine_Analyze.py), B04의 "분석 실행" 버튼은 재분석(force) 용도임을 UI에 명시 (예: 버튼명 "재분석 실행")

2.4.4 B05_wf2_Route 재구현 계획

사용자 흐름:

[좌측 메뉴]                    [우측 메인 영역]
┌────────────────┐            ┌──────────────────────┐
│ WF2 경로 설계  │            │ 지표면 3D 뷰        │
│ ─────────────  │   ──────→  │ + 경로 선 그려짐    │
│ 시작점(B점)  │            │                    │
│ 끝점(E점)    │            │ [마우스: 경로점    │
│ 중간점(C점)  │            │  클릭하여 추가]    │
│ 도움점(A점)  │            │                    │
│ 피해회피점(F점)            │ [▼] 다음 단계 진행  │
│              │            └──────────────────────┘
│ 알고리즘:    │
│ ○ Dijkstra   │
│ ○ Ridge-Valley
│              │
│ 임도 등급:   │
│ ○ 간선임도   │
│ ○ 지선임도   │
│ ○ 작업임도   │
│              │
│ 최소 곡선반경: │
│ [______] m   │
│              │
│ 포장 여부:   │
│ ☐ 포장       │
│              │
│ [경로 계산]  │
└────────────────┘

구현:

  1. 0_old의 RouteDesignStage.tsx 참고
  2. 좌측: 매개변수 입력 (알고리즘, 등급, 곡선반경, 포장)
  3. 우측: 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     │
│              │
│ 엔드포인트   │
│ 포함:        │
│ ☐ 포함       │
│              │
│ [생성]       │
└────────────────┘

구현:

  1. 0_old의 LongitudinalProfile.tsx, CrossSectionGrid.tsx 참고
  2. 좌측: 종횡단 매개변수 입력
  3. 우측:
    • 탭 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_UPLOADEDWF1_ANALYZING (분석 시작 시)
    • WF1_ANALYZINGWF1_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 같은 축약 방식 금지)

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. 질의응답 정리

사용자 피드백 적용:

  1. 진행률 추적: localStorage + 폴링 으로 페이지 이탈 후에도 복구 가능
  2. 데이터 구조: LAS → JSON 변환 후 저장, 프론트는 저장된 데이터만 조회
  3. 모바일 대응: 전체 화면 사용으로 자동 반응형
  4. THREE.js: 프로젝트에 설치됨, 0_old와 동일 방식 사용
  5. WF4~WF6: 현재는 기능 없음 (향후 구현)
  6. 0_old 참고: 콘텐츠/렌더링은 0_old, 레이아웃/테마는 현재 프로젝트 기준

계획서 최종 검토일: 2026-07-10
버전: 2.0 (0_old 분석 기반)
상태: 완료 (코딩 팀 진행 대기)