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

18 KiB
Raw Blame History

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: 사용자의 모든 프로젝트 조회

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: 프로젝트의 최신 경로 조회

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: 경로의 모든 횡단면 조회

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: 프로젝트 총 비용 계산

SELECT 
  SUM(quantity_actual * unit_price) as total_cost,
  category
FROM quantity_items
WHERE project_id = :project_id
GROUP BY category;

예제 5: 사용자의 감시 로그 (최근 30일)

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) 모델 정의