feat(B03): 새 자료로 갈기 전에 「지우고 진행할까」 확인 한 단계 신설

업로드 하나가 그 프로젝트의 설계 산출물·초기값 스냅숏을 되돌릴 수 없게 지운다.
창 넷이 한 프로젝트를 볼 수 있어 말없이 지우면 남의 작업이 사라진다.

- `describe_existing_outputs`: 지워질 것을 사람 말로 낸다(전처리·노선·횡단·도면·
  수량·원가·초기값). 빈 폴더는 세지 않는다.
- 지울 것이 있는데 확인이 없으면 409 `confirm_required` — 무엇이 지워지는지 함께 준다.
- 세 갈래(직행·청크·보관함 연결) 전부에 `confirm_replace` 를 붙임.
- ⚠ 기본값은 확인 켬(True) — 자동 절차(체인·스크립트)는 물음에 안 걸린다.
  사람이 올리는 라우터만 False 로 불러 확인을 받는다.
- 화면: 409 를 받으면 「되돌릴 수 없습니다」와 지워질 목록을 보이고 한 번 묻는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-08 18:14:54 +09:00
co-authored by Claude Opus 5
parent d57c0f71ce
commit 09e1c983ae
7 changed files with 181 additions and 16 deletions
+10 -1
View File
@@ -59,6 +59,10 @@ from B03_FileInput.B03_FileInput_Router_Helpers import (
from B03_FileInput.B03_FileInput_Router_Helpers import (
_SHAPEFILE_REQUIRED_TYPES as _SHAPEFILE_REQUIRED_TYPES,
)
from B03_FileInput.B03_FileInput_Router_Helpers import (
OutputsWouldBeDiscarded,
_confirm_replace_response,
)
from B03_FileInput.B03_FileInput_Router_Helpers import (
_already_uploaded as _already_uploaded,
)
@@ -132,6 +136,7 @@ async def upload_project_files(
project_id: UUID,
files: list[UploadFile] = File(...),
las_free: bool = Form(False),
confirm_replace: bool = Form(False),
session: dict[str, Any] = Depends(verify_session),
) -> FileUploadResponse | JSONResponse:
"""프로젝트 입력 파일을 저장·분석하고 DB 메타데이터를 기록한다."""
@@ -258,7 +263,7 @@ async def upload_project_files(
)
)
point_cloud_input_id = await _complete_file_input_if_ready(
connection, project_id, las_free
connection, project_id, las_free, confirm_replace
)
await connection.commit()
except Exception:
@@ -282,6 +287,10 @@ async def upload_project_files(
task_name=f"b04-preprocess-auto-{project_id}",
)
return FileUploadResponse(project_id=str(project_id), files=results)
except OutputsWouldBeDiscarded as exc:
for saved_path in saved_paths:
saved_path.unlink(missing_ok=True)
return _confirm_replace_response(exc)
except LookupError as exc:
return lookup_error_response(exc, logger, context="B03 업로드", project_id=project_id)
except (OSError, ValueError) as exc: