diff --git a/backend/src/routes/admin.js b/backend/src/routes/admin.js index 5e76aaf..3093c70 100644 --- a/backend/src/routes/admin.js +++ b/backend/src/routes/admin.js @@ -89,7 +89,7 @@ function buildItemLabelFromSrc(src) { return normalized || 'item' } -const upload = createMemoryUpload(multer, { fileSize: 8 * 1024 * 1024, maxCount: 50 }) +const upload = createMemoryUpload(multer, { fileSize: 20 * 1024 * 1024, maxCount: 100 }) const avatarUpload = createMemoryUpload(multer, { fileSize: 4 * 1024 * 1024 }) function decorateAdminUser(user, primaryAdmin) { @@ -199,7 +199,7 @@ router.post('/templates/:templateId/thumbnail', requireAdmin, upload.single('thu res.json({ template: updated }) }) -router.post('/templates/:templateId/images', requireAdmin, upload.array('images', 50), async (req, res) => { +router.post('/templates/:templateId/images', requireAdmin, upload.array('images', 100), async (req, res) => { const files = Array.isArray(req.files) ? req.files : [] if (!files.length) return res.status(400).json({ error: 'file_required' }) const templateId = getTemplateIdFromParams(req) diff --git a/docs/history.md b/docs/history.md index 6ea6d8b..167b988 100644 --- a/docs/history.md +++ b/docs/history.md @@ -1,5 +1,9 @@ # 의사결정 이력 +## 2026-04-03 v1.4.41 +- 관리자 기본 아이템 업로드는 운영자가 한 번에 많은 캐릭터 이미지를 정리하는 작업이 잦으므로, 서버 개별 파일 제한뿐 아니라 한 요청당 업로드 개수와 프록시 본문 크기 제한도 같이 넉넉하게 올려두는 편이 맞다고 판단했다. +- 다중 업로드가 프런트에서 한 번의 `FormData` 요청으로 묶여 나가는 구조라면, 백엔드 `multer`만 올리고 Nginx `client_max_body_size`를 그대로 두면 병목이 남을 수 있으므로 프런트 프록시 제한도 함께 상향하는 쪽으로 정리했다. + ## 2026-04-03 v1.4.40 - 공유 링크 진입 화면은 사용자가 조작 가능한 편집 화면보다 `뷰어 모드`로 명확히 분리하는 편이 안전하므로, 비로그인 사용자와 타인 티어표는 기본적으로 드래그 없는 완성본 열람 상태를 보여주기로 정리했다. - 공유 링크를 받은 비로그인 사용자도 다시 전달할 수 있어야 하므로 `공유하기`는 로그인 여부와 무관하게 뷰어 모드에서 열어두고, `내 티어표로 복사`는 로그인한 타인 열람자에게만 노출하는 쪽으로 권한을 나눴다. diff --git a/docs/spec.md b/docs/spec.md index 1c12436..71e88ef 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -135,7 +135,7 @@ - `POST /api/admin/templates` - `POST /api/admin/templates/:templateId/thumbnail` - `POST /api/admin/templates/:templateId/images` - - 여러 이미지를 한 번에 업로드할 수 있고, 별도 라벨이 없으면 파일명 기준으로 기본 아이템 이름을 만든다. + - 여러 이미지를 한 번에 최대 `100개`까지 업로드할 수 있고, 별도 라벨이 없으면 파일명 기준으로 기본 아이템 이름을 만든다. - `PATCH /api/admin/templates/:templateId/items/:itemId` - `GET /api/admin/tierlists` - `GET /api/admin/template-requests` @@ -220,7 +220,9 @@ ## 업로드 제한 메모 - 프로필 아바타 업로드는 파일당 최대 `3MB`다. -- 관리자 게임 썸네일/기본 아이템 업로드와 사용자 커스텀 이미지 업로드는 파일당 최대 `6MB`다. +- 관리자 템플릿 썸네일/기본 아이템 업로드는 파일당 최대 `20MB`다. +- 사용자 커스텀 이미지 업로드는 파일당 최대 `6MB`다. +- 운영 프런트 Nginx는 다중 이미지 업로드 한 번의 요청 본문을 최대 `1024MB`까지 허용한다. - 현재는 업로드 전에 이미지 리사이즈/압축을 하지 않고 원본 파일을 그대로 저장한다. ## 운영 환경 변수 diff --git a/docs/todo.md b/docs/todo.md index 3d85e95..d87dafc 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -1,6 +1,8 @@ # 할 일 및 이슈 ## 단기 확인 +- `v1.4.41`에서 관리자 템플릿 기본 아이템 다중 업로드를 `100개/파일당 20MB`와 Nginx `client_max_body_size 1024m`으로 올렸으므로, 운영 NAS 앞단 리버스 프록시에도 별도 본문 크기 제한이 있으면 같은 수준으로 맞춰야 하는지 확인한다. +- 실제 QA에서는 10개 이상, 50개 이상, 100개 근처의 이미지 묶음을 한 번에 올렸을 때 브라우저/프런트 Nginx/백엔드 중 어느 단계에서도 `413`이나 업로드 실패가 나지 않는지 확인한다. - `v1.4.40`에서 `preview=1` 공유 화면을 뷰어 모드로 정리했으므로, 비로그인/로그인한 타인/작성자 본인 세 경우에 드래그 편집이 막히고 오른쪽 레일 버튼이 각각 `공유하기`, `내 티어표로 복사`, `수정 모드로 전환` 조건대로 노출되는지 확인한다. 특히 비로그인/타인이 일반 편집 URL로 직접 들어왔을 때도 자동으로 `preview=1`로 바뀌는지 본다. - 작성자 본인 편집 화면에는 `뷰어 모드로 보기`가 추가됐으므로, 저장된 본인 티어표에서 뷰어 모드로 진입한 뒤 다시 `수정 모드로 전환`으로 돌아오는 왕복 라우팅이 자연스러운지 QA한다. - 뷰어 모드 오른쪽 레일이 공통 로컬 레일 마운트를 다시 사용하게 바뀌었으므로, 데스크톱/태블릿 폭에서 광고가 상단에 나오고 액션 카드가 하단으로 내려가며, 우측 레일 접기/펼치기 시 콘텐츠가 깨지지 않는지 확인한다. diff --git a/docs/update.md b/docs/update.md index 6cf391b..a1fff00 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,5 +1,9 @@ # 업데이트 로그 +## 2026-04-03 v1.4.41 +- 관리자 템플릿 기본 아이템 다중 업로드 제한을 한 번에 `100개`, 파일당 `20MB`까지 받을 수 있도록 백엔드 `multer` 설정과 업로드 라우트 배열 제한을 함께 상향했다. +- 프런트 Nginx 프록시에도 `client_max_body_size 1024m`을 추가해, 여러 이미지를 한 번의 `FormData` 요청으로 올릴 때 합산 본문 크기 제한 때문에 먼저 `413`으로 막히는 상황을 줄였다. + ## 2026-04-03 v1.4.40 - 공유 링크로 여는 `preview=1` 화면을 `뷰어 모드`로 정의하고, 드래그/편집 없이 완성본만 보이는 상태에서 오른쪽 레일 상단에는 광고, 하단에는 공유·복사·수정 전환 액션을 노출하도록 정리했다. - 비로그인 사용자나 작성자 본인이 아닌 사용자가 일반 편집 URL로 저장된 티어표를 직접 열어도 자동으로 `preview=1` 뷰어 모드 주소로 전환되도록 로딩 후 라우팅을 보정했다. diff --git a/frontend/nginx.conf b/frontend/nginx.conf index 9ef451e..d83a404 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -1,6 +1,7 @@ server { listen 80; server_name _; + client_max_body_size 1024m; root /usr/share/nginx/html; index index.html;