Files
Aislo/.agent/db_schema_simple.md
T
2026-07-05 18:10:16 +09:00

500 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# DB 스키마 (테이블 및 열 목록)
## 1. 사용자 & 인증 그룹
### 1-1. users 테이블
```
users
├── id (INT, PK) — 사용자 고유 번호
├── email (TEXT, UNIQUE) — 로그인 이메일
├── password_hash (TEXT) — 비밀번호 암호화 저장
├── name (TEXT) — 사용자 이름
├── company_id (INT, FK → companies.id) — 소속 회사
├── role (TEXT) — 역할: admin, user, guest
├── created_at (TIMESTAMP) — 가입일
├── updated_at (TIMESTAMP) — 수정일
└── deleted_at (TIMESTAMP, NULL) — 삭제일 (soft delete)
```
### 1-2. companies 테이블
```
companies
├── id (INT, PK) — 회사 고유 번호
├── name (TEXT, UNIQUE) — 회사명
├── created_by (INT, FK → users.id) — 회사 생성자
├── created_at (TIMESTAMP) — 생성일
└── updated_at (TIMESTAMP) — 수정일
```
---
## 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")
├── stored_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. point_cloud_metadata 테이블
```
point_cloud_metadata
├── id (INT, PK)
├── input_file_id (INT, FK → input_files.id) — LAS 파일 참조
├── 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 (건물)
└── ...
```
---
## 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 파일
├── status (TEXT) — 상태: PROCESSING, COMPLETE, FAILED
├── crs_epsg (INT) — 좌표계
├── resolution_m (FLOAT) — 해상도 (래스터인 경우, NULL 가능)
├── stored_path (TEXT) — 저장 경로 (예: "storage/.../processed/surface/dem.tif")
├── bounds (GEOMETRY) — 모델 범위 (다각형)
├── metadata (JSONB) — 생성 파라미터
│ ├── filter_type (필터링 방식)
│ ├── creation_time (생성 시각)
│ └── ...
├── created_at (TIMESTAMP)
└── completed_at (TIMESTAMP)
```
### 4-2. terrain_layers 테이블
```
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
├── stored_path (TEXT) — 저장 경로 (GeoJSON, GeoTIFF, LAS 등)
└── statistics (JSONB) — 통계
├── min_z, max_z, mean_slope
└── ...
```
---
## 5. 경로 & 설계 그룹
### 5-1. routes 테이블 (WF2 출력)
```
routes
├── id (INT, PK) — 경로 고유 번호
├── project_id (UUID, FK → projects.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 경로 좌표 열
├── 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, ...]) — 설계 표고
└── stored_path (TEXT) — 저장 경로 (예: "storage/.../sections/longitudinal.json")
```
### 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) — 메모
└── stored_path (TEXT) — 저장 경로 (예: "storage/.../sections/cross_0020m.json")
```
---
## 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) — 설계 노트
├── last_modified_by (INT, FK → users.id) — 마지막 수정자
└── created_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) — 계산 날짜
└── data (JSONB) — 계산 과정 메모
├── formula (계산식)
└── ...
```
---
## 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) — 버전 (프로젝트 확정 시 자동 증가)
└── 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")
├── stored_path (TEXT) — 저장 경로 (예: "storage/.../outputs/estimation/견적서_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 링크
```
storage/
├── {company_slug}/
│ └── {user_slug}/
│ └── {project_id}/ ← projects.storage_path
│ ├── raw/ ← input_files.stored_path
│ │ ├── las/
│ │ ├── tif/
│ │ ├── tfw/
│ │ ├── prj/
│ │ └── dxf/
│ ├── processed/ ← surface_models.stored_path, terrain_layers.stored_path
│ │ ├── surface/
│ │ ├── points/
│ │ └── tiles/
│ ├── sections/ ← longitudinal_sections.stored_path, cross_sections.stored_path
│ │ ├── longitudinal.json
│ │ ├── cross_0000m.json
│ │ ├── cross_0020m.json
│ │ └── ...
│ └── outputs/ ← output_files.stored_path
│ ├── estimation/
│ ├── drawings/
│ ├── reports/
│ └── bundles/
```
---
## 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(...) |
---
## 요약
**총 17개 테이블:**
1. users, companies
2. projects, project_versions
3. input_files, point_cloud_metadata
4. surface_models, terrain_layers
5. routes, route_points, route_statistics
6. longitudinal_sections, cross_sections
7. structures, quantity_items
8. outputs, output_files
9. audit_logs, change_logs
**다음 단계:**
- [ ] PostgreSQL에 위 테이블 생성
- [ ] 관계(FK) 설정
- [ ] 인덱스 추가
- [ ] Alembic 마이그레이션 코드 작성
- [ ] Python ORM(SQLAlchemy) 모델 정의