--- document_type: database priority: CRITICAL --- # 데이터베이스 스키마 명세 (MariaDB) MariaDB v10.6+를 사용하며, 총 18개의 테이블로 구성됩니다. ORM 없이 Raw SQL과 `aiomysql` 드라이버를 사용합니다. **공간 데이터(GEOMETRY)는 지원 한계로 인해 JSONB 또는 TEXT(GeoJSON)로 저장합니다.** ## 테이블 목록 및 컬럼 구조 ### 1. 사용자 & 프로젝트 (Core) * **`users`**: `id`(PK), `email`, `password_hash`, `name`, `position`, `department`, `phone`, `company_id`(FK) * **`companies`**: `id`(PK), `name`, `business_registration_number`, `business_address`, `business_owner`, `business_status` * **`projects`**: `id`(UUID, PK), `user_id`(FK), `company_id`(FK), `name`, `region`, `road_type`, `status`, `crs_epsg`, `storage_path` * **`project_versions`**: `id`, `project_id`, `version_num`, `data`(JSONB) ### 2. 파일 & 지표면 데이터 (WF0, WF1) * **`input_files`**: `id`(PK), `project_id`(FK), `file_type`(las, tif 등), `original_filename`, `raw_file_path`, `crs_epsg`, `metadata`(JSONB) * **`processed_point_cloud`**: `id`, `input_file_id`, `project_id`, `processed_file_path`, `converted_file_path`, `min_z`, `max_z` 등 통계치 * **`surface_models`**: `id`, `project_id`, `model_type`(dem_grid, tin 등), `model_file_path`, `generation_params`(JSONB) * **`terrain_layers`**: `id`, `surface_model_id`, `layer_name`, `layer_file_path`(geojson 등) ### 3. 경로 설계 (WF2) * **`routes`**: `id`(PK), `project_id`, `surface_model_id`, `status`, `geometry`(LineString JSON), `route_data_path`, `constraints`(JSONB) * **`route_points`**: `id`, `route_id`, `chainage_m`, `geometry`(Point JSON), `elevation_m` * **`route_statistics`**: `id`, `route_id`, `mean_slope`, `cut_volume_m3`, `fill_volume_m3` ### 4. 종횡단 및 구조물 설계 (WF3, WF4) * **`longitudinal_sections`**: `id`, `project_id`, `route_id`, `longitudinal_file_path`, `data`(JSONB - chainages, elevations 등 배열) * **`cross_sections`**: `id`, `route_id`, `chainage_m`, `cross_section_file_path`, `data`(JSONB - left_slope, cut_volume_m3 등) * **`structures`**: `id`, `cross_section_id`, `structure_type`, `location`(LEFT/RIGHT/CENTER), `length_m`, `geometry`(Polygon JSON), `structure_data_path` ### 5. 수량 산출 및 산출물 (WF5, WF6) * **`quantity_items`**: `id`, `project_id`, `category`, `item_name`, `quantity_design`, `quantity_actual`, `unit_price`, `quantity_data_path` * **`outputs`**: `id`, `project_id`, `output_type`, `outputs_directory_path` * **`output_files`**: `id`, `output_id`, `file_type`, `output_file_path` ### 6. 로그 (Audit) * **`audit_logs`**, **`change_logs`** --- ## 💡 주요 원칙 (DB vs File System) - **DB에는 메타데이터와 파일 시스템의 "상대 경로"만 기록합니다.** (예: `input_files.raw_file_path = "B03_FileInput/input/las/cloud.las"`) - 대용량 파일(LAS, TIF, GeoJSON)은 MariaDB에 Blob으로 저장하지 않습니다. ## 📝 쿼리 작성 예제 (Raw SQL & aiomysql) ```python # 쿼리에는 ORM이 아닌 %s 플레이스홀더를 사용해야 함 async def get_project_route(pool, project_id: str): async with pool.acquire() as conn: async with conn.cursor() as cur: await cur.execute(""" SELECT r.id, r.total_length_m, r.route_data_path FROM routes r WHERE r.project_id = %s ORDER BY r.computed_at DESC LIMIT 1 """, (project_id,)) return await cur.fetchone() ```