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`
@@ -38,36 +42,24 @@
## ۳. فلوی عضویت و فعالسازی
```
خرید پکیج طلایی (56M تومان)
نمایش مودال قرارداد (غیرقابل‌بسته‌شدن)
مشاهده متن قرارداد ← ReadContract RPC
درخواست OTP ← RequestContractOtp (Kavenegar SMS)
وارد کردن کد ← VerifyContractOtp
امضای قرارداد ← AcceptContract
├─→ شارژ ۲ کیف پول: Balance += 56M, DiscountBalance += 112M (2×)
│ (NetworkBalance شارژ نمی‌شود — فقط برای کمیسیون)
├─→ کسر هزینه فعالسازی (25.2M از Balance)
├─→ واریز 25.2M به Pool هفتگی (ClubActivationFee)
├─→ قرارگیری در درخت باینری
└─→ رفرش JWT Token (claims جدید)
```mermaid
flowchart TD
A["خرید پکیج طلایی — 56M"] --> B["نمایش مودال قرارداد\nغیرقابل‌بسته‌شدن"]
B --> C["مشاهده متن قرارداد\nReadContract RPC"]
C --> D["درخواست OTP\nRequestContractOtp — Kavenegar"]
D --> E["وارد کردن کد\nVerifyContractOtp"]
E --> F["امضای قرارداد\nAcceptContract"]
⚠️ در خرید با وام دایا:
├─→ Balance += 56M
└─→ DiscountBalance += 112M (دو برابر — DayaLoanAmount × 2)
F --> G["شارژ ۲ کیف‌پول\nBalance += 56M\nDiscountBalance += 112M"]
F --> H["کسر فعالسازی\n−25.2M از Balance"]
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 هفتگی و توزیع
```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‌ها
SP: sp_CalculateWeeklyBalances → sp_CalculateWeeklyCommissionPool
فرمت هفته: "YYYY-Www" (شمسی، شنبه‌پایه)
```
> فرمت هفته: `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 @@
## ۱. معماری کلی مالی
```
┌──────────────────────────────────────────────────────────────────┐
│ FourSat Payment Architecture │
├──────────────┬──────────────┬──────────────┬─────────────────────┤
ZarinPal Daya Loan │ Manual Pay │ Discount Wallet │
│ (IPG) │ (API) │ (Card2Card) │ (Internal) │
├──────────────┴──────────────┴──────────────┴─────────────────────┤
│ PYMS (Payment Service) │
│ gRPC ←→ CMS ←→ FrontOffice/BackOffice │
├──────────────────────────────────────────────────────────────────┤
│ 3 Wallet System │
│ Balance (نقدی) │ NetworkBalance (شبکه) │ DiscountBalance │
└──────────────────────────────────────────────────────────────────┘
```mermaid
flowchart TD
subgraph GATEWAYS["درگاه‌ها"]
ZP["ZarinPal\nIPG"]
DL["Daya Loan\nAPI"]
MP["Manual Pay\nCard2Card"]
DW["Discount Wallet\nInternal"]
end
ZP --> PYMS["PYMS — Payment Service\ngRPC ↔ CMS ↔ FrontOffice/BackOffice"]
DL --> PYMS
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 @@
### ۲.۱ فلوی پرداخت
```
کاربر → انتخاب محصول → درخواست پرداخت
CMS → CreatePaymentRequest (gRPC to PYMS)
PYMS → ZarinPal API → دریافت Authority
Redirect کاربر → صفحه پرداخت ZarinPal
بازگشت با Authority → CMS VerifyPayment
├─→ موفق: ثبت سفارش + شارژ کیف‌پول (در صورت نیاز)
└─→ ناموفق: نمایش پیام خطا
```mermaid
flowchart TD
A["کاربر → انتخاب محصول\nدرخواست پرداخت"] --> B["CMS → CreatePaymentRequest\ngRPC to PYMS"]
B --> C["PYMS → ZarinPal API\nدریافت Authority"]
C --> D["Redirect کاربر\nصفحه پرداخت ZarinPal"]
D --> E["بازگشت با Authority\nCMS VerifyPayment"]
E -->|موفق| F["✅ ثبت سفارش\n+ شارژ کیف‌پول"]
E -->|ناموفق| G["❌ نمایش پیام خطا"]
```
### ۲.۲ تنظیمات ZarinPal
@@ -62,21 +61,14 @@ Redirect کاربر → صفحه پرداخت ZarinPal
### ۳.۱ معماری
```
Hangfire Recurring Job (هر ۲۰ دقیقه — cron: */20 * * * *)
DayaLoanProcessorJob.Execute()
بررسی LoanRequests با Status=Pending
برای هر درخواست:
├─→ ارسال به DayaLoan API ([AutomaticRetry(Attempts=3)])
├─→ در صورت تأیید: Balance += 56M, DiscountBalance += 112M (2×)
├─→ ثبت Transaction + Log
└─→ در صورت رد: Status=Rejected + ارسال SMS
```mermaid
flowchart TD
A["Hangfire Recurring Job\nهر ۲۰ دقیقه — */20 * * * *"] --> B["DayaLoanProcessorJob.Execute"]
B --> C["بررسی LoanRequests\nStatus = Pending"]
C --> D["برای هر درخواست:"]
D --> E["ارسال به DayaLoan API\nAutomaticRetry Attempts=3"]
E -->|تأیید| F["✅ Balance += 56M\nDiscountBalance += 112M\n+ ثبت Transaction + Log"]
E -->|رد| G["❌ Status = Rejected\n+ ارسال SMS"]
```
### ۳.۲ Mock Mode
@@ -108,21 +100,14 @@ DayaLoanProcessorJob.Execute()
> ⚠️ **وضعیت: طراحی‌شده — پیاده‌سازی نشده**
```
فلوی پیشنهادی:
کاربر → انتخاب "کارت‌به‌کارت"
نمایش شماره‌کارت مقصد + مبلغ
کاربر → واریز + آپلود تصویر رسید
ادمین BackOffice → مشاهده لیست درخواست‌ها
تأیید/رد → شارژ خودکار کیف‌پول
```mermaid
flowchart TD
A["کاربر → انتخاب کارت‌به‌کارت"] --> B["نمایش شماره‌کارت مقصد\n+ مبلغ"]
B --> C["کاربر → واریز\n+ آپلود تصویر رسید"]
C --> D["ادمین BackOffice\nمشاهده لیست درخواست‌ها"]
D --> E{"تأیید / رد؟"}
E -->|تأیید| F["✅ شارژ خودکار کیف‌پول"]
E -->|رد| G["❌ اطلاع‌رسانی به کاربر"]
```
**موجودیت‌های مورد نیاز:**
@@ -149,22 +134,13 @@ MaxDiscountPercent محصول = 40% (هر محصول درصد تخفیف مخص
### ۵.۲ فلوی خرید فروشگاه تخفیفی
```
کاربر (عضو باشگاه) → مشاهده محصول
قیمت تخفیف‌خورده نمایش داده می‌شود
افزودن به سبد → بررسی DiscountBalance
├─→ DiscountBalance کافی:
│ سهم تخفیف از DiscountBalance کسر
│ باقیمانده → IPG (ZarinPal)
└─→ DiscountBalance ناکافی:
فقط به اندازه موجودی از تخفیف
باقیمانده بیشتر → IPG
```mermaid
flowchart TD
A["کاربر عضو باشگاه\nمشاهده محصول"] --> B["قیمت تخفیف‌خورده نمایش داده می‌شود"]
B --> C["افزودن به سبد\nبررسی DiscountBalance"]
C --> D{"موجودی کافی؟"}
D -->|کافی| E["سهم تخفیف از DiscountBalance\nباقیمانده → IPG ZarinPal"]
D -->|ناکافی| F["فقط به اندازه موجودی\nباقیمانده بیشتر → IPG"]
```
### ۵.۳ دسترسی فروشگاه تخفیفی
+59 -66
View File
@@ -7,21 +7,31 @@
## ۱. دو فروشگاه FourSat
```
┌─────────────────────────────────────────────────────────┐
│ FourSat Stores │
├───────────────────────┬─────────────────────────────────┤
│ Regular Store │ Discount Store │
│ (/store) │ (/discount-store) │
├───────────────────────┼─────────────────────────────────┤
│ • همه کاربران │ • فقط اعضای باشگاه │
│ • پرداخت 100% نقدی │ • پرداخت ترکیبی (تخفیف+نقد) │
│ • قیمت عادی │ • تخفیف بر اساس MaxDiscountPercent │
│ • VAT = 10% │ • VAT = 9% (در کد PlaceOrder) │
├───────────────────────┴─────────────────────────────────┤
│ Shared: Products, Categories, │
│ Inventory, ProductImages (1:1 square) │
└─────────────────────────────────────────────────────────┘
```mermaid
flowchart LR
subgraph RS["Regular Store — /store"]
R1["همه کاربران"]
R2["پرداخت 100% نقدی"]
R3["قیمت عادی"]
R4["VAT = 10%"]
end
subgraph DS["Discount Store — /discount-store"]
D1["فقط اعضای باشگاه"]
D2["پرداخت ترکیبی تخفیف+نقد"]
D3["تخفیف بر اساس MaxDiscountPercent"]
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 (هر دو فروشگاه)
```
بارگذاری اولیه: 12 محصول
اسکرول → نمایش دکمه "نمایش محصولات بیشتر"
کلیک → LoadMore() → skip += 12
محصولات جدید اضافه به لیست (append)
تکرار تا Products.Count >= TotalCount
مخفی‌شدن دکمه
```mermaid
flowchart TD
A["بارگذاری اولیه: 12 محصول"] --> B["اسکرول → نمایش دکمه\nنمایش محصولات بیشتر"]
B --> C["کلیک → LoadMore\nskip += 12"]
C --> D["محصولات جدید append به لیست"]
D --> E{"Products.Count >= TotalCount?"}
E -->|خیر| B
E -->|بله| F["مخفی‌شدن دکمه"]
```
---
@@ -100,17 +101,14 @@ public int MaxDiscountPercent { get; set; } // 0 تا 100 — درصد تخفی
### ۳.۳ فلوی سفارش و موجودی
```
سفارش جدید
بررسی Quantity - ReservedQuantity >= OrderQuantity?
├─→ بله: ReservedQuantity += OrderQuantity
│ پرداخت موفق → Quantity -= OrderQuantity, Reserved -= OrderQuantity
│ پرداخت ناموفق → Reserved -= OrderQuantity (آزادسازی)
└─→ خیر: نمایش "موجودی کافی نیست"
```mermaid
flowchart TD
A["سفارش جدید"] --> B{"Quantity - Reserved >= OrderQty?"}
B -->|بله| C["Reserved += OrderQty"]
C --> D{"پرداخت موفق؟"}
D -->|موفق| E["✅ Quantity -= OrderQty\nReserved -= OrderQty"]
D -->|ناموفق| F["❌ Reserved -= OrderQty\nآزادسازی"]
B -->|خیر| G["نمایش: موجودی کافی نیست"]
```
---
@@ -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)
```
درختی / سلسله‌مراتبی
├── سلامت و زیبایی
│ ├── مکمل‌ها
│ ├── مراقبت پوست
│ └── مراقبت مو
├── تغذیه
│ ├── ارگانیک
│ └── رژیمی
└── ورزشی
```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 @@
## ۱. فلوی کامل چرخه کاربر
```
ورود به سایت
ثبت‌نام (موبایل + OTP)
تکمیل پروفایل
┌─────────────────────┬────────────────────────┐
│ مسیر عادی │ مسیر باشگاه │
├─────────────────────┼────────────────────────┤
│ خرید از فروشگاه │ خرید پکیج طلایی (56M) │
│ مشاهده بلاگ │ امضای قرارداد (OTP) │
│ استفاده از خدمات │ فعالسازی (25M) │
│ │ عضویت در درخت باینری │
│ │ دسترسی فروشگاه تخفیفی │
│ │ دسترسی فیچرهای باشگاه │
│ │ کسب کمیسیون هفتگی │
└─────────────────────┴────────────────────────┘
```mermaid
flowchart TD
A["ورود به سایت"] --> B["ثبت‌نام — موبایل + OTP"]
B --> C["تکمیل پروفایل"]
C --> D{"مسیر؟"}
D -->|عادی| E["🛒 خرید از فروشگاه\nمشاهده بلاگ\nاستفاده از خدمات"]
D -->|باشگاه| F["🏆 خرید پکیج طلایی 56M"]
F --> G["امضای قرارداد OTP"]
G --> H["فعالسازی 25.2M"]
H --> I["عضویت درخت باینری"]
I --> J["دسترسی فروشگاه تخفیفی\nفیچرهای باشگاه\nکمیسیون هفتگی"]
```
---
@@ -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:
• UserId
• PhoneNumber
• IsClubMember (bool)
• Roles[] (Admin, Customer)
• ReferralCode
```
**JWT Claims:** `UserId`, `PhoneNumber`, `IsClubMember`, `Roles[]`, `ReferralCode`
### ۲.۲ اصلاحات ثبت‌نام
@@ -76,16 +56,15 @@ JWT Claims:
### ۳.۱ مشکل قبلی
```
قبل:
Admin و Customer هر دو از یک DbContext و Identity استفاده می‌کردند
یک ادمین می‌توانست به صورت Customer هم ظاهر شود ← تداخل Claims
```mermaid
flowchart LR
subgraph BEFORE["قبل — مشکل"]
A1["Admin + Customer"] --> A2["یک DbContext\nیک Identity\nتداخل Claims"]
end
بعد (اصلاح‌شده):
ICurrentUserService → تشخیص دقیق نقش فعلی
✅ جداسازی Authorization Policy
✅ Admin claims فقط در BackOffice
✅ Customer claims فقط در FrontOffice
subgraph AFTER["بعد اصلاح‌شده ✅"]
B1["ICurrentUserService"] --> B2["جداسازی Policy\nAdmin → BackOffice\nCustomer → FrontOffice"]
end
```
### ۳.۲ ICurrentUserService
@@ -110,29 +89,16 @@ public interface ICurrentUserService {
### ۴.۱ فلوی امضای قرارداد
```
خرید پکیج طلایی → Redirect به صفحه قرارداد
نمایش Modal غیرقابل‌بسته‌شدن
ReadContract RPC → نمایش متن قرارداد (Markdown/HTML)
کاربر باید تا انتهای متن اسکرول کند
فعال شدن دکمه "ارسال کد تأیید"
RequestContractOtp → ارسال SMS
ورود کد ← VerifyContractOtp
├─→ معتبر: AcceptContract → فعالسازی عضویت
└─→ نامعتبر: پیام خطا (حداکثر ۵ تلاش)
```mermaid
flowchart TD
A["خرید پکیج طلایی\nRedirect به صفحه قرارداد"] --> B["نمایش Modal\nغیرقابل‌بسته‌شدن"]
B --> C["ReadContract RPC\nنمایش متن قرارداد"]
C --> D["اسکرول تا انتها"]
D --> E["فعال شدن دکمه\nارسال کد تأیید"]
E --> F["RequestContractOtp\nارسال SMS"]
F --> G["ورود کد\nVerifyContractOtp"]
G -->|معتبر| H["✅ AcceptContract\nفعالسازی عضویت"]
G -->|نامعتبر| I["❌ پیام خطا\nحداکثر ۵ تلاش"]
```
### ۴.۲ ذخیره‌سازی قرارداد
@@ -206,20 +172,12 @@ else
## ۷. کدهای معرف (Referral)
```
هر عضو باشگاه → یک ReferralCode یکتا
لینک: https://foursat.ir/register?ref={ReferralCode}
ثبت‌نام با لینک:
ذخیره ReferrerId در پروفایل کاربر جدید
هنگام خرید پکیج → زیرمجموعه Referrer در درخت باینری
Referrer → دریافت bonus (طبق شرایط باشگاه)
```mermaid
flowchart TD
A["هر عضو باشگاه\nیک ReferralCode یکتا"] --> B["لینک:\nhttps://foursat.ir/register?ref=CODE"]
B --> C["ثبت‌نام با لینک\nذخیره ReferrerId"]
C --> D["خرید پکیج\nزیرمجموعه Referrer در درخت"]
D --> E["Referrer\nدریافت bonus"]
```
---
+26 -48
View File
@@ -9,14 +9,15 @@
### ۱.۱ معماری ساده‌شده (Shopify-style)
```
قبل (پیچیده):
SitePage → SitePageSetting → SitePageContent → Template → ... (7 جدول)
```mermaid
flowchart LR
subgraph BEFORE["قبل — پیچیده"]
X1["SitePage"] --> X2["SitePageSetting"] --> X3["SitePageContent"] --> X4["Template\n... 7 جدول"]
end
بعد (ساده):
SitePage (PageType, JsonSettings, IsPublished)
└─→ هر PageType → یک typed editor در BackOffice
subgraph AFTER["بعد ساده ✅"]
Y1["SitePage\nPageType + JsonSettings"] --> Y2["هر PageType\nیک typed editor"]
end
```
### ۱.۲ انواع صفحات
@@ -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 (configurable)
• فرمت‌های مجاز: jpg, png, webp, pdf, doc, docx
• تصاویر: resize خودکار به 800×800 (محصولات)
```
> محدودیت: حداکثر 10MB • jpg, png, webp, pdf, doc, docx • Resize: 800×800 (محصولات)
### ۳.۲ Storage Strategy
@@ -198,20 +192,12 @@ CREATE TABLE SystemConfigurations (
### ۶.۱ معماری
```
Hangfire Recurring Job (هر ۵ دقیقه)
ChatikaJob → بررسی پیام‌های جدید کاربران
ارسال به Chatika API (با Polly retry ×3)
دریافت پاسخ → ذخیره در ChatMessages
نمایش در UI باشگاه (real-time via SignalR planned)
```mermaid
flowchart TD
A["Hangfire Recurring Job\nهر ۵ دقیقه"] --> B["ChatikaJob\nبررسی پیام‌های جدید"]
B --> C["ارسال به Chatika API\nPolly retry ×3"]
C --> D["دریافت پاسخ\nذخیره در ChatMessages"]
D --> E["نمایش در UI باشگاه\nSignalR planned"]
```
### ۶.۲ فعلی vs آینده
@@ -228,20 +214,12 @@ ChatikaJob → بررسی پیام‌های جدید کاربران
### ۷.۱ ساختار
```
Hero Section (انیمیشن fade-in)
ویژگی‌ها (Features Grid — 3 ستونه)
محصولات ویژه (Carousel)
آمار (Counter animation — اصلاح‌شده)
CTA — Call to Action (ثبت‌نام / ورود)
```mermaid
flowchart TD
A["🎨 Hero Section\nانیمیشن fade-in"] --> B["✨ ویژگی‌ها\nFeatures Grid — 3 ستونه"]
B --> C["📦 محصولات ویژه\nCarousel"]
C --> D["📊 آمار\nCounter animation\nlinear interpolation"]
D --> E["🚀 CTA\nثبت‌نام / ورود"]
```
### ۷.۲ اصلاح انیمیشن Counter