docs: convert all ASCII charts to Mermaid diagrams

Converted 40+ ASCII art diagrams across 12 files to Mermaid:
- flowchart TD/LR for process flows and architecture
- erDiagram for entity relationships
- graph TD for tree structures (binary tree, categories)
- gantt for roadmap sprints

Files: BUSINESS-01 to 05, TECH-01/03/04/05, OVERVIEW-01/02/05
Directory tree structures kept as plain code blocks (Mermaid N/A)
This commit is contained in:
masoodafar-web
2026-02-18 23:36:39 +03:30
parent aef6861e21
commit 1b04ba5326
12 changed files with 544 additions and 739 deletions
+43 -56
View File
@@ -18,15 +18,19 @@
## ۲. ساختار درخت باینری ## ۲. ساختار درخت باینری
```mermaid
graph TD
ROOT["Root"] --- L["Left"]
ROOT --- R["Right"]
L --- L1["L1"] & L2["L2"]
R --- R1["R1"] & R2["R2"]
L1 --- L1a["..."] & L1b["..."]
L2 --- L2a["..."] & L2b["..."]
R1 --- R1a["..."] & R1b["..."]
R2 --- R2a["..."] & R2b["..."]
``` ```
Root
/ \ > ← بدون محدودیت عمق
Left Right
/ \ / \
L1 L2 R1 R2
/ \ / \ / \ / \
... ... ... ... ... ← بدون محدودیت عمق
```
**قوانین:** **قوانین:**
- هر نود حداکثر ۲ فرزند (Binary) — `MaxDirectChildrenPerLeg = 1` - هر نود حداکثر ۲ فرزند (Binary) — `MaxDirectChildrenPerLeg = 1`
@@ -38,36 +42,24 @@
## ۳. فلوی عضویت و فعالسازی ## ۳. فلوی عضویت و فعالسازی
``` ```mermaid
خرید پکیج طلایی (56M تومان) flowchart TD
A["خرید پکیج طلایی — 56M"] --> B["نمایش مودال قرارداد\nغیرقابل‌بسته‌شدن"]
B --> C["مشاهده متن قرارداد\nReadContract RPC"]
نمایش مودال قرارداد (غیرقابل‌بسته‌شدن) C --> D["درخواست OTP\nRequestContractOtp — Kavenegar"]
D --> E["وارد کردن کد\nVerifyContractOtp"]
E --> F["امضای قرارداد\nAcceptContract"]
مشاهده متن قرارداد ← ReadContract RPC
درخواست OTP ← RequestContractOtp (Kavenegar SMS)
وارد کردن کد ← VerifyContractOtp
امضای قرارداد ← AcceptContract
├─→ شارژ ۲ کیف پول: Balance += 56M, DiscountBalance += 112M (2×)
│ (NetworkBalance شارژ نمی‌شود — فقط برای کمیسیون)
├─→ کسر هزینه فعالسازی (25.2M از Balance)
├─→ واریز 25.2M به Pool هفتگی (ClubActivationFee)
├─→ قرارگیری در درخت باینری
└─→ رفرش JWT Token (claims جدید)
⚠️ در خرید با وام دایا: F --> G["شارژ ۲ کیف‌پول\nBalance += 56M\nDiscountBalance += 112M"]
├─→ Balance += 56M F --> H["کسر فعالسازی\n−25.2M از Balance"]
└─→ DiscountBalance += 112M (دو برابر — DayaLoanAmount × 2) F --> I["واریز 25.2M\nبه Pool هفتگی"]
F --> J["قرارگیری در\nدرخت باینری"]
F --> K["رفرش JWT Token\nclaims جدید"]
``` ```
> ⚠️ در خرید با وام دایا: Balance += 56M, DiscountBalance += 112M (DayaLoanAmount × 2)
> NetworkBalance شارژ نمی‌شود — فقط برای کمیسیون
--- ---
## ۴. الگوریتم محاسبه کمیسیون هفتگی ## ۴. الگوریتم محاسبه کمیسیون هفتگی
@@ -103,12 +95,15 @@
### ۴.۳ Pool هفتگی و توزیع ### ۴.۳ Pool هفتگی و توزیع
```mermaid
flowchart LR
A["هر فعالسازی عضو\n25.2M واریز"] --> B["Pool هفتگی"]
B --> C["sp_CalculateWeeklyBalances"]
C --> D["sp_CalculateWeeklyCommissionPool"]
D --> E["توزیع بر اساس\nUserBalance / TotalBalance"]
``` ```
منبع Pool: هر فعالسازی عضو → 25.2M واریز به Pool
توزیع: بر اساس WeeklyBalance هر عضو / مجموع WeeklyBalance‌ها > فرمت هفته: `YYYY-Www` (شمسی، شنبه‌پایه)
SP: sp_CalculateWeeklyBalances → sp_CalculateWeeklyCommissionPool
فرمت هفته: "YYYY-Www" (شمسی، شنبه‌پایه)
```
--- ---
@@ -141,24 +136,16 @@ SP: sp_CalculateWeeklyBalances → sp_CalculateWeeklyCommissionPool
## ۷. یکپارچه‌سازی وام دایا ## ۷. یکپارچه‌سازی وام دایا
```mermaid
flowchart TD
A["Hangfire Worker\nهر ۲۰ دقیقه — */20 * * * *"] --> B["بررسی درخواست‌های pending"]
B --> C["ارسال به API دایا\nMock/Real switchable"]
C --> D["دریافت نتیجه"]
D --> E["Balance += 56M"]
D --> F["DiscountBalance += 112M\nDayaLoanAmount × 2"]
``` ```
Hangfire Worker (هر ۲۰ دقیقه — cron: */20 * * * *)
بررسی درخواست‌های pending
ارسال به API دایا (Mock/Real switchable)
دریافت نتیجه → شارژ ۲ کیف‌پول
├─→ Balance += 56M (DayaLoanAmount)
└─→ DiscountBalance += 112M (DayaLoanAmount × 2 — دو برابر)
مجموع: 168M
Hangfire retry: [AutomaticRetry(Attempts = 3)] > مجموع شارژ: 168M — Hangfire retry: `[AutomaticRetry(Attempts = 3)]`
```
--- ---
+52 -76
View File
@@ -7,19 +7,27 @@
## ۱. معماری کلی مالی ## ۱. معماری کلی مالی
``` ```mermaid
┌──────────────────────────────────────────────────────────────────┐ flowchart TD
│ FourSat Payment Architecture │ subgraph GATEWAYS["درگاه‌ها"]
├──────────────┬──────────────┬──────────────┬─────────────────────┤ ZP["ZarinPal\nIPG"]
ZarinPal Daya Loan │ Manual Pay │ Discount Wallet │ DL["Daya Loan\nAPI"]
│ (IPG) │ (API) │ (Card2Card) │ (Internal) │ MP["Manual Pay\nCard2Card"]
├──────────────┴──────────────┴──────────────┴─────────────────────┤ DW["Discount Wallet\nInternal"]
│ PYMS (Payment Service) │ end
│ gRPC ←→ CMS ←→ FrontOffice/BackOffice │
├──────────────────────────────────────────────────────────────────┤ ZP --> PYMS["PYMS — Payment Service\ngRPC ↔ CMS ↔ FrontOffice/BackOffice"]
│ 3 Wallet System │ DL --> PYMS
│ Balance (نقدی) │ NetworkBalance (شبکه) │ DiscountBalance │ MP --> PYMS
└──────────────────────────────────────────────────────────────────┘ DW --> PYMS
PYMS --> WALLETS
subgraph WALLETS["3 Wallet System"]
W1["💰 Balance\nنقدی"]
W2["🌟 NetworkBalance\nشبکه"]
W3["🏷️ DiscountBalance\nتخفیفی"]
end
``` ```
--- ---
@@ -28,23 +36,14 @@
### ۲.۱ فلوی پرداخت ### ۲.۱ فلوی پرداخت
``` ```mermaid
کاربر → انتخاب محصول → درخواست پرداخت flowchart TD
A["کاربر → انتخاب محصول\nدرخواست پرداخت"] --> B["CMS → CreatePaymentRequest\ngRPC to PYMS"]
B --> C["PYMS → ZarinPal API\nدریافت Authority"]
CMS → CreatePaymentRequest (gRPC to PYMS) C --> D["Redirect کاربر\nصفحه پرداخت ZarinPal"]
D --> E["بازگشت با Authority\nCMS VerifyPayment"]
E -->|موفق| F["✅ ثبت سفارش\n+ شارژ کیف‌پول"]
PYMS → ZarinPal API → دریافت Authority E -->|ناموفق| G["❌ نمایش پیام خطا"]
Redirect کاربر → صفحه پرداخت ZarinPal
بازگشت با Authority → CMS VerifyPayment
├─→ موفق: ثبت سفارش + شارژ کیف‌پول (در صورت نیاز)
└─→ ناموفق: نمایش پیام خطا
``` ```
### ۲.۲ تنظیمات ZarinPal ### ۲.۲ تنظیمات ZarinPal
@@ -62,21 +61,14 @@ Redirect کاربر → صفحه پرداخت ZarinPal
### ۳.۱ معماری ### ۳.۱ معماری
``` ```mermaid
Hangfire Recurring Job (هر ۲۰ دقیقه — cron: */20 * * * *) flowchart TD
A["Hangfire Recurring Job\nهر ۲۰ دقیقه — */20 * * * *"] --> B["DayaLoanProcessorJob.Execute"]
B --> C["بررسی LoanRequests\nStatus = Pending"]
DayaLoanProcessorJob.Execute() C --> D["برای هر درخواست:"]
D --> E["ارسال به DayaLoan API\nAutomaticRetry Attempts=3"]
E -->|تأیید| F["✅ Balance += 56M\nDiscountBalance += 112M\n+ ثبت Transaction + Log"]
بررسی LoanRequests با Status=Pending E -->|رد| G["❌ Status = Rejected\n+ ارسال SMS"]
برای هر درخواست:
├─→ ارسال به DayaLoan API ([AutomaticRetry(Attempts=3)])
├─→ در صورت تأیید: Balance += 56M, DiscountBalance += 112M (2×)
├─→ ثبت Transaction + Log
└─→ در صورت رد: Status=Rejected + ارسال SMS
``` ```
### ۳.۲ Mock Mode ### ۳.۲ Mock Mode
@@ -108,21 +100,14 @@ DayaLoanProcessorJob.Execute()
> ⚠️ **وضعیت: طراحی‌شده — پیاده‌سازی نشده** > ⚠️ **وضعیت: طراحی‌شده — پیاده‌سازی نشده**
``` ```mermaid
فلوی پیشنهادی: flowchart TD
کاربر → انتخاب "کارت‌به‌کارت" A["کاربر → انتخاب کارت‌به‌کارت"] --> B["نمایش شماره‌کارت مقصد\n+ مبلغ"]
B --> C["کاربر → واریز\n+ آپلود تصویر رسید"]
C --> D["ادمین BackOffice\nمشاهده لیست درخواست‌ها"]
نمایش شماره‌کارت مقصد + مبلغ D --> E{"تأیید / رد؟"}
E -->|تأیید| F["✅ شارژ خودکار کیف‌پول"]
E -->|رد| G["❌ اطلاع‌رسانی به کاربر"]
کاربر → واریز + آپلود تصویر رسید
ادمین BackOffice → مشاهده لیست درخواست‌ها
تأیید/رد → شارژ خودکار کیف‌پول
``` ```
**موجودیت‌های مورد نیاز:** **موجودیت‌های مورد نیاز:**
@@ -149,22 +134,13 @@ MaxDiscountPercent محصول = 40% (هر محصول درصد تخفیف مخص
### ۵.۲ فلوی خرید فروشگاه تخفیفی ### ۵.۲ فلوی خرید فروشگاه تخفیفی
``` ```mermaid
کاربر (عضو باشگاه) → مشاهده محصول flowchart TD
A["کاربر عضو باشگاه\nمشاهده محصول"] --> B["قیمت تخفیف‌خورده نمایش داده می‌شود"]
B --> C["افزودن به سبد\nبررسی DiscountBalance"]
قیمت تخفیف‌خورده نمایش داده می‌شود C --> D{"موجودی کافی؟"}
D -->|کافی| E["سهم تخفیف از DiscountBalance\nباقیمانده → IPG ZarinPal"]
D -->|ناکافی| F["فقط به اندازه موجودی\nباقیمانده بیشتر → IPG"]
افزودن به سبد → بررسی DiscountBalance
├─→ DiscountBalance کافی:
│ سهم تخفیف از DiscountBalance کسر
│ باقیمانده → IPG (ZarinPal)
└─→ DiscountBalance ناکافی:
فقط به اندازه موجودی از تخفیف
باقیمانده بیشتر → IPG
``` ```
### ۵.۳ دسترسی فروشگاه تخفیفی ### ۵.۳ دسترسی فروشگاه تخفیفی
+59 -66
View File
@@ -7,21 +7,31 @@
## ۱. دو فروشگاه FourSat ## ۱. دو فروشگاه FourSat
``` ```mermaid
┌─────────────────────────────────────────────────────────┐ flowchart LR
│ FourSat Stores │ subgraph RS["Regular Store — /store"]
├───────────────────────┬─────────────────────────────────┤ R1["همه کاربران"]
│ Regular Store │ Discount Store │ R2["پرداخت 100% نقدی"]
│ (/store) │ (/discount-store) │ R3["قیمت عادی"]
├───────────────────────┼─────────────────────────────────┤ R4["VAT = 10%"]
│ • همه کاربران │ • فقط اعضای باشگاه │ end
│ • پرداخت 100% نقدی │ • پرداخت ترکیبی (تخفیف+نقد) │
│ • قیمت عادی │ • تخفیف بر اساس MaxDiscountPercent │ subgraph DS["Discount Store — /discount-store"]
│ • VAT = 10% │ • VAT = 9% (در کد PlaceOrder) │ D1["فقط اعضای باشگاه"]
├───────────────────────┴─────────────────────────────────┤ D2["پرداخت ترکیبی تخفیف+نقد"]
│ Shared: Products, Categories, │ D3["تخفیف بر اساس MaxDiscountPercent"]
│ Inventory, ProductImages (1:1 square) │ D4["VAT = 9%"]
└─────────────────────────────────────────────────────────┘ end
subgraph SHARED["مشترک"]
S1["Products"]
S2["Categories"]
S3["Inventory"]
S4["ProductImages 1:1"]
end
RS --> SHARED
DS --> SHARED
``` ```
--- ---
@@ -50,23 +60,14 @@ public async Task<ProductListResult> GetProductsPagedAsync(
### ۲.۲ پیاده‌سازی UI (هر دو فروشگاه) ### ۲.۲ پیاده‌سازی UI (هر دو فروشگاه)
``` ```mermaid
بارگذاری اولیه: 12 محصول flowchart TD
A["بارگذاری اولیه: 12 محصول"] --> B["اسکرول → نمایش دکمه\nنمایش محصولات بیشتر"]
B --> C["کلیک → LoadMore\nskip += 12"]
اسکرول → نمایش دکمه "نمایش محصولات بیشتر" C --> D["محصولات جدید append به لیست"]
D --> E{"Products.Count >= TotalCount?"}
E -->|خیر| B
کلیک → LoadMore() → skip += 12 E -->|بله| F["مخفی‌شدن دکمه"]
محصولات جدید اضافه به لیست (append)
تکرار تا Products.Count >= TotalCount
مخفی‌شدن دکمه
``` ```
--- ---
@@ -100,17 +101,14 @@ public int MaxDiscountPercent { get; set; } // 0 تا 100 — درصد تخفی
### ۳.۳ فلوی سفارش و موجودی ### ۳.۳ فلوی سفارش و موجودی
``` ```mermaid
سفارش جدید flowchart TD
A["سفارش جدید"] --> B{"Quantity - Reserved >= OrderQty?"}
B -->|بله| C["Reserved += OrderQty"]
بررسی Quantity - ReservedQuantity >= OrderQuantity? C --> D{"پرداخت موفق؟"}
D -->|موفق| E["✅ Quantity -= OrderQty\nReserved -= OrderQty"]
├─→ بله: ReservedQuantity += OrderQuantity D -->|ناموفق| F["❌ Reserved -= OrderQty\nآزادسازی"]
│ پرداخت موفق → Quantity -= OrderQuantity, Reserved -= OrderQuantity B -->|خیر| G["نمایش: موجودی کافی نیست"]
│ پرداخت ناموفق → Reserved -= OrderQuantity (آزادسازی)
└─→ خیر: نمایش "موجودی کافی نیست"
``` ```
--- ---
@@ -159,17 +157,11 @@ public class BundleItem {
### ۵.۲ فلو ### ۵.۲ فلو
``` ```mermaid
ادمین → ساخت باندل → انتخاب محصولات + تعیین قیمت flowchart TD
A["ادمین → ساخت باندل\nانتخاب محصولات + تعیین قیمت"] --> B["نمایش در فروشگاه\nبا تگ باندل"]
B --> C["خرید → تمام محصولات\nیکجا به سبد"]
نمایش در فروشگاه با تگ "باندل" C --> D["پرداخت → کسر موجودی\nهر محصول جداگانه"]
خرید → تمام محصولات باندل یکجا به سبد
پرداخت → کسر موجودی هر محصول جداگانه
``` ```
--- ---
@@ -207,21 +199,22 @@ public class BundleItem {
## ۷. دسته‌بندی‌ها (Categories) ## ۷. دسته‌بندی‌ها (Categories)
``` ```mermaid
درختی / سلسله‌مراتبی graph TD
ROOT["دسته‌بندی‌ها"] --> A["سلامت و زیبایی"]
├── سلامت و زیبایی ROOT --> B["تغذیه"]
│ ├── مکمل‌ها ROOT --> C["ورزشی"]
│ ├── مراقبت پوست
│ └── مراقبت مو
├── تغذیه
│ ├── ارگانیک
│ └── رژیمی
└── ورزشی
مدل: Category (Id, Name, ParentId?, ImageUrl, IsActive, SortOrder) A --> A1["مکمل‌ها"]
A --> A2["مراقبت پوست"]
A --> A3["مراقبت مو"]
B --> B1["ارگانیک"]
B --> B2["رژیمی"]
``` ```
> مدل: `Category (Id, Name, ParentId?, ImageUrl, IsActive, SortOrder)`
--- ---
## ۸. خلاصه وضعیت ## ۸. خلاصه وضعیت
+45 -87
View File
@@ -7,27 +7,19 @@
## ۱. فلوی کامل چرخه کاربر ## ۱. فلوی کامل چرخه کاربر
``` ```mermaid
ورود به سایت flowchart TD
A["ورود به سایت"] --> B["ثبت‌نام — موبایل + OTP"]
B --> C["تکمیل پروفایل"]
ثبت‌نام (موبایل + OTP) C --> D{"مسیر؟"}
D -->|عادی| E["🛒 خرید از فروشگاه\nمشاهده بلاگ\nاستفاده از خدمات"]
تکمیل پروفایل
D -->|باشگاه| F["🏆 خرید پکیج طلایی 56M"]
F --> G["امضای قرارداد OTP"]
┌─────────────────────┬────────────────────────┐ G --> H["فعالسازی 25.2M"]
│ مسیر عادی │ مسیر باشگاه │ H --> I["عضویت درخت باینری"]
├─────────────────────┼────────────────────────┤ I --> J["دسترسی فروشگاه تخفیفی\nفیچرهای باشگاه\nکمیسیون هفتگی"]
│ خرید از فروشگاه │ خرید پکیج طلایی (56M) │
│ مشاهده بلاگ │ امضای قرارداد (OTP) │
│ استفاده از خدمات │ فعالسازی (25M) │
│ │ عضویت در درخت باینری │
│ │ دسترسی فروشگاه تخفیفی │
│ │ دسترسی فیچرهای باشگاه │
│ │ کسب کمیسیون هفتگی │
└─────────────────────┴────────────────────────┘
``` ```
--- ---
@@ -36,28 +28,16 @@
### ۲.۱ فلوی ثبت‌نام ### ۲.۱ فلوی ثبت‌نام
```mermaid
flowchart TD
A["صفحه ثبت‌نام"] --> B["ورود شماره موبایل"]
B --> C["ارسال OTP\nKavenegar SMS API"]
C --> D["تأیید کد OTP"]
D -->|کاربر جدید| E["ساخت User\n+ JWT Token"]
D -->|کاربر موجود| F["ورود\n+ JWT Token"]
``` ```
صفحه ثبت‌نام
ورود شماره موبایل
ارسال OTP (Kavenegar SMS API)
تأیید کد OTP
├─→ کاربر جدید: ساخت User + JWT Token
└─→ کاربر موجود: ورود + JWT Token
JWT Claims: **JWT Claims:** `UserId`, `PhoneNumber`, `IsClubMember`, `Roles[]`, `ReferralCode`
• UserId
• PhoneNumber
• IsClubMember (bool)
• Roles[] (Admin, Customer)
• ReferralCode
```
### ۲.۲ اصلاحات ثبت‌نام ### ۲.۲ اصلاحات ثبت‌نام
@@ -76,16 +56,15 @@ JWT Claims:
### ۳.۱ مشکل قبلی ### ۳.۱ مشکل قبلی
``` ```mermaid
قبل: flowchart LR
Admin و Customer هر دو از یک DbContext و Identity استفاده می‌کردند subgraph BEFORE["قبل — مشکل"]
یک ادمین می‌توانست به صورت Customer هم ظاهر شود ← تداخل Claims A1["Admin + Customer"] --> A2["یک DbContext\nیک Identity\nتداخل Claims"]
end
بعد (اصلاح‌شده): subgraph AFTER["بعد اصلاح‌شده ✅"]
ICurrentUserService → تشخیص دقیق نقش فعلی B1["ICurrentUserService"] --> B2["جداسازی Policy\nAdmin → BackOffice\nCustomer → FrontOffice"]
✅ جداسازی Authorization Policy end
✅ Admin claims فقط در BackOffice
✅ Customer claims فقط در FrontOffice
``` ```
### ۳.۲ ICurrentUserService ### ۳.۲ ICurrentUserService
@@ -110,29 +89,16 @@ public interface ICurrentUserService {
### ۴.۱ فلوی امضای قرارداد ### ۴.۱ فلوی امضای قرارداد
``` ```mermaid
خرید پکیج طلایی → Redirect به صفحه قرارداد flowchart TD
A["خرید پکیج طلایی\nRedirect به صفحه قرارداد"] --> B["نمایش Modal\nغیرقابل‌بسته‌شدن"]
B --> C["ReadContract RPC\nنمایش متن قرارداد"]
نمایش Modal غیرقابل‌بسته‌شدن C --> D["اسکرول تا انتها"]
D --> E["فعال شدن دکمه\nارسال کد تأیید"]
E --> F["RequestContractOtp\nارسال SMS"]
ReadContract RPC → نمایش متن قرارداد (Markdown/HTML) F --> G["ورود کد\nVerifyContractOtp"]
G -->|معتبر| H["✅ AcceptContract\nفعالسازی عضویت"]
G -->|نامعتبر| I["❌ پیام خطا\nحداکثر ۵ تلاش"]
کاربر باید تا انتهای متن اسکرول کند
فعال شدن دکمه "ارسال کد تأیید"
RequestContractOtp → ارسال SMS
ورود کد ← VerifyContractOtp
├─→ معتبر: AcceptContract → فعالسازی عضویت
└─→ نامعتبر: پیام خطا (حداکثر ۵ تلاش)
``` ```
### ۴.۲ ذخیره‌سازی قرارداد ### ۴.۲ ذخیره‌سازی قرارداد
@@ -206,20 +172,12 @@ else
## ۷. کدهای معرف (Referral) ## ۷. کدهای معرف (Referral)
``` ```mermaid
هر عضو باشگاه → یک ReferralCode یکتا flowchart TD
لینک: https://foursat.ir/register?ref={ReferralCode} A["هر عضو باشگاه\nیک ReferralCode یکتا"] --> B["لینک:\nhttps://foursat.ir/register?ref=CODE"]
B --> C["ثبت‌نام با لینک\nذخیره ReferrerId"]
ثبت‌نام با لینک: C --> D["خرید پکیج\nزیرمجموعه Referrer در درخت"]
D --> E["Referrer\nدریافت bonus"]
ذخیره ReferrerId در پروفایل کاربر جدید
هنگام خرید پکیج → زیرمجموعه Referrer در درخت باینری
Referrer → دریافت bonus (طبق شرایط باشگاه)
``` ```
--- ---
+26 -48
View File
@@ -9,14 +9,15 @@
### ۱.۱ معماری ساده‌شده (Shopify-style) ### ۱.۱ معماری ساده‌شده (Shopify-style)
``` ```mermaid
قبل (پیچیده): flowchart LR
SitePage → SitePageSetting → SitePageContent → Template → ... (7 جدول) subgraph BEFORE["قبل — پیچیده"]
X1["SitePage"] --> X2["SitePageSetting"] --> X3["SitePageContent"] --> X4["Template\n... 7 جدول"]
end
بعد (ساده): subgraph AFTER["بعد ساده ✅"]
SitePage (PageType, JsonSettings, IsPublished) Y1["SitePage\nPageType + JsonSettings"] --> Y2["هر PageType\nیک typed editor"]
end
└─→ هر PageType → یک typed editor در BackOffice
``` ```
### ۱.۲ انواع صفحات ### ۱.۲ انواع صفحات
@@ -97,21 +98,14 @@ message GetBlogPostsRequest {
### ۳.۱ معماری ### ۳.۱ معماری
```mermaid
flowchart TD
A["آپلود فایل\nتصویر / سند"] --> B["FileManagementService"]
B --> C["ذخیره در فایل‌سیستم\n+ ثبت در DB"]
C --> D["مسیر: /app/uploads/year/month/guid.ext\nURL: /api/files/guid"]
``` ```
آپلود فایل (تصویر/سند)
FileManagementService → ذخیره در فایل‌سیستم + ثبت در DB
مسیر فیزیکی: /app/uploads/{year}/{month}/{guid}.{ext}
مسیر URL: /api/files/{guid}
محدودیت‌ها: > محدودیت: حداکثر 10MB • jpg, png, webp, pdf, doc, docx • Resize: 800×800 (محصولات)
• حداکثر حجم: 10MB (configurable)
• فرمت‌های مجاز: jpg, png, webp, pdf, doc, docx
• تصاویر: resize خودکار به 800×800 (محصولات)
```
### ۳.۲ Storage Strategy ### ۳.۲ Storage Strategy
@@ -198,20 +192,12 @@ CREATE TABLE SystemConfigurations (
### ۶.۱ معماری ### ۶.۱ معماری
``` ```mermaid
Hangfire Recurring Job (هر ۵ دقیقه) flowchart TD
A["Hangfire Recurring Job\nهر ۵ دقیقه"] --> B["ChatikaJob\nبررسی پیام‌های جدید"]
B --> C["ارسال به Chatika API\nPolly retry ×3"]
ChatikaJob → بررسی پیام‌های جدید کاربران C --> D["دریافت پاسخ\nذخیره در ChatMessages"]
D --> E["نمایش در UI باشگاه\nSignalR planned"]
ارسال به Chatika API (با Polly retry ×3)
دریافت پاسخ → ذخیره در ChatMessages
نمایش در UI باشگاه (real-time via SignalR planned)
``` ```
### ۶.۲ فعلی vs آینده ### ۶.۲ فعلی vs آینده
@@ -228,20 +214,12 @@ ChatikaJob → بررسی پیام‌های جدید کاربران
### ۷.۱ ساختار ### ۷.۱ ساختار
``` ```mermaid
Hero Section (انیمیشن fade-in) flowchart TD
A["🎨 Hero Section\nانیمیشن fade-in"] --> B["✨ ویژگی‌ها\nFeatures Grid — 3 ستونه"]
B --> C["📦 محصولات ویژه\nCarousel"]
ویژگی‌ها (Features Grid — 3 ستونه) C --> D["📊 آمار\nCounter animation\nlinear interpolation"]
D --> E["🚀 CTA\nثبت‌نام / ورود"]
محصولات ویژه (Carousel)
آمار (Counter animation — اصلاح‌شده)
CTA — Call to Action (ثبت‌نام / ورود)
``` ```
### ۷.۲ اصلاح انیمیشن Counter ### ۷.۲ اصلاح انیمیشن Counter
+170 -241
View File
@@ -7,283 +7,212 @@
## ۱. فلوی کلان کاربر (User Journey) ## ۱. فلوی کلان کاربر (User Journey)
``` ```mermaid
┌─────────────────────────────────────────────────────────────────────────┐ flowchart TD
│ FourSat — User Journey │ A["🌐 ورود به سایت"] --> B{"آیا ثبت‌نام کرده؟"}
├─────────────────────────────────────────────────────────────────────────┤ B -->|خیر| C["Landing Page"]
│ │ C --> D["ثبت‌نام\nموبایل + OTP"]
│ [ورود به سایت] │ D --> E["پروفایل"]
│ │ │ E --> F
│ ▼ │
│ ◆ آیا ثبت‌نام کرده؟ ◆──── خیر ───→ [Landing Page] │ B -->|بله| G["Login + JWT"]
│ │ │ │ G --> H{"عضو باشگاه؟"}
│ بله [ثبت‌نام] │ H -->|خیر| F["🛒 Regular Store\nخرید عادی — IPG پرداخت"]
│ │ موبایل + OTP │ H -->|بله| I["🏆 Club Member Dashboard"]
│ ▼ │ │
│ [Login + JWT] ▼ │ I --> J["فروشگاه تخفیفی\nper-product MaxDiscount%"]
│ │ [پروفایل] │ I --> K["درخت شبکه\nباینری"]
│ ▼ │ │ I --> L["کمیسیون\nهفتگی"]
│ ◆ عضو باشگاه؟ ◆ ▼ │ I --> M["Chatika AI"]
│ │ │ ┌───────────────┐ │
│ بله خیر │ Regular Store │ │
│ │ │ │ خرید عادی │ │
│ │ └──────────────→│ IPG پرداخت │ │
│ │ └───────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Club Member Dashboard │ │
│ ├──────────┬──────────┬──────────┬─────────────┤ │
│ │ فروشگاه │ درخت شبکه │ کمیسیون │ Chatika AI │ │
│ │ تخفیفی │ باینری │ هفتگی │ │ │
│ │ (per-product) │ │ │ │ │
│ └──────────┴──────────┴──────────┴─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
``` ```
--- ---
## ۲. فلوی مالی (Financial Flow) ## ۲. فلوی مالی (Financial Flow)
``` ```mermaid
┌─────────────────────────────────────────────────────────────────────────┐ flowchart TD
│ FourSat — Financial Flow │ subgraph INPUT["═══ ورودی پول ═══"]
├─────────────────────────────────────────────────────────────────────────┤ Z1["ZarinPal IPG"]
│ │ Z2["Daya Loan"]
│ ═══════════════════ ورودی پول ═══════════════════ │ Z3["Manual Pay"]
│ │ end
│ [ZarinPal IPG] ──→ ┐ │
│ [Daya Loan] ──→ ├──→ [PYMS Service] ──→ [DB Transaction] │ Z1 --> PYMS["PYMS Service"]
│ [Manual Pay] ──→ ┘ │ │ Z2 --> PYMS
│ ▼ │ Z3 --> PYMS
│ ═══════════ توزیع به کیف‌پول‌ها ═══════════ │ PYMS --> TX[("DB Transaction")]
│ │
│ ┌────────────────┐ ┌─────────────────┐ ┌──────────────────┐ │ TX --> W1 & W2 & W3
│ │ 💰 Balance │ │ 🌟 NetworkBal │ │ 🏷️ DiscountBal │ │
│ │ (نقدی) │ │ (طلایی/کمیسیون)│ │ (تخفیفی) │ │ subgraph WALLETS["═══ توزیع به کیف‌پول‌ها ═══"]
│ │ │ │ │ │ │ │ W1["💰 Balance — نقدی\n• IPG: +56M\n• Daya: +56M\n• فعالسازی: −25.2M\n• خرید فروشگاه"]
│ │ • IPG: +56M │ │ • شارژ نمی‌شود │ │ • IPG: +112M │ │ W2["🌟 NetworkBalance — طلایی\n• شارژ نمی‌شود\n• فقط محاسبه کمیسیون\n• سقف 300/هفته"]
│ │ • Daya: +56M │ │ • فقط برای │ │ • Daya: +112M │ │ W3["🏷️ DiscountBalance — تخفیفی\n• IPG: +112M\n• Daya: +112M\n• per-product MaxDiscount%"]
│ │ • فعالسازی │ │ محاسبه │ │ (دو برابر) │ │ end
│ │ -25.2M │ │ کمیسیون │ │ • per-product │ │
│ │ • خرید فروشگاه │ │ • سقف 300/هفته │ │ MaxDiscount% │ │ W1 & W2 --> POOL
│ └───────┬────────┘ └────────┬────────┘ └────────┬─────────┘ │
│ │ │ │ │ subgraph POOL["═══ Weekly Commission Pool ═══"]
│ ▼ ▼ ▼ │ P1["هر فعالسازی → 25.2M واریز به Pool"]
│ ═══════════════════ خروجی پول ═══════════════════ │ P2["sp_CalculateWeeklyBalances"]
│ │ P3["sp_CalculateWeeklyCommissionPool"]
│ ┌──────────────────────────────────────────────────────┐ │ P4["UserShare = UserBalance / TotalBalance"]
│ │ Weekly Commission Pool │ │ P5["Cap: MAX 300 per leg per week"]
│ │ │ │ P1 --> P2 --> P3 --> P4 --> P5
│ │ Source: هر فعالسازی → 25.2M واریز │ │ end
│ │ Calculate: sp_CalculateWeeklyBalances │ │
│ │ Distribute: sp_CalculateWeeklyCommissionPool │ │
│ │ Formula: UserShare = UserBalance / TotalBalance │ │
│ │ Cap: MAX 300 per leg per week │ │
│ │ Carryover: به هفته بعد (max 300, else flush) │ │
│ │ │ │
│ │ ┌─ Member A: Balance=150 → Share=150/600 → 25% ─┐ │ │
│ │ │ Member B: Balance=200 → Share=200/600 → 33% │ │ │
│ │ │ Member C: Balance=250 → Share=250/600 → 42% │ │ │
│ │ └─ Total: 600 ─┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
``` ```
--- ---
## ۳. فلوی داده (Data Flow) ## ۳. فلوی داده (Data Flow)
``` ```mermaid
┌─────────────────────────────────────────────────────────────────────────┐ flowchart TD
│ FourSat — Data Flow │ CLIENT["🌐 Browser / Client"] -->|HTTPS| NGINX["nginx / K8s Ingress"]
├─────────────────────────────────────────────────────────────────────────┤
│ │ NGINX -->|"/"| FO["FrontOffice :5003\nBlazor Server"]
│ [Browser/Client] │ NGINX -->|"/admin"| BO["BackOffice :5002\nBlazor WASM"]
│ │ │ NGINX -->|"/hangfire"| CMS
│ │ HTTPS │
│ ▼ │ FO -->|gRPC| CMS["CMS Microservice :5001"]
│ [nginx / K8s Ingress] │ BO -->|gRPC| CMS
│ │ │
│ ├──→ / ──────────→ [FrontOffice :5003] (Blazor Server) │ CMS --> MEDIATR["MediatR\nCommands / Queries → Handlers"]
│ │ │ │ CMS --> HF["Hangfire\n• DayaLoan — */20 min\n• Commission — Sunday 00:05\n• Chatika — */5 min"]
│ ├──→ /admin ─────→ [BackOffice :5002] (Blazor WASM) │ CMS --> EXT["External Services\n• ZarinPal API\n• Kavenegar API\n• DayaLoan API\n• Chatika API"]
│ │ │ │
│ └──→ /hangfire ──→ [CMS :5001] (Dashboard) │ MEDIATR --> EF["EF Core 9"]
│ │ │ HF --> EF
│ ┌─────────────────────────────┘ │ EF --> DB[("SQL Server 2022\nSchema: CMS\n~15 tables + 3 SPs")]
│ │ gRPC (Protobuf v3, HTTP/2) │
│ ▼ │
│ [CMS Microservice :5001] │
│ │ │
│ ├──→ [MediatR] ──→ Commands/Queries ──→ Handlers │
│ │ │ │
│ ├──→ [Hangfire] ──→ Background Jobs │ │
│ │ • DayaLoan (15min) │ │
│ │ • Commission (weekly) │ │
│ │ • Chatika (5min) │ │
│ │ • InventorySync (hourly) │ │
│ │ │ │
│ └──→ [External Services] │ │
│ • ZarinPal API │ │
│ • Kavenegar API ▼ │
│ • DayaLoan API [EF Core 9] │
│ • Chatika API │ │
│ ▼ │
│ [SQL Server 2022] │
│ Schema: [CMS] │
│ ~15 main tables │
│ + 3 Stored Procs │
│ │
└─────────────────────────────────────────────────────────────────────────┘
``` ```
--- ---
## ۴. درخت باینری شبکه (Network Tree) ## ۴. درخت باینری شبکه (Network Tree)
``` ```mermaid
┌─────────┐ graph TD
│ Root │ ROOT["🔵 Root — Admin"]
│ (Admin) │ ROOT --- A["👤 User A\nL=120 | R=80"]
└────┬────┘ ROOT --- B["👤 User B\nL=0 | R=150"]
┌─────────┴─────────┐
┌────▼────┐ ┌────▼────┐
│ User A │ │ User B │
│ L=120 │ │ L=0 │
│ R=80 │ │ R=150 │
└────┬────┘ └────┬────┘
┌───────┴───────┐ ┌──────┴──────┐
┌────▼──┐ ┌────▼──┐ ┌──▼───┐ ┌───▼──┐
│User C │ │User D │ │User E│ │User F│
│Active │ │Active │ │Pend. │ │Active│
└───────┘ └───────┘ └──────┘ └──────┘
Legend: A --- C["✅ User C\nActive"]
L = Left leg sales this week A --- D["✅ User D\nActive"]
R = Right leg sales this week B --- E["⏳ User E\nPending"]
Active = فعال (contract signed) B --- F["✅ User F\nActive"]
Pend. = در انتظار فعالسازی
شبکه روی entity User مدل شده (NetworkParentId, LegPosition) style ROOT fill:#1976D2,color:#fff
محاسبه کمیسیون تا عمق 15 سطح — درخت بدون محدودیت عمق style C fill:#4CAF50,color:#fff
style D fill:#4CAF50,color:#fff
style E fill:#FF9800,color:#fff
style F fill:#4CAF50,color:#fff
``` ```
> **راهنما:**
> - `L` / `R` = فروش پای چپ / راست این هفته
> - **Active** = فعال (قرارداد امضا شده) — **Pending** = در انتظار فعالسازی
> - شبکه روی entity `User` مدل شده (`NetworkParentId`, `LegPosition`)
> - محاسبه کمیسیون تا عمق ۱۵ سطح — درخت بدون محدودیت عمق
--- ---
## ۵. فلوی خرید — Regular vs Discount Store ## ۵. فلوی خرید — Regular vs Discount Store
### ۵.۱ Regular Store
```mermaid
flowchart TD
A1["مشاهده محصولات"] --> B1["Lazy Load — 12 per page"]
B1 --> C1["افزودن به سبد"]
C1 --> D1["بررسی موجودی"]
D1 --> E1["Checkout"]
E1 --> F1["ZarinPal IPG\n100% نقدی"]
F1 --> G1["ثبت سفارش"]
G1 --> H1["کسر موجودی"]
H1 --> I1["SMS تأیید"]
``` ```
┌────────────────────────────────┬──────────────────────────────────┐
│ Regular Store │ Discount Store │ ### ۵.۲ Discount Store
├────────────────────────────────┼──────────────────────────────────┤
│ │ │ ```mermaid
│ [مشاهده محصولات] │ [مشاهده محصولات] ← فقط باشگاه │ flowchart TD
│ │ │ │ │ A2["مشاهده محصولات\nفقط اعضای باشگاه"] --> B2["Lazy Load — 12 per page"]
│ ▼ │ ▼ │ B2 --> C2["افزودن به سبد"]
│ [Lazy Load — 12 per page] │ [Lazy Load — 12 per page] │ C2 --> D2["بررسی موجودی + DiscountBalance"]
│ │ │ │ │ D2 --> E2["محاسبه سهم تخفیف\nMaxDiscount% هر محصول"]
│ ▼ │ ▼ │ E2 --> F2["محاسبه سهم نقدی\nباقیمانده"]
│ [افزودن به سبد] │ [افزودن به سبد] │ F2 --> G2["کسر از DiscountBalance"]
│ │ │ │ │ G2 --> H2["ZarinPal IPG\nبرای باقیمانده نقدی"]
│ ▼ │ ▼ │ H2 --> I2["ثبت سفارش ترکیبی"]
│ [بررسی موجودی] │ [بررسی موجودی] │ I2 --> J2["کسر موجودی"]
│ │ │ [بررسی DiscountBalance] │ J2 --> K2["SMS تأیید"]
│ ▼ │ │ │
│ [Checkout] │ ▼ │
│ │ │ [محاسبه سهم تخفیف (MaxDiscount%)]│
│ ▼ │ [محاسبه سهم نقدی (باقیمانده)] │
│ [ZarinPal IPG] │ │ │
│ [100% نقدی] │ ▼ │
│ │ │ [کسر از DiscountBalance] │
│ ▼ │ [ZarinPal IPG برای باقیمانده] │
│ [ثبت سفارش] │ │ │
│ │ │ ▼ │
│ ▼ │ [ثبت سفارش ترکیبی] │
│ [کسر موجودی] │ [کسر موجودی] │
│ │ │ │ │
│ ▼ │ ▼ │
│ [SMS تأیید] │ [SMS تأیید] │
│ │ │
└────────────────────────────────┴──────────────────────────────────┘
``` ```
--- ---
## ۶. معماری Deployment ## ۶. معماری Deployment
``` ```mermaid
┌──────────────────────────────────────────────────────────────┐ flowchart TD
│ Production Server │ subgraph SERVER["🖥️ Production Server — 45.149.79.127"]
│ 45.149.79.127 │ NGINX["nginx\n:80 / :443"]
├──────────────────────────────────────────────────────────────┤ subgraph K8S["☸ Kubernetes Cluster"]
│ │ CMS["CMS ×2\n:5001 gRPC"]
│ ┌─────────┐ ┌────────────────────────────────────┐ │ FO["FrontOffice ×2\n:5003 Blazor Server"]
│ │ nginx │────→│ Kubernetes Cluster │ │ BO["BackOffice ×1\n:5002 Static"]
│ │ :80/:443│ │ │ │ DB[("SQL Server\n:1433")]
│ └─────────┘ │ ┌───────────┐ ┌───────────────┐ │ │ NEXUS["Nexus\n:8081"]
│ │ │CMS ×2 │ │FrontOffice ×2 │ │ │ HF["Hangfire\ninside CMS"]
│ │ │:5001 gRPC │ │:5003 Blazor │ │ │ end
│ │ └─────┬─────┘ └───────────────┘ │ │ end
│ │ │ │ │
│ │ ┌─────▼─────┐ ┌───────────────┐ │ │ NGINX --> CMS
│ │ │SQL Server │ │BackOffice ×1 │ │ │ NGINX --> FO
│ │ │:1433 │ │:5002 Static │ │ │ NGINX --> BO
│ │ └───────────┘ └───────────────┘ │ │ CMS --> DB
│ │ │ │ CMS --> HF
│ │ ┌───────────┐ ┌───────────────┐ │ │
│ │ │Nexus │ │Hangfire │ │ │ style SERVER fill:#f5f5f5,stroke:#333
│ │ │:8081 │ │(inside CMS) │ │ │ style K8S fill:#e3f2fd,stroke:#1976D2
│ │ └───────────┘ └───────────────┘ │ │
│ └────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
``` ```
--- ---
## ۷. Entity Relationship (ساده‌شده) ## ۷. Entity Relationship (ساده‌شده)
``` ```mermaid
┌──────────┐ ┌──────────────┐ erDiagram
User │────→│ ClubMembership User ||--o{ ClubMembership : has
│ +Network │ │ │ User ||--o| UserWallet : has
│ ParentId│ └──────────────┘ User ||--o{ UserContract : signs
│ +LegPos │ User ||--o{ UserOrder : places
└────┬─────┘ User ||--o{ ChatMessage : sends
User }o--o| User : "NetworkParentId"
├────→ ┌──────────┐ ┌──────────┐
│ │ Order │────→│ OrderItem│────→ [Product] UserOrder ||--|{ OrderItem : contains
│ └──────────┘ └──────────┘ OrderItem }o--|| Product : references
UserOrder ||--o{ Transaction : has
├────→ ┌──────────────┐
│ │ Transaction │ Product ||--o| Inventory : has
│ └──────────────┘ Product }o--|| Category : belongs_to
Product ||--o{ ProductImage : has
├────→ ┌──────────────┐
│ │ UserWallet │────→ Balance + NetworkBalance + DiscountBalance UserWallet ||--o{ UserWalletChangeLog : logs
│ └──────────────┘
BlogPost }o--|| Category : belongs_to
├────→ ┌──────────────┐
│ │ UserContract UserWallet {
│ └──────────────┘ long Balance
long NetworkBalance
└────→ ┌──────────────┐ long DiscountBalance
│ ChatMessage │ }
└──────────────┘ User {
Guid NetworkParentId
┌──────────┐ ┌───────────┐ int LegPosition
│ Product │────→│ Inventory │ }
│ │────→│ Category │ UserContract {
│ │────→│ Images │ Guid SignGuid
└──────────┘ string SignedPdfFile
}
┌──────────┐ ┌──────────────────────┐
│ SitePage │ │ SystemConfiguration │
│ (typed) │ │ (key-value) │
└──────────┘ └──────────────────────┘
┌──────────┐
│ BlogPost │────→ [Tags, Category, Author]
└──────────┘
``` ```
+19 -28
View File
@@ -71,34 +71,25 @@ totalDoc/
## نقشه ارتباط فایل‌ها ## نقشه ارتباط فایل‌ها
``` ```mermaid
┌──────────────┐ graph TD
O2: INDEX │ ← شما اینجا هستید INDEX["📋 O2: INDEX\nشما اینجا هستید"]
└──────┬───────┘ INDEX --> BIZ["📁 Business\nB1-B5"]
INDEX --> TECH["📁 Technical\nT1-T5"]
┌─────────────────┼──────────────────┐ INDEX --> OVR["📁 Overview\nO1-O5"]
│ │ │
┌────▼────┐ ┌────▼─────┐ ┌────▼─────┐ BIZ --- B12["B1 ↔ B2\nمالی / باشگاه"]
│Business │ │Technical │ │Overview │ BIZ --- B23["B2 ↔ B3\nپرداخت / فروشگاه"]
│ (B1-B5) │ │ (T1-T5) │ │ (O1-O5) │ BIZ --- B34["B3 ↔ B4\nفروشگاه / کاربر"]
└────┬────┘ └────┬─────┘ └────┬─────┘ BIZ --- B45["B4 ↔ B5\nکاربر / محتوا"]
│ │ │
┌────┴────────────────┴──────────────────┴────┐ BIZ --- TECH
│ │ TECH --- T12["T1 ↔ T2 — CMS/UI"]
│ B1 ←→ B2 (مالی/باشگاه) │ TECH --- T13["T1 ↔ T3 — CMS/Deploy"]
│ B2 ←→ B3 (پرداخت/فروشگاه) │ TECH --- T34["T3 ↔ T4 — Deploy/Migration"]
│ B3 ←→ B4 (فروشگاه/کاربر) │ TECH --- T15["T1 ↔ T5 — CMS/API"]
│ B4 ←→ B5 (کاربر/محتوا) │
│ B1 ←→ T1 (باشگاه/CMS) │ OVR --- OX["O1: دیاگرام‌ها\nO3: تاریخچه\nO5: نقشه راه"]
│ T1 ←→ T2 (CMS/UI) │
│ T1 ←→ T3 (CMS/Deploy) │
│ T3 ←→ T4 (Deploy/Migration) │
│ T1 ←→ T5 (CMS/API) │
│ O1: دیاگرام = بصری B1-B5 + T1-T5 │
│ O3: تاریخچه = changelog B1-B5 + T1-T5 │
│ O5: آینده = roadmap B1-B5 + T1-T5 │
│ │
└──────────────────────────────────────────────┘
``` ```
--- ---
+32 -30
View File
@@ -69,40 +69,42 @@ Documentation ████████████████████
### Q1 1404 (فروردین-خرداد) ### Q1 1404 (فروردین-خرداد)
``` ```mermaid
Sprint 1 (فروردین): gantt
├── H2: Mobile Responsive title Q1 1404 — فروردین تا خرداد
├── H1: Product Bundle dateFormat YYYY-MM-DD
└── M4: SEO Meta Tags section Sprint 1 فروردین
H2 Mobile Responsive :a1, 2025-03-21, 5d
Sprint 2 (اردیبهشت): H1 Product Bundle :a2, after a1, 3d
├── M1: Manual Payment (if approved) M4 SEO Meta Tags :a3, after a2, 2d
├── M2: SignalR Chatika section Sprint 2 اردیبهشت
└── M6: Dashboard Charts M1 Manual Payment :b1, 2025-04-21, 3d
M2 SignalR Chatika :b2, after b1, 2d
Sprint 3 (خرداد): M6 Dashboard Charts :b3, after b2, 3d
├── M3: Dark Mode section Sprint 3 خرداد
├── H3: Rate Limiting M3 Dark Mode :c1, 2025-05-22, 2d
└── L1: PWA H3 Rate Limiting :c2, after c1, 2d
L1 PWA :c3, after c2, 3d
``` ```
### Q2 1404 (تیر-شهریور) ### Q2 1404 (تیر-شهریور)
``` ```mermaid
Sprint 4 (تیر): gantt
├── L3: Monitoring title Q2 1404 — تیر تا شهریور
├── L4: Log Aggregation dateFormat YYYY-MM-DD
└── L2: API Versioning section Sprint 4 تیر
L3 Monitoring :d1, 2025-06-22, 3d
Sprint 5 (مرداد): L4 Log Aggregation :d2, after d1, 3d
├── L5: Product Compare L2 API Versioning :d3, after d2, 2d
├── L6: Wishlist section Sprint 5 مرداد
└── L7: Email Templates L5 Product Compare :e1, 2025-07-23, 2d
L6 Wishlist :e2, after e1, 2d
Sprint 6 (شهریور): L7 Email Templates :e3, after e2, 2d
├── L8: Refund System section Sprint 6 شهریور
├── Performance Optimization L8 Refund System :f1, 2025-08-23, 5d
└── Security Audit Performance Optimization :f2, after f1, 3d
Security Audit :f3, after f2, 3d
``` ```
--- ---
+45 -37
View File
@@ -22,30 +22,38 @@
## ۲. معماری لایه‌ای CMS ## ۲. معماری لایه‌ای CMS
``` ```mermaid
┌──────────────────────────────────────────────────────┐ flowchart TD
Presentation Layer subgraph PRES["💻 Presentation Layer"]
FrontOffice (Blazor Server) ←─gRPC─→ CMS │ FO["FrontOffice\nBlazor Server"]
BackOffice (Blazor WASM) ←─gRPC─→ CMS │ BO["BackOffice\nBlazor WASM"]
├──────────────────────────────────────────────────────┤ end
│ Application Layer │
│ Commands (MediatR IRequest<T>) │ FO & BO -->|gRPC| APP
│ Queries (MediatR IRequest<T>) │
Validators (FluentValidation) │ subgraph APP["⚙️ Application Layer"]
│ Handlers (IRequestHandler<TReq, TRes>) │ CMD["Commands\nMediatR IRequest"]
├──────────────────────────────────────────────────────┤ QRY["Queries\nMediatR IRequest"]
│ Domain Layer │ VAL["Validators\nFluentValidation"]
│ Entities, Enums, Value Objects │ HND["Handlers\nIRequestHandler"]
│ Domain Events, Interfaces │ end
├──────────────────────────────────────────────────────┤
│ Infrastructure Layer │ APP --> DOM
│ EF Core DbContext (CMSDbContext) │
│ Repositories, External Services │ subgraph DOM["📦 Domain Layer"]
│ Hangfire Jobs, File Storage │ ENT["Entities, Enums\nValue Objects\nDomain Events"]
├──────────────────────────────────────────────────────┤ end
│ Database │
│ SQL Server — Schema: [CMS] │ DOM --> INF
└──────────────────────────────────────────────────────┘
subgraph INF["🔧 Infrastructure Layer"]
EF["EF Core DbContext"]
SVC["External Services"]
HF["Hangfire Jobs"]
FS["File Storage"]
end
INF --> DB[("🗄️ SQL Server\nSchema: CMS")]
``` ```
--- ---
@@ -191,22 +199,22 @@ Engine: MSSQL 2022-CU16, Collation=Arabic_CI_AS
### ۶.۱ قبل vs بعد ### ۶.۱ قبل vs بعد
``` ```mermaid
قبل: flowchart LR
FrontOffice → BFF (REST) → CMS (gRPC) subgraph BEFORE["قبل"]
BackOffice → BFF (REST) → CMS (gRPC) F1["FrontOffice"] -->|REST| BFF1["BFF"]
B1["BackOffice"] -->|REST| BFF1
BFF1 -->|gRPC| C1["CMS"]
end
بعد (فعلی): subgraph AFTER["بعد فعلی ✅"]
FrontOffice → CMS (gRPC مستقیم) F2["FrontOffice"] -->|gRPC| C2["CMS"]
BackOffice → CMS (gRPC مستقیم) B2["BackOffice"] -->|gRPC| C2
end
مزایا:
✅ حذف لایه واسط → کاهش latency
✅ حذف maintenance اضافی
✅ Type-safe از proto تا UI
✅ کاهش ۱ سرویس در deployment
``` ```
> مزایا: حذف لایه واسط → کاهش latency • Type-safe از proto تا UI • کاهش ۱ سرویس در deployment
### ۶.۲ سازگاری API ### ۶.۲ سازگاری API
``` ```
+24 -30
View File
@@ -214,21 +214,21 @@ jobs:
### ۵.۱ فلوی آماده‌سازی ### ۵.۱ فلوی آماده‌سازی
``` ```mermaid
سرور اینترنت‌دار: flowchart TD
1. pull-base-images.sh → دانلود Docker images subgraph ONLINE["🌐 سرور اینترنت‌دار"]
2. cache-nuget-packages.shدانلود NuGet packages A1["pull-base-images.sh\nدانلود Docker images"] --> A2["cache-nuget-packages.sh\nدانلود NuGet packages"]
3. save-images.shذخیره تصاویر به tar A2 --> A3["save-images.sh\nذخیره تصاویر به tar"]
4. بسته‌بندی همه فایل‌ها A3 --> A4["بسته‌بندی"]
end
انتقال فیزیکی (USB/HDD): A4 -->|"💾 انتقال فیزیکی\nUSB / HDD"| B1
tar files + nuget packages + k8s manifests
سرور آفلاین: subgraph OFFLINE["🔒 سرور آفلاین"]
1. load-images.shبارگذاری تصاویر B1["load-images.sh\nبارگذاری تصاویر"] --> B2["setup-nexus-complete.sh\nراه‌اندازی Nexus"]
2. setup-nexus-complete.sh → راه‌اندازی Nexus (NuGet proxy) B2 --> B3["build-all-offline.sh\nبیلد با Nexus محلی"]
3. build-all-offline.sh → بیلد با Nexus محلی B3 --> B4["k8s-deploy.sh\nاستقرار در K8s"]
4. k8s-deploy.sh → استقرار در Kubernetes end
``` ```
### ۵.۲ اسکریپت‌های کلیدی ### ۵.۲ اسکریپت‌های کلیدی
@@ -250,12 +250,12 @@ jobs:
### ۶.۱ نقش ### ۶.۱ نقش
``` ```mermaid
Nexus (داخلی): graph TD
├── NuGet proxycache.nuget.org packages NEXUS["Nexus داخلی"] --> NP["NuGet proxy\ncache nuget.org"]
├── NuGet hostedبسته‌های proto داخلی NEXUS --> NH["NuGet hosted\nبسته‌های proto داخلی"]
├── Docker proxycache Docker Hub images NEXUS --> DP["Docker proxy\ncache Docker Hub"]
└── Docker hostedتصاویر داخلی FourSat NEXUS --> DH["Docker hosted\nتصاویر داخلی FourSat"]
``` ```
### ۶.۲ NuGet.config ### ۶.۲ NuGet.config
@@ -303,17 +303,11 @@ Proto packages: BaGet (internal) at http://localhost:5555
### ۸.۱ فلوی بسته‌بندی ### ۸.۱ فلوی بسته‌بندی
``` ```mermaid
CMS/src/Protos/*.proto flowchart TD
A["CMS/src/Protos/*.proto"] --> B["pack-protos.sh\ndotnet pack → .nupkg"]
B --> C["Push to BaGet / Nexus"]
pack-protos.sh → dotnet pack → .nupkg C --> D["BackOffice + FrontOffice\ndotnet restore → مصرف proto"]
push to BaGet/Nexus
BackOffice + FrontOffice → dotnet restore → مصرف proto
``` ```
### ۸.۲ نام بسته ### ۸.۲ نام بسته
+23 -25
View File
@@ -23,30 +23,24 @@ Timeline:
### ۲.۱ قبل ### ۲.۱ قبل
```mermaid
flowchart LR
FO1["FrontOffice"] -->|HTTP/REST| BFF["BFF"]
BO1["BackOffice"] -->|HTTP/REST| BFF
BFF -->|gRPC| CMS1["CMS"]
``` ```
FrontOffice ──HTTP/REST──→ BFF ──gRPC──→ CMS
BackOffice ──HTTP/REST──→ BFF ──gRPC──→ CMS
BFF مسئولیت‌ها: **BFF مسئولیت‌ها:** تبدیل REST↔gRPC • Aggregation • Auth proxy • Rate limiting
• تبدیل REST↔gRPC
• Aggregation
• Auth proxy
• Rate limiting
```
### ۲.۲ بعد (فعلی) ### ۲.۲ بعد (فعلی)
```mermaid
flowchart LR
FO2["FrontOffice"] -->|gRPC| CMS2["CMS مستقیم"]
BO2["BackOffice"] -->|gRPC| CMS2
``` ```
FrontOffice ──gRPC──→ CMS (مستقیم)
BackOffice ──gRPC──→ CMS (مستقیم)
مزایا: **مزایا:** ✅ حذف ۱ سرویس • کاهش ~50ms latency • Type-safety از proto تا UI • ساده‌سازی debug
✅ حذف ۱ سرویس از deployment
✅ کاهش ~50ms latency per request
✅ Type-safety از proto تا UI
✅ ساده‌سازی debug و logging
✅ کاهش maintenance cost
```
### ۲.۳ مراحل مهاجرت ### ۲.۳ مراحل مهاجرت
@@ -78,18 +72,22 @@ BackOffice ──gRPC──→ CMS (مستقیم)
### ۳.۱ قبل ### ۳.۱ قبل
``` ```mermaid
Client → nginx → Ocelot Gateway → { CMS, BFF, FileService } flowchart LR
CL1["Client"] --> NG1["nginx"] --> OC["Ocelot Gateway"]
URL routing, rate limiting, auth OC --> CMS3["CMS"]
OC --> BFF2["BFF"]
OC --> FS1["FileService"]
``` ```
### ۳.۲ بعد ### ۳.۲ بعد
``` ```mermaid
Client → nginx → Ingress → { CMS, BackOffice, FrontOffice } flowchart LR
CL2["Client"] --> NG2["nginx"] --> ING["K8s Ingress"]
Path-based routing in Ingress ING --> CMS4["CMS"]
ING --> BO3["BackOffice"]
ING --> FO3["FrontOffice"]
``` ```
### ۳.۳ دلایل حذف ### ۳.۳ دلایل حذف
+6 -15
View File
@@ -294,21 +294,12 @@ public class ProductService : IProductService
## ۵. Proto Package Distribution ## ۵. Proto Package Distribution
``` ```mermaid
CMS/src/Protos/*.proto flowchart TD
A["CMS/src/Protos/*.proto"] --> B["pack-protos.sh"]
B --> C["Foursat.CMSMicroservice.Protobuf.nupkg\nv1.0.x"]
pack-protos.sh C --> D["Push to BaGet / Nexus"]
D --> E["BackOffice + FrontOffice\nPackageReference"]
Foursat.CMSMicroservice.Protobuf.nupkg (v1.0.x)
Push to BaGet (http://localhost:5555) or Nexus
BackOffice: <PackageReference Include="Foursat.CMSMicroservice.Protobuf" />
FrontOffice: <PackageReference Include="Foursat.CMSMicroservice.Protobuf" />
``` ```
--- ---