diff --git a/backend/app/config.py b/backend/app/config.py index 2edf067..c963867 100644 --- a/backend/app/config.py +++ b/backend/app/config.py @@ -26,7 +26,8 @@ class Settings(BaseSettings): s3_bucket: str = "aramesh-media" # پیشوند عمومی مسیر تصاویر — Traefik آن را به باکت پروکسی می‌کند media_public_base: str = "/media" - media_max_upload_mb: int = 10 + # رندرهای معماری حجیم‌اند — لبه (Traefik api-bodylimit) باید همیشه بزرگ‌تر از این باشد + media_max_upload_mb: int = 25 # نشانی کامل سایت (مثل https://aramesh.example) — برای sitemap و آدرس مطلق OG site_url: str = "" diff --git a/frontend/src/admin/adminClient.ts b/frontend/src/admin/adminClient.ts index c3600a4..2a0a5bc 100644 --- a/frontend/src/admin/adminClient.ts +++ b/frontend/src/admin/adminClient.ts @@ -3,6 +3,9 @@ import { API_URL } from '../config' const TOKEN_KEY = 'aramesh_admin_token' +/** سقف آپلود — هم‌اندازهٔ media_max_upload_mb بک‌اند (تنظیمات) */ +const MAX_UPLOAD_BYTES = 25 * 1024 * 1024 + /** رویداد تغییر وضعیت ورود — لایه‌های دیگر (مثل نوار ادمین) با آن همگام می‌مانند */ export const AUTH_CHANGE_EVENT = 'aramesh:auth-change' @@ -43,9 +46,11 @@ async function authFetch(path: string, options: RequestInit = {}): Promise const detail = typeof data?.detail === 'string' ? data.detail - : res.status === 409 - ? 'رکوردی با این مقدار تکراری وجود دارد' - : 'خطا در ذخیره‌سازی — دوباره تلاش کنید' + : res.status === 413 + ? 'حجم فایل بیش از حد مجاز است (حداکثر ۲۵ مگابایت)' + : res.status === 409 + ? 'رکوردی با این مقدار تکراری وجود دارد' + : 'خطا در ذخیره‌سازی — دوباره تلاش کنید' throw new HttpError(res.status, detail) } return res.status === 204 ? (null as T) : ((await res.json()) as T) @@ -88,6 +93,10 @@ export const adminApi = { authFetch(`/api/admin/${resource}/reorder`, { method: 'POST', body: JSON.stringify({ ids }) }), upload: async (file: File, name?: string): Promise<{ url: string; key: string }> => { + // پیش‌چک سمت کاربر — خطای ۴۱۳ لبه/CDN به‌صورت صفحه HTML می‌رسد و پیام خاص از دست می‌رود + if (file.size > MAX_UPLOAD_BYTES) { + throw new HttpError(413, 'حجم فایل بیش از ۲۵ مگابایت است — فایل را کوچک‌تر کنید') + } const fd = new FormData() fd.append('file', file) if (name && name.trim()) fd.append('name', name.trim())