662 lines
28 KiB
Markdown
662 lines
28 KiB
Markdown
# DB 스키마 (테이블 및 열 목록)
|
||
|
||
## 1. 사용자 & 인증 그룹
|
||
|
||
### 1-1. users 테이블
|
||
```
|
||
users
|
||
├── id (INT, PK) — 사용자 고유 번호
|
||
├── email (TEXT, UNIQUE) — 로그인 이메일
|
||
├── password_hash (TEXT) — 비밀번호 암호화 저장
|
||
├── name (TEXT) — 사용자 이름
|
||
├── position (TEXT) — 직급 (예: 과장, 대리, 사원)
|
||
├── department (TEXT) — 부서명 (예: 설계팀, 영업팀)
|
||
├── phone (TEXT) — 연락처 (예: 010-1234-5678)
|
||
├── company_id (INT, FK → companies.id) — 소속 회사
|
||
├── created_at (TIMESTAMP) — 가입일
|
||
├── updated_at (TIMESTAMP) — 수정일
|
||
└── deleted_at (TIMESTAMP, NULL) — 삭제일 (soft delete)
|
||
```
|
||
|
||
### 1-2. companies 테이블
|
||
```
|
||
companies
|
||
├── id (INT, PK) — 회사 고유 번호
|
||
├── name (TEXT, UNIQUE) — 회사명
|
||
├── business_registration_number (TEXT, UNIQUE) — 사업자등록번호
|
||
├── business_address (TEXT) — 사업장 주소
|
||
├── business_owner (TEXT) — 사업주 이름
|
||
├── business_status (TEXT) — 기업 상태 (예: 활동중, 폐업, 휴업)
|
||
├── created_by (INT, FK → users.id) — 회사 생성자
|
||
├── created_at (TIMESTAMP) — 생성일
|
||
├── updated_at (TIMESTAMP) — 수정일
|
||
└── deleted_at (TIMESTAMP, NULL) — 삭제일 (soft delete)
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 프로젝트 그룹
|
||
|
||
### 2-1. projects 테이블
|
||
```
|
||
projects
|
||
├── id (UUID, PK) — 프로젝트 고유 ID (예: 550e8400-e29b-41d4-a716-446655440000)
|
||
├── user_id (INT, FK → users.id) — 프로젝트 소유자
|
||
├── company_id (INT, FK → companies.id) — 소속 회사
|
||
├── name (TEXT) — 프로젝트명 (예: "2025년 산불진화임도")
|
||
├── region (TEXT) — 지역명 (예: "울진군 금강송면")
|
||
├── road_type (TEXT) — 임도 종류: 간선임도, 지선임도, 산불진화임도, 계류보전
|
||
├── project_year (INT) — 사업 연도 (예: 2025)
|
||
├── estimated_length_m (FLOAT) — 추정 연장 (미터)
|
||
├── memo (TEXT) — 비고/메모
|
||
├── status (TEXT) — 상태: NEW, FILE_UPLOADED, WF1_ANALYZING, WF1_COMPLETE, WF2_COMPLETE, ... , CONFIRMED, DONE
|
||
├── crs_epsg (INT) — 좌표계 (예: 5178 = 한국 표준)
|
||
├── bbox (GEOMETRY) — 프로젝트 전체 범위 (다각형)
|
||
├── created_at (TIMESTAMP) — 생성일
|
||
├── updated_at (TIMESTAMP) — 수정일
|
||
├── deleted_at (TIMESTAMP, NULL) — 삭제일 (soft delete)
|
||
└── storage_path (TEXT) — 파일시스템 경로 (예: "storage/회사/사용자/project_uuid")
|
||
```
|
||
|
||
### 2-2. project_versions 테이블 (선택사항)
|
||
```
|
||
project_versions
|
||
├── id (INT, PK)
|
||
├── project_id (UUID, FK → projects.id)
|
||
├── version_num (INT) — 버전 번호 (1, 2, 3, ...)
|
||
├── snapshot_at (TIMESTAMP) — 스냅샷 시점
|
||
├── status (TEXT) — 저장된 상태
|
||
├── data (JSONB) — 설계 데이터 스냅샷 (JSON 형식)
|
||
└── created_at (TIMESTAMP)
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 파일 & 입력 데이터 그룹
|
||
|
||
### 3-1. input_files 테이블 (원본 입력 파일 — 영구저장소)
|
||
```
|
||
input_files
|
||
├── id (INT, PK) — 파일 고유 번호
|
||
├── project_id (UUID, FK → projects.id) — 속한 프로젝트
|
||
├── file_type (TEXT) — 파일 종류: las, tif, tfw, prj, dxf, dwg, other
|
||
├── original_filename (TEXT) — 원래 파일명 (예: "cloud_merged.las")
|
||
├── raw_file_path (TEXT) — 원본 저장 경로 (예: "storage/.../raw/las/cloud_merged.las")
|
||
├── file_size_mb (FLOAT) — 파일 크기 (MB)
|
||
├── upload_by (INT, FK → users.id) — 업로드한 사용자
|
||
├── upload_at (TIMESTAMP) — 업로드 날짜
|
||
├── crs_epsg (INT) — 파일 좌표계 (예: 5178)
|
||
├── metadata (JSONB) — 파일 메타데이터 (해상도, 범위, 포인트 수 등)
|
||
│ ├── resolution_m (좌표계 기준 해상도)
|
||
│ ├── data_range (데이터 범위)
|
||
│ └── ...
|
||
└── status (TEXT) — 상태: UPLOADED, PROCESSED, ARCHIVED
|
||
```
|
||
|
||
### 3-2. processed_point_cloud 테이블 (변환된 포인트클라우드 데이터 — 영구저장소)
|
||
```
|
||
processed_point_cloud
|
||
├── id (INT, PK) — 변환 데이터 고유 번호
|
||
├── input_file_id (INT, FK → input_files.id) — 원본 LAS 파일 참조
|
||
├── project_id (UUID, FK → projects.id)
|
||
├── process_type (TEXT) — 변환 방식: filtered, sampled, classified 등
|
||
├── processed_file_path (TEXT) — 변환된 파일 경로 (예: "storage/.../processed/las/ground_filtered.las")
|
||
├── converted_format (TEXT) — 변환 포맷: las, ply, laz 등 (컴퓨터가 빠르게 읽기 위해)
|
||
├── converted_file_path (TEXT) — 변환 포맷 저장 경로 (예: "storage/.../processed/ply/cloud_sampled_10m.ply")
|
||
├── point_count (INT) — 포인트 개수
|
||
├── min_z (FLOAT) — 최저 높이
|
||
├── max_z (FLOAT) — 최고 높이
|
||
├── mean_z (FLOAT) — 평균 높이
|
||
├── x_min (FLOAT) — 최소 경도
|
||
├── x_max (FLOAT) — 최대 경도
|
||
├── y_min (FLOAT) — 최소 위도
|
||
├── y_max (FLOAT) — 최대 위도
|
||
├── density_per_sqm (FLOAT) — 단위 면적당 포인트 밀도
|
||
├── classification_summary (JSONB) — 분류 요약
|
||
│ ├── ground (지표면 포인트)
|
||
│ ├── vegetation (식생)
|
||
│ ├── building (건물)
|
||
│ └── ...
|
||
├── processing_params (JSONB) — 변환 파라미터
|
||
├── processed_at (TIMESTAMP) — 변환 완료 날짜
|
||
└── status (TEXT) — 상태: PROCESSING, COMPLETE, FAILED
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 지표면 & 분석 결과 그룹
|
||
|
||
### 4-1. surface_models 테이블 (WF1 출력 — 지표면 분석 결과)
|
||
```
|
||
surface_models
|
||
├── id (INT, PK) — 지표면 모델 고유 번호
|
||
├── project_id (UUID, FK → projects.id)
|
||
├── model_type (TEXT) — 모델 종류: dem_grid, tin, mesh_triangulated, contour_lines
|
||
├── source_file_id (INT, FK → input_files.id) — 원본 LAS 파일
|
||
├── processed_cloud_id (INT, FK → processed_point_cloud.id) — 변환된 포인트클라우드 참조
|
||
├── status (TEXT) — 상태: PROCESSING, COMPLETE, FAILED
|
||
├── crs_epsg (INT) — 좌표계
|
||
├── resolution_m (FLOAT) — 해상도 (래스터인 경우, NULL 가능)
|
||
├── model_file_path (TEXT) — 모델 저장 경로 (예: "storage/.../processed/surface/dem.tif")
|
||
├── bounds (GEOMETRY) — 모델 범위 (다각형)
|
||
├── generation_params (JSONB) — 생성 파라미터
|
||
│ ├── filter_type (필터링 방식)
|
||
│ ├── algorithm (사용 알고리즘)
|
||
│ ├── params (알고리즘 파라미터)
|
||
│ └── creation_time (생성 시각)
|
||
├── created_at (TIMESTAMP)
|
||
└── completed_at (TIMESTAMP)
|
||
```
|
||
|
||
### 4-2. terrain_layers 테이블 (WF1 산출물 — 각 지형 레이어)
|
||
```
|
||
terrain_layers
|
||
├── id (INT, PK) — 레이어 고유 번호
|
||
├── surface_model_id (INT, FK → surface_models.id)
|
||
├── layer_name (TEXT) — 레이어명 (예: "지표", "제1층", "제2층" 등)
|
||
├── geometry_type (TEXT) — 기하 종류: POINTCLOUD, GRID, MESH, CONTOUR
|
||
├── layer_file_path (TEXT) — 레이어 파일 저장 경로 (예: "storage/.../processed/surface/layer_1.geojson")
|
||
├── file_format (TEXT) — 파일 형식: geojson, geotiff, ply, obj 등
|
||
├── file_size_mb (FLOAT) — 파일 크기
|
||
├── bounds (GEOMETRY) — 레이어 범위
|
||
├── statistics (JSONB) — 통계
|
||
│ ├── min_z, max_z, mean_slope
|
||
│ ├── point_count (포인트 개수)
|
||
│ └── ...
|
||
└── created_at (TIMESTAMP)
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 경로 & 설계 그룹
|
||
|
||
### 5-1. routes 테이블 (WF2 출력 — 경로 설계 결과)
|
||
```
|
||
routes
|
||
├── id (INT, PK) — 경로 고유 번호
|
||
├── project_id (UUID, FK → projects.id)
|
||
├── surface_model_id (INT, FK → surface_models.id) — 기반 지표면 모델
|
||
├── status (TEXT) — 상태: DRAFT, CONFIRMED, ARCHIVED
|
||
├── start_point (GEOMETRY(Point)) — 시작점 좌표 (3D)
|
||
├── end_point (GEOMETRY(Point)) — 종료점 좌표 (3D)
|
||
├── start_chainage_m (FLOAT) — 시작점 측점 (m)
|
||
├── end_chainage_m (FLOAT) — 종료점 측점 (m)
|
||
├── total_length_m (FLOAT) — 총 연장 (m)
|
||
├── grade_percent (JSONB array) — 각 구간 종단 경사도 (%)
|
||
│ └── [2.5, 1.8, 3.2, ...]
|
||
├── constraints (JSONB) — 설계 제약조건
|
||
│ ├── max_grade (% 최대경사도)
|
||
│ ├── min_radius (m 최소곡선반경)
|
||
│ ├── avoidance_zones ([폴리곤 배열])
|
||
│ └── ...
|
||
├── algorithm_params (JSONB) — 알고리즘 파라미터
|
||
│ ├── cost_weights (비용함수 가중치)
|
||
│ └── ...
|
||
├── geometry (GEOMETRY(LineString, Z)) — 3D 경로 좌표 열
|
||
├── route_data_path (TEXT) — 경로 데이터 저장 경로 (예: "storage/.../computed/route/route_main.geojson")
|
||
├── computed_at (TIMESTAMP) — 계산 완료 날짜
|
||
└── created_at (TIMESTAMP)
|
||
```
|
||
|
||
### 5-2. route_points 테이블 (웹 렌더링용 샘플)
|
||
```
|
||
route_points
|
||
├── id (INT, PK)
|
||
├── route_id (INT, FK → routes.id)
|
||
├── chainage_m (FLOAT) — 측점 (m)
|
||
├── geometry (GEOMETRY(Point, Z)) — 포인트 좌표
|
||
├── elevation_m (FLOAT) — 높이
|
||
├── slope_percent (FLOAT) — 경사도 (%)
|
||
└── sequence_num (INT) — 순서번호
|
||
```
|
||
|
||
### 5-3. route_statistics 테이블
|
||
```
|
||
route_statistics
|
||
├── id (INT, PK)
|
||
├── route_id (INT, FK → routes.id)
|
||
├── min_slope (FLOAT) — 최소 경사도 (%)
|
||
├── max_slope (FLOAT) — 최대 경사도 (%)
|
||
├── mean_slope (FLOAT) — 평균 경사도 (%)
|
||
├── cut_volume_m3 (FLOAT) — 절토량 (m³)
|
||
├── fill_volume_m3 (FLOAT) — 성토량 (m³)
|
||
├── tree_cutting_volume (FLOAT) — 목재 절감 추정량
|
||
└── cost_score (FLOAT) — 알고리즘 점수
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 종단면 & 횡단면 그룹
|
||
|
||
### 6-1. longitudinal_sections 테이블 (WF3 출력 — 종단면)
|
||
```
|
||
longitudinal_sections
|
||
├── id (INT, PK) — 종단면 고유 번호
|
||
├── project_id (UUID, FK → projects.id)
|
||
├── route_id (INT, FK → routes.id)
|
||
├── computed_at (TIMESTAMP) — 계산 날짜
|
||
├── geometry (GEOMETRY(LineString, Z)) — 종단면 지형 좌표열
|
||
├── data (JSONB) — 상세 데이터
|
||
│ ├── chainages ([0, 20, 40, 60, ...]) — 측점 배열 (m)
|
||
│ ├── elevations ([100.5, 102.3, 101.8, ...]) — 지표 표고 배열
|
||
│ ├── grades ([2.5, 1.8, 1.0, ...]) — 경사도 배열 (%)
|
||
│ └── design_elevations ([100.0, 102.0, 101.5, ...]) — 설계 표고
|
||
├── longitudinal_file_path (TEXT) — 저장 경로 (예: "storage/.../computed/sections/longitudinal.json")
|
||
└── status (TEXT) — 상태: DRAFT, CONFIRMED
|
||
```
|
||
|
||
### 6-2. cross_sections 테이블 (WF3 출력 — 횡단면)
|
||
```
|
||
cross_sections
|
||
├── id (INT, PK) — 횡단면 고유 번호
|
||
├── project_id (UUID, FK → projects.id)
|
||
├── route_id (INT, FK → routes.id)
|
||
├── chainage_m (FLOAT) — 측점 (예: 0, 20, 40, ... m)
|
||
├── sequence_num (INT) — 횡단면 순번 (1번째, 2번째, ...)
|
||
├── geometry (GEOMETRY(LineString, Z)) — 지형 횡단선 좌표열
|
||
├── geometry_design (GEOMETRY(LineString, Z)) — 설계 횡단선 좌표열
|
||
├── data (JSONB) — 상세 데이터
|
||
│ ├── left_slope (FLOAT, %) — 좌측 사면 경사
|
||
│ ├── right_slope (FLOAT, %) — 우측 사면 경사
|
||
│ ├── width_m (FLOAT) — 노폭
|
||
│ ├── cut_volume_m3 (FLOAT) — 절토량
|
||
│ ├── fill_volume_m3 (FLOAT) — 성토량
|
||
│ ├── structures ([]) — 이 단면 내 구조물 ID 배열
|
||
│ └── notes (TEXT) — 메모
|
||
├── cross_section_file_path (TEXT) — 저장 경로 (예: "storage/.../computed/sections/cross_0020m.json")
|
||
└── status (TEXT) — 상태: DRAFT, CONFIRMED
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 설계 & 구조물 그룹
|
||
|
||
### 7-1. structures 테이블 (WF4 출력 — 구조물)
|
||
```
|
||
structures
|
||
├── id (INT, PK) — 구조물 고유 번호
|
||
├── project_id (UUID, FK → projects.id)
|
||
├── cross_section_id (INT, FK → cross_sections.id)
|
||
├── structure_type (TEXT) — 종류: 낙석방지책, 돌붙임, 계간수로, 낙차공, 등
|
||
├── chainage_m (FLOAT) — 측점 (m)
|
||
├── location (TEXT) — 위치: LEFT, CENTER, RIGHT
|
||
├── length_m (FLOAT) — 길이
|
||
├── width_m (FLOAT) — 폭
|
||
├── height_m (FLOAT) — 높이
|
||
├── material (TEXT) — 재료: 강재, 콘크리트, 목재, 돌 등
|
||
├── quantity (INT) — 개수
|
||
├── unit_price (FLOAT) — 단가
|
||
├── geometry (GEOMETRY(Polygon)) — 3D 배치 도형
|
||
├── design_notes (JSONB) — 설계 노트
|
||
├── structure_data_path (TEXT) — 구조물 데이터 저장 경로 (예: "storage/.../computed/structures/struct_0020m_001.json")
|
||
├── last_modified_by (INT, FK → users.id) — 마지막 수정자
|
||
├── created_at (TIMESTAMP)
|
||
└── updated_at (TIMESTAMP)
|
||
```
|
||
|
||
### 7-2. quantity_items 테이블 (WF5 출력 — 수량 산출)
|
||
```
|
||
quantity_items
|
||
├── id (INT, PK) — 수량 항목 고유 번호
|
||
├── project_id (UUID, FK → projects.id)
|
||
├── category (TEXT) — 대분류: 토공, 구조물, 포장, 배수, 녹화, 안전시설
|
||
├── item_name (TEXT) — 항목명 (예: "절토 일반", "낙석방지책 설치")
|
||
├── unit (TEXT) — 단위: m3, 개, m, m2
|
||
├── quantity_design (FLOAT) — 설계 수량
|
||
├── quantity_actual (FLOAT) — 실제 수량 (사용자 수정 가능)
|
||
├── unit_price (FLOAT) — 단가
|
||
├── total_price (FLOAT) — 소계 (quantity_actual × unit_price)
|
||
├── standard_reference (TEXT) — 기준 참고 자료
|
||
├── computed_at (TIMESTAMP) — 계산 날짜
|
||
├── quantity_data_path (TEXT) — 수량 데이터 저장 경로 (예: "storage/.../computed/quantities/items.json")
|
||
└── data (JSONB) — 계산 과정 메모
|
||
├── formula (계산식)
|
||
├── source (데이터 출처)
|
||
└── ...
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 산출물 & 문서 그룹
|
||
|
||
### 8-1. outputs 테이블 (WF6 출력 — 최종 산출물 세트)
|
||
```
|
||
outputs
|
||
├── id (INT, PK) — 산출물 세트 고유 번호
|
||
├── project_id (UUID, FK → projects.id)
|
||
├── output_type (TEXT) — 종류: estimation_excel, drawing_dxf, report_pdf, all_bundle
|
||
├── status (TEXT) — 상태: GENERATING, COMPLETE, FAILED
|
||
├── generated_by (INT, FK → users.id) — 생성자
|
||
├── generated_at (TIMESTAMP) — 생성 날짜
|
||
├── version (INT) — 버전 (프로젝트 확정 단계에서 자동 증가)
|
||
├── outputs_directory_path (TEXT) — 산출물 저장 폴더 (예: "storage/.../outputs/v1/")
|
||
└── metadata (JSONB) — 메타데이터
|
||
├── template_used (사용한 양식)
|
||
├── company_name (회사명)
|
||
├── project_name (프로젝트명)
|
||
├── total_cost (총 비용)
|
||
└── generation_time_sec (생성 소요 시간)
|
||
```
|
||
|
||
### 8-2. output_files 테이블 (최종 산출 파일들)
|
||
```
|
||
output_files
|
||
├── id (INT, PK) — 파일 고유 번호
|
||
├── output_id (INT, FK → outputs.id)
|
||
├── file_type (TEXT) — 파일 형식: xlsx, pdf, dxf, dwg, json, zip
|
||
├── original_filename (TEXT) — 파일명 (예: "견적서_v1.xlsx")
|
||
├── output_file_path (TEXT) — 저장 경로 (예: "storage/.../outputs/v1/견적서.xlsx")
|
||
├── file_size_mb (FLOAT) — 파일 크기
|
||
├── created_at (TIMESTAMP) — 생성 날짜
|
||
└── download_count (INT) — 다운로드 횟수
|
||
```
|
||
|
||
---
|
||
|
||
## 9. 변경 이력 & 감시 그룹
|
||
|
||
### 9-1. audit_logs 테이블 (보안 감시)
|
||
```
|
||
audit_logs
|
||
├── id (INT, PK) — 로그 고유 번호
|
||
├── user_id (INT, FK → users.id) — 행동 수행자
|
||
├── action (TEXT) — 행동: CREATE, READ, UPDATE, DELETE, EXPORT, DOWNLOAD
|
||
├── entity_type (TEXT) — 대상 타입: projects, routes, structures, outputs 등
|
||
├── entity_id (TEXT) — 대상 ID
|
||
├── timestamp (TIMESTAMP) — 시간
|
||
├── ip_address (TEXT) — IP 주소
|
||
└── details (JSONB) — 상세 정보
|
||
├── old_value (변경 전 값)
|
||
├── new_value (변경 후 값)
|
||
└── reason (변경 사유)
|
||
```
|
||
|
||
### 9-2. change_logs 테이블 (설계 변경 기록)
|
||
```
|
||
change_logs
|
||
├── id (INT, PK) — 변경 고유 번호
|
||
├── project_id (UUID, FK → projects.id)
|
||
├── changed_by (INT, FK → users.id) — 변경자
|
||
├── changed_at (TIMESTAMP) — 변경 날짜
|
||
├── entity_type (TEXT) — 대상 타입: routes, cross_sections, structures, quantity_items
|
||
├── entity_id (INT) — 대상 ID
|
||
├── old_value (JSONB) — 변경 전 값
|
||
├── new_value (JSONB) — 변경 후 값
|
||
└── reason (TEXT) — 변경 사유
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 테이블 간 관계도 (폴더처럼 표현)
|
||
|
||
```
|
||
users (사용자)
|
||
├── ↓ FK: company_id
|
||
├─→ companies (회사)
|
||
│ ├── ↓ FK
|
||
│ └─→ projects (프로젝트)
|
||
│ ├── ↓ FK
|
||
│ ├─→ input_files (입력 파일)
|
||
│ │ └─→ point_cloud_metadata (포인트클라우드 메타)
|
||
│ ├─→ surface_models (지표면 모델)
|
||
│ │ └─→ terrain_layers (지형 레이어)
|
||
│ ├─→ routes (경로)
|
||
│ │ ├─→ route_points (경로 포인트)
|
||
│ │ ├─→ route_statistics (경로 통계)
|
||
│ │ ├─→ longitudinal_sections (종단면)
|
||
│ │ └─→ cross_sections (횡단면)
|
||
│ │ └─→ structures (구조물)
|
||
│ ├─→ quantity_items (수량 항목)
|
||
│ ├─→ outputs (산출물)
|
||
│ │ └─→ output_files (산출물 파일)
|
||
│ ├─→ project_versions (프로젝트 버전)
|
||
│ ├─→ audit_logs (감시 로그)
|
||
│ └─→ change_logs (변경 로그)
|
||
```
|
||
|
||
---
|
||
|
||
## 11. 파일시스템 경로와 DB 링크 (워크플로우 기반 구조)
|
||
|
||
### 파일시스템 구조 (6단계 워크플로우에 맞춤)
|
||
|
||
```
|
||
storage/
|
||
├── {company_slug}/
|
||
│ └── {user_slug}/
|
||
│ └── {project_id}/ ← projects.storage_path
|
||
│ │
|
||
│ ├── B03_FileInput/ ← WF0: 파일 입력
|
||
│ │ ├── input/ (원본 입력 파일들)
|
||
│ │ │ ├── las/
|
||
│ │ │ │ └── cloud_merged.las ← input_files.raw_file_path
|
||
│ │ │ ├── tif/
|
||
│ │ │ ├── tfw/
|
||
│ │ │ ├── prj/
|
||
│ │ │ └── dxf/
|
||
│ │ └── metadata.json (파일 메타데이터)
|
||
│ │
|
||
│ ├── B04_wf1_Surface/ ← WF1: 지표면 분석
|
||
│ │ ├── processed/ (변환된 포인트클라우드)
|
||
│ │ │ ├── cloud_filtered.las ← processed_point_cloud.processed_file_path
|
||
│ │ │ └── cloud_sampled.ply ← processed_point_cloud.converted_file_path
|
||
│ │ ├── models/ (지표면 모델)
|
||
│ │ │ ├── dem_2m.tif ← surface_models.model_file_path
|
||
│ │ │ ├── tin_mesh.obj
|
||
│ │ │ ├── layer_ground.geojson ← terrain_layers.layer_file_path
|
||
│ │ │ ├── layer_1.geojson
|
||
│ │ │ └── ...
|
||
│ │ └── analysis_report.json
|
||
│ │
|
||
│ ├── B05_wf2_Route/ ← WF2: 경로 설계
|
||
│ │ ├── route/
|
||
│ │ │ ├── route_main.geojson ← routes.route_data_path
|
||
│ │ │ ├── route_points.json
|
||
│ │ │ └── route_statistics.json ← route_statistics 데이터
|
||
│ │ └── design_params.json
|
||
│ │
|
||
│ ├── B06_wf3_ProfileCross/ ← WF3: 종횡단 생성
|
||
│ │ ├── longitudinal/
|
||
│ │ │ └── longitudinal.json ← longitudinal_sections.longitudinal_file_path
|
||
│ │ ├── cross_sections/
|
||
│ │ │ ├── cross_0000m.json ← cross_sections.cross_section_file_path
|
||
│ │ │ ├── cross_0020m.json
|
||
│ │ │ ├── cross_0040m.json
|
||
│ │ │ └── ...
|
||
│ │ └── sections_index.json
|
||
│ │
|
||
│ ├── B07_wf4_DesignDetail/ ← WF4: 상세 설계
|
||
│ │ ├── structures/
|
||
│ │ │ ├── struct_0020m_001.json ← structures.structure_data_path
|
||
│ │ │ ├── struct_0020m_002.json
|
||
│ │ │ ├── struct_0040m_001.json
|
||
│ │ │ └── ...
|
||
│ │ └── design_review.json
|
||
│ │
|
||
│ ├── B08_wf5_Quantity/ ← WF5: 수량 산출
|
||
│ │ ├── quantities/
|
||
│ │ │ └── items.json ← quantity_items.quantity_data_path
|
||
│ │ ├── breakdown_by_category.json (항목별 집계)
|
||
│ │ └── cost_summary.json (비용 요약)
|
||
│ │
|
||
│ └── B09_wf6_Estimation/ ← WF6: 견적·문서
|
||
│ ├── v1/ ← outputs.outputs_directory_path
|
||
│ │ ├── 견적서.xlsx ← output_files.output_file_path
|
||
│ │ ├── 설계도.dxf
|
||
│ │ ├── 보고서.pdf
|
||
│ │ ├── 종단면도.pdf
|
||
│ │ └── 횡단면도.pdf
|
||
│ ├── v2/
|
||
│ │ ├── 견적서.xlsx
|
||
│ │ └── ...
|
||
│ └── bundles/
|
||
│ ├── v1_complete.zip (버전 1 전체 패키지)
|
||
│ └── v2_complete.zip (버전 2 전체 패키지)
|
||
```
|
||
|
||
**핵심 개념:**
|
||
- **B03_FileInput/**: WF0 파일 입력 단계 (사용자 업로드 원본)
|
||
- **B04_wf1_Surface/**: WF1 지표면 분석 결과 (DEM, TIN, 메시, 레이어)
|
||
- **B05_wf2_Route/**: WF2 경로 설계 결과 (경로 GeoJSON)
|
||
- **B06_wf3_ProfileCross/**: WF3 종횡단 생성 결과 (종단면, 횡단면 JSON)
|
||
- **B07_wf4_DesignDetail/**: WF4 상세 설계 결과 (구조물 배치)
|
||
- **B08_wf5_Quantity/**: WF5 수량 산출 결과 (수량 항목)
|
||
- **B09_wf6_Estimation/**: WF6 최종 산출물 (Excel, PDF, DXF)
|
||
|
||
**장점:**
|
||
✅ 워크플로우 단계와 폴더가 1:1 대응 → 직관적
|
||
✅ 각 단계의 입력/출력이 명확히 분리
|
||
✅ 각 단계 재실행 시 폴더만 초기화하면 됨
|
||
✅ 버전 관리 (v1, v2, ...) 단순화
|
||
|
||
|
||
---
|
||
|
||
## 12. 핵심 쿼리 예제
|
||
|
||
### 예제 1: 사용자의 모든 프로젝트 조회
|
||
```sql
|
||
SELECT p.id, p.name, p.status, p.created_at
|
||
FROM projects p
|
||
WHERE p.user_id = :user_id AND p.deleted_at IS NULL
|
||
ORDER BY p.created_at DESC;
|
||
```
|
||
|
||
### 예제 2: 프로젝트의 최신 경로 조회
|
||
```sql
|
||
SELECT r.id, r.total_length_m, r.geometry, r.status
|
||
FROM routes r
|
||
WHERE r.project_id = :project_id
|
||
ORDER BY r.computed_at DESC
|
||
LIMIT 1;
|
||
```
|
||
|
||
### 예제 3: 경로의 모든 횡단면 조회
|
||
```sql
|
||
SELECT cs.id, cs.chainage_m, cs.geometry, cs.data
|
||
FROM cross_sections cs
|
||
WHERE cs.route_id = :route_id
|
||
ORDER BY cs.chainage_m;
|
||
```
|
||
|
||
### 예제 4: 프로젝트 총 비용 계산
|
||
```sql
|
||
SELECT
|
||
SUM(quantity_actual * unit_price) as total_cost,
|
||
category
|
||
FROM quantity_items
|
||
WHERE project_id = :project_id
|
||
GROUP BY category;
|
||
```
|
||
|
||
### 예제 5: 사용자의 감시 로그 (최근 30일)
|
||
```sql
|
||
SELECT action, entity_type, timestamp, details
|
||
FROM audit_logs
|
||
WHERE user_id = :user_id AND timestamp > NOW() - INTERVAL '30 days'
|
||
ORDER BY timestamp DESC;
|
||
```
|
||
|
||
---
|
||
|
||
## 13. 데이터 타입 가이드
|
||
|
||
| 타입 | 설명 | 예제 |
|
||
|------|------|------|
|
||
| INT | 정수 | 1, 2, 100 |
|
||
| FLOAT | 실수 | 1.5, 2.25, 100.75 |
|
||
| TEXT | 문자열 (가변) | "프로젝트명", "울진군" |
|
||
| TIMESTAMP | 날짜 + 시간 | 2025-07-05 15:30:00 |
|
||
| BOOLEAN | 참/거짓 | TRUE, FALSE |
|
||
| UUID | 36자 고유 ID | 550e8400-e29b-41d4-a716-446655440000 |
|
||
| JSONB | JSON 데이터 | {"key": "value", "array": [1,2,3]} |
|
||
| GEOMETRY | 지리 좌표 | POINT(127.5 37.5), LINESTRING(...) |
|
||
|
||
---
|
||
|
||
## 요약
|
||
|
||
### 주요 변경사항
|
||
1. ✅ **users 테이블**: position(직급), department(부서), phone(연락처) 추가
|
||
2. ✅ **companies 테이블**: business_registration_number, business_address, business_owner, business_status 추가
|
||
3. ✅ **경로 관리 추가**: 모든 데이터의 저장소 경로를 DB에 기록
|
||
4. ✅ **processed_point_cloud 테이블 신규**: LAS → 빠른 포맷 변환 추적
|
||
5. ✅ **파일 경로 세분화**:
|
||
- `raw_file_path`: 원본 파일 위치
|
||
- `processed_file_path / converted_file_path`: 변환된 파일 위치
|
||
- `*_file_path`: 각 워크플로우 단계별 산출물 위치
|
||
|
||
### 총 18개 테이블:
|
||
1. **사용자/회사**: users, companies (2개)
|
||
2. **프로젝트**: projects, project_versions (2개)
|
||
3. **입력 데이터**: input_files, processed_point_cloud (2개)
|
||
4. **지표면 분석**: surface_models, terrain_layers (2개)
|
||
5. **경로 설계**: routes, route_points, route_statistics (3개)
|
||
6. **단면 설계**: longitudinal_sections, cross_sections (2개)
|
||
7. **구조물/수량**: structures, quantity_items (2개)
|
||
8. **산출물**: outputs, output_files (2개)
|
||
9. **감시/이력**: audit_logs, change_logs (2개)
|
||
|
||
### DB vs 파일시스템 역할 분리
|
||
| 저장 위치 | 내용 | 예시 |
|
||
|----------|------|------|
|
||
| **DB** | 메타데이터 + 경로정보 | 파일명, 크기, 좌표계, 상태, 저장경로 |
|
||
| **파일시스템** | 실제 파일 데이터 | LAS, DXF, Excel, PDF, JSON, GeoJSON 파일들 |
|
||
|
||
**워크플로우 6단계에 따른 파일 흐름:**
|
||
```
|
||
B03_FileInput/ (WF0: 파일 입력)
|
||
└─ input/*.las, *.tif, *.prj, *.tfw
|
||
↓
|
||
B04_wf1_Surface/ (WF1: 지표면 분석)
|
||
├─ processed/*.ply (변환된 포인트클라우드)
|
||
└─ models/*.tif, *.geojson (DEM, TIN, 레이어)
|
||
↓
|
||
B05_wf2_Route/ (WF2: 경로 설계)
|
||
└─ route/*.geojson (최적 경로)
|
||
↓
|
||
B06_wf3_ProfileCross/ (WF3: 종횡단 생성)
|
||
├─ longitudinal/*.json (종단면)
|
||
└─ cross_sections/*.json (횡단면 배열)
|
||
↓
|
||
B07_wf4_DesignDetail/ (WF4: 상세 설계)
|
||
└─ structures/*.json (구조물 배치)
|
||
↓
|
||
B08_wf5_Quantity/ (WF5: 수량 산출)
|
||
└─ quantities/*.json (수량 항목)
|
||
↓
|
||
B09_wf6_Estimation/ (WF6: 견적·문서)
|
||
├─ v1/*.xlsx, *.pdf, *.dxf (최종 산출물 v1)
|
||
├─ v2/*.xlsx, *.pdf, *.dxf (최종 산출물 v2)
|
||
└─ bundles/*.zip (완전 패키지)
|
||
```
|
||
|
||
**각 단계별 재실행:**
|
||
- 예: B05 경로 설계 재실행 → `B05_wf2_Route/route/` 폴더만 초기화
|
||
- 예: B09 문서 재생성 → `B09_wf6_Estimation/v3/` 폴더 생성 (v1, v2는 유지)
|
||
|
||
### 워크플로우 기반 폴더 구조의 이점
|
||
|
||
| 항목 | 이전 (raw/processed/computed) | 현재 (B04/B05/B06/.../B09) |
|
||
|------|-----|------|
|
||
| **직관성** | 계층적이나 추상적 | ✅ 워크플로우 단계와 정확히 일치 |
|
||
| **단계 재실행** | 어느 폴더를 초기화할지 모호 | ✅ 해당 B0X 폴더만 초기화 |
|
||
| **버전 관리** | outputs/v1, v2, ... 만 가능 | ✅ 모든 단계에서 가능 |
|
||
| **파일 찾기** | raw/ 또는 processed/ 에서 검색 | ✅ B0X_Naming으로 명확함 |
|
||
| **API 라우터** | 경로 결정이 복잡 | ✅ `f"storage/{company}/{user}/{project_id}/B{step}_*/..."` |
|
||
|
||
### 다음 단계:
|
||
- [X] MariaDB에 위 테이블 생성 (18개 테이블)
|
||
- [ ] 관계(FK) 설정
|
||
- [ ] 인덱스 추가 (경로 조회, 프로젝트별 필터 등)
|
||
- [ ] Alembic 마이그레이션 코드 작성<<<<<< 확인 필요(mariaDB사용중)
|
||
- [ ] Python ORM(SQLAlchemy) 모델 정의<<<<<< 확인 필요(mariaDB사용중)
|
||
- [ ] API 라우터에서 파일 경로 저장 로직 추가
|
||
- B03 파일 업로드 → `input_files.raw_file_path` 저장
|
||
- B04 WF1 실행 → `surface_models.model_file_path`, `terrain_layers.layer_file_path` 저장
|
||
- B05 WF2 실행 → `routes.route_data_path` 저장
|
||
- B06 WF3 실행 → `longitudinal_sections.longitudinal_file_path`, `cross_sections.cross_section_file_path` 저장
|
||
- B07 WF4 실행 → `structures.structure_data_path` 저장
|
||
- B08 WF5 실행 → `quantity_items.quantity_data_path` 저장
|
||
- B09 WF6 실행 → `outputs.outputs_directory_path`, `output_files.output_file_path` 저장
|