Files
CMS/docs/cms-data-and-business.md

21 KiB
Raw Blame History

مستندات داده و بیزینس مایکروسرویس 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: باندل یا سرویس قابل فروش با عنوان، توضیح، تصویر و قیمت ثابت که می‌تواند داخل سفارش کاربر قرار گیرد.
  • CategoryProduct 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. احراز هویت و ورود

  1. کاربر شماره موبایل را ارسال می‌کند؛ OtpTokenCQ یک رکورد جدید با کد هش‌شده، زمان انقضا و شمارش تلاش‌ها می‌سازد. درصورت وجود رکورد فعال، ابتدا Attempts چک و درصورت عبور از سقف، خطای تجاری برگردانده می‌شود.
  2. کاربر کد را ارسال می‌کند؛ سیستم hash تولید می‌کند و با CodeHash مقایسه می‌شود. در صورت موفقیت، IsUsed و IsMobileVerified تنظیم می‌شوند و تاریخ تایید موبایل ذخیره می‌گردد.
  3. اگر کاربر برای اولین‌بار وارد شود، کیف پول و Role پیش‌فرض ایجاد می‌شود. سپس سرویس JWT توکن امضا شده (همراه با Claims نقش‌ها) را برمی‌گرداند.

2. مدیریت کاتالوگ و محتوای فروش

  • اپراتور BackOffice از طریق دسته‌ها، تگ‌ها و محصولات API های CategoryCQ, ProductsCQ, TagCQ و … اقلام را CRUD می‌کند.
  • تصاویر از طریق ProductImagesCQ ثبت و سپس با ProductGallerysCQ به محصولات لینک می‌شوند تا ترتیب نمایش قابل تغییر باشد.
  • باندل‌های اشتراکی یا خدمات از طریق PackageCQ تعریف می‌شوند و در سفارش‌ها استفاده می‌شوند.
  • قوانین کیفیت داده: عنوان و توضیح محصول نمی‌تواند خالی باشد، تصویر شاخص باید پیش از انتشار محصول مشخص شود و حداقل یک دسته فعال برای محصول الزامی است.
  • وضعیت فعال/غیرفعال دسته‌ها در API لیست محصولات اعمال می‌شود تا محصولات دسته غیرفعال نمایش داده نشوند.

3. تجربه خرید (Cart → Order → Transaction)

  1. FrontOffice اقلام را در UserCarts ثبت/ویرایش می‌کند.
  2. هنگام تسویه، Handler های UserOrderCQ سفارش و اقلام FactorDetails را می‌سازند، آدرس پیش‌فرض UserAddress را ضمیمه می‌کنند و وضعیت پرداخت را Pending قرار می‌دهند.
  3. پس از موفقیت درگاه، سرویس تراکنش (TransactionsCQ) شناسه مرجع را ذخیره و PaymentStatus سفارش و تراکنش را Success می‌کند؛ تاریخ پرداخت نیز ست می‌شود.
  4. وضعیت ارسال (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 قرار می‌گیرند.