6.2 KiB
6.2 KiB
백엔드 제어 명세서 (backend.md)
1. 아키텍처 및 라우팅 (Architecture)
- 수직 통합: 백엔드 로직은 페이지 폴더(
A01_,B01_등)별로 격리. 거대 단일 모듈 금지. - 파일 분할: 파일 수 제한 없음. 코드 집중 방지를 위해 기능별 분할 자율화.
- 파일명 규칙:
[폴더명]_Router.py,[폴더명]_Engine.py,[폴더명]_Schema.py형태 준수. - 루트 main.py: 라우터 등록(
include_router)만 수행. 비즈니스 로직 작성 금지.
2. DB 및 MariaDB (Database)
- 비동기 통신:
async/await및aiomysql드라이버 사용 강제. (asyncmy는 Cython 빌드 필요로 Windows 환경 미채택) - 쿼리 방식: ORM 사용 금지. Raw SQL 작성 원칙. 파라미터 바인딩은
%s플레이스홀더 사용. - 커넥션/트랜잭션: 풀에서
pool.acquire()로 커넥션 확보 후connection.cursor()로 커서 생성. 다건 쓰기는connection.begin()→commit()/ 예외 시rollback(). - 자동 증가 ID:
INSERT후cursor.lastrowid로 조회 (PostgreSQL의RETURNING id미지원). - 공간 데이터: GEOMETRY 타입 미지원. 좌표, 다각형, 경로 등은 JSON 형식으로 저장 후 애플리케이션에서 처리.
3. 설정 및 저장소 (Config & Storage)
- 하드코딩 금지: 제어 변수/파라미터 하드코딩 금지.
config/config_system.py에서import필수. - 물리 파일 격리: 포인트 클라우드, 분석 중간 파일, 메쉬, 임시 커서는 DB 저장 금지.
- 저장 경로:
storage/[고객사명]/[사용자명]/[프로젝트ID]/에 물리 파일 저장 후 DB에는 경로만 기록. - 단계별 루트 강제: 프로젝트 저장소 내부는 실제 워크플로우 페이지명과 동일한
B03_FileInput/~B09_wf6_Estimation/폴더로 분리한다.raw/,processed/,computed/를 프로젝트 루트의 공용 폴더로 만들지 않는다. - 경로 정의 우선순위: 단계별 세부 폴더와 DB 경로 열의 기준은
.agent/db_schema_simple.md의 「파일시스템 경로와 DB 링크」를 따른다. - 경로 생성 책임: 페이지별 백엔드는 자기 단계 폴더만 생성·수정한다. 다른 단계의 산출물을 직접 삭제하거나 덮어쓰지 않고 stale 상태를 통해 재계산 필요성을 전파한다.
- DB 저장 형식: DB에는 프로젝트 루트 기준 상대 경로를 기록하고, 실제 파일 접근 시 설정의 저장소 루트와 안전하게 결합한다. 사용자 입력 경로를 직접 결합하거나 절대 경로를 DB에 저장하지 않는다.
- MariaDB 특성:
- 공간 기하 데이터(좌표, 폴리곤, 경로 등)는 GEOMETRY 타입 미지원 → JSON 또는 TEXT로 저장
- 예:
{"type": "Point", "coordinates": [127.5, 37.5]}(GeoJSON 형식) - 애플리케이션(Python)에서 JSON 파싱 후 기하 연산 처리
4. 검증 및 예외 처리 (Error Handling)
- 데이터 검증: 모든 JSON 요청은 라우터 진입 전 Pydantic 모델로 타입/범위 필수 검증.
- 예외 포획: 모든 지형/메쉬 연산은
try-except필수 처리. - 반환 포맷: 에러 발생 시
{"status": "error", "message": "원인"}표준 포맷 반환.
5. 워크플로우 상태 동기화 (Workflow State Sync)
5.1 다중 브라우저 동시 작업 원칙
- 브라우저 독립성: 같은 계정/프로젝트를 여러 브라우저에서 동시 접근 가능. 각 브라우저는 서버 데이터 기반 독립 작동.
- 클라이언트 상태 격리:
localStorage는 브라우저별 격리(도메인 단위 공유). 공유 데이터는 항상 서버 영구저장소 우선. - 영구저장소 설계: 계산 결과는
.agent/db_schema_simple.md에 정의된 페이지별 단계 폴더에 저장한다.B03_FileInput/— 원본 입력 및 파일 메타데이터B04_wf1_Surface/— 변환 포인트클라우드, 지표면 모델 및 분석 결과B05_wf2_Route/— 경로, 경로점 및 설계 파라미터B06_wf3_ProfileCross/— 종단·횡단 결과 및 인덱스
- 워크플로우 상태: 여러 단계가 공유하는
workflow.json의 실제 위치는 저장소 경로 유틸에서 단일하게 정의하며, 원자적 쓰기를 적용한다. 단계별 결과 파일의 위치를 프로젝트 루트의result_*.json이름으로 추정하지 않는다.
5.2 Stale 상태 감지 및 전파
- workflow.json 구조:
{ "current_stage": "route", "completed": ["scan", "surface"], "stale_from": "route", "stage1_confirmed": {...} } - Stale 발생 조건:
- 상위 단계(예: surface) 재계산 → 하위 단계(route, section) 자동으로
stale_from설정 - 다른 브라우저에서 변경 감지 → 기존 결과 무효화
- 상위 단계(예: surface) 재계산 → 하위 단계(route, section) 자동으로
- 상태 업데이트 함수:
def _patch_workflow_stale(project_id: str, stale_from: str | None) -> None: """workflow.json의 stale_from 필드만 원자적 업데이트""" wf_path = get_project_workflow_path(project_id) # 기존 상태 유지하며 stale_from만 변경
5.3 클라이언트 폴링 패턴 (Polling)
- 주기: GET
/api/projects/{project_id}/workflow— 3초마다 호출 - 응답: workflow.json 전체 반환 (현재 단계, 완료 이력, stale 상태 포함)
- 클라이언트 동작:
- stale 감지 → 사용자에게 선택지 제시
- "계속하기" → 기존 결과 유지 (위험 경고)
- "재계산하기" → 상위 단계 재실행 (모든 하위 결과 초기화)
- 구현 예시:
setInterval(async () => { const workflow = await fetch(`/api/projects/${projectId}/workflow`); if (workflow.stale_from && workflow.stale_from !== currentStage) { handleStaleness(workflow.stale_from); // 사용자에게 알림 } }, 3000);
5.4 WebSocket 확장 (미래 선택사항)
- 실시간 알림: 폴링 대신 WebSocket으로 업그레이드 가능 (응답성 향상)
- 전송 메시지:
{ "type": "workflow_changed", "project_id": "...", "stale_from": "route", "changed_by": "other_browser" } - 마이그레이션 시기: 사용자 수 증가 또는 실시간성 요구 시 적용