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

24 KiB
Raw Blame History

DB 구조 설계 제안서

작성일: 2026-07-05
대상: 임도 설계 및 견적 자동화 웹앱 (프로젝트 기반 멀티테넌트)
기술 스택: PostgreSQL v17 + PostGIS v3.4 / asyncpg / FastAPI


1. 설계 원칙

1.1 멀티테넌트 아키텍처

  • 프로젝트 단위 데이터 격리: 각 사용자의 프로젝트는 별도의 논리적 네임스페이스로 관리
  • 하이브리드 저장소:
    • DB: 사용자, 프로젝트 메타데이터, 설계 결과(경로, 단면, 수량) 저장
    • 파일시스템: 원본 입력파일(LAS/TIF/DXF), 중간 산출물(mesh/타일), 최종 산출물(DXF/Excel/PDF) 저장
  • 스토리지 경로: storage/{회사명}/{사용자명}/{프로젝트ID}/ 하위로 자동 생성

1.2 데이터 계층 분리

[입력] LAS, TFW, PRJ, TIF → [분석] DEM/Mesh/필터 → [설계] 경로, 단면 → [산출] DXF, Excel
      (storage)              (DB + storage)      (DB + storage)        (storage)

1.3 공간 데이터 전용 설계

  • PostGIS 기하학적 타입 활용 (geometry, geography)
  • 좌표계 일관성: EPSG 코드 저장 후 필요 시 변환
  • 벡터 데이터(경로, 경계선) ↔ 래스터 샘플링 간 추적 가능하도록 설계

2. 핵심 Entity 및 관계

2.1 사용자 및 인증 (users, user_sessions)

users
├── id (PK)
├── email (UNIQUE)
├── password_hash
├── name
├── company (FK → companies)
├── role (admin, user, guest)
├── created_at, updated_at

companies
├── id (PK)
├── name (UNIQUE)
├── created_by (FK → users)
├── members [] (users, M:N via user_company_roles)
├── created_at, updated_at

user_sessions (토큰 저장 — optional, Redis 권장)
├── id (PK)
├── user_id (FK → users)
├── token
├── expires_at

설계 의도:

  • 회사 단위로 프로젝트, 사용자를 그룹화
  • 회사별 권한 분리 (협업 확장성)
  • 향후 팀 공유 프로젝트 기능 추가 가능

2.2 프로젝트 메타데이터 (projects, project_versions)

projects
├── id (PK, UUID)
├── user_id (FK → users) — 소유자
├── company_id (FK → companies)
├── name
├── region (지역명: 예 "울진군 금강송면")
├── road_type (간선임도, 지선임도, 산불진화임도, 계류보전)
├── project_year (사업 연도, INT)
├── estimated_length_m (추정 연장)
├── memo
├── status (NEW, ANALYZING, WF1_COMPLETE, WF2_COMPLETE, ... , CONFIRMED, DONE)
├── crs_epsg (좌표계, INT — 예: 5178)
├── bbox (GEOMETRY(Polygon)) — 전체 프로젝트 범위
├── created_at, updated_at
├── deleted_at (soft delete)

project_versions (버전 관리 — 선택)
├── id (PK)
├── project_id (FK → projects)
├── version_num
├── snapshot_at (스냅샷 시점)
├── status (저장된 상태)
└── data (JSONB — 설계 데이터 스냅샷)

설계 의도:

  • 프로젝트 생명주기 추적 (NEW → WF1 → WF2 → ... → CONFIRMED)
  • 좌표계 메타데이터 저장 (변환 오류 방지)
  • 버전 관리는 (선택) — 회원가입 초기엔 미필수, 협업 필요 시 추가

2.3 입력 파일 관리 (input_files)

input_files
├── id (PK)
├── project_id (FK → projects)
├── file_type (las, tif, tfw, prj, dxf, dwg, other)
├── original_filename
├── stored_path (storage/{...}/raw/{file_type}/{filename})
├── file_size_mb
├── upload_by (FK → users)
├── upload_at
├── crs_epsg (파일이 가진 좌표계)
├── metadata (JSONB — 해상도, 데이터 범위, 포인트 수 등)
└── status (UPLOADED, PROCESSED, ARCHIVED)

point_cloud_metadata
├── id (PK)
├── input_file_id (FK → input_files, LAS만)
├── point_count (INT)
├── min_z, max_z, mean_z (높이)
├── x_min, x_max, y_min, y_max (공간 범위)
├── densitiy_per_sqm (밀도)
└── classification_summary (JSONB — {ground: N, vegetation: N, building: N, ...})

설계 의도:

  • 입력 파일의 생명주기 추적
  • 포인트클라우드 메타데이터로 전처리 여부 판단
  • storage 폴더와 DB 간 일관성 확보

2.4 지표면 모델 및 분석 결과 (surface_models, terrain_layers)

surface_models (WF1 출력)
├── id (PK)
├── project_id (FK → projects)
├── model_type (dem_grid, tin, mesh_triangulated, contour_lines)
├── source_file_id (FK → input_files, LAS)
├── status (PROCESSING, COMPLETE, FAILED)
├── crs_epsg
├── resolution_m (래스터 경우, NULL if 벡터)
├── stored_path (storage/{...}/processed/surface/)
├── bounds (GEOMETRY(Polygon)) — 모델 범위
├── metadata (JSONB — 필터링 파라미터, 생성 시각 등)
├── created_at, completed_at

terrain_layers
├── id (PK)
├── surface_model_id (FK → surface_models)
├── layer_name (지표, 제1층, 제2층 등 15종)
├── geometry_type (POINTCLOUD, GRID, MESH, CONTOUR)
├── stored_path (GeoJSON / GeoTIFF / LAS 등)
└── statistics (JSONB — min_z, max_z, mean_slope, etc.)

설계 의도:

  • WF1 분석 결과(DEM, TIN, mesh 등)의 출처와 메타데이터 추적
  • 층(layer)별로 렌더링 최적화 가능
  • 재분석 시 기존 결과와 비교 가능

2.5 경로 설계 (routes, route_points, route_statistics)

routes (WF2 출력)
├── id (PK)
├── project_id (FK → projects)
├── status (DRAFT, CONFIRMED, ARCHIVED)
├── start_point (GEOMETRY(Point)) — 지형 위 실제 좌표
├── end_point (GEOMETRY(Point))
├── start_chainage_m, end_chainage_m (측점)
├── total_length_m
├── grade_percent[] (JSONB array — 각 구간 종단 경사도)
├── constraints (JSONB — max_grade, min_radius, avoidance_zones)
├── algorithm_params (JSONB — 비용함수 가중치, 계산 시간 등)
├── computed_at
└── geometry (GEOMETRY(LineString, Z) — 3D 경로)

route_points (경로 포인트 샘플, 웹 렌더링용)
├── id (PK)
├── route_id (FK → routes)
├── chainage_m (측점)
├── geometry (GEOMETRY(Point, Z))
├── elevation_m, slope_percent
└── sequence_num

route_statistics
├── id (PK)
├── route_id (FK → routes)
├── min_slope, max_slope, mean_slope
├── cut_volume_m3, fill_volume_m3
├── tree_cutting_volume (목재 추정)
└── cost_score (알고리즘 점수)

설계 의도:

  • 경로의 기하학적 정보(3D LineString) + 측점 기반 추적
  • 재계산 시 이전 결과와 버전 비교 가능
  • 사용자가 수정한 경로도 저장 가능 (draft ↔ confirmed)

2.6 종단면 및 횡단면 (longitudinal_sections, cross_sections)

longitudinal_sections
├── id (PK)
├── project_id (FK → projects)
├── route_id (FK → routes)
├── computed_at
├── geometry (GEOMETRY(LineString, Z)) — 경로 따라가며 샘플링한 표고
├── data (JSONB)
│   ├── chainages [0, 20, 40, ...]
│   ├── elevations [100.5, 102.3, ...]
│   ├── grades [2.5, 1.8, ...]
│   └── design_elevations [100.0, 102.0, ...] (설계 기준)
└── stored_path (storage/{...}/sections/longitudinal.json)

cross_sections
├── id (PK)
├── project_id (FK → projects)
├── route_id (FK → routes)
├── chainage_m (측점)
├── sequence_num (1st, 2nd, ...)
├── geometry (GEOMETRY(LineString, Z)) — 지형 횡단면
├── geometry_design (GEOMETRY(LineString, Z)) — 설계 횡단면
├── data (JSONB)
│   ├── left_slope, right_slope
│   ├── width_m
│   ├── cut_volume_m3, fill_volume_m3
│   ├── structures [] (낙석방지책, 돌붙임 등)
│   └── notes
└── stored_path (storage/{...}/sections/cross_{chainage}.json)

설계 의도:

  • 종단면: 경로 따라 세로 방향 표고 추적
  • 횡단면: 20m 간격 가로 방향 단면 + 설계 기준
  • JSONB로 유연한 추가 메타데이터 저장

2.7 설계 및 구조물 (design_details, structures, quantity_items)

structures (WF4 구조물 라이브러리)
├── id (PK)
├── project_id (FK → projects)
├── cross_section_id (FK → cross_sections)
├── structure_type (낙석방지책, 돌붙임, 계간수로, 낙차공, etc.)
├── chainage_m, location (LEFT, CENTER, RIGHT)
├── length_m, width_m, height_m (기본 치수)
├── material (강재, 콘크리트, 목재, 돌 등)
├── quantity (개수)
├── unit_price (단가)
├── geometry (GEOMETRY(Polygon)) — 3D 구조물 배치
├── design_notes (JSONB)
└── last_modified_by (FK → users)

quantity_items (WF5 수량 산출)
├── id (PK)
├── project_id (FK → projects)
├── category (토공, 구조물, 포장, 배수, 녹화, 안전시설)
├── item_name (예: "절토 일반", "낙석방지책 설치" 등)
├── unit (m3, 개, m, m2)
├── quantity_design (설계 수량)
├── quantity_actual (실제 수량, 사용자 수정 가능)
├── unit_price (단가)
├── total_price (수량 × 단가)
├── standard_reference (설계 기준 참고 자료)
├── computed_at
└── data (JSONB — 계산 과정 메모)

설계 의도:

  • 구조물은 횡단면별로 배치
  • 수량 항목은 자동 계산 + 사용자 수정 가능
  • 단가와 기준 추적으로 감시/감독 기록 남김

2.8 산출물 관리 (outputs, output_files)

outputs
├── id (PK)
├── project_id (FK → projects)
├── output_type (estimation_excel, drawing_dxf, report_pdf, all_bundle)
├── status (GENERATING, COMPLETE, FAILED)
├── generated_by (FK → users)
├── generated_at
├── version (프로젝트 확정 단계에서 자동 증가)
├── metadata (JSONB)
│   ├── template_used
│   ├── company_name, project_name
│   ├── total_cost
│   └── generation_time_sec
└── created_at

output_files
├── id (PK)
├── output_id (FK → outputs)
├── file_type (xlsx, pdf, dxf, dwg, json, zip)
├── original_filename
├── stored_path (storage/{...}/outputs/{output_type}/{filename})
├── file_size_mb
├── created_at
└── download_count (통계)

설계 의도:

  • 산출물 생성 이력 추적
  • 같은 프로젝트 다중 버전 관리 (재산출 가능)
  • 다운로드 통계로 사용 현황 파악

2.9 변경 이력 및 감시 (audit_logs, change_logs)

audit_logs (접근 제어 감시)
├── id (PK)
├── user_id (FK → users)
├── action (CREATE, READ, UPDATE, DELETE, EXPORT)
├── entity_type (projects, routes, structures, etc.)
├── entity_id
├── timestamp
├── ip_address
└── details (JSONB)

change_logs (설계 변경 기록)
├── id (PK)
├── project_id (FK → projects)
├── changed_by (FK → users)
├── changed_at
├── entity_type (routes, cross_sections, structures)
├── entity_id
├── old_value (JSONB)
├── new_value (JSONB)
└── reason (사용자 입력 선택)

설계 의도:

  • 보안 감시 (audit_logs)
  • 설계 변경 추적 및 롤백 가능성 (change_logs)

3. 파일시스템 디렉토리 구조

storage/
├── {company_slug}/
│   ├── {user_slug}/
│   │   └── {project_uuid}/
│   │       ├── raw/                          # 입력 원본
│   │       │   ├── las/
│   │       │   ├── tif/
│   │       │   ├── prj/
│   │       │   ├── tfw/
│   │       │   └── dwg_dxf/
│   │       ├── processed/                    # 중간 산출물 (DB에 메타데이터만 저장)
│   │       │   ├── surface/
│   │       │   │   ├── dem_grid_2m.tif
│   │       │   │   ├── tin_mesh.obj / .gltf
│   │       │   │   └── contours.geojson
│   │       │   ├── points/
│   │       │   │   ├── ground_filtered.las
│   │       │   │   └── ground_sampled_10m.ply
│   │       │   └── tiles/
│   │       │       └── (3D Tiles / MVT 렌더링 최적화)
│   │       ├── sections/                    # 단면 데이터 (JSON)
│   │       │   ├── longitudinal.json
│   │       │   ├── cross_0000m.json
│   │       │   ├── cross_0020m.json
│   │       │   └── ...
│   │       └── outputs/                     # 최종 산출물
│   │           ├── estimation/
│   │           │   ├── v1_2025-07-05.xlsx
│   │           │   ├── v2_2025-07-10.xlsx
│   │           │   └── ...
│   │           ├── drawings/
│   │           │   ├── v1_base.dxf
│   │           │   ├── v1_detailed.dxf
│   │           │   └── ...
│   │           ├── reports/
│   │           │   ├── v1_report.pdf
│   │           │   └── ...
│   │           └── bundles/
│   │               ├── v1_20250705.zip    # 완전 묶음
│   │               └── ...
│   └── {project_uuid2}/
│       └── ...
├── temp/                                   # 임시 처리 파일 (일정 기간 후 삭제)
└── cache/                                  # 렌더링 캐시 (3D Tiles, 이미지 타일)

4. 주요 쿼리 패턴 및 인덱스 전략

4.1 자주 사용할 조회 패턴

-- 사용자의 전체 프로젝트 목록 (상태별 필터)
SELECT * FROM projects 
WHERE user_id = :user_id AND deleted_at IS NULL 
ORDER BY created_at DESC;

-- 프로젝트의 최신 경로
SELECT * FROM routes 
WHERE project_id = :project_id AND status IN ('CONFIRMED', 'DRAFT') 
ORDER BY computed_at DESC LIMIT 1;

-- 경로의 횡단면 일괄 조회 (웹 렌더링)
SELECT chainage_m, geometry FROM cross_sections 
WHERE route_id = :route_id AND status = 'CONFIRMED' 
ORDER BY chainage_m;

-- 수량 항목별 비용 집계
SELECT category, SUM(total_price) as subtotal 
FROM quantity_items 
WHERE project_id = :project_id 
GROUP BY category;

-- 공간 범위 쿼리 (지도 렌더링)
SELECT id, geometry FROM routes 
WHERE project_id = :project_id 
AND ST_Intersects(geometry, ST_GeomFromText(:bbox_wkt));

4.2 권장 인덱스

-- 사용자별 프로젝트 조회
CREATE INDEX idx_projects_user_deleted 
ON projects(user_id, deleted_at);

-- 프로젝트별 경로 최신순
CREATE INDEX idx_routes_project_computed 
ON routes(project_id, computed_at DESC);

-- 경로의 횡단면 측점 순
CREATE INDEX idx_cross_sections_route_chainage 
ON cross_sections(route_id, chainage_m);

-- PostGIS 공간 인덱스
CREATE INDEX idx_routes_geometry 
ON routes USING GIST(geometry);

CREATE INDEX idx_cross_sections_geometry 
ON cross_sections USING GIST(geometry);

-- 수량 항목 범위 쿼리
CREATE INDEX idx_quantity_project_category 
ON quantity_items(project_id, category);

-- 감시 로그 시간순
CREATE INDEX idx_audit_logs_timestamp 
ON audit_logs(user_id, timestamp DESC);

5. API 라우터 구조 (FastAPI)

5.1 라우터 계층화

routers/
├── auth.py                     # 인증 (로그인, 회원가입, 토큰 갱신)
├── users.py                    # 사용자 프로필
├── companies.py                # 회사 관리
├── projects.py                 # 프로젝트 CRUD + 상태 관리
├── files.py                    # 파일 업로드/다운로드
├── workflows/
│   ├── wf1_surface.py         # WF1: 지표면 분석 (LAS → DEM/mesh)
│   ├── wf2_route.py           # WF2: 경로 설계
│   ├── wf3_sections.py        # WF3: 종횡단 생성
│   ├── wf4_design.py          # WF4: 상세 설계 (구조물)
│   ├── wf5_quantity.py        # WF5: 수량 산출
│   └── wf6_outputs.py         # WF6: 산출물 생성 (Excel/PDF/DXF)
├── analysis.py                 # 분석 결과 조회 (읽기 전용)
└── admin.py                    # 관리자 기능 (감시 로그 등)

5.2 주요 엔드포인트 예시

POST   /api/auth/register          사용자 가입
POST   /api/auth/login             로그인
GET    /api/users/me               현재 사용자 정보
PATCH  /api/users/{user_id}        프로필 수정

POST   /api/projects               프로젝트 생성
GET    /api/projects               사용자 프로젝트 목록
GET    /api/projects/{proj_id}     프로젝트 상세
PATCH  /api/projects/{proj_id}     프로젝트 수정 (이름, 메모 등)

POST   /api/projects/{proj_id}/files/upload          파일 업로드
GET    /api/projects/{proj_id}/files                 파일 목록

POST   /api/projects/{proj_id}/wf1/analyze           WF1 시작
GET    /api/projects/{proj_id}/wf1/status            WF1 진행률
GET    /api/projects/{proj_id}/wf1/surface-models    생성된 표면

POST   /api/projects/{proj_id}/wf2/calculate-route   WF2 경로 계산
GET    /api/projects/{proj_id}/wf2/routes            경로 목록
PATCH  /api/projects/{proj_id}/wf2/routes/{route_id} 경로 수정

GET    /api/projects/{proj_id}/wf3/cross-sections    횡단면 목록
GET    /api/projects/{proj_id}/wf3/sections/{ch}     특정 측점 상세

POST   /api/projects/{proj_id}/wf4/structures        구조물 추가
PATCH  /api/projects/{proj_id}/wf4/structures/{id}   구조물 수정

GET    /api/projects/{proj_id}/wf5/quantities        수량 항목
PATCH  /api/projects/{proj_id}/wf5/quantities/{id}   수량 수정

POST   /api/projects/{proj_id}/wf6/generate-output   산출물 생성
GET    /api/projects/{proj_id}/outputs               산출물 목록
GET    /api/projects/{proj_id}/outputs/{id}/download 다운로드

POST   /api/projects/{proj_id}/confirm               프로젝트 확정

6. 비동기 작업 및 백그라운드 처리 (Celery / asyncio)

6.1 장시간 작업 큐

작업 목록:
1. WF1 분석 (LAS 필터링 → 지형 변환) — 수십 분
2. WF2 경로 계산 (최적화 알고리즘) — 수 분
3. WF6 산출물 생성 (DXF/Excel/PDF) — 수 분

구현 방식:
- Celery + Redis (프로덕션)
  또는
- FastAPI BackgroundTasks + asyncio (초기 단계)

상태 추적:
- jobs 테이블에 task_id, status, progress, error_msg 저장
- WebSocket 또는 polling으로 진행률 클라이언트에 전송

7. 마이그레이션 및 테이블 생성 전략

7.1 alembic 기반 버전 관리

alembic/
├── versions/
│   ├── 001_initial_schema.py      (users, companies, projects)
│   ├── 002_spatial_tables.py      (routes, cross_sections, PostGIS)
│   ├── 003_audit_and_logs.py      (audit_logs, change_logs)
│   └── ...
└── env.py

7.2 초기 마이그레이션 단계

  1. 사용자 / 회사 / 프로젝트 (로그인 후 필수)
  2. 입력 파일 메타데이터 (파일 업로드 후 필수)
  3. 경로 / 단면 / 구조물 (워크플로우 실행 후 필수)
  4. 감시 로그 (선택, 나중에 추가 가능)

8. 데이터 일관성 및 검증 규칙

8.1 데이터 무결성 제약

-- 외래키 제약
ALTER TABLE projects 
ADD CONSTRAINT fk_projects_user FOREIGN KEY (user_id) 
REFERENCES users(id) ON DELETE RESTRICT;

-- Unique 제약
ALTER TABLE users ADD CONSTRAINT uq_users_email UNIQUE(email);
ALTER TABLE companies ADD CONSTRAINT uq_companies_name UNIQUE(name);

-- Check 제약 (상태 머신)
ALTER TABLE projects ADD CONSTRAINT check_project_status 
CHECK (status IN ('NEW', 'ANALYZING', 'WF1_COMPLETE', ..., 'DONE'));

8.2 좌표계 검증

# Python 유효성 검사
from pyproj import CRS

def validate_crs(epsg_code: int):
    try:
        crs = CRS.from_epsg(epsg_code)
        return True
    except:
        raise ValueError(f"Invalid EPSG code: {epsg_code}")

# 좌표 변환 시 예외 처리
def transform_coordinates(src_epsg, tgt_epsg, coords):
    transformer = Transformer.from_crs(f"EPSG:{src_epsg}", f"EPSG:{tgt_epsg}")
    return transformer.transform(coords.x, coords.y)

8.3 입력 파일 검증

# 파일 타입 검증
ALLOWED_EXTENSIONS = {
    'las': laspy.read,
    'tif': rasterio.open,
    'prj': lambda f: f.read().decode('utf-8'),
    'dxf': ezdxf.readfile,
}

# 파일 크기 제한 (config에서 읽기)
MAX_FILE_SIZE_MB = 500

def validate_upload(file, file_type):
    if file.size > MAX_FILE_SIZE_MB * 1024 * 1024:
        raise ValueError(f"File too large: {file.size / 1024 / 1024:.1f}MB")

9. 초기 vs 장기 구현 로드맵

Phase 1 (초기, 회원가입 MVP — 2-3주)

필수 테이블: users, companies, projects, input_files, audit_logs
API: 인증, 프로젝트 CRUD, 파일 업로드
워크플로우: 파일 입력(B03)까지만 DB 연동

Phase 2 (WF1-WF3, 분석 — 4-6주)

추가 테이블: surface_models, routes, cross_sections, change_logs
API: WF1 분석 시작, 경로 계산, 단면 조회
백그라운드: Celery 작업 큐 도입

Phase 3 (WF4-WF6, 산출물 — 6-8주)

추가 테이블: structures, quantity_items, outputs, output_files
API: 구조물 추가, 수량 산출, 산출물 생성
기능: Excel/PDF/DXF 자동 생성

Phase 4 (협업 및 감시, 선택)

추가 기능: 팀 공유 프로젝트, 권한 세분화, 비용 청구
감시: audit_logs 기반 컴플라이언스 리포트


10. 보안 및 성능 고려사항

10.1 보안

  • 인증: JWT 토큰 (httponly cookie)
  • 권한: user_id 기반 row-level security (RLS) + 애플리케이션 검증
  • 파일 접근: 서명된 URL 또는 토큰 검증
  • 감시: audit_logs에 모든 수정 기록
  • SQL injection 방지: ORM (SQLAlchemy) + 파라미터화된 쿼리

10.2 성능 최적화

  • 쿼리: 인덱스 전략 (위 4.2 참고)
  • 캐싱: Redis에 자주 조회하는 메타데이터 캐시 (설정값, 사용자 권한 등)
  • 파일 저장소: 클라우드 스토리지 옵션 (AWS S3, GCS) 고려
  • 3D 렌더링: LOD/타일링으로 대용량 지형 최적화
  • 비동기: 장시간 작업은 백그라운드 큐에서 처리

10.3 백업 및 복구

  • DB 백업: 일 1회 자동 백업 (point-in-time recovery)
  • 파일 백업: 중요 산출물은 별도 저장소에 복제
  • 버전 관리: change_logs로 프로젝트 상태 롤백 가능

11. 검토 항목 및 다음 단계

체크리스트

  • ERD(Entity-Relationship Diagram) 작성 및 리뷰
  • 좌표계 변환 로직 검증 (EPSG 코드)
  • 파일 저장소 정책 확정 (로컬 vs 클라우드)
  • 권한 모델 세밀화 (팀 공유 필요성 판단)
  • 비용 청구 로직 정의 (필요 시)
  • 성능 테스트 (대용량 파일, 대량 사용자)
  • 법적 데이터 보관 기간 확인

다음 작업

  1. ERD 다이어그램 생성 — dbdiagram.io 또는 draw.io
  2. alembic 마이그레이션 초안 작성 — Phase 1 테이블부터
  3. FastAPI 모델(Pydantic) 정의 — 입력/출력 스키마
  4. API 문서(OpenAPI) — Swagger 자동 생성
  5. 테스트 DB 구성 — 로컬 PostgreSQL + 샘플 데이터

12. 참고: 구현 언어 & 도구

영역 도구 용도
ORM SQLAlchemy 2.0 + asyncpg async DB 쿼리
마이그레이션 Alembic DB 버전 관리
검증 Pydantic v2 입력 데이터 검증
공간 쿼리 GeoAlchemy2 + PostGIS 기하학 연산
비동기 Celery + Redis 또는 FastAPI BackgroundTasks 장시간 작업
파일 처리 laspy, rasterio, geopandas, ezdxf 공간 데이터
문서 생성 openpyxl, reportlab, ezdxf Excel/PDF/DXF 출력

이 제안서는 기초 설계 단계입니다. 다음 리뷰에서 변경, 추가, 삭제 사항을 정리한 후 ERD 및 마이그레이션 코드로 구체화하겠습니다.