From 0b511a8db05c3e3bb37d4816691942431c02da4e Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Thu, 9 Apr 2026 14:24:13 +0900 Subject: [PATCH] =?UTF-8?q?fix(upload):=20100MB=20=EC=B4=88=EA=B3=BC=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=82=AC=EC=A0=84=20=EC=B0=A8=EB=8B=A8=20?= =?UTF-8?q?+=20NAS=20file=5Fwatcher=20=EC=95=88=EB=82=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit home-caddy 의 request_body max_size 100MB 한도 (infra_inventory.md D8 / Cloudflare 섹션 참조) 에 걸리는 업로드 시 사용자 콘솔에 의미 없는 413 만 나오던 문제. 이제: 1. 클라이언트 사전 검사: 100MB 초과 파일은 업로드 자체를 시도 안 하고 즉시 toast 로 안내 (파일명 + 크기 + NAS 우회 경로) 2. 서버 fallback: 사전 검사를 통과했으나 인프라 한도에 걸려 413 응답이 오는 경우에도 같은 안내 메시지 NAS 우회 경로: NAS 의 PKM 폴더에 직접 두면 file_watcher 가 5분 간격으로 자동 인덱싱. 이게 100MB+ 파일의 정식 처리 경로 (infra_inventory.md Cloudflare 섹션의 413 정책). --- .../src/lib/components/UploadDropzone.svelte | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/frontend/src/lib/components/UploadDropzone.svelte b/frontend/src/lib/components/UploadDropzone.svelte index 6c44e6b..dea01ef 100644 --- a/frontend/src/lib/components/UploadDropzone.svelte +++ b/frontend/src/lib/components/UploadDropzone.svelte @@ -6,6 +6,11 @@ let { onupload = () => {} } = $props(); + // home-caddy `request_body max_size 100MB` (infra_inventory.md D8 / Cloudflare 섹션 참조). + // 100MB 초과 파일은 NAS PKM 폴더 직접 마운트 → file_watcher 5분 간격 자동 인덱싱 경로 사용. + const MAX_UPLOAD_BYTES = 100 * 1024 * 1024; + const NAS_FALLBACK_HINT = '대용량 파일은 NAS의 PKM 폴더에 직접 두면 file_watcher 가 5분 이내에 자동 인덱싱합니다.'; + let dragging = $state(false); let uploading = $state(false); let uploadFiles = $state([]); @@ -56,7 +61,24 @@ }); async function handleFiles(fileList) { - const files = Array.from(fileList || []); + const allFiles = Array.from(fileList || []); + if (allFiles.length === 0) return; + + // 사전 크기 검사 — 100MB 초과는 즉시 차단 + NAS file_watcher 안내 + const tooLarge = allFiles.filter(f => f.size > MAX_UPLOAD_BYTES); + const files = allFiles.filter(f => f.size <= MAX_UPLOAD_BYTES); + + if (tooLarge.length > 0) { + const names = tooLarge + .map(f => `${f.name} (${(f.size / 1024 / 1024).toFixed(1)}MB)`) + .join(', '); + addToast( + 'error', + `100MB 초과 파일은 업로드 불가 (${tooLarge.length}건: ${names}). ${NAS_FALLBACK_HINT}`, + 10000 + ); + } + if (files.length === 0) return; uploading = true; @@ -78,6 +100,14 @@ } catch (err) { uploadFiles[i].status = 'failed'; failed++; + // 서버 측 413 (사전 검사 통과했지만 인프라 한도에 걸린 경우) + if (err && err.status === 413) { + addToast( + 'error', + `${files[i].name}: 서버 거절 (Payload Too Large). ${NAS_FALLBACK_HINT}`, + 10000 + ); + } } uploadFiles = [...uploadFiles]; }