임동욱 임동욱 08-19
merge: 첨부파일 크기 사전 차단
@6ccc2228fcc8be5baec7ba586e28acd02f60111a
app/(protected)/(basic)/boards/_components/board-attachment-field.tsx
--- app/(protected)/(basic)/boards/_components/board-attachment-field.tsx
+++ app/(protected)/(basic)/boards/_components/board-attachment-field.tsx
@@ -1,6 +1,9 @@
 'use client';
 
+import { useState } from 'react';
+import { FoxHelperText } from '@fox/core/components/fox-helper-text';
 import { Field } from '@/components/ui/field';
+import { MAX_ATTACHMENT_BYTES } from '@/lib/data/repositories/file-repository';
 
 interface BoardAttachmentFieldProps {
   label?: string;
@@ -23,10 +26,16 @@
  * 새 파일을 고르면 기존 첨부는 교체된다(백엔드 필드가 `atchFileId` 하나뿐이다). 파일을 고르지
  * 않으면 기존 첨부가 그대로 유지된다.
  */
+const OVERSIZE_MESSAGE = `첨부파일은 ${Math.floor(
+  MAX_ATTACHMENT_BYTES / (1024 * 1024)
+)}MB 이하만 올릴 수 있습니다.`;
+
 export function BoardAttachmentField({
   label = '첨부파일',
   attachmentId,
 }: BoardAttachmentFieldProps) {
+  const [error, setError] = useState<string | undefined>(undefined);
+
   return (
     <Field label={label}>
       {/* 기존 첨부 id를 함께 제출해 "파일을 안 골랐으면 유지"를 서버가 판단할 수 있게 한다. */}
@@ -45,11 +54,23 @@
         </p>
       ) : null}
 
+      {/* 이슈: 상한을 넘는 파일은 Server Action 본문이 잘려 500으로 끝나고 액션이 실행되지
+          않는다. 서버에서 잡을 수 없어 브라우저에서 미리 막는다. */}
       <input
         type="file"
         name="attachment"
         className="w-full text-body-sm text-foreground file:mr-3 file:rounded-md file:border file:border-border file:bg-surface file:px-3 file:py-1.5 file:text-body-sm file:text-foreground"
+        onChange={(event) => {
+          const file = event.target.files?.[0];
+          if (file && file.size > MAX_ATTACHMENT_BYTES) {
+            event.target.value = '';
+            setError(OVERSIZE_MESSAGE);
+            return;
+          }
+          setError(undefined);
+        }}
       />
+      {error && <FoxHelperText type="danger" message={error} />}
     </Field>
   );
 }
next.config.ts
--- next.config.ts
+++ next.config.ts
@@ -22,7 +22,9 @@
 const nextConfig: NextConfig = {
   experimental: {
     serverActions: {
-      bodySizeLimit: '10mb',
+      // 이슈: 앱의 파일 상한(첨부 10MB)보다 반드시 커야 한다. 같거나 작으면 초과 파일이 413으로
+      // 잘려 액션이 실행되지 않고, 우리가 준비한 "10MB 이하만" 메시지 대신 처리 불가한 오류가 뜬다.
+      bodySizeLimit: '20mb',
     },
   },
 
Add a comment
List