معماری بکاند Server-First و مرزهای تایپشده سرویسها
معماری بکاند مبتنی بر Server Actions، درگاههای تایپشده Hono، اعتبارسنجی سختگیرانه، مدیریت امن نشستها و مسیر اجرای async برای رشد مقیاس
Server Actions به عنوان مرز Mutation محصول
مسیر کوتاهتر از نیت کاربر تا mutation اعتبارسنجیشده سمت سرور
Server Actions جایگزین مد روز برای تمام APIها نیستند؛ مرزی دقیق برای mutationهایی هستند که به رابط محصول نزدیکاند. وقتی کاربر فرم ارسال میکند، تنظیمی را تغییر میدهد یا یک دستور دامنهای را اجرا میکند، سرور میتواند همان intent را مستقیم دریافت کند، اعتبارسنجی کند، mutation را اجرا کند و بخشهای وابسته UI را در یک roundtrip کنترلشده تازه کند. ارزش اصلی این الگو در جادوی RPC نیست؛ در کم کردن glue code تکراری و نگه داشتن کدهای صرفاً سروری داخل server graph است.
این الگو وقتی قوی است که action هنوز یک command محصول را بیان کند، نه یک endpoint عمومی و بیهویت. action should کاربر را احراز هویت کند، payload را اعتبارسنجی کند، سرویس دامنه را صدا بزند، در صورت نیاز داخل transaction بنویسد و نتیجه تایپشده یا refresh مسیر وابسته را برگرداند. این کار کلاینت را سبکتر میکند، wrapperهای تکراری fetch را حذف میکند و بیان state نامعتبر را سختتر میسازد. اما هر مسیری که نیاز به public access، versioning، webhook یا ترافیک سرویسبهسرویس دارد، باید وارد مرز API مستقل شود.
Hono به عنوان درگاه تایپشده API
APIهای عمومی، webhookها و مسیر آماده برای جداسازی سرویس بدون سنگینی framework
Hono متعلق به یک مسیر متفاوت در بکاند است. وقتی سیستم به سطح HTTP صریح نیاز دارد، مثل API عمومی، webhook امضاشده، کلاینت موبایل، اتصال خارجی یا میکروسرویس آینده، بهتر است این مرز از چرخه UI جدا باشد. ارزش Hono در تجربه تایپاسکریپتی تمیز، routing سریع و مدلی است که بعداً میتواند با اصطکاک کمتر به سرویس مستقل تبدیل شود.
این جداسازی بکاند را صادق نگه میدارد: Server Actions نزدیک mutationهای محصول میمانند، و Hono مالک قراردادهای API پایدار میشود. Redis میتواند کنار این gateway برای rate limit، خواندنهای تکراری و cache کوتاهعمر قرار بگیرد. workerها هم کارهای کند را از مسیر request خارج میکنند. نتیجه microservices زودهنگام نیست؛ یک بکاند ماژولار با مرزهای قابل مشاهده است تا هر فشار، وقتی واقعاً لازم شد، به مسیر درست خودش منتقل شود.
مسیرهای داغ Go برای محاسبات سنگین
تست فشار، trace و جداسازی سرویس بر اساس شواهد واقعی
Go نباید صرفاً چون در نمودار معماری جذاب است وارد سیستم شود. ارزش Go زمانی مشخص میشود که اندازهگیری ثابت کند یک مسیر مشخص در بکاند CPU-heavy، بسیار concurrent، realtime-oriented یا برای چرخه request در Node.js پرهزینه است. قبل از هر جداسازی، سیستم باید با تست فشار قابل تکرار سنجیده شود و با trace، لاگ ساختاریافته و percentileهای latency مشاهده شود تا گلوگاه واقعاً معلوم باشد.
وقتی مسیر داغ ثابت شد، انتقال باید جراحیشده و محدود باشد: فقط workload محاسباتی یا concurrent پشت یک مرز کوچک و تایپشده منتقل میشود، در حالی که بکاند اصلی Next.js/Hono همچنان مالک orchestration، احراز هویت، validation، قواعد persistence و جریان محصول میماند. این روش از rewrite زودهنگام جلوگیری میکند و یک مدل رشد عملی میسازد: Node.js محصول را هماهنگ میکند و Go مسیرهای باریکی را جذب میکند که concurrency خام و مصرف قابل پیشبینی منابع در آنها مهم است.
اعتبارسنجی تدافعی دادهها در لبه سرور
Schema ورودی، command تایپشده و خروجی پاکسازیشده
مرز سرور جایی است که اعتماد باید به دست بیاید. هر payload ورودی تا قبل از عبور از schema صریح، ناشناس و غیرقابل اعتماد است: شکل داده، نوع، طول، enumها، شناسهها و بازههای دامنهای قبل از رسیدن درخواست به منطق کسبوکار بررسی میشوند. این کار جلوی ورود state ناقص، فیلدهای اضافه و مقادیری را میگیرد که فقط در مرورگر معتبر به نظر میرسیدند.
همین انضباط در مسیر خروج هم لازم است. ردیف دیتابیس پاسخ API نیست؛ ستونهای داخلی، پرچمهای امنیتی، یادداشتهای خصوصی و جزئیات پیادهسازی باید قبل از serialize شدن از مسیر schema خروجی عبور کنند. در این مدل validator یک helper پراکنده نیست؛ قرارداد مرز است: Ingress یک command تایپشده برای لایه دامنه تولید میکند و Egress یک پاسخ امن برای کلاینت.
سیستمهای احراز هویت ماژولار و مدیریت نشستها
کوکی HttpOnly، چرخش، ابطال و مالکیت سرور بر وضعیت هویت
احراز هویت فقط صفحه login نیست. مسئله اصلی بکاند این است که هویت کاربر چطور بین requestها باقی بماند، بدون اینکه به یک secret قابل خواندن در کلاینت تبدیل شود. توکنی که در localStorage یا sessionStorage ذخیره شود، توسط JavaScript قابل خواندن است و در برابر XSS، replay و سرقت credential بلندمدت آسیبپذیر میشود. مدل امنتر، credential حساس را داخل کوکی HttpOnly و تحت کنترل سرور نگه میدارد.
یک موتور احراز هویت ماژولار مثل Better-Auth میتواند صدور نشست، flagهای کوکی، rotation، انقضا و revoke را مالکیت کند تا لایه اپلیکیشن روی authorization دامنه متمرکز بماند. flagهای Secure، SameSite و HttpOnly سطح افشای مرورگر را کم میکنند؛ middleware و server functionها هم قبل از شروع کار محافظتشده، نشست را بررسی میکنند. نکته مهم مالکیت چرخه عمر است: login، refresh، logout، رفتار مشکوک و ابطال نشست چنددستگاهی باید stateهای صریح باشند، نه چکهای پراکنده.
الگوهای دسترسی چندسطحی و ایزولهسازی دامینها (RBAC & ReBAC)
قابلیت با RBAC، مرزبندی دامین، و مالکیت رکورد با ReBAC
Authorization فقط یک شرط ساده بعد از login نیست. در بکاند جدی، هر command محافظتشده باید از چند لایه تصمیم عبور کند: ابتدا نشست، actor را مشخص میکند؛ سپس RBAC بررسی میکند که این actor اصلا قابلیت کلی اجرای عملیات را دارد یا نه؛ و بعد درخواست فقط وارد همان دامین، tenant یا bounded context میشود که مالک resource است. این مدل باعث میشود منطق permission در مرز امن سرور متمرکز بماند و به چکهای پراکنده داخل UI یا handlerهای جداگانه تبدیل نشود.
لایه عمیقتر ReBAC است. حتی اگر نقش کاربر معتبر باشد، بکاند هنوز باید رابطه زنده میان actor، subject، resource و مرز دامین را در لایه داده تایید کند. این یعنی شناسه قابل حدسزدن یک رکورد برای دسترسی کافی نیست؛ رابطه واقعی باید وجود داشته باشد. نتیجه این مدل، مهار خطاهای IDOR و BOLA، جلوگیری از نشت افقی داده و خروجیسازی امن با DTOهای حداقلی است. در عمل، قابلیت مشخص میکند یک عملیات اصلا مجاز هست یا نه؛ scope دامین مشخص میکند این عملیات کجا مجاز است؛ و رابطه رکورد تعیین میکند دقیقا کدام داده میتواند خوانده یا تغییر داده شود.
آماده ورود به فاز ۴: معماری دیتابیس و مدلسازی داده هستید؟
در فاز بعدی به طراحی اسکیماهای تایپسیف رابطهای، مدیریت Connection Pooling با PgBouncer، مانیتورینگ IOPS و تراکنشهای امن دیتابیس خواهیم پرداخت.