21 KiB
21 KiB
مستندات داده و بیزینس مایکروسرویس CMS
معماری و لایهها
- پشته فنی: .NET 9 + ASP.NET Core WebAPI، MediatR برای پیادهسازی CQRS، EF Core برای دسترسی داده، Mapster برای مپینگ DTO و gRPC/Protobuf برای قرارداد سرویس بین BFF ها و FrontOffice.
- ساختار پروژه: لایههای Domain (موجودیت و قواعد)، Application (CQRS Commands/Queries، ولیدیشن، DTO)، Infrastructure (EF Core + سرویسهای جانبی) و WebApi (ورودی HTTP/gRPC) به همراه پروژه مستقل Protobuf جهت بهاشتراکگذاری قراردادها.
- الگوی کلی: هر درخواست ورودی از طریق WebApi به MediatR ارسال و Handler مربوطه داده را از DbContext میخواند/مینویسد. تمام موجودیتها از
BaseAuditableEntityارث میبرند و ستونهایId,Created,CreatedBy,LastModified,IsDeletedرا به صورت یکپارچه فراهم میکنند. - ملاحظات مقیاسپذیری: Handler ها stateless هستند و میتوانند افقی مقیاس شوند. کنترل تراکنشها توسط EF Core انجام میشود و در عملیات چندمرحلهای (مثلاً ثبت سفارش) تغییرات داخل یک
TransactionScopeواحد اعمال میشود تا سازگاری داده حفظ شود. - پایش و ردگیری: رفتارهای
Common/Behavioursبرای لاگگیری و اعتبارسنجی فعالاند و برای هر درخواست یک شناسه ردگیری تولید میکنند تا ارتباط بین لاگ BackOffice و FrontOffice حفظ گردد.
مدل داده
برای فهم بهتر بیزینس، موجودیتها در پنج خوشه اصلی (هویت، کاتالوگ، سفارش، کیف پول، قرارداد) دستهبندی شدهاند و هر خوشه قواعد و قیود مخصوص خود را دارد.
لایه کاربر و هویت
- User: اطلاعات هویتی، وضعیت تایید موبایل، تنظیمات اعلان، کد ارجاع و رابطه والد/فرزند. ارتباط یکبهچند با آدرسها، نقشها، سفارشها، قراردادها، کیف پول و سبد خرید.
- Role / UserRole: تعریف نقشهای سیستمی و نگاشت چند-به-چند کاربر به نقش. جهت کنترل دسترسی BackOffice.
- OtpToken: ذخیره توکنهای OTP با هش کد، هدف (Purpose)، زمان انقضا، تعداد تلاش و وضعیت مصرف برای جریان لاگین/ثبتنام.
لایه محتوا و کاتالوگ محصول
- Category: ساختار درختی دستهبندی با عنوان، توضیحات، تصویر، ترتیب نمایش و وضعیت فعال بودن.
ParentIdبرای تو در تویی و ارتباط باPruductCategory. - Tag / PruductTag: برچسبهای قابل جستجو برای محصولات با وضعیت فعال و ترتیب. جدول واسط
PruductTagاتصال چند-به-چند محصول و تگ را نگه میدارد. - Products: جزئیات کامل محصول شامل توضیحات کوتاه/طولانی، قیمت، تخفیف، نرخ، تصاویر اصلی/Thumbnail، آمار فروش و موجودی. ارتباط با سبد، گالری، فاکتور، دسته و تگ.
- ProductImages / ProductGallerys: مدیریت داراییهای تصویری.
ProductImagesمشخصات فایل را نگه میدارد وProductGallerysرابطه هر تصویر با یک محصول را ثبت میکند تا چیدمان گالری قابل کنترل باشد. - Package: باندل یا سرویس قابل فروش با عنوان، توضیح، تصویر و قیمت ثابت که میتواند داخل سفارش کاربر قرار گیرد.
- Category–Product Pivot (
PruductCategory): ردیفهای عضویت محصول در دستههای متعدد. هر ردیف شاملProductIdوCategoryIdاست.
لایه سفارش و تراکنش
- UserCarts: آیتمهای سبد خرید کاربر، شامل شناسه محصول، کاربر و تعداد. منبع اصلی عملیات افزودن/حذف سبد در FrontOffice.
- UserAddress: آدرسهای پستی کاربران با عنوان، متن آدرس، کد پستی، شهر، وضعیت پیشفرض و ارتباط با سفارشها.
- UserOrder: سفارش نهایی شامل مبلغ، ارجاع به پکیج/تراکنش، وضعیت و تاریخ پرداخت، روش پرداخت، وضعیت ارسال، کد رهگیری و توضیحات ارسال. همچنین به آدرس کاربر و آیتمهای فاکتور (
FactorDetails) متصل است. - FactorDetails: اقلام درون سفارش؛ هر ردیف به محصول و سفارش اشاره دارد و تعداد، قیمت واحد، تخفیف و وضعیت تغییر قیمت را نگه میدارد.
- Transactions: لاگ مالی سطح درگاه با مبلغ، توضیح، وضعیت/تاریخ پرداخت، شناسه مرجع درگاه و نوع تراکنش (Persistent در Enum
TransactionType). سفارشها میتوانند به یک تراکنش اشاره کنند.
لایه کیف پول و تسویه
- UserWallet: کیف پول ریالی/شبکهای هر کاربر با موجودی جاری و موجودی شبکه (
NetworkBalance). - UserWalletChangeLog: ژورنال تغییرات کیف پول شامل موجودی قبل/بعد، مقدار تغییر، تغییر شبکه، اینکه افزایش یا کاهش بوده و شناسه مرجع (مثلاً تراکنش یا سفارش). ستون
Createdمنبع اصلی timestamp فاکتور کیف پول است.
لایه قرارداد و رعایت الزامات
- Contract: قالب قراردادها با عنوان، توضیحات، متن HTML و نوع قرارداد (
ContractType). - UserContract: سوابق موافقت کاربر با قراردادها، شامل فایل PDF امضا شده و
SignGuidبرای ردیابی امضا.
ماژولها و بیزینس مفصل
کاربران و هویت
- ثبتنام: با دریافت موبایل، رکورد
Userساخته و OTP برای تایید ارسال میشود. شرط یکتایی موبایل در سطح پایگاه داده enforced است و در Handler نیز بررسی میشود. - تکمیل پروفایل: کاربر میتواند نام، کد ملی، تاریخ تولد و تنظیمات اعلان را تکمیل کند. فعالسازی اعلانها به BFF اطلاع میدهد تا Subscription در سرویس پوش ثبت شود.
- مدیریت نقش: Admin میتواند از API
UserRoleCQبرای افزودن نقش جدید استفاده کند؛ در صورت حذف نقش، ابتدا باید عضویتهای فعال کاربر قطع شود.
کاتالوگ و محتوا
- دستهبندی درختی: سطح بینهایت تو در تو پشتیبانی میشود. حذف یک دسته زمانی مجاز است که هیچ
Categorysفرزند و هیچPruductCategoryفعالی نداشته باشد؛ در غیر این صورت باید انتقال انجام شود. - چرخه محصول: ایجاد محصول شامل ثبت داده متنی، بارگذاری تصویر شاخص، تعریف قیمت و تعیین تخفیف است. تغییر قیمت در Handler ثبت شده و قوانین جلوگیری از عدد منفی یا Discount بزرگتر از 100٪ اعمال میشود.
- گالری و تصاویر: ابتدا تصویر در
ProductImagesثبت و سپس باProductGallerysبه محصول متصل میشود تا یک تصویر بتواند در چند محصول استفاده شود. حذف تصویر اگر در گالری فعال باشد ممنوع است. - پکیجها: برای فروش سرویس اشتراکی یا باندل؛ فیلد
Priceمبنای محاسبه سفارشهای نوع Package است و تغییر قیمت روی سفارشهای ثبتشده تاثیر ندارد زیرا مبلغ درUserOrder.Amountذخیره میشود.
سفارش، پرداخت و لجستیک
- سبد خرید: عملیات Add/Update/Delete روی
UserCartsانجام میشود. در هر لحظه برای ترکیب (User, Product) تنها یک رکورد وجود دارد. اگر Count صفر شود، رکورد حذف منطقی میشود تا تاریخچه حفظ گردد. - Checkout: Handler
SubmitShopBuyOrderاقلام سبد را قفل خوشبینانه کرده، سفارش (UserOrder) و اقلام فاکتور (FactorDetails) را میسازد، آدرس پیشفرض را نگاشت و وضعیت پرداخت را Pending میگذارد. - پرداخت آنلاین: پس از هدایت به درگاه، سیستم CallBack در
TransactionsCQرا دریافت میکند؛ شناسه مرجع (RefId) و مبلغ تطبیق داده میشود. در صورت موفقیت،PaymentStatusسفارش و تراکنش Success شده وPaymentDateذخیره میشود. در صورت Reject، سبد به حالت قبل بازگردانده میشود. - پرداخت با کیف پول: اگر موجودی کافی باشد، به صورت اتمیک از کیف پول کسر و سفارش Success میشود؛ نیازی به تراکنش درگاه نیست.
- لجستیک: فیلدهای
DeliveryStatus,TrackingCode,DeliveryDescriptionوضعیت ارسال را پوشش میدهند. هر تغییر وضعیت میتواند Notification برای کاربر یا تیم پشتیبانی ایجاد کند.
کیف پول و تسویه داخلی
- ساخت کیف پول: همزمان با ثبتنام یا اولین تراکنش، رکورد
UserWalletساخته میشود. موجودی شبکه برای پشتیبانی از داراییهای خارج از پلتفرم است. - ChangeLog: هر تغییر موجودی همراه با مقدار قبل/بعد، مقدار شبکه، نوع عملیات (Increase/Decrease) و
ReferenceIdثبت میشود تا audit کافی فراهم گردد. Handler ها Idempotency را با بررسی ReferenceId رعایت میکنند. - واریز: میتواند از طریق درگاه آنلاین یا عملیات دستی ادمین باشد. پس از تایید بانک، مبلغ به
Balanceافزوده و ChangeLog با نوع Deposit ذخیره میشود. - برداشت/تسویه: درخواست Withdrawal ابتدا به صف تایید دستی میرود (Business Rule). پس از تایید، مبلغ از
Balanceکم و اگر نیاز به ارسال به شبکه بلاکچین باشد،NetworkBalanceنیز بهروزرسانی میشود. - بازپرداخت سفارش: در صورت لغو سفارش پرداختشده، مقدار پرداختی با ChangeLog نوع Refund به کیف پول برمیگردد تا کاربر بتواند مجدد خرید کند یا برداشت انجام دهد.
قرارداد و انطباق
- مدیریت نسخه: هر بار که متن قرارداد تغییر کند، رکورد جدیدی در
Contractساخته میشود.UserContractبا نگه داشتنContractIdمشخص میکند کاربر کدام نسخه را امضا کرده است. - فرآیند امضا: برای امضای دیجیتال، سیستم
SignGuidرا به سرویس امضای بیرونی ارسال میکند. پس از تکمیل، فایل PDF در فضای ذخیرهسازی آپلود و مسیر آن درUserContract.SignedPdfFileثبت میشود. - کنترل پذیرش قوانین: فیلدهای
IsRulesAcceptedوRulesAcceptedAtدر موجودیت User نیز نگهداری میشوند تا بتوان دفعات قبول قوانین عمومی را از قراردادهای اختصاصی تفکیک کرد.
گزارش و مانیتورینگ
- تمام Queries دارای پارامترهای Paging و Sorting هستند تا BackOffice بتواند داشبورد مدیریتی بسازد.
- به کمک Mapster Projection فقط ستونهای مورد نیاز خوانده میشود؛ در موارد خاص (مثل تاریخ تراکنش کیف پول) Projection دستی به DTO اعمال شده است.
- ساختار CQRS اجازه میدهد که در آینده Event Handler یا Outbox برای همگامسازی با سرویسهای دیگر اضافه شود.
فرایندهای بیزینسی کلیدی
1. احراز هویت و ورود
- کاربر شماره موبایل را ارسال میکند؛
OtpTokenCQیک رکورد جدید با کد هششده، زمان انقضا و شمارش تلاشها میسازد. درصورت وجود رکورد فعال، ابتدا Attempts چک و درصورت عبور از سقف، خطای تجاری برگردانده میشود. - کاربر کد را ارسال میکند؛ سیستم hash تولید میکند و با
CodeHashمقایسه میشود. در صورت موفقیت،IsUsedوIsMobileVerifiedتنظیم میشوند و تاریخ تایید موبایل ذخیره میگردد. - اگر کاربر برای اولینبار وارد شود، کیف پول و Role پیشفرض ایجاد میشود. سپس سرویس JWT توکن امضا شده (همراه با Claims نقشها) را برمیگرداند.
2. مدیریت کاتالوگ و محتوای فروش
- اپراتور BackOffice از طریق دستهها، تگها و محصولات API های
CategoryCQ,ProductsCQ,TagCQو … اقلام را CRUD میکند. - تصاویر از طریق
ProductImagesCQثبت و سپس باProductGallerysCQبه محصولات لینک میشوند تا ترتیب نمایش قابل تغییر باشد. - باندلهای اشتراکی یا خدمات از طریق
PackageCQتعریف میشوند و در سفارشها استفاده میشوند. - قوانین کیفیت داده: عنوان و توضیح محصول نمیتواند خالی باشد، تصویر شاخص باید پیش از انتشار محصول مشخص شود و حداقل یک دسته فعال برای محصول الزامی است.
- وضعیت فعال/غیرفعال دستهها در API لیست محصولات اعمال میشود تا محصولات دسته غیرفعال نمایش داده نشوند.
3. تجربه خرید (Cart → Order → Transaction)
- FrontOffice اقلام را در
UserCartsثبت/ویرایش میکند. - هنگام تسویه، Handler های
UserOrderCQسفارش و اقلامFactorDetailsرا میسازند، آدرس پیشفرض UserAddress را ضمیمه میکنند و وضعیت پرداخت راPendingقرار میدهند. - پس از موفقیت درگاه، سرویس تراکنش (
TransactionsCQ) شناسه مرجع را ذخیره وPaymentStatusسفارش و تراکنش راSuccessمیکند؛ تاریخ پرداخت نیز ست میشود. - وضعیت ارسال (
DeliveryStatus) در طول فرایند Fulfillment آپدیت شده و کد رهگیری پستی داخل سفارش نگهداری میشود.
- سناریو شکست درگاه: اگر درگاه خطا دهد، سفارش در حالت Pending باقی میماند و Job زمانبندی شده این سفارشها را بعد از زمان مشخص لغو میکند تا سبد دوباره آزاد شود.
- امکان پرداخت ترکیبی (کیف پول + درگاه) وجود دارد؛ ابتدا از کیف پول برداشت و سپس باقیمانده به درگاه ارسال میشود.
4. کیف پول و صورتحساب داخلی
- هر کاربر دقیقا یک کیف پول فعال دارد (
UserWalletCQ). - واریز/برداشت (چه ناشی از پرداخت آنلاین چه عملیات دستی) همیشه یک رکورد در
UserWalletChangeLogایجاد میکند تا موجودی قبلی، مقدار تغییر و منبع (ReferenceId) مشخص باشد. - FrontOffice برای نمایش تاریخ دقیق تراکنشها از
Createdلاگ استفاده میکند؛ بنابراین Handler هایUserWalletChangeLogCQحتماCreatedAtرا به DTO و gRPC پاسخ اضافه میکنند. - ChangeLog ها قابلیت فیلتر بر اساس نوع عملیات، بازه تاریخی و ReferenceId دارند و مقادیر در DTO به timestamp یونیکس هم تبدیل میشود تا فرانت به راحتی فرمت کند.
- عملیات دستی ادمین حتما توضیح (Description) و شناسه اپراتور را ثبت میکند تا audit کامل باشد.
5. قراردادها و انطباق
- محتوای قرارداد (Term of Service، قرارداد نمایندگی و …) در
Contractنگهداری میشود. - هنگام امضا، یک
UserContractشامل فایل PDF امضا شده وSignGuidایجاد میگردد تا سوابق حقوقی نگهداری شود. این اطلاعات در درخواستهای بعدی احراز میشوند تا از کاربران فقط یکبار امضا گرفته شود. - در صورت بهروزرسانی متن قرارداد، کاربران باید مجدداً آن را تایید کنند؛ FrontOffice هنگام ورود این شرط را بررسی و کاربر را به صفحه امضا هدایت میکند.
- سیستم گزارش میدهد چه تعداد کاربر هر نسخه را امضا کردهاند تا تیم حقوقی مطمئن شود پوشش قانونی کامل است.
نکات پیادهسازی و توسعه
- CQRS پوشهبندی: هر ماژول (مثلاً
UserWalletCQ) شامل زیرپوشههای Commands و Queries است. درخواستهای gRPC از پروژه Protobuf با DTO های Application نگاشت میشوند. - همگامسازی قراردادها: هر زمان فیلد جدیدی به موجودیت اضافه شود باید DTO، Handler و قرارداد Protobuf متناظر نیز بهروزرسانی و
dotnet buildبرای تولید مجدد stubs اجرا شود. سپس BFF ها باید پکیج جدید را دریافت کنند. - اتصال با BFF: CMS WebApi سرویسهای gRPC را در پورت تعریف شده در
appsettingsاکسپوز میکند. BFF ها با استفاده از Channel مطمئن (TLS داخلی) به آن متصل میشوند و Mapster را برای تبدیل به مدلهای فرانت استفاده میکنند. - Dependency Injection: تمام Handler ها و سرویسها در
CMSMicroservice.Application/ConfigureServices.csوCMSMicroservice.Infrastructure/ConfigureServices.csثبت میشوند تا تستپذیری افزایش یابد. - اعتبارسنجی و لاگ: Behaviour های مشترک (LoggingBehaviour, ValidationBehaviour) روی Pipeline MediatR نشستهاند تا قبل از اجرای Handler، ورودیها چک و لاگ ساختارمند تولید شود.
- زمانبندی تمیزکاری: ستون
IsDeletedبرای Soft Delete بهکار میرود. Handler هایی که لیست میدهند معمولا فیلتر!IsDeletedرا اعمال میکنند؛ برای نمایش آرشیو باید صراحتاً flag درخواست شود. - Enums مهم:
PaymentStatus,PaymentMethod,DeliveryStatus,ContractType,TransactionTypeطیف وضعیتهای مالی/قراردادی را استاندارد میکنند و باید بین FrontOffice و BackOffice همسو نگه داشته شوند. - آیتمهای Idempotent: عملیات حساس مثل واریز کیف پول یا ثبت سفارش از ReferenceId استفاده میکنند تا در تکرار درخواستها نتیجهی تکراری ایجاد نشود.
مسیرهای مرتبط
- ساختار کد:
CMS/src/CMSMicroservice.Domain/Entities,CMSMicroservice.Application/*CQ,CMSMicroservice.Protobuf/Protos. - مستند حاضر:
CMS/docs/cms-data-and-business.md - نقاط تماس بیرونی: gRPC Endpoint های
CMSMicroservice.WebApiبه صورت داخلی مصرف میشوند و از طریق FrontOffice/BackOffice BFF در اختیار UI قرار میگیرند.