feat(B01): 임시 보관함 UI를 그룹+파일 리스트 컨테이너로 개편

프로젝트/사용자 관리 컨테이너와 같은 형태로 통일한다. 등록 폼을 화면에 상시
노출하지 않고, 우측 상단 [+] 모달로 받아 그룹(임시 프로젝트명) 아래 파일 표를
그린다.

프론트엔드
- B01_Dashboard_UI_TempModal.ts 신설: 등록/추가 모달(임시 프로젝트명 + 파일 선택,
  고른 파일을 모달 안 표로 표시, 하단 [취소][확인] — 기존 대시보드 모달과 동일 규격)
- B01_Dashboard_UI_TempUpload.ts: 섹션 전체(제목·[+]·목록)를 반환하도록 변경.
  그룹 카드 + 파일 표(종류/파일명/크기/상태/작업), 그룹별 [파일 추가],
  파일별 [삭제], 진행률은 해당 파일 행 안에서 표시
- 청크마다 목록을 다시 조회하지 않고 막대 DOM만 갱신하도록 정리
- 대시보드 배치: 프로젝트 컨테이너 바로 아래(역할 3분기 모두)

백엔드
- DELETE /api/temp-uploads/{batch_id}/files/{file_type}: DB 행과 임시 저장소
  실제 파일을 함께 삭제. 필수 파일이 빠지면 상태를 uploading으로 되돌리고
  만료일은 최초 완료 시점 기준을 유지

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-08 13:23:58 +09:00
co-authored by Claude Fable 5
parent 17834d8189
commit f60ecc255f
9 changed files with 601 additions and 192 deletions
@@ -178,6 +178,63 @@ async def upsert_temp_batch_file(
)
async def get_temp_batch_file(
connection: aiomysql.Connection,
*,
batch_id: str,
file_type: str,
) -> dict[str, Any]:
"""묶음 안 파일 1건(종류로 지정). 삭제 전 실제 저장 경로를 알아내는 용도."""
async with connection.cursor(aiomysql.DictCursor) as cursor:
await cursor.execute(
"""
SELECT batch_id, file_type, original_filename, relative_path, file_size_bytes
FROM temp_upload_files
WHERE batch_id = %s AND file_type = %s
""",
(batch_id, file_type),
)
row = await cursor.fetchone()
if not row:
raise LookupError("보관함 파일을 찾을 수 없습니다.")
return dict(row)
async def delete_temp_batch_file(
connection: aiomysql.Connection,
*,
batch_id: str,
file_type: str,
) -> None:
"""묶음 안 파일 1건 삭제(행만 — 실제 파일은 라우터가 지운다)."""
async with connection.cursor() as cursor:
await cursor.execute(
"DELETE FROM temp_upload_files WHERE batch_id = %s AND file_type = %s",
(batch_id, file_type),
)
async def mark_temp_batch_incomplete(
connection: aiomysql.Connection,
*,
batch_id: str,
) -> None:
"""필수 파일이 빠지면 다시 '업로드 중'으로 되돌린다.
만료일(`expires_at`)은 손대지 않는다 — 보관 기한은 **처음 완료 시점** 기준이고,
파일을 지웠다 다시 올리는 것으로 기한이 늘어나면 안 된다.
"""
async with connection.cursor() as cursor:
await cursor.execute(
"""
UPDATE temp_upload_batches
SET status = 'uploading'
WHERE id = %s AND status = 'completed'
""",
(batch_id,),
)
async def get_temp_batch_file_types(
connection: aiomysql.Connection,
*,