From d7c32dab2ac2303dd7a0f44790ac0916e5167024 Mon Sep 17 00:00:00 2001 From: masoodafar-web Date: Wed, 18 Feb 2026 21:43:59 +0330 Subject: [PATCH] consolidate: move all project-level docs to totalDoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - BackOffice/docs → totalDoc/backoffice/ (AUDIT + CHANGELOG) - FrontOffice/docs → totalDoc/frontoffice/ (CHANGELOG + UI-UNIFICATION-PLAN) - CMS/README.md → totalDoc/cms/CMS-README.md - DataMigration/README.md → totalDoc/migration/DATAMIGRATION-README.md - deployment/README.md → totalDoc/deployment/DEPLOYMENT-README.md - Updated INDEX.md with new paths and sections --- INDEX.md | 39 +- backoffice/BACKOFFICE-AUDIT.md | 1010 ++++++++++++++++++++++++++++ backoffice/BACKOFFICE-CHANGELOG.md | 850 +++++++++++++++++++++++ cms/CMS-README.md | 445 ++++++++++++ deployment/DEPLOYMENT-README.md | 161 +++++ frontoffice/CHANGELOG.md | 311 +++++++++ frontoffice/UI-UNIFICATION-PLAN.md | 542 +++++++++++++++ migration/DATAMIGRATION-README.md | 425 ++++++++++++ 8 files changed, 3776 insertions(+), 7 deletions(-) create mode 100644 backoffice/BACKOFFICE-AUDIT.md create mode 100644 backoffice/BACKOFFICE-CHANGELOG.md create mode 100644 cms/CMS-README.md create mode 100644 deployment/DEPLOYMENT-README.md create mode 100644 frontoffice/CHANGELOG.md create mode 100644 frontoffice/UI-UNIFICATION-PLAN.md create mode 100644 migration/DATAMIGRATION-README.md diff --git a/INDEX.md b/INDEX.md index 7bef203..4f7e1eb 100644 --- a/INDEX.md +++ b/INDEX.md @@ -10,7 +10,7 @@ | می‌خواهم بدانم... | مستند | |-------------------|-------| -| **کل تغییرات BackOffice چه بوده؟** | [`BackOffice/docs/BACKOFFICE-CHANGELOG.md`](../BackOffice/docs/BACKOFFICE-CHANGELOG.md) | +| **کل تغییرات BackOffice چه بوده؟** | [`backoffice/BACKOFFICE-CHANGELOG.md`](backoffice/BACKOFFICE-CHANGELOG.md) | | **ساختار و معماری BackOffice چیست؟** | [`ui-modernization/BACKOFFICE-ARCHITECTURE.md`](ui-modernization/BACKOFFICE-ARCHITECTURE.md) | | **یکسان‌سازی فروشگاه‌ها چه بوده؟** | [`ui-modernization/BACKOFFICE-STORE-UNIFICATION.md`](ui-modernization/BACKOFFICE-STORE-UNIFICATION.md) | | **وضعیت فروشگاه تخفیفی؟** | [`business/DISCOUNT-STORE-STATUS.md`](business/DISCOUNT-STORE-STATUS.md) | @@ -30,7 +30,12 @@ | **سرویس انقضای سفارش؟** | [`cms/payment-gateway.md`](cms/payment-gateway.md) (بخش ۱۱) | | **بهبود سیستم موجودی؟** | [`cms/INVENTORY-IMPROVEMENTS.md`](cms/INVENTORY-IMPROVEMENTS.md) | | **تصاویر مربعی محصولات؟** | [`ui-modernization/PRODUCT-IMAGES-SQUARE.md`](ui-modernization/PRODUCT-IMAGES-SQUARE.md) | -| **Audit report کامل BackOffice؟** | [`BackOffice/docs/BACKOFFICE-AUDIT.md`](../BackOffice/docs/BACKOFFICE-AUDIT.md) | +| **Audit report کامل BackOffice؟** | [`backoffice/BACKOFFICE-AUDIT.md`](backoffice/BACKOFFICE-AUDIT.md) | +| **تغییرات FrontOffice؟** | [`frontoffice/CHANGELOG.md`](frontoffice/CHANGELOG.md) | +| **طرح یکسان‌سازی UI فرانت؟** | [`frontoffice/UI-UNIFICATION-PLAN.md`](frontoffice/UI-UNIFICATION-PLAN.md) | +| **README پروژه CMS؟** | [`cms/CMS-README.md`](cms/CMS-README.md) | +| **README دیپلوی؟** | [`deployment/DEPLOYMENT-README.md`](deployment/DEPLOYMENT-README.md) | +| **README مهاجرت داده؟** | [`migration/DATAMIGRATION-README.md`](migration/DATAMIGRATION-README.md) | --- @@ -47,10 +52,11 @@ | [discount-shop-business.md](business/discount-shop-business.md) | فروشگاه تخفیفی: پرداخت ترکیبی، درصد تخفیف، entity design | | [manual-payment-system.md](business/manual-payment-system.md) | پرداخت دستی: کارت به کارت، تأیید ادمین، آپلود FMS | -## 📂 cms/ — مستندات فنی CMS (۱۵ فایل) +## 📂 cms/ — مستندات فنی CMS (۱۹ فایل) | فایل | توضیح | |------|-------| +| [CMS-README.md](cms/CMS-README.md) | 📘 README اصلی پروژه CMS | | [BFF-REMOVAL-PLAN.md](cms/BFF-REMOVAL-PLAN.md) | ✅ پلن حذف BFF — Permission Interceptor + تغییرات config | | [REMAINING-TASKS.md](cms/REMAINING-TASKS.md) | وضعیت ۴۹/۴۹ متد — همه انجام شده ✅ | | [FRONTOFFICE-CMS-API-COMPATIBILITY.md](cms/FRONTOFFICE-CMS-API-COMPATIBILITY.md) | ماتریس سازگاری API بین FrontOffice و CMS | @@ -70,10 +76,11 @@ | [FILE-MANAGEMENT-ARCHITECTURE.md](cms/FILE-MANAGEMENT-ARCHITECTURE.md) | 🆕 معماری جامع مدیریت فایل: IFileManager, LocalFileManager, ImagePathResolverInterceptor, UploadsController (HTTP سرو عمومی + FMS Fallback), ذخیره دیسکی | | [REGISTRATION-FLOW-FIXES.md](cms/REGISTRATION-FLOW-FIXES.md) | 🆕 فیکس فلوی ثبت‌نام: ایجاد کاربر جدید در VerifyOtpToken، رفع lookup موبایل AcceptContract، رفع sync IsCompleteRegister | -## 📂 deployment/ — مستندات استقرار (۴ فایل) +## 📂 deployment/ — مستندات استقرار (۶ فایل) | فایل | توضیح | |------|-------| +| [DEPLOYMENT-README.md](deployment/DEPLOYMENT-README.md) | 📘 README اصلی پوشه deployment | | [OFFLINE-DEPLOYMENT-GUIDE.md](deployment/OFFLINE-DEPLOYMENT-GUIDE.md) | راهنمای جامع استقرار آفلاین + تنظیمات Nexus | | [CICD-PIPELINE-GUIDE.md](deployment/CICD-PIPELINE-GUIDE.md) | 🔄 راهنمای CI/CD Pipeline: معماری DinD، فیکس‌های dockerd، Runner ConfigMap، عیب‌یابی، SERVER_PASSWORD، باگ cross-deploy، قالب workflow Production | | [INFRASTRUCTURE-GUIDE.md](deployment/INFRASTRUCTURE-GUIDE.md) | 🔄 مشخصات سرور Staging + Production، DB credentials دوگانه، Gitea، Kestrel protocol، Ingress annotations، Proto v0.0.179 | @@ -89,10 +96,11 @@ | [BACKOFFICE-STORE-UNIFICATION.md](ui-modernization/BACKOFFICE-STORE-UNIFICATION.md) | 🆕 یکسان‌سازی فروشگاه عادی و تخفیفی: NavMenu restructure، حذف آمار سفارشات، رفع PaymentDate، بازنویسی ۴ صفحه | | [PRODUCT-IMAGES-SQUARE.md](ui-modernization/PRODUCT-IMAGES-SQUARE.md) | 🆕 تصاویر مربعی محصولات: aspect-ratio 1:1 در ۹ فایل، هر دو فروشگاه، همه سایزها | -## 📂 migration/ — مستندات مهاجرت BFF→CMS (۶ فایل) +## 📂 migration/ — مستندات مهاجرت BFF→CMS (۷ فایل) | فایل | توضیح | |------|-------| +| [DATAMIGRATION-README.md](migration/DATAMIGRATION-README.md) | 📘 README پروژه DataMigration | | [GATEWAY-REMOVAL-MIGRATION-PLAN.md](migration/GATEWAY-REMOVAL-MIGRATION-PLAN.md) | پلن استراتژیک حذف هر دو Gateway (BFF) | | [FRONTOFFICE-TO-CMS-MIGRATION.md](migration/FRONTOFFICE-TO-CMS-MIGRATION.md) | مهاجرت کامل FrontOffice: proto changes، field aliasing + لاگ تغییرات | | [MIGRATION-PROGRESS.md](migration/MIGRATION-PROGRESS.md) | لاگ پیشرفت مهاجرت: نسخه‌های proto، خطاها، وضعیت سرویس‌ها | @@ -102,7 +110,23 @@ --- -## 📊 آمار تجمیع +## � backoffice/ — مستندات پنل مدیریت (۲ فایل) + +| فایل | توضیح | +|------|-------| +| [BACKOFFICE-AUDIT.md](backoffice/BACKOFFICE-AUDIT.md) | 🔍 گزارش آدیت عمیق BackOffice: ۵۸ آیتم، ۹۸٪ تکمیل، ۶ فاز | +| [BACKOFFICE-CHANGELOG.md](backoffice/BACKOFFICE-CHANGELOG.md) | 📝 چنج‌لاگ BackOffice: فاز ۱ تا ۱۷ | + +## 📂 frontoffice/ — مستندات فرانت‌آفیس (۲ فایل) + +| فایل | توضیح | +|------|-------| +| [CHANGELOG.md](frontoffice/CHANGELOG.md) | 📝 چنج‌لاگ FrontOffice | +| [UI-UNIFICATION-PLAN.md](frontoffice/UI-UNIFICATION-PLAN.md) | 🎨 طرح یکسان‌سازی UI فروشگاه‌ها | + +--- + +## �📊 آمار تجمیع | مرحله | تعداد فایل | حذف شده | |-------|-----------|---------| @@ -117,4 +141,5 @@ | session File Mgmt + Content (+1 doc) | **36** | — | | session Registration Flow Fix (+1 doc) | **37** | — | | session Inventory + Images + Docs (+2 docs) | **39** | — | -| **نهایی** | **39 + INDEX** | **۱۹۱ فایل حذف/ادغام** | +| consolidate project-level docs (+7 files, 2 folders) | **46** | — | +| **نهایی** | **46 + INDEX** | **۱۹۱ فایل حذف/ادغام** | diff --git a/backoffice/BACKOFFICE-AUDIT.md b/backoffice/BACKOFFICE-AUDIT.md new file mode 100644 index 0000000..fd5df5c --- /dev/null +++ b/backoffice/BACKOFFICE-AUDIT.md @@ -0,0 +1,1010 @@ +# 🔍 BackOffice Admin Panel — Deep Audit Report + +**تاریخ:** ۱۴۰۴/۰۴ +**نسخه:** v7.0 — Global Search + Notifications + Export All + NavMenu Badge +**آخرین بروزرسانی:** ۱۴۰۴/۰۴/۱۳ (July 4, 2025) +**هدف:** بررسی عمیق یکپارچگی دیزاین سیستم، UX/UI، بیزینس لاجیک، ساختار صفحات و ناوبری پنل مدیریت + +--- + +## 🏆 وضعیت اجرا — خلاصه + +| فاز | عنوان | وضعیت | تعداد آیتم | انجام‌شده | +|---|---|---|---|---| +| فاز ۱ | زیرساخت دیزاین سیستم | ✅ **کامل** | 5 | 5/5 | +| فاز ۲ | بازطراحی لایوت صفحات | ✅ **کامل** | 6 | 6/6 | +| فاز ۲.۵ | پاکسازی ساختاری | ✅ **کامل** | 7 | 7/7 | +| فاز ۳ | UX بهبودها | ✅ **کامل** | 6 | 6/6 | +| فاز ۳.۵ | ادغام صفحات | ✅ **کامل** | 6 | 6/6 | +| فاز ۴ | فیکس‌های بیزینسی | ✅ **کامل** | 11 | 10/11 | +| فاز ۴.۵ | Cross-Navigation | 🟡 **بخشی** | 5 | 3/5 | +| فاز ۵ | صفحات مفقود (CMS) | ✅ **اکثراً** | 8 | 7/8 | +| فاز ۶ | فیچرهای جدید | ✅ **اکثراً** | 5 | 4/5 | +| | **مجموع** | | **58** | **57/58 (≈98%)** | + +> **۱۶ مورد 🔴 بحرانی → همه انجام شده ✅** +> **۲۴ مورد 🟡 مهم → ۲۳ انجام شده، ۱ باقی‌مانده (DayaLoan — blocked on backend)** +> **۱۸ مورد 🟢 جزئی → ۱۸ انجام شده ✅** + +--- + +## 📋 فهرست + +1. [خلاصه اجرایی](#-خلاصه-اجرایی) +2. [مشکلات بحرانی (Critical)](#-مشکلات-بحرانی-critical) +3. [مشکلات دیزاین سیستم](#-مشکلات-دیزاین-سیستم) +4. [ناهماهنگی‌های لایوت صفحات](#-ناهماهنگیهای-لایوت-صفحات) +5. [مشکلات UX/UI](#-مشکلات-uxui) +6. [تحلیل عمیق جریان‌های UX](#-تحلیل-عمیق-جریانهای-ux) +7. [ضعف‌های بیزینسی و فیچرهای ناقص](#-ضعفهای-بیزینسی-و-فیچرهای-ناقص) +8. [تحلیل تطبیقی CMS ↔ BackOffice](#-تحلیل-تطبیقی-cms--backoffice) +9. [تحلیل ساختاری صفحات و ناوبری](#-تحلیل-ساختاری-صفحات-و-ناوبری) +10. [جدول یافته‌ها به تفکیک صفحه](#-جدول-یافتهها-به-تفکیک-صفحه) +11. [برنامه اجرایی (Action Plan)](#-برنامه-اجرایی-action-plan) + +--- + +## 🎯 خلاصه اجرایی + +پنل مدیریت BackOffice از **۳ الگوی متفاوت لایوت** استفاده می‌کند که هیچ‌کدام با هم هماهنگ نیستند. تم رنگی با FrontOffice متفاوت است، رنگ‌های هاردکد در CSS وجود دارد، صفحه لاگین بسیار ابتدایی است، و چندین فیچر بیزینسی ناقص یا غیرفعال هستند. + +### آمار سریع +| معیار | وضعیت | +|---|---| +| تعداد صفحات | ~40+ صفحه | +| الگوهای لایوت متفاوت | **۳** (باید ۱ باشد) | +| رنگ‌های هاردکد | **۴+** مورد | +| Dark Mode | ❌ ندارد (تنظیمات toggle دارد ولی عملکرد ندارد) | +| Breadcrumb / مسیریابی | ❌ ندارد | +| نوتیفیکیشن لحظه‌ای | ❌ ندارد | +| صفحات بدون Loading State | ~۵ مورد | +| صفحات بدون Empty State | ~۸ مورد | +| فیچرهای غیرفعال/ناقص | ۷+ مورد | +| entity‌های CMS بدون صفحه در BackOffice | **۵** مورد | +| جریان‌های UX شکسته | **۴** مورد | + +--- + +## 🚨 مشکلات بحرانی (Critical) + +### C1 — سه الگوی لایوت ناسازگار + +صفحات از سه الگوی کاملاً متفاوت استفاده می‌کنند: + +| الگو | صفحات | ویژگی | +|---|---|---| +| **Pattern A: `BasePageComponent`** | User, Products, Package, Category, UserOrder, Transactions, UserAddress, UserRole, Role | پنل فیلتر ثابت سمت راست (20%) + جدول (80%)، ارتفاع ثابت 85vh | +| **Pattern B: `MudContainer` آزاد** | Blog, Tag, Content, Settings, DiscountShop, PublicMessages, Commission, Network, Club, Inventory, SystemManagement | فیلتر بالای جدول، بدون ساختار ثابت | +| **Pattern C: بدون Container** | Index (Dashboard) | مستقیم `MudStack` + `MudGrid` بدون `MudContainer` | + +**مشکل:** +- Pattern A فیلتر را در یک ستون عمودی ثابت نمایش می‌دهد (مناسب دسکتاپ، مشکل‌دار در موبایل) +- Pattern B فیلتر را بالای جدول می‌گذارد (استاندارد‌تر) +- Pattern C هیچ ساختاری ندارد +- `BasePageComponent` ارتفاع 85vh هاردکد دارد — responsive نیست +- `BasePageComponent` عرض ثابت xs="2" و xs="10" دارد — در صفحات کوچک شکسته می‌شود + +### C2 — تم رنگی ناهماهنگ با FrontOffice + +| جزء | BackOffice | FrontOffice | وضعیت | +|---|---|---|---| +| Primary | `#0380C0` (آبی) | `#6366f1` (ایندیگو) | ❌ ناهماهنگ | +| Secondary | `#5E4DF9` | `#8b5cf6` | ❌ ناهماهنگ | +| PaletteDark | ندارد | ✅ کامل | ❌ ندارد | +| Loading Color (CSS) | `#1b6ec2` (هاردکد) | متغیر تم | ❌ هاردکد | +| NavMenu Active | `#0380C0` (هاردکد CSS) | متغیر تم | ❌ هاردکد | +| User Icon Border | `#5e4df9` (inline style) | — | ❌ هاردکد | + +### C3 — صفحه لاگین بسیار ابتدایی + +- فقط یک MudPaper ساده با عرض `35%` و ارتفاع `200px` +- بدون لوگو، بدون برندینگ +- بدون عنوان "پنل مدیریت" +- عرض ثابت — در موبایل شکسته می‌شود +- صفحه VerifyCode هم همین مشکلات را دارد (ارتفاع `230px` ثابت) + +### C4 — عنوان اپ قدیمی + +- `MainLayout.razor`: "پنل مدیریت **فرصت**" — باید "پنل مدیریت **کارا بازار سلامت**" باشد + +--- + +## 🎨 مشکلات دیزاین سیستم + +### D1 — Elevation ناسازگار + +| صفحه | Elevation | +|---|---| +| Dashboard Index cards | `MudPaper` (بدون elevation) | +| SystemOverview cards | `MudCard Outlined` | +| Commission Dashboard cards | `MudCard Elevation="2"` | +| Inventory stats cards | `MudCard` (پیش‌فرض = 1) | +| HealthDashboard | `MudCard Elevation="2"` و `"3"` | + +**باید:** همه کارت‌های آماری از یک استایل واحد استفاده کنند. + +### D2 — عدم وجود کامپوننت `StatCard` مشترک + +داشبورد‌ها (Index, SystemOverview, Commission, Inventory) همه کارت‌های آماری دارند اما هرکدام ساختار متفاوتی دارند: +- Index: `MudPaper > MudStack > subtitle2 + h5` +- SystemOverview: `MudCard Outlined > body2 + h5` +- Commission: `MudCard Elevation=2 > h6(color) + h4 + body2` +- Inventory: `MudCard > MudStack Row > (caption + h5) + Icon` + +### D3 — MudDataGrid Height ناسازگار + +| صفحه | Height | +|---|---| +| User, Products, Package, Category | `72vh` (داخل BasePageComponent) | +| Blog, Tag | `65vh` | +| Club, WithdrawalRequests | `75vh` | +| Inventory | `60vh` | +| Content, DiscountShop | بدون Height مشخص | +| Commission WeeklyReports | بدون Height مشخص | + +### D4 — PageSize ناسازگار + +| صفحه | PageSizes | PagerText | +|---|---|---| +| User, Products, Package | `30, 60, 90` | فارسی (بعضی) | +| Blog, Tag | `10, 25, 50` | `RowsPerPageString="تعداد در صفحه"` | +| Commission WeeklyReports | پیش‌فرض | — | +| DiscountShop | پیش‌فرض | — | + +### D5 — MaxWidth ناسازگار + +| صفحه | MaxWidth | +|---|---| +| Blog, Content | `MaxWidth.Large` | +| Tag | `MaxWidth.Medium` | +| Commission, Dashboard, Club, Inventory, Settings | `MaxWidth.ExtraLarge` | +| DiscountShop | `MaxWidth.ExtraExtraLarge` | +| Network | `MaxWidth.ExtraExtraLarge` | +| Pages با BasePageComponent | بدون Container (تمام عرض) | + +### D6 — Button Size و Style ناسازگار + +- بعضی دکمه‌ها `Size.Large` (Products, Package) و بعضی `Size.Small` +- همه دکمه‌ها `Style="cursor:pointer;"` دارند — این **غیرضروری** است (MudButton خودش cursor:pointer دارد) +- Pattern ثابتی برای دکمه "افزودن" نیست: + - Products: `Variant.Filled Color.Primary Size.Large` + - Blog: `Variant.Filled Color.Primary + StartIcon` + - DiscountShop: `Variant.Filled Color.Primary FullWidth + StartIcon` + +### D7 — رنگ‌های هاردکد در CSS + +**`wwwroot/css/app.css`:** +```css +/* Loading progress — باید از متغیر تم استفاده کند */ +background-color: #1b6ec2; /* هاردکد */ +``` + +**`Shared/NavMenu.razor.css`:** +```css +/* Active state — باید از CSS variable استفاده کند */ +color: #0380C0; /* هاردکد */ +``` + +**`Shared/MainLayout.razor`:** +```html + +Style="border: 1px solid #5e4df9;" +``` + +**`wwwroot/css/admin-org-chart.css`:** +```css +/* Border colors هاردکد */ +border-left: 4px solid #4caf50; /* green */ +border-left: 4px solid #ff9800; /* orange */ +border-left: 4px solid #1976d2; /* blue */ +``` + +--- + +## 📐 ناهماهنگی‌های لایوت صفحات + +### L1 — BasePageComponent مشکلات ریسپانسیو + +```html + + + +``` + +- بدون breakpoint — همیشه side-by-side +- `Height="85vh"` ثابت — scroll internal +- فیلتر panel عرض ثابت برای متن فارسی کم است + +### L2 — Drawer همیشه Temporary + +```html + +``` +- در دسکتاپ هم drawer پنهان است و فقط با hamburger باز می‌شود +- **باید:** در دسکتاپ `Responsive` باشد و در موبایل `Temporary` + +### L3 — MainContent padding ناکافی + +```html + + +``` +- `mt-5` اضافی (AppBar خودش جا می‌گیرد) +- بعضی صفحات داخل `MudContainer` هم `Class="mt-4"` دارند — double margin + +### L4 — عدم وجود Breadcrumb + +هیچ صفحه‌ای breadcrumb ندارد. برای پنل مدیریتی با سلسله‌مراتب عمیق (مثلاً Users > User Orders > Order Details) این ضروری است. + +--- + +## 🖥 مشکلات UX/UI + +### U1 — عدم وجود Loading State یکپارچه + +| صفحه | Loading State | +|---|---| +| Dashboard (Index) | ❌ ندارد — داده‌ها بدون loading ظاهر می‌شوند | +| SystemOverview | ✅ `MudProgressCircular` | +| Commission Dashboard | ✅ `MudProgressCircular` | +| Inventory | ❌ ندارد (فقط stats ندارند) | +| DiscountShop | ✅ `MudDataGrid Loading` | +| Content | ✅ `MudDataGrid Loading` | +| Login | ❌ فقط دکمه Disabled می‌شود | + +### U2 — عدم وجود Empty State + +اکثر صفحات وقتی داده‌ای نیست، جدول خالی نشان می‌دهند. فقط Commission WeeklyReports یک `MudAlert` نشان می‌دهد. + +### U3 — Delete Confirmation ناسازگار + +- User: `ShowMessageBox` با "حذف/لغو" +- Products: `ShowMessageBox` با "حذف/لغو" +- Blog: احتمالاً `ShowMessageBox` (مشابه) +- **مشکل:** هیچ‌کدام نام آیتم را نشان نمی‌دهند — فقط "آیا مطمئنید؟" +- **باید:** "آیا از حذف «نام محصول» مطمئنید؟" + +### U4 — عدم وجود اعلان/نوتیفیکیشن + +- هیچ سیستم نوتیفیکیشن لحظه‌ای وجود ندارد +- AppBar فقط نام کاربر دارد — بدون bell icon +- سفارش‌های جدید، درخواست‌های برداشت جدید و غیره بدون اطلاع‌رسانی هستند + +### U5 — عدم وجود جستجوی سراسری + +- هیچ global search در AppBar وجود ندارد +- هر صفحه فیلتر مخصوص خودش را دارد + +### U6 — تاریخ شمسی ناسازگار + +- بعضی صفحات از `MiladiToJalali()` استفاده می‌کنند +- بعضی از `PersianDateTime.ConvertToPersianDateTime()` +- بعضی `ToString("yyyy/MM/dd")` (میلادی!) نشان می‌دهند +- `MudDatePicker` تقویم میلادی دارد — باید جلالی باشد + +### U7 — عدم وجود Dark Mode Toggle + +- `CustomMudTheme.cs` هیچ `PaletteDark` ندارد +- هیچ toggle در AppBar وجود ندارد + +### U8 — عدم وجود Profile/Settings کاربر ادمین + +- AppBar فقط شماره موبایل نشان می‌دهد +- بدون dropdown menu برای پروفایل، تنظیمات، خروج +- خروج فقط از NavMenu امکان‌پذیر است + +--- + +## � تحلیل عمیق جریان‌های UX + +### UXF1 — جریان مدیریت سفارش شکسته + +**مسیر فعلی:** کاربر → لیست سفارش‌ها → جزئیات (دیالوگ) → ؟ + +**مشکلات:** +- آمار سفارش‌ها (مجموع، نمودار وضعیت ارسال) **کامنت شده** — ادمین هیچ overview ندارد +- `_paidOrders` و `_totalPaidAmount` در Dashboard فقط از **۱۰ سفارش اخیر** محاسبه می‌شود (PageSize=10) — عدد نمایشی **اشتباه** است +- بعد از تغییر وضعیت ارسال، هیچ notification به کاربر ارسال نمی‌شود +- اگر ادمین از صفحه User → Orders برود، هیچ breadcrumb نیست تا بفهمد از کجا آمده +- فیلتر `MudDatePicker` تقویم **میلادی** دارد — ادمین ایرانی با تاریخ میلادی آشنا نیست +- فیلتر `DeliveryStatus` مقدارهای `0-4` دارد ولی domain enum مقدار `None=0, Pending=1, InTransit=2, Delivered=3, Returned=4, Cancelled=5` دارد — **Cancelled=5 در فیلتر وجود ندارد!** + +### UXF2 — جریان مالی کاربر (Wallet) وجود ندارد + +**CMS domain:** +- `UserWallet` سه نوع موجودی دارد: `Balance` (اصلی)، `NetworkBalance` (کارمزد/طلایی)، `DiscountBalance` (تخفیف) +- `UserWalletChangeLog` تاریخچه کامل تغییرات هر سه موجودی را ثبت می‌کند + +**BackOffice:** +- ❌ **هیچ صفحه‌ای برای مشاهده موجودی کیف پول کاربران وجود ندارد** +- ❌ هیچ صفحه‌ای برای تاریخچه تغییرات کیف پول وجود ندارد +- فقط در ManualPayments می‌توان شارژ دستی انجام داد — ولی ادمین نمی‌تواند موجودی فعلی را ببیند! +- **سناریو:** ادمین باید موجودی کاربر را بررسی کند → مجبور است مستقیم به DB مراجعه کند + +### UXF3 — جریان فعال‌سازی عضویت باشگاه ناقص + +**CMS domain flow (کامل):** +1. کاربر پکیج می‌خرد (Direct یا DayaLoan) +2. قرارداد عضویت باشگاه امضا می‌شود (`UserContract`) +3. عضویت باشگاه فعال می‌شود (`ClubMembership`) +4. فیچرهای باشگاه اختصاص داده می‌شود (`UserClubFeature`) +5. کاربر وارد شبکه باینری می‌شود (`NetworkParentId + LegPosition`) + +**BackOffice:** +- ✅ صفحه ClubMembers: فعال‌سازی، غیرفعال‌سازی، مشاهده جزئیات +- ❌ **مدیریت ClubFeature (فیچرهای باشگاه) وجود ندارد** — ادمین نمی‌تواند فیچرها را مدیریت کند +- ❌ **مدیریت UserClubFeature وجود ندارد** — نمی‌توان فیچر خاصی را برای کاربر خاص فعال/غیرفعال کرد +- ❌ **مدیریت قراردادها (UserContract) وجود ندارد** — فایل‌های قرارداد امضاشده قابل مشاهده نیست +- ❌ **تاریخچه عضویت باشگاه (ClubMembershipHistory) وجود ندارد** +- ❌ صفحه ClubMembers تاریخ‌ها را **میلادی** نشان می‌دهد + +### UXF4 — جریان وام دایا کاملاً غایب + +**CMS domain:** +- `DayaLoanContract` entity: شامل کد ملی، شماره قرارداد، وضعیت (`Pending/Approved/Rejected/Disbursed/Completed/Failed`)، آخرین استعلام، پردازش شارژ کیف پول +- `DayaLoanCQ`: Commands + EventHandlers + Services — سیستم کامل وام + +**BackOffice:** +- ❌ **هیچ صفحه‌ای برای مدیریت وام دایا وجود ندارد** +- فقط در `UserNetworkInfo` یک نمایش ساده "وضعیت دایا" وجود دارد +- ادمین نمی‌تواند: وام‌های جدید را ببیند، وضعیت را تغییر دهد، استعلام دستی بزند + +### UXF5 — جریان پرداخت دستی (ManualPayment) بدون تأیید مناسب + +**CMS domain:** +- `ManualPaymentStatus`: `Pending → Approved/Rejected/Cancelled` +- تأیید باید توسط SuperAdmin انجام شود — جداسازی نقش creator و approver + +**BackOffice:** +- ✅ صفحه ManualPayments وجود دارد با فیلتر و جزئیات +- ❌ **دکمه تأیید/رد مستقیم در لیست وجود ندارد** — فقط "جزئیات" می‌توان دید +- ❌ هیچ تفاوت بصری بین Pending (نیاز به اقدام) و بقیه وضعیت‌ها نیست +- ❌ عدم وجود counter/badge برای تعداد درخواست‌های در انتظار +- ❌ تصویر فیش واریزی (`ImagePath`) قابل مشاهده نیست +- ❌ بدون فیلتر تاریخی + +### UXF6 — جریان کمیسیون و برداشت — Gap Analysis + +**CMS domain (کامل):** +1. Worker هفتگی: `CalculateWeeklyBalances` → `CalculateWeeklyCommissionPool` → `ProcessUserPayouts` +2. واریز به NetworkBalance کیف پول +3. کاربر درخواست برداشت (`RequestWithdrawal`) +4. ادمین تأیید (`ApproveWithdrawal`) یا رد (`RejectWithdrawal`) +5. پردازش نهایی (`ProcessWithdrawal`) +6. تاریخچه (`CommissionPayoutHistory`) + +**BackOffice — آنچه وجود دارد:** +- ✅ Commission Dashboard (نمای استخر) +- ✅ WeeklyReports (تاریخچه هفتگی) +- ✅ UserPayouts (پرداخت‌ها) +- ✅ WithdrawalRequests (درخواست‌ها) +- ✅ WithdrawalReports (گزارش) +- ✅ WorkerControl (کنترل worker) + +**BackOffice — آنچه ناقص است:** +- ❌ **در WithdrawalRequests دکمه Approve/Reject وجود ندارد** (فقط لیست نمایش می‌دهد) +- ❌ وقتی worker اجرا می‌شود، هیچ progress indicator لحظه‌ای نیست +- ❌ بعد از محاسبه دستی، نتیجه به ادمین نشان داده نمی‌شود (فقط refresh لازم است) +- ❌ تاریخچه اجرای worker (`WorkerExecutionLog`) قابل مشاهده نیست (صفحه WorkerControl آن را نمایش نمی‌دهد) +- ❌ هیچ alert/notification خودکار وقتی درخواست برداشت جدید ثبت می‌شود + +### UXF7 — جریان مدیریت محصولات — ناهماهنگی دو فروشگاه + +**CMS domain:** +- **Products** (محصولات اصلی/پکیج): `Product`, `ProductCategory`, `ProductGallery`, `ProductImage`, `ProductTag` +- **DiscountProducts** (فروشگاه تخفیفی): `DiscountProduct`, `DiscountProductCategory`, `DiscountProductImage` +- **Inventory**: `InventoryItem`, `StockMovement`, `Warehouse` — مشترک بین هر دو + +**BackOffice:** +- Products: دارای BulkEdit، Excel Export، Gallery، Tag assignment، Category drag-drop — **کامل و خوب** +- DiscountProducts: فیلتر دسته‌بندی پیاده‌سازی نشده (`TODO: Load categories`)، بدون Gallery، بدون Tag +- ❌ **هیچ لینکی بین InventoryItem و DiscountProduct وجود ندارد** — ادمین نمی‌فهمد موجودی کدام محصول تخفیفی کم است +- ❌ DiscountProducts از `Items` (client-side) بجای `ServerData` استفاده می‌کند — با داده زیاد کُند می‌شود + +### UXF8 — جریان User Profile ادمین + +**مشکل:** ادمین هیچ "هویت" در سیستم ندارد: +- AppBar فقط `sub` claim (شماره موبایل) نشان می‌دهد +- بدون dropdown menu +- بدون نمایش نام/نقش +- بدون عکس پروفایل +- خروج فقط از drawer ممکن است +- **Settings page** دارای toggleهایی برای Dark Mode و زبان است — ولی **هیچ‌کدام عملکرد واقعی ندارند** (فقط local state هستند) + +--- + +## �💼 ضعف‌های بیزینسی و فیچرهای ناقص + +### B1 — DiscountShop Widget غیرفعال در Dashboard + +```razor + +@* *@ +``` +- پیام "در حال توسعه" نشان می‌دهد + +### B2 — UserOrder آمار کامنت‌شده + +```razor +@* + + جمع سفارش‌ها در بازه فعلی + ... + + *@ +``` +- آمار سفارش و نمودار وضعیت ارسال کامنت شده‌اند + +### B3 — DiscountShop Categories خالی + +```razor +همه +@* TODO: Load categories *@ +``` +- فیلتر دسته‌بندی DiscountProducts هنوز پیاده‌سازی نشده + +### B4 — Dashboard Index محاسبات ناقص + +```csharp +_paidOrders = orderResult.Models.Count(m => m.PaymentStatus==PaymentStatus.Success); +_totalPaidAmount = orderResult.Models + .Where(m => m.PaymentStatus==PaymentStatus.Success) + .Aggregate(0L, (sum, m) => sum + m.Amount); +``` +- فقط از ۱۰ سفارش اول (`PageSize = 10`) آمار می‌گیرد — **نادرست!** +- `_paidOrders` و `_totalPaidAmount` از کل داده‌ها محاسبه نمی‌شوند + +### B5 — عدم وجود Export/خروجی در اکثر صفحات + +| صفحه | Export | +|---|---| +| Products | ✅ Excel | +| بقیه صفحات | ❌ ندارند | + +### B6 — عدم وجود Audit Trail / لاگ فعالیت ادمین + +- هیچ سیستم لاگ فعالیت ادمین وجود ندارد +- حذف، ویرایش، تغییر وضعیت بدون ثبت در audit log + +### B7 — عدم وجود تأیید دومرحله‌ای برای عملیات حساس + +- محاسبه دستی کمیسیون بدون تأیید مضاعف +- حذف گروهی محصولات فقط یک confirm ساده دارد +- تغییر تنظیمات سیستم بدون نیاز به تأیید مجدد رمز + +### B8 — WithdrawalRequests فقط نمایشی است + +- CMS دارای `ApproveWithdrawal`, `RejectWithdrawal`, `ProcessWithdrawal` commands است +- BackOffice صفحه WithdrawalRequests فقط **لیست** نشان می‌دهد +- **هیچ دکمه تأیید/رد/پردازش وجود ندارد** — ادمین نمی‌تواند درخواست‌ها را مدیریت کند +- این یک **شکاف بحرانی عملیاتی** است + +### B9 — Discount Shop Orders وضعیت ارسال بدون اقدام + +- DiscountOrdersMainPage سفارش‌ها را نشان می‌دهد +- دکمه "تغییر وضعیت" وجود دارد اما flow مبهم است +- CMS دارای `UpdateOrderStatus` و `CancelOrderByAdmin` هست +- ❌ هیچ workflow واضحی برای تغییر وضعیت Pending→Processing→Shipped→Delivered وجود ندارد +- ❌ کد رهگیری پستی قابل ثبت نیست + +### B10 — Settings page عملکرد ندارد + +- `UserSettings.razor` دارای toggleهای Dark Mode، زبان، حالت فشرده، PageSize +- **هیچ‌کدام persistent نیستند** — بعد از refresh همه reset می‌شوند +- احتمالاً با `localStorage` ذخیره شود ولی هیچ جای دیگر خوانده نمی‌شود + +--- + +## 🔀 تحلیل تطبیقی CMS ↔ BackOffice + +### Entity‌های CMS بدون صفحه مدیریت در BackOffice + +| CMS Entity | Domain Feature | BackOffice صفحه | وضعیت | +|---|---|---|---| +| **UserWallet** | ۳ نوع موجودی (اصلی/شبکه/تخفیف) | ❌ ندارد | 🔴 بحرانی — ادمین نمی‌تواند موجودی ببیند | +| **UserWalletChangeLog** | تاریخچه تمام تغییرات مالی | ❌ ندارد | 🔴 بحرانی — بدون audit trail مالی | +| **DayaLoanContract** | مدیریت وام دایا (6 وضعیت) | ❌ ندارد | 🟡 مهم — اگر سیستم فعال است | +| **ClubFeature** | فیچرهای باشگاه (تعریف) | ❌ ندارد | 🟡 مهم | +| **UserClubFeature** | فیچرهای فعال شده برای هر کاربر | ❌ ندارد | 🟡 مهم | +| **UserContract** | قراردادهای امضاشده + PDF | ❌ ندارد | 🟡 مهم — قراردادها قابل مشاهده نیست | +| **ClubMembershipHistory** | تاریخچه عضویت | ❌ ندارد | 🟢 | +| **CommissionPayoutHistory** | تاریخچه پرداخت کمیسیون | ❌ ندارد | 🟢 | +| **NetworkMembershipHistory** | تاریخچه تغییرات شبکه | ❌ ندارد | 🟢 | +| **WorkerExecutionLog** | تاریخچه اجرای worker | ❌ ندارد (query وجود دارد) | 🟢 | + +### CMS Commands بدون UI در BackOffice + +| CMS Command | عملکرد | BackOffice UI | وضعیت | +|---|---|---|---| +| `ApproveWithdrawal` | تأیید درخواست برداشت | ❌ دکمه ندارد | 🔴 بحرانی | +| `RejectWithdrawal` | رد درخواست برداشت | ❌ دکمه ندارد | 🔴 بحرانی | +| `ProcessWithdrawal` | پردازش نهایی برداشت | ❌ دکمه ندارد | 🔴 بحرانی | +| `AssignClubFeature` | اختصاص فیچر به کاربر | ❌ صفحه ندارد | 🟡 | +| `MoveInNetwork` | جابه‌جایی در شبکه | ❌ دکمه ندارد | 🟡 | +| `RemoveFromNetwork` | حذف از شبکه | ❌ دکمه ندارد | 🟡 | +| `CancelOrderByAdmin` | لغو سفارش توسط ادمین | ❌/✅ فقط برای UserOrder (نه DiscountOrder) | 🟡 | +| `ProcessManualMembershipPayment` | پردازش پرداخت دستی عضویت | ❓ نامشخص | 🟡 | + +### CMS Queries بدون UI در BackOffice + +| CMS Query | عملکرد | وضعیت | +|---|---|---| +| `GetCommissionPayoutHistory` | تاریخچه پرداخت هر کاربر | ❌ | +| `GetClubMembershipHistory` | تاریخچه عضویت | ❌ | +| `GetNetworkMembershipHistory` | تاریخچه شبکه | ❌ | +| `GetWorkerExecutionLogs` | لاگ‌های worker | ❌ | +| `GetWeekDefinitions` | لیست هفته‌ها | ✅ (در WeekNumberPicker) | +| `GetUserWeeklyBalances` | موجودی هفتگی کاربر | ✅ | +| `GetDiscountSalesReport` | گزارش فروش تخفیفی | ✅ | + +### سه‌گانه کیف پول — خلأ بحرانی + +CMS سه نوع موجودی برای هر کاربر دارد: + +``` +UserWallet { + Balance → موجودی اصلی (شارژ مستقیم + درگاه) + NetworkBalance → موجودی شبکه/طلایی (از کمیسیون — قابل برداشت نقدی) + DiscountBalance → موجودی تخفیف (فقط خرید از فروشگاه تخفیفی) +} +``` + +**BackOffice هیچ نمایی از این سه موجودی ندارد.** ادمین برای: +- بررسی موجودی کاربر → باید DB بزند +- ردیابی تغییرات مالی → هیچ راهی ندارد +- تأیید ManualPayment → نمی‌داند موجودی قبل و بعد چقدر بود +- تأیید درخواست برداشت → نمی‌داند NetworkBalance فعلی کاربر چقدر است + +--- + +## 🏗 تحلیل ساختاری صفحات و ناوبری + +### ۱. صفحات Stub (بدون Backend واقعی) + +صفحاتی که UI دارند ولی **هیچ API واقعی ندارند** و کاربر را گمراه می‌کنند: + +| صفحه | مسیر | مشکل | خطوط کد | تأثیر | +|---|---|---|---|---| +| **Transactions** | `/payment/transactions` | 🔴 **کاملاً خالی** — `LoadServerData` فقط `Array.Empty` برمی‌گرداند. TODO: Connect to API | 180 | کاربر GridEmpty می‌بیند | +| **AlertsMonitoring** | `/system/alerts` | 🔴 **100% داده Mock** — `GenerateMockAlerts()` با `Task.Delay(500)` | 422 | آلارم‌ها واقعی نیست | +| **HealthDashboard** | `/system/health` | 🟡 **نیمه Mock** — سرویس‌ها از API، ولی CPU/RAM/Disk/Network همه **hardcoded** (45.2%, 62.8%...) | 468 | متریک‌ها تقلبی | +| **UserSettings** | `/settings` | 🟡 **Backend جعلی** — تغییر رمز: فقط فیلد را خالی می‌کند + Snackbar. نوتیفیکیشن: فقط localStorage. 2FA: فقط localStorage | 418 | اعتماد کاذب | + +**توصیه:** +- Transactions → **حذف از پروژه** یا مخفی کردن تا API آماده شود +- AlertsMonitoring → **حذف از NavMenu** + نشان دادن badge «در حال توسعه» +- HealthDashboard → حذف بخش Resource Metrics تا زمان اتصال واقعی +- UserSettings → حذف تب‌های Notifications و Security یا نمایش پیام «به‌زودی» + +### ۲. صفحات تکراری / قابل ادغام + +#### 🔴 دو داشبورد موازی و ناسازگار + +| | Index (`/`) | SystemOverview (`/dashboard/overview`) | +|---|---|---| +| **تمرکز** | آمار عمومی (کاربران، محصولات، سفارش‌ها) | آمار شبکه/باشگاه/کمیسیون | +| **Stat Cards** | 7 عدد (MudPaper ساده) | 4+3 عدد (MudCard Outlined) | +| **Design Pattern** | `MudPaper Class="pa-4"` | `MudCard Outlined` | +| **Loading** | ❌ ندارد | ✅ MudProgressCircular | +| **جدول** | آخرین 5 سفارش (MudTable) | ❌ ندارد | +| **Quick Actions** | ❌ ندارد | ✅ 6 دکمه Shortcut | +| **محاسبه آمار** | 🔴 نادرست (PageSize=10) | ✅ صحیح (از metadata) | + +**مشکل:** کاربر دو «داشبورد» با design متفاوت می‌بیند. هیچ‌کدام کامل نیست. +**توصیه:** ادغام در یک Dashboard واحد — Stat Cards بالا + Quick Actions + آخرین سفارش‌ها + خلاصه کمیسیون. + +#### 🔴 DiscountOrders + SalesReports — ۶۰% تکرار + +| عنصر | DiscountOrdersMainPage | SalesReports | +|---|---|---| +| `GetOrdersAsync` | ✅ | ✅ (دوباره!) | +| جدول سفارش‌ها | ✅ 8 ستون | ✅ 6 ستون (همان‌ها) | +| `GetStatusColor()` | ✅ | ✅ **copy-paste یکسان** | +| `GetStatusText()` | ✅ | ✅ **copy-paste یکسان** | +| فیلتر تاریخ | ❌ | ✅ | +| چارت‌ها | ❌ | ✅ | +| Export | ❌ | ✅ CSV/PDF | +| تغییر وضعیت | ✅ dialog | ❌ | + +**توصیه:** ادغام در یک صفحه با **۲ تب**: «مدیریت سفارشات» + «گزارشات و چارت‌ها» + +#### 🟡 Club Statistics — کارکرد حداقلی + +- 4 Stat Card + 3 Chart + یک جدول «اعضای اخیر» که **همیشه خالی** است (list initialize نمی‌شود) +- تمام linkهایش به ClubMembers هدایت می‌کنند +- **توصیه:** تبدیل به header/summary در بالای ClubMembers یا تب «آمار» در همان صفحه + +#### 🟡 Commission: Payouts vs WithdrawalRequests — Lifecycle یکسان + +| | UserPayouts | WithdrawalRequests | +|---|---|---| +| **داده** | Payout per user/week | Withdrawal requests | +| **Status** | 6 state (0-5) | 6 state (0-5) — **همان enum** | +| **Approve** | ✅ `ApproveCommissionPayout` | ✅ `ApproveWithdrawal` | +| **Reject** | ✅ `RejectCommissionPayout` | ✅ `RejectWithdrawal` | +| **Process** | ❌ | ✅ `ProcessWithdrawal` | +| **Bank Info** | ❌ | ✅ IBAN/BankRef/TrackingCode | + +هر دو یک lifecycle را نشان می‌دهند (Payout → Withdrawal Request → Process). کاربر برداشت را هم در Payouts و هم در WithdrawalRequests می‌بیند. +**توصیه:** ادغام در یک صفحه با **۲ تب**: «پرداخت‌ها» + «درخواست‌های برداشت» یا حداقل cross-link. + +#### 🟡 Blog + Tag — الگوی یکسان + +| | BlogCategories | TagManagement | +|---|---|---| +| **Columns** | ID, Title, Slug, PostCount, Status, Sort | ID, Name, Title, IsActive, Sort | +| **Actions** | Create/Edit/Delete via Dialog | Create/Edit/Delete via Dialog | +| **Pattern** | BasePageComponent + ServerData | BasePageComponent + ServerData | +| **Code-behind** | ~102 lines | ~114 lines | + +**ساختار کد 95% یکسان.** هر دو CRUD ساده‌اند. +**توصیه:** تبدیل به تب‌هایی در صفحه Blog یا یک صفحه «مدیریت محتوا» مشترک. + +#### 🟡 سه صفحه System — قابل ادغام + +Alerts (Mock) + Health (نیمه‌Mock) + WorkerControl (نیمه‌فعال) + Configuration (فعال) +**توصیه:** ادغام در یک `/system` با ۴ تب. فعلاً فقط Configuration و WorkerControl کاربردی‌اند. + +### ۳. مشکلات ساختاری NavMenu + +#### لینک‌های مرده در منو + +| لینک در NavMenu | مقصد | مشکل | +|---|---|---| +| `ترتیب دسته‌بندی‌ها` | `/products/categories-dragdrop` | 🔴 **صفحه‌ای با این route وجود ندارد!** — احتمالاً باید `/ProductCategoriesPage/` باشد | + +#### صفحات بدون لینک در منو + +| صفحه | مسیر | وضعیت | +|---|---|---| +| **Transactions** | `/payment/transactions` | 🔴 لینکی ندارد — در NavMenu فقط ManualPayments هست | +| **WorkerControl** | `/system/worker-control` | 🔴 لینکی ندارد — در بخش سیستم نیست | +| **InventoryAddStock** | `RouteConstance` تعریف شده | 🟡 route موجود ولی صفحه‌ای استفاده نمی‌کند | + +#### عدم تطابق گروه‌بندی + +| مشکل | جزئیات | +|---|---| +| **تکرار عنوان «فروشگاه تخفیفی»** | هم به‌عنوان `MudText` section header و هم `MudNavGroup` — دو بار عنوان نمایش داده می‌شود | +| **«پیام‌های عمومی» زیر فروشگاه تخفیفی** | ارتباطی با فروشگاه ندارد — باید در «مدیریت محتوا» باشد | +| **«پرداخت‌ها و فعالسازی‌ها» — فقط یک آیتم** | گروه NavGroup با یک زیرآیتم، بی‌معنی — باید Flat link باشد یا Transactions هم اضافه شود | +| **«مدیریت پکیج» جدای از محصولات** | پکیج و محصولات مرتبط‌اند ولی پکیج flat link و محصولات NavGroup | +| **سفارش‌ها flat link ولی DiscountOrders در NavGroup** | دو نوع سفارش با ساختار منو متفاوت | + +#### پیشنهاد ساختار منوی بازنگری‌شده + +``` +📊 داشبورد (ادغام Index + SystemOverview) + +💰 کمیسیون و شبکه + ├─ داشبورد کمیسیون + ├─ گزارش‌های هفتگی + ├─ پرداخت و برداشت (ادغام Payouts + WithdrawalRequests) + ├─ گزارش برداشت‌ها + ├─ درخت شبکه + ├─ موجودی‌های شبکه + └─ آمار شبکه + +🎫 باشگاه مشتریان + ├─ اعضا و آمار (ادغام ClubMembers + Statistics) + └─ مدیریت فیچرها (جدید — از CMS) + +🛒 فروشگاه + ├─ 🏷 محصولات + │ ├─ لیست محصولات + │ ├─ ویرایش دسته‌جمعی + │ ├─ دسته‌بندی‌ها + │ └─ تگ‌ها (از مدیریت محتوا به اینجا) + ├─ 📦 پکیج‌ها + ├─ 📋 سفارش‌ها (همه) (UserOrders + DiscountOrders — tab) + └─ 🏪 فروشگاه تخفیفی + ├─ محصولات تخفیفی + ├─ دسته‌بندی‌ها + └─ گزارش فروش (ادغام با سفارشات) + +📦 انبارداری + ├─ موجودی انبار + ├─ محصولات کم‌موجود + ├─ مدیریت انبارها + └─ تاریخچه تغییرات + +👥 مدیریت + ├─ کاربران + ├─ نقش‌ها + ├─ 💳 کیف پول کاربران (جدید — از CMS) + ├─ 💰 پرداخت‌های دستی + └─ 📄 قراردادها (جدید — از CMS) + +📝 مدیریت محتوا + ├─ بلاگ (پست‌ها + دسته‌بندی‌ها) (ادغام در یک صفحه) + ├─ صفحات سایت + └─ پیام‌های عمومی (از فروشگاه تخفیفی به اینجا) + +⚙️ سیستم + ├─ تنظیمات سیستم + ├─ مدیریت Worker + ├─ نسخه اپلیکیشن‌ها (از Settings به اینجا) + └─ سلامت سیستم + +👤 تنظیمات حساب +🚪 خروج +``` + +### ۴. ناوبری بین صفحات — لینک‌های Cross-Reference ناقص + +| از | به | وضعیت | +|---|---|---| +| User → UserOrders | `/UserOrderPage/{userId}` | ✅ | +| User → UserAddress | `/UserAddressPage/{userId}` | ✅ | +| Products → ProductCategories | `/ProductCategoriesPage/{productId}` | ✅ | +| Products → BulkEdit | `/ProductsBulkEditPage/` | ✅ | +| Inventory → Movements | `/InventoryMovementsPage/?itemId=` | ✅ | +| **UserOrder → User** | ❌ | 🔴 **نام کاربر کلیک‌نخور** — نمی‌توان از سفارش به پروفایل کاربر رفت | +| **UserOrder → Product** | ❌ | 🔴 **محصول سفارش لینک ندارد** | +| **Inventory → Products** | ❌ | 🟡 نام محصول نشان داده می‌شود ولی لینک ندارد | +| **Products → Inventory** | ❌ | 🟡 ستون «موجودی» وجود دارد ولی drill-down ندارد | +| **DiscountShop → Products** | ❌ | 🔴 دو سیستم محصول کاملاً جدا — cross-link ندارند | +| **Commission → User** | ❌ | 🟡 نام کاربر در Payouts نشان داده می‌شود ولی به پروفایل لینک ندارد | +| **ManualPayment → User** | ❌ | 🟡 UserName بدون لینک | +| **هیچ صفحه‌ای → Wallet** | ❌ | 🔴 صفحه کیف پول اصلاً وجود ندارد | + +### ۵. الگوهای کد تکراری (Code Duplication) + +| الگوی تکراری | تکرار | فایل‌ها | +|---|---|---| +| `GetStatusColor()` / `GetStatusText()` برای CommissionPayoutStatus | **4×** | Payouts, WithdrawalRequests, WeeklyReports, PayoutDetailsDialog | +| `GetStatusColor()` / `GetStatusText()` برای DiscountOrder | **2×** | DiscountOrdersMainPage, SalesReports | +| الگوی CRUD ساده (Grid + Create/Edit Dialog) | **6×** | BlogCategory, Tag, Package, Role, DiscountCategory, ClubFeature(!) | +| فیلتر BasePageComponent با `SubmitFilter()` | **9×** | User, Products, Package, Category, UserOrder, Transactions, UserAddress, UserRole, Role | +| `UserAutoComplete` component usage | **5×** | UserOrder, Payouts, WithdrawalRequests, WithdrawalReports, BalancesReport | +| Mock data pattern `GenerateMock*()` | **2×** | AlertsMonitoring, HealthDashboard | + +### ۶. تحلیل کاربردی — صفحات «ارزش‌آفرین» vs «کم‌کاربرد» + +| صفحه | فرکانس استفاده تخمینی | ارزش | یادداشت | +|---|---|---|---| +| Dashboard | روزانه | 🔴 ناقص | باید بهترین صفحه باشد — فعلاً ضعیف‌ترین | +| UserOrders | روزانه | ✅ بالا | صفحه اصلی عملیات روزانه | +| Products | هفتگی | ✅ بالا | مدیریت کاتالوگ | +| Commission Payouts | هفتگی | ✅ بالا | مدیریت مالی | +| WithdrawalRequests | روزانه | 🔴 ناقص | بدون approve/reject = عملاً بی‌فایده | +| Inventory | روزانه | ✅ بالا | مدیریت موجودی | +| ManualPayments | روزانه | 🟡 ناقص | بدون quick-approve | +| Users | هفتگی | ✅ خوب | CRUD ساده ولی کافی | +| Club Members | هفتگی | 🟡 متوسط | فاقد feature management | +| Network Tree | هفتگی | ✅ خوب | ویژوالیزیشن خوب | +| Blog | ماهانه | ✅ خوب | CRUD کامل | +| DiscountShop | هفتگی | 🟡 ناقص | فیلتر خراب، client-side paging | +| Alerts | — | 🔴 بی‌کاربرد | 100% mock | +| Transactions | — | 🔴 بی‌کاربرد | 100% خالی | +| Health | ماهانه | 🟡 ناقص | فقط service status واقعی | +| Settings | یک‌بار | 🟡 ناقص | فقط theme واقعی | + +--- + +## 📊 جدول یافته‌ها به تفکیک صفحه + +| صفحه | الگوی لایوت | Loading | Empty State | Pager فارسی | تاریخ شمسی | Export | مشکلات خاص | +|---|---|---|---|---|---|---|---| +| **Index** | C (بدون Container) | ❌ | ❌ | — | ❌ میلادی | ❌ | آمار نادرست از ۱۰ رکورد | +| **SystemOverview** | B | ✅ | ❌ | — | ❌ | ❌ | Widget غیرفعال | +| **User** | A (BasePageComponent) | ❌ | ❌ | ✅ | — | ❌ | — | +| **UserOrder** | A | ❌ | ❌ | ✅ | ✅ جلالی | ❌ | آمار کامنت‌شده | +| **Package** | A | ❌ | ❌ | ✅ | — | ❌ | — | +| **Products** | A | ❌ | ❌ | ❌ | — | ✅ | cursor:pointer زائد | +| **Category** | A (سفارشی + درخت) | ❌ | ❌ | — | — | ❌ | — | +| **Blog** | B | ❌ | ❌ | ✅ | ❌ میلادی | ❌ | — | +| **Tag** | B | ❌ | ❌ | ✅ | — | ❌ | — | +| **Content** | B | ✅ | ❌ | — | ❌ میلادی | ❌ | — | +| **PublicMessages** | B | ✅ | ❌ | — | — | ❌ | — | +| **Commission Dashboard** | B | ✅ | ❌ | — | ✅ | ❌ | — | +| **WeeklyReports** | B | ✅ | ✅ | — | ❌ میلادی | ❌ | — | +| **WithdrawalRequests** | B | ❌ | ❌ | — | — | ❌ | — | +| **Network Tree** | B | ✅ | ✅ | — | — | ✅ PNG | — | +| **Club Members** | B | ❌ | ❌ | — | ❌ میلادی | ❌ | — | +| **Inventory** | B | ❌ | ❌ | — | — | ❌ | — | +| **DiscountShop** | B | ✅ | ❌ | — | — | ❌ | TODO: دسته‌بندی | +| **Settings** | B | ✅ | ❌ | — | — | ❌ | — | +| **Configuration** | B | ❌ | — | — | — | ❌ | — | +| **HealthDashboard** | B | ❌ | ❌ | — | — | ❌ | — | +| **WorkerControl** | B | ❌ | — | — | ✅ | ❌ | — | +| **Login** | EmptyLayout | ❌ | — | — | — | — | عرض ثابت 35% | +| **VerifyCode** | EmptyLayout | ❌ | — | — | — | — | ارتفاع ثابت | + +--- + +## 🛠 برنامه اجرایی (Action Plan) — با وضعیت پیاده‌سازی + +### فاز ۱: زیرساخت دیزاین سیستم (Critical) — ✅ کامل + +| # | کار | فایل(ها) | اولویت | وضعیت | +|---|---|---|---|---| +| 1.1 | یکسان‌سازی تم رنگی با FrontOffice + اضافه کردن PaletteDark | `CustomMudTheme.cs` | 🔴 | ✅ تم #6366f1 Indigo + PaletteDark کامل | +| 1.2 | حذف تمام رنگ‌های هاردکد از CSS و inline styles | `app.css`, `NavMenu.razor.css`, `MainLayout.razor`, `admin-org-chart.css` | 🔴 | ✅ حذف شد | +| 1.3 | اصلاح عنوان اپ: "فرصت" → "کارا بازار سلامت" | `MainLayout.razor` | 🔴 | ✅ اصلاح شد | +| 1.4 | Dark Mode Toggle | `MainLayout.razor`, `CustomMudTheme.cs` | 🟡 | ✅ toggle در AppBar + PaletteDark | +| 1.5 | ساخت کامپوننت `StatCard` مشترک | `Common/BaseComponents/` | 🟡 | ✅ غیرضروری شد (داشبورد ادغام شد) | + +### فاز ۲: بازطراحی لایوت صفحات — ✅ کامل + +| # | کار | فایل(ها) | اولویت | وضعیت | +|---|---|---|---|---| +| 2.1 | بازنویسی `BasePageComponent` — responsive + فیلتر بالای جدول | `BasePageComponent.razor` | 🔴 | ✅ فیلتر collapsible بالای جدول، responsive | +| 2.2 | یکسان‌سازی MaxWidth همه صفحات | تمام صفحات | 🟡 | ✅ MainLayout MudContainer wrapper | +| 2.3 | یکسان‌سازی DataGrid Height | تمام صفحات | 🟡 | ✅ همه `calc(100vh - 240px)` | +| 2.4 | یکسان‌سازی PageSize و Pager فارسی | تمام صفحات | 🟡 | ✅ همه 20/50/100 + متن فارسی | +| 2.5 | اضافه کردن Breadcrumb به MainLayout | `MainLayout.razor` | 🟡 | ✅ AppBreadcrumb.razor ساخته شد | +| 2.6 | بازطراحی صفحات Login + VerifyCode | `LoginPage.razor`, `VerifyCodePage.razor` | 🔴 | ✅ طراحی جدید responsive + برندینگ | + +### فاز ۲.۵: پاکسازی ساختاری — ✅ کامل (7/7) + +| # | کار | اولویت | وضعیت | +|---|---|---|---| +| 2.5.1 | حذف/مخفی کردن Transactions page (stub خالی) | 🔴 | ✅ حذف از NavMenu | +| 2.5.2 | حذف Alerts از NavMenu (mock) | 🔴 | ✅ حذف شد | +| 2.5.3 | فیکس لینک مرده `categories-dragdrop` در NavMenu | 🔴 | ✅ حذف شد | +| 2.5.4 | اضافه کردن WorkerControl به NavMenu بخش سیستم | 🟡 | ✅ در SystemHub تب شد | +| 2.5.5 | حذف تب‌های Notifications/Security از UserSettings (fake backend) | 🟡 | ✅ تب‌ها به «به‌زودی» placeholder تبدیل شدند | +| 2.5.6 | حذف hardcoded resource metrics از HealthDashboard | 🟡 | ✅ متریک‌ها با placeholder «Prometheus/Grafana» جایگزین شدند | +| 2.5.7 | انتقال «پیام‌های عمومی» از بخش فروشگاه تخفیفی به مدیریت محتوا | 🟢 | ✅ در NavMenu جدید منتقل شد | + +### فاز ۳: UX بهبودها — ✅ کامل (6/6) + +| # | کار | فایل(ها) | اولویت | وضعیت | +|---|---|---|---|---| +| 3.1 | Loading State یکپارچه | تمام صفحات | 🟡 | ✅ صفحات جدید دارند | +| 3.2 | Empty State یکپارچه (NoRecordsContent) | تمام صفحات | 🟡 | ✅ ۳۳ DataGrid | +| 3.3 | Delete Confirmation با نام آیتم | تمام صفحات | 🟢 | ✅ ۱۱ صفحه اصلاح شد | +| 3.4 | User Menu در AppBar (پروفایل + خروج) | `MainLayout.razor` | 🟡 | ✅ MudMenu با نام + خروج | +| 3.5 | Dark Mode Toggle | `MainLayout.razor`, `CustomMudTheme.cs` | 🟢 | ✅ toggle + PaletteDark | +| 3.6 | تاریخ شمسی یکپارچه در تمام صفحات | تمام صفحات | 🟡 | ✅ **۱۹+ فایل** — `.MiladiToJalali()` / `.MiladiToJalaliWithTime()` از DateTimeConverterCL | + +### فاز ۳.۵: ادغام صفحات — ✅ کامل (5/6) + +| # | کار | صفحات مبدأ | نتیجه | اولویت | وضعیت | +|---|---|---|---|---|---| +| 3.5.1 | ادغام ۲ داشبورد | Index + SystemOverview | یک Dashboard واحد | 🔴 | ✅ Index.razor merged | +| 3.5.2 | ادغام DiscountOrders + SalesReports | ۲ صفحه → ۱ صفحه + ۲ تب | DiscountShopHub | 🟡 | ✅ | +| 3.5.3 | ادغام Club Members + Statistics | ۲ صفحه → ۱ صفحه + header | ClubHub | 🟡 | ✅ | +| 3.5.4 | ادغام Blog + BlogCategories + Tags | ۳ صفحه → ۱ صفحه + ۳ تب | BlogHub | 🟢 | ✅ | +| 3.5.5 | ادغام System pages | Config+Worker+Health → ۱ + ۳ تب | SystemHub | 🟢 | ✅ | +| 3.5.6 | Extract shared status helpers | حذف ۴ تکرار GetStatusColor/Text | Helper مشترک | 🟢 | ⏭ Skip — هر context مقادیر متفاوت دارد (domain-specific) | + +### فاز ۴: فیکس‌های بیزینسی — ✅ کامل (10/11) + +| # | کار | فایل(ها) | اولویت | وضعیت | +|---|---|---|---|---| +| 4.1 | اصلاح محاسبه آمار Dashboard (از metadata نه page data) | `Index.razor` | 🔴 | ✅ داشبورد merged با API درست | +| 4.2 | اضافه کردن دکمه‌های تأیید/رد به WithdrawalRequests | `WithdrawalRequests.razor` | 🔴 | ✅ + ViewDetailsDialog + RejectReasonDialog | +| 4.3 | اضافه کردن دکمه‌های تأیید/رد به ManualPayments | `ManualPaymentsMainPage.razor` | 🔴 | ✅ Approve/Reject با confirmation | +| 4.4 | اضافه کردن `Cancelled=5` به فیلتر DeliveryStatus | `UserOrderMainPage.razor` | 🔴 | ✅ MudSelectItem اضافه شد | +| 4.5 | فعال‌سازی DiscountShop Widget | `SystemOverview.razor` | 🟡 | ⏭ SystemOverview حذف شد (ادغام) | +| 4.6 | آنکامنت آمار UserOrder | `UserOrderMainPage.razor` | 🟡 | ✅ آمار + نمودار فعال شد | +| 4.7 | پیاده‌سازی فیلتر دسته‌بندی DiscountShop | `DiscountProductsMainPage.razor` | 🟡 | ✅ دسته‌بندی‌ها از IDiscountCategoryService بارگذاری می‌شوند | +| 4.8 | تبدیل DiscountProducts از Items به ServerData | `DiscountProductsMainPage.razor` | 🟡 | ✅ ServerData + pagination سمت سرور | +| 4.9 | Settings page — persist با localStorage | `UserSettings.razor` | 🟡 | ✅ تب General با localStorage کار می‌کند (از قبل) | +| 4.10 | حذف `cursor:pointer` زائد از همه دکمه‌ها | تمام صفحات (17 فایل) | 🟢 | ✅ حذف شد از تمام فایل‌ها | +| 4.11 | حذف `Console.WriteLine` از همه فایل‌ها | 11 فایل | 🟢 | ✅ حذف شد از تمام فایل‌ها | + +### فاز ۴.۵: Cross-Navigation — 🟡 بخشی انجام شد (3/5) + +| # | کار | اولویت | وضعیت | +|---|---|---|---| +| 4.5.1 | لینک نام کاربر در UserOrders → پروفایل کاربر | 🟡 | ✅ MudLink به `/network/user-info/{UserId}` | +| 4.5.2 | لینک نام کاربر در Commission Payouts/Withdrawals → پروفایل کاربر | 🟡 | ✅ MudLink به `/network/user-info/{UserId}` | +| 4.5.3 | لینک نام محصول در Inventory → صفحه محصول | 🟢 | ⏭ Skip — صفحه جزئیات محصول وجود ندارد | +| 4.5.4 | لینک موجودی در Products → صفحه انبار | 🟢 | ⏭ Skip — صفحه جزئیات محصول وجود ندارد | +| 4.5.5 | بازنگری کلی NavMenu طبق ساختار پیشنهادی | 🟡 | ✅ انجام شد در فاز ۲.۵ | + +### فاز ۵: صفحات مفقود (CMS-Derived) — ✅ اکثراً کامل (7/8) + +| # | کار | CMS Entity/Command | اولویت | وضعیت | +|---|---|---|---|---| +| 5.1 | **صفحه مدیریت کیف پول کاربران** | `UserWallet`, `UserWalletChangeLog` | 🔴 | ✅ WalletManagementPage.razor (۲ تب) | +| 5.2 | **Workflow تأیید درخواست برداشت** | `ApproveWithdrawal`, `RejectWithdrawal` | 🔴 | ✅ در فاز ۴.۲ انجام شد | +| 5.3 | **صفحه مدیریت وام دایا** | `DayaLoanContract` | 🟡 | ⏸ **نیاز به proto بک‌اند** — فعلاً امکان‌پذیر نیست | +| 5.4 | **مدیریت فیچرهای باشگاه** | `ClubFeature`, `UserClubFeature` | 🟡 | ✅ ClubFeaturesPage.razor (۲ تب) | +| 5.5 | **نمایش قراردادهای کاربران** | `UserContract` | 🟡 | ✅ UserContractPage.razor + ContractDetailsDialog | +| 5.6 | **لاگ اجرای Worker‌ها** | `GetWorkerExecutionLogs` | 🟢 | ✅ تب WorkerControl در SystemHub قبلاً شامل لاگ‌هاست | +| 5.7 | **تاریخچه عضویت باشگاه** | `GetClubMembershipHistory` | 🟢 | ✅ MemberDetailsDialog — تب تاریخچه با فیلدهای Created, Action, Reason, PerformedBy | +| 5.8 | **تاریخچه تغییرات شبکه** | `GetNetworkMembershipHistory` | 🟢 | ✅ UserNetworkInfo — تب تاریخچه با فیلدهای OldParentId, NewParentId, OldNetworkLeg, NewNetworkLeg | + +### فاز ۶: فیچرهای جدید (اختیاری) — ✅ اکثراً تکمیل + +| # | کار | اولویت | وضعیت | +|---|---|---|---| +| 6.1 | سیستم نوتیفیکیشن (Bell icon + Dropdown) | 🟢 | ✅ Bell icon + MudMenu placeholder در MainLayout — آماده اتصال به بک‌اند | +| 6.2 | Global Search در AppBar | 🟢 | ✅ GlobalSearch.razor — جستجوی صفحات + کاربران (gRPC) — Autocomplete | +| 6.3 | Export Excel در تمام صفحات | 🟢 | ✅ **۱۰ صفحه** — Products, ClubMembers, WithdrawalRequests, WeeklyReports, UserOrders, MovementsPage, Users, DiscountOrders, ManualPayments, Inventory | +| 6.4 | Audit Trail / لاگ فعالیت ادمین | 🟢 | ⏸ نیاز به بک‌اند — endpoint لاگ فعالیت ادمین موجود نیست | +| 6.5 | نمایش counter پرداخت‌های Pending در NavMenu | 🟢 | ✅ MudBadge روی «درخواست‌های برداشت» — real-time از gRPC | + +--- + +## 🔑 اولویت‌بندی نهایی — وضعیت اجرا + +### ✅ انجام شده — فوری (فاز ۱ + ۲): +1. ~~تم رنگی + حذف هاردکدها + PaletteDark~~ ✅ +2. ~~اصلاح عنوان اپ~~ ✅ +3. ~~بازنویسی BasePageComponent (responsive)~~ ✅ +4. ~~بازطراحی Login/VerifyCode~~ ✅ +5. ~~یکسان‌سازی الگوهای صفحات~~ ✅ +6. ~~اصلاح محاسبه آمار Dashboard~~ ✅ + +### ✅ انجام شده — عملیات بحرانی (فاز ۴ + ۵): +7. ~~⚡ دکمه‌های تأیید/رد درخواست برداشت~~ ✅ + ViewDetails + RejectReason dialogs +8. ~~⚡ دکمه‌های تأیید/رد پرداخت دستی~~ ✅ +9. ~~⚡ صفحه کیف پول کاربران (۳ موجودی + تاریخچه)~~ ✅ WalletManagementPage +10. ~~اضافه کردن Cancelled به فیلتر سفارش‌ها~~ ✅ + +### ✅ انجام شده — UX یکپارچه (فاز ۳): +11. ~~Loading/Empty State یکپارچه~~ ✅ NoRecordsContent ۳۳ گرید +12. ~~User Menu در AppBar~~ ✅ +13. ~~Breadcrumb~~ ✅ AppBreadcrumb.razor +14. ~~ادغام صفحات~~ ✅ ۵ hub page ساخته شد + +### ✅ انجام شده — صفحات مفقود (فاز ۵): +15. ~~مدیریت فیچرهای باشگاه~~ ✅ ClubFeaturesPage.razor +16. ~~نمایش قراردادهای کاربران~~ ✅ UserContractPage.razor + ContractDetailsDialog + +### ❌ باقی‌مانده — اولویت‌بندی شده: + +#### مهم 🟡 (۱ مورد): +1. DayaLoanContract صفحه (5.3) — **نیاز به بک‌اند (blocked)** + +#### جزئی 🟢 (۰ مورد — همه انجام شدند به‌جز Audit Trail): +~~2. سیستم نوتیفیکیشن (6.1)~~ ✅ +~~3. Global Search (6.2)~~ ✅ +~~4. Audit Trail (6.4)~~ ⏸ نیاز به بک‌اند + +--- + +## 📊 خلاصه کمّی مشکلات — بروزرسانی + +| شدت | تعداد اولیه | انجام‌شده | باقی‌مانده | +|---|---|---|---| +| 🔴 بحرانی | **16** | **16** ✅ | **0** | +| 🟡 مهم | **24** | **23** | **1** (DayaLoan — blocked) | +| 🟢 جزئی | **18** | **18** ✅ | **0** | +| **مجموع** | **58** | **57 (≈98%)** | **1 (≈2%)** | + +> **همه ۱۶ مورد بحرانی 🔴 انجام شده‌اند.** +> **همه ۱۸ مورد جزئی 🟢 انجام شده‌اند.** +> **فازهای ۱ تا ۶ تکمیل شدند** (به‌جز DayaLoan و Audit Trail که نیاز به بک‌اند دارند). +> تنها مورد باقی‌مانده: DayaLoanContract (5.3) — blocked on backend proto. + +### خلاصه ادغام‌ها — نتیجه + +| عمل | انجام شد؟ | نتیجه | +|---|---|---| +| ۲ داشبورد → ۱ | ✅ | Index.razor (unified dashboard) | +| DiscountOrders + Sales → tabs | ✅ | DiscountShopHub.razor | +| Club Members + Stats → tabs | ✅ | ClubHub.razor | +| Blog + BlogCat + Tag → tabs | ✅ | BlogHub.razor | +| System (3 pages) → tabs | ✅ | SystemHub.razor | +| حذف Transactions (stub) | ✅ | از NavMenu حذف شد | +| **صرفه‌جویی** | | **-9 صفحه مستقل** | + +### فایل‌های جدید ساخته‌شده + +| فایل | عملکرد | +|---|---| +| `Shared/AppBreadcrumb.razor` | Breadcrumb خودکار با عنوان فارسی | +| `Pages/DiscountShop/DiscountShopHub.razor` | Hub سفارشات + گزارش فروش | +| `Pages/Club/ClubHub.razor` | Hub اعضا + آمار باشگاه | +| `Pages/Club/ClubFeaturesPage.razor` | فیچرهای باشگاه + فیچرهای کاربر | +| `Pages/Blog/BlogHub.razor` | Hub پست + دسته‌بندی + تگ | +| `Pages/SystemManagement/SystemHub.razor` | Hub تنظیمات + Worker + سلامت | +| `Pages/Wallet/WalletManagementPage.razor` | کیف‌پول + تاریخچه تغییرات | +| `Pages/Contract/UserContractPage.razor` | لیست قراردادهای کاربران | +| `Pages/Contract/ContractDetailsDialog.razor` | جزئیات قرارداد | +| `Pages/Commission/Components/WithdrawalDetailsDialog.razor` | جزئیات درخواست برداشت | +| `Pages/Commission/Components/RejectReasonDialog.razor` | ورود دلیل رد درخواست | +| `Shared/GlobalSearch.razor` | جستجوی جهانی (صفحات + کاربران) در AppBar | + +--- + +*این داکیومنت نسخه ۷.۰ است و شامل وضعیت پیاده‌سازی تمام فازها می‌شود.* +*تاریخ بروزرسانی: تیر ۱۴۰۴ (July 2025)* +*وضعیت: ۵۷ از ۵۸ مورد انجام شده (≈98%) — تمام موارد بحرانی و جزئی تکمیل* +*مبنای اجرایی: فاز‌های ۱ تا ۶ + فازهای ۲.۵/۳.۵/۴.۵ به‌ترتیب اولویت* diff --git a/backoffice/BACKOFFICE-CHANGELOG.md b/backoffice/BACKOFFICE-CHANGELOG.md new file mode 100644 index 0000000..7109d3d --- /dev/null +++ b/backoffice/BACKOFFICE-CHANGELOG.md @@ -0,0 +1,850 @@ +# 📝 BackOffice — Changelog + +**آخرین بروزرسانی:** اسفند ۱۴۰۴ (February 18, 2026) + +--- + +## 🏷 فاز ۱۷ — بهبود سیستم موجودی + اتوکامپلیت تخفیفی (اسفند ۱۴۰۴) + +> **هدف:** UX هوشمند ورود کالا با autocomplete اختصاصی برای هر نوع فروشگاه + +### ۱۷.۱ — کامپوننت DiscountProductsAutoComplete ✅ + +- **فایل‌ها:** `Pages/AutoComplete/DiscountProductsAutoComplete.razor(.cs)` +- **الگو:** مشابه `ProductsAutoComplete` موجود +- **gRPC Client:** `DiscountProductContract.DiscountProductContractClient` +- **دِبانس:** ۷۰۰ms، حداکثر ۹ نتیجه +- **نکته:** `SearchQuery` از نوع `string` (نه `StringValue`) + +### ۱۷.۲ — UX هوشمند AddStockDialog ✅ + +- **فایل:** `Pages/Inventory/Components/AddStockDialog.razor` +- **تغییر:** فیلد عددی خام شناسه محصول → autocomplete هوشمند +- **رفتار:** + - انتخاب «فروشگاه عادی» → نمایش `ProductsAutoComplete` + - انتخاب «فروشگاه اعتباری» → نمایش `DiscountProductsAutoComplete` + - ولیدیشن قبل از submit + +### ۱۷.۳ — Merge به production ✅ + +- **برنچ:** `kub-stage` → `production` +- **ریموت:** `kub-stage` (Gitea) + +--- + +## 🏷 فاز ۱۶ — ساده‌سازی صفحات سایت + ادیتورهای Shopify-style (اسفند ۱۴۰۴) + +> **هدف:** مدیریت typed صفحات سایت با فرم‌های اختصاصی + +### ۱۶.۱ — صفحه مدیریت PageSettings ✅ + +- **فایل‌ها:** `Pages/Content/PageSettingsManagementPage.razor(.cs)` +- **قابلیت‌ها:** لیست ۴ صفحه ثابت (landing/about/contact/licenses)، ویرایش تنظیمات، مدیریت تصاویر + +### ۱۶.۲ — ادیتورهای اختصاصی Shopify-style ✅ + +| فایل | صفحه | +|------|------| +| `AboutSettingsEditor.razor` | درباره ما: ارزش‌ها + اعضای تیم | +| `ContactSettingsEditor.razor` | تماس: آدرس/تلفن/ایمیل/شبکه‌های اجتماعی | +| `LandingSettingsEditor.razor` | لندینگ: Hero + Steps + Features + Stats + FAQ + Testimonials | +| `LicensesSettingsEditor.razor` | مجوزها: JSON array | + +### ۱۶.۳ — سرویس gRPC و دیالوگ‌ها ✅ + +- `ISitePageSettingsService` + `SitePageSettingsService` +- `PageSettingsEditDialog` + `PageImagesDialog` + `PageImageEditDialog` +- `PageSettingsModels.cs` — مدل‌های typed برای JSON + +### ۱۶.۴ — Proto v0.0.180 ✅ + +- **تغییر:** `Foursat.CMSMicroservice.Protobuf` → `0.0.180` + +--- + +## 🏷 فاز ۱۵ — Production Deploy + فیکس CI/CD Cross-Deploy (اسفند ۱۴۰۴) + +> **هدف:** دیپلوی به سرور Production و رفع باگ cross-deploy + +### ۱۵.۱ — Merge به برنچ production ✅ + +- **کامیت:** `4454b8d` — merge `kub-stage` → `production` +- **ریموت:** `kub-stage` (Gitea) + +### ۱۵.۲ — فیکس باگ Cross-Deploy ✅ + +- **مشکل:** Gitea Act Runner همه workflowهای `.gitea/workflows/` را اجرا می‌کرد — بدون توجه به `branches:` filter +- **عارضه:** push به `production` باعث دیپلوی همزمان به staging و production می‌شد +- **رفع:** حذف فایل‌های workflow staging از برنچ production +- **فایل حذف شده:** `.gitea/workflows/deploy.yml` (staging) از برنچ production + +### ۱۵.۳ — بروزرسانی Proto به v0.0.179 ✅ + +- **تغییر:** `Foursat.CMSMicroservice.Protobuf` → `0.0.179` +- **فایل:** `BackOffice.csproj` + +### ۱۵.۴ — فیکس K8S_SERVER در prod-deploy.yml ✅ + +- **مشکل:** `K8S_SERVER` هنوز `194.5.195.53` (staging) بود +- **رفع:** تغییر به `45.149.79.127` (production) +- **فیکس اضافی:** `kubectl rollout restart` → `kubectl set image` (تا ایمیج SHA-tagged واقعاً set بشه) + +### ۱۵.۵ — ساخت appsettings.Production.json ✅ + +- **مشکل:** فایل `appsettings.Production.json` وجود نداشت → `GwUrl` fallback به `localhost` +- **رفع:** ساخت `wwwroot/appsettings.Production.json` با `GwUrl=https://cms.kbs1.ir` + +### ۱۵.۶ — فیکس nginx image path در Dockerfile (production branch) ✅ + +- **مشکل:** Dockerfile روی برنچ production از `library/nginx:alpine` استفاده می‌کرد — وجود نداشت +- **ارور:** `manifest for 194.5.195.53:32082/library/nginx:alpine not found` +- **رفع:** تغییر به `194.5.195.53:32082/nginx:alpine` +- **کامیت:** `743403e` (مستقیم روی برنچ production) + +--- + +## 🏷 فاز ۱۴ — فیکس Docker Build + Deployment (بهمن ۱۴۰۴) + +> **هدف:** رفع مشکلات Docker build و CI/CD pipeline + +### ۱۴.۱ — تغییر به NuGet Package ✅ + +- **مشکل:** `ProjectReference` به `../../../CMS/src/CMSMicroservice.Protobuf/` خارج از Docker build context بود +- **رفع:** تغییر به `PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.178"` +- **فایل:** `BackOffice.csproj` + +### ۱۴.۲ — حذف COPY libs/ از Dockerfile ✅ + +- **مشکل:** `COPY ["libs/", "libs/"]` فیل می‌شد — `libs/` خارج از build context +- **رفع:** حذف خط — دیگه نیازی به DLLهای BFF نیست +- **فایل:** `Dockerfile` + +### ۱۴.۳ — تغییر nginx:alpine به رجیستری لوکال ✅ + +- **مشکل:** `FROM nginx:alpine` از Docker Hub → TLS handshake timeout +- **رفع:** `FROM 194.5.195.53:32082/nginx:alpine` +- **فایل:** `Dockerfile` + +### ۱۴.۴ — اضافه شدن SERVER_PASSWORD secret ✅ + +- **مشکل:** مرحله Deploy to Kubernetes با `Permission denied` فیل می‌شد +- **رفع:** سکرت `SERVER_PASSWORD` به ریپو Gitea اضافه شد (BackOffice + FrontOffice) + +--- + +## 🏷 فاز ۱۳ — بهبودهای UI بک‌آفیس (بهمن ۱۴۰۴) + +> **هدف:** رفع مشکلات بصری، بهبود UX فرم‌ها و ناوبری + +### ۱۳.۱ — فیکس کامپوننت Image (پیشوند `/uploads/`) ✅ + +- **مشکل:** تصاویر آپلود‌شده (بلاگ، صفحات سایت، سکشن‌ها) در بک‌آفیس نمایش داده نمی‌شدند — مسیر `GwUrl + Src` با مسیر `UploadsController` هماهنگ نبود +- **رفع:** اضافه شدن `/uploads/` بین `FileBaseUrl` و مسیر نسبی تصویر +- **فایل:** `BackOffice/Common/BaseComponents/Image.razor.cs` + +### ۱۳.۲ — فیکس فیلتر هفته در گزارش‌های هفتگی ✅ + +- **مشکل:** فیلتر هفته از `MudTextField` (ورودی متنی) استفاده می‌کرد — کاربر باید عدد حدس می‌زد +- **رفع:** جایگزینی با `WeekNumberPicker` — انتخاب هفته از لیست با بایندینگ `WeekDefinitionId` +- **فایل‌ها:** + - `CMS/src/CMSMicroservice.Protobuf/Protos/commission.proto` — تغییر فیلدها از `StringValue` به `Int64Value` + - `CMS/.../CommissionCQ/Queries/GetAllWeeklyPools/GetAllWeeklyPoolsQuery.cs` + `Handler.cs` + - `BackOffice/Pages/Commission/WeeklyReports.razor` + +### ۱۳.۳ — فیکس دانلود PDF قراردادها ✅ + +- **مشکل:** فیلد `SignedPdfFile` محتوای HTML کامل دارد (نه URL فایل PDF) — دکمه دانلود کار نمی‌کرد +- **رفع:** تابع JS جدید `jsHtmlToPdf()` برای باز کردن HTML در پنجره جدید و چاپ/ذخیره به‌عنوان PDF +- **فایل‌ها:** + - `BackOffice/wwwroot/js/main.js` — تابع `jsHtmlToPdf` + - `BackOffice/Pages/Contract/UserContractPage.razor` + - `BackOffice/Pages/Contract/ContractDetailsDialog.razor` + +### ۱۳.۴ — یکسان‌سازی ارتفاع ویرایشگر HTML ✅ + +- **مشکل:** ارتفاع `MudHtmlEditor` در صفحات مختلف متفاوت بود — برخی خیلی کوتاه +- **رفع:** اضافه شدن `MinHeight="300px"` به تمام ۷ ویرایشگر HTML +- **فایل‌ها:** `BlogPostEditDialog`, `SitePageSectionEditDialog`, `DiscountShop/ProductFormDialog`, `Package/CreateDialog`, `Package/UpdateDialog`, `Products/CreateDialog`, `Products/UpdateDialog` + +### ۱۳.۵ — تولید خودکار اسلاگ بلاگ ✅ + +- **مشکل:** کاربر باید اسلاگ URL را دستی وارد می‌کرد — غیرضروری و مستعد خطا +- **رفع:** حذف فیلد اسلاگ از فرم، تولید خودکار `post-{GUID}` در بک‌اند (حداکثر ۲۰ کاراکتر) +- **فایل‌ها:** + - `CMS/.../BlogPostCQ/Commands/CreateBlogPost/CreateBlogPostCommandHandler.cs` + - `CMS/.../BlogPostCQ/Commands/UpdateBlogPost/UpdateBlogPostCommandHandler.cs` + - `BackOffice/Pages/Blog/Components/BlogPostEditDialog.razor` + +### ۱۳.۶ — انتقال تگ‌ها به منوی جداگانه ✅ + +- **مشکل:** تگ‌ها فقط از تب سوم بلاگ قابل دسترسی بودند — ولی تگ‌ها بین محصولات و بلاگ مشترکند +- **رفع:** اضافه شدن مسیر `/tags` به `TagManagementPage`، لینک جدید «مدیریت تگ‌ها» در منوی ناوبری، حذف تب تگ‌ها از `BlogHub` +- **فایل‌ها:** + - `BackOffice/Pages/Tag/TagManagementPage.razor` + - `BackOffice/Shared/NavMenu.razor` + - `BackOffice/Pages/Blog/BlogHub.razor` + +### ۱۳.۷ — تولید خودکار کلید سکشن ✅ + +- **مشکل:** کاربر باید کلید سکشن صفحه سایت را دستی وارد می‌کرد (مثلاً `about-us-section`) +- **رفع:** فیلد اختیاری شد، تولید خودکار `section-{GUID}` (حداکثر ۲۰ کاراکتر) در هندلر CMS +- **فایل‌ها:** + - `CMS/.../SitePageCQ/Commands/CreateSitePageSection/CreateSitePageSectionCommandHandler.cs` + - `CMS/.../SitePageCQ/Commands/CreateSitePageSection/CreateSitePageSectionCommandValidator.cs` + - `BackOffice/Pages/Content/Components/SitePageSectionEditDialog.razor` + +--- + +## 🏷 فاز ۱۲ — فیکس فلوی ثبت‌نام / ورود FrontOffice (بهمن ۱۴۰۴) + +> **هدف:** رفع ۳ باگ بحرانی در فلوی ثبت‌نام و ورود FrontOffice +> **مستند کامل:** [`totalDoc/cms/REGISTRATION-FLOW-FIXES.md`](../../totalDoc/cms/REGISTRATION-FLOW-FIXES.md) + +### ۱۲.۱ — رفع ایجاد کاربر جدید در VerifyOtpToken 🔴 ✅ + +- **مشکل:** `UserCQ/VerifyOtpTokenCommandHandler` کاربران جدید ایجاد نمی‌کرد — فقط خطای «کاربر یافت نشد» +- **رفع:** اضافه شدن لاجیک کامل: اعتبارسنجی کد معرف، بررسی ظرفیت درخت باینری (حداکثر ۲ فرزند)، تعیین شاخه (چپ/راست)، ایجاد User + UserRole + UserWallet، رویدادهای دامنه +- **فایل:** `CMS/src/CMSMicroservice.Application/UserCQ/Commands/VerifyOtpToken/VerifyOtpTokenCommandHandler.cs` + +### ۱۲.۲ — رفع جستجوی موبایل در AcceptContract 🔴 ✅ + +- **مشکل:** `_currentUserService.Username` = `"{FirstName} {LastName}"` — نه شماره موبایل! در نتیجه OTP و کاربر هیچوقت پیدا نمی‌شد +- **رفع:** ابتدا کاربر از `UserId` پیدا شود، سپس `user.Mobile` برای جستجوی OTP استفاده شود +- **فایل:** `CMS/src/CMSMicroservice.Application/UserCQ/Commands/AcceptContract/AcceptContractCommandHandler.cs` + +### ۱۲.۳ — رفع `IsCompleteRegister()` در FrontOffice 🟡 ✅ + +- **مشکل:** `InitUserAuthInfo().GetAwaiter()` بدون `.GetResult()` — عملیات async اجرا نمی‌شود، منوی کناری وضعیت نادرست +- **رفع:** تغییر به `InitUserAuthInfo().GetAwaiter().GetResult()` +- **فایل:** `FrontOffice/src/FrontOffice.Main/Utilities/AuthService.cs` + +--- + +## 🏷 فاز ۱۱ — رفع خطای صفحات + سرویس عمومی تصاویر (بهمن ۱۴۰۴) + +> **هدف:** رفع خطای ۳ صفحه BackOffice + ایجاد اندپوینت HTTP عمومی برای سرو تصاویر + +### ۱۱.۱ — سرویس عمومی سرو تصاویر (CMS) ✅ + +- **`UploadsController`** — اندپوینت `GET /uploads/{path}` برای سرو مستقیم فایل‌ها +- `[AllowAnonymous]` — بدون نیاز به احراز هویت +- کش مرورگر ۲۴ ساعته (`ResponseCache`) +- پشتیبانی از Range Requests +- **FMS Fallback:** اگر فایل محلی نباشد، از `dl.afrino.co` دانلود و کش می‌شود +- `IHttpClientFactory` با named client `"FMS"` (timeout: 30s) +- **فایل‌ها:** `CMS/WebApi/Controllers/UploadsController.cs`, `CMS/WebApi/Program.cs` + +### ۱۱.۲ — رفع صفحه «صفحات سایت» ✅ + +- اضافه شدن **دکمه «افزودن صفحه جدید»** به بالای صفحه +- اضافه شدن **دکمه «حذف»** (آیکون قرمز) برای هر ردیف +- ایجاد **`SitePageCreateDialog`** — دیالوگ ایجاد صفحه جدید با فیلدها: + - کلید صفحه (PageKey)، عنوان، توضیحات متا، عنوان هیرو، زیرعنوان هیرو، تصویر هیرو، وضعیت +- Proto: اضافه شدن `CreateSitePage` و `DeleteSitePage` RPC +- CQRS: `CreateSitePageCommand/Handler` و `DeleteSitePageCommand/Handler` +- **فایل‌ها:** + - `sitepage.proto` — 2 RPC جدید + پیام‌های Request/Response + - `SitePageCQ/Commands/CreateSitePage/` — Command + Handler + - `SitePageCQ/Commands/DeleteSitePage/` — Command + Handler + - `CMS/WebApi/Services/SitePageService.cs` — 2 override جدید + - `BackOffice/Services/Content/ISitePageService.cs` — `CreateAsync` + `DeleteAsync` + `SitePageCreateDto` + - `BackOffice/Services/Content/SitePageService.cs` — پیاده‌سازی Create/Delete + - `BackOffice/Pages/Content/SitePageManagementPage.razor` — دکمه‌های Add/Delete + - `BackOffice/Pages/Content/SitePageManagementPage.razor.cs` — متدهای CreatePage/DeletePage + - `BackOffice/Pages/Content/Components/SitePageCreateDialog.razor` + `.razor.cs` + +### ۱۱.۳ — رفع صفحه «قراردادها» (Contracts) ✅ + +- **مشکل:** صفحه `/contracts` اصلاً بارگذاری نمی‌شد — crash در DI +- **علت:** `UserContractContract.UserContractContractClient` در DI ثبت نشده بود +- **رفع:** اضافه شدن `using CMSMicroservice.Protobuf.Protos.UserContract` و ثبت gRPC client +- **فایل:** `BackOffice/Common/Configure/ConfigureService.cs` + +### ۱۱.۴ — رفع صفحه «کیف پول کاربران» (Wallets) ✅ + +- **مشکل:** صفحه `/wallets` اصلاً بارگذاری نمی‌شد — crash در DI +- **علت:** دو سرویس ثبت نشده بود: + - `UserWalletContract.UserWalletContractClient` + - `UserWalletChangeLogContract.UserWalletChangeLogContractClient` +- **رفع:** اضافه شدن using‌ها و ثبت هر دو gRPC client +- **فایل:** `BackOffice/Common/Configure/ConfigureService.cs` + +--- + +## 🏷 فاز ۱۰ — بهبود مدیریت محتوا: بلاگ + صفحات سایت (بهمن ۱۴۰۴) + +> **هدف:** فعال‌سازی آپلود تصویر باینری و ادیتور HTML در صفحات بلاگ و صفحات سایت + +### ۱۰.۱ — بهبود ادیتور پست بلاگ ✅ + +- **`MudTextField Lines="10"`** → **`MudHtmlEditor`** برای ویرایش محتوای HTML +- **فیلد متنی مسیر تصویر** → **`MudFileUpload`** با پیش‌نمایش تصویر (`Image` component) +- حذف فیلد `FeaturedImageThumbnailPath` (تولید خودکار توسط بک‌اند) +- اضافه شدن `MudForm` با اعتبارسنجی + حالت بارگذاری (`_loading`) +- مدیریت خطا: try-catch + Snackbar +- **فایل‌ها:** `Pages/Blog/Components/BlogPostEditDialog.razor` + `.razor.cs` + +### ۱۰.۲ — بهبود ادیتور صفحه سایت ✅ + +- **فیلد متنی Hero Image** → **`MudFileUpload`** با پیش‌نمایش تصویر +- اضافه شدن `MudForm` + حالت آپلود + مدیریت خطا +- **فایل‌ها:** `Pages/Content/Components/SitePageEditDialog.razor` + `.razor.cs` + +### ۱۰.۳ — بهبود ادیتور بخش صفحه سایت (Section) ✅ + +- **`MudTextField Lines="8"`** → **`MudHtmlEditor`** برای ویرایش محتوای HTML بخش‌ها +- **فیلدهای متنی تصویر/thumbnail** → **`MudFileUpload`** با پیش‌نمایش +- اضافه شدن `MudForm` + حالت آپلود + مدیریت خطا +- **فایل‌ها:** `Pages/Content/Components/SitePageSectionEditDialog.razor` + `.razor.cs` + +### ۱۰.۴ — تغییرات Proto ✅ + +| Proto | تغییر | +|-------|-------| +| `blogpost.proto` | اضافه شدن `BlogImageFileModel` + فیلد `image_file` در Create/Update | +| `sitepage.proto` | اضافه شدن `SitePageImageFileModel` + فیلد `image_file` در Update/CreateSection/UpdateSection | + +### ۱۰.۵ — تغییرات CQRS (بک‌اند CMS) ✅ + +- **Commands:** اضافه شدن `ImageFileBytes`, `ImageMime`, `ImageFileName` به: + - `CreateBlogPostCommand`, `UpdateBlogPostCommand` + - `UpdateSitePageCommand`, `CreateSitePageSectionCommand`, `UpdateSitePageSectionCommand` +- **Handlers:** تزریق `IFileManager` + فراخوانی `UploadImageAsync`: + - BlogPost → `Images/BlogPosts/` + - SitePage → `Images/SitePages/` + - SitePageSection → `Images/SitePageSections/` + +### ۱۰.۶ — تغییرات سرویس‌های BackOffice ✅ + +- `BlogPostService.cs` — ارسال `BlogImageFileModel` با `ByteString.CopyFrom(dto.ImageFile)` +- `SitePageService.cs` — ارسال `SitePageImageFileModel` در Update/CreateSection/UpdateSection +- **DTOs:** اضافه شدن `ImageFile`, `ImageMime`, `ImageFileName` به `BlogPostEditDto`, `SitePageEditDto`, `SitePageSectionEditDto` + +### خلاصه آمار فاز ۱۰ +| معیار | تعداد | +|---|---| +| فایل‌های proto تغییریافته | 2 | +| Command‌های بروزشده | 5 | +| Handler‌های بروزشده | 5 | +| سرویس‌های gRPC تغییریافته | 2 (BlogPostService + SitePageService) | +| دیالوگ‌های UI بازنویسی‌شده | 3 (BlogPost, SitePage, SitePageSection) | +| سرویس‌های BackOffice بروزشده | 2 | +| DTO‌های بروزشده | 3 | +| Build | 0 Error ✅ (هر ۳ پروژه) | + +--- + +## 🏷 فاز ۹ — معماری مدیریت فایل + رفع سفارشات + مهاجرت DB (بهمن ۱۴۰۴) + +> **مستند کامل معماری فایل:** [`totalDoc/cms/FILE-MANAGEMENT-ARCHITECTURE.md`](../../totalDoc/cms/FILE-MANAGEMENT-ARCHITECTURE.md) + +### ۹.۱ — حذف کد مرده FMS ✅ +- حذف ۳ فایل غیرقابل استفاده مرتبط با FMS خارجی (`https://dl.afrino.co`): + +| فایل حذف‌شده | شرح | +|-------------|------| +| `Infrastructure/Services/FmsFileManager.cs` | پیاده‌سازی HTTP upload به FMS | +| `Application/Common/FileManager/FileManagementService.cs` | سرویس قدیمی مدیریت فایل | +| `Application/Common/FileManager/IFileManagementService.cs` | اینترفیس قدیمی | + +### ۹.۲ — رفع صفحه سفارشات (Orders) ✅ + +**مشکل ۱ — صفحه خالی (بدون پیغام خطا)** +- **علت:** `ServerReload` بدون try-catch — exception‌های gRPC ساکت می‌شدند +- **رفع:** اضافه شدن try-catch + نمایش خطا با Snackbar +- **فایل:** `Pages/UserOrder/UserOrderMainPage.razor.cs` + +**مشکل ۲ — Shadow FK تکراری در OrderVAT** +- **علت:** `.WithOne()` بدون inverse navigation → EF Core یک shadow FK اضافی می‌ساخت +- **رفع:** `.WithOne()` → `.WithOne(x => x.OrderVAT)` +- **فایل:** `Persistence/Configurations/OrderVATConfiguration.cs` + +**مشکل ۳ — فیلترهای oneof همیشه فعال** +- **علت:** فیلدهای proto `oneof` مقدار پیش‌فرض enum دارند (هیچ‌وقت null نیستند)، پس `PaymentStatus != null` همیشه true بود +- **رفع:** `PaymentStatus != null` → `HasPaymentStatus == true` (و مشابه برای DeliveryStatus و PaymentMethod) +- **فایل‌ها:** `UserOrderService.cs` — هر دو متد `GetAllUserOrderByFilter` و `GetCustomerOrders` + +### ۹.۳ — مهاجرت DB: حذف محدودیت طول ستون‌های تصویر ✅ + +- **علت:** data URI‌های base64 بزرگ‌تر از `nvarchar(500)` بودند → truncation خاموش +- **رفع:** حذف `HasMaxLength(500)` از تمام ستون‌های image path +- **Migration:** `RemoveImagePathMaxLength` + +| Entity | ستون‌ها | +|--------|---------| +| Product | `ImagePath`, `ImageThumbnailPath` | +| DiscountProduct | `ImagePath`, `ImageThumbnailPath` | +| Category | `ImagePath` | +| DiscountCategory | `ImagePath` | +| BlogPost | `FeaturedImagePath`, `FeaturedImageThumbnailPath` | +| SitePage | `HeroImagePath` | +| SitePageSection | `ImagePath`, `ImageThumbnailPath` | + +### ۹.۴ — بازنویسی کامل مدیریت فایل: ذخیره دیسکی ✅ + +**معماری قبلی:** ذخیره data URI مستقیم در DB (ناکارآمد + حجم بالا) + +**معماری جدید:** +1. فایل‌ها در دیسک ذخیره می‌شوند: `Uploads/Images/{folder}/{guid}.jpg` +2. مسیر نسبی در DB ذخیره می‌شود +3. `ImagePathResolverInterceptor` هنگام serve تبدیل به base64 می‌کند + +**فایل‌های اصلی:** + +| فایل | شرح | +|------|------| +| `Application/Common/FileManager/IFileManager.cs` | اینترفیس: Upload, UploadImage, Delete, ResolveImageUrl | +| `Infrastructure/Services/LocalFileManager.cs` | پیاده‌سازی: ImageSharp, main 1200×1200 + thumb 300×300, JPEG Q75 | +| `WebApi/Interceptors/ImagePathResolverInterceptor.cs` | gRPC Interceptor: walk بازگشتی response → تبدیل path به data URI | + +**تنظیمات:** +- `FileStorage:UploadPath` → پوشه ریشه آپلود (پیش‌فرض: `AppContext.BaseDirectory/Uploads`) +- gRPC MaxReceiveMessageSize: 50MB + +### ۹.۵ — پاکسازی LoggingBehaviour ✅ + +- **قبل:** فیلدهای باینری (byte[] تصاویر) کامل در لاگ چاپ می‌شدند → لاگ‌های چند مگابایتی +- **بعد:** + - فرمت: `JsonFormatter.Default.Format()` به جای `{@Request}` + - Regex: حذف فیلدهای باینری (`File`, `ImageFile`, `image_file`, `file`) + - محدودیت: حداکثر 2000 کاراکتر +- **فایل:** `WebApi/Common/Behaviours/LoggingBehaviour.cs` + +### خلاصه آمار فاز ۹ +| معیار | تعداد | +|---|---| +| فایل‌های حذف‌شده (کد مرده) | 3 | +| فایل‌های جدید | 2 (LocalFileManager بازنویسی + ImagePathResolverInterceptor) | +| فایل‌های ویرایش‌شده | ~12 | +| باگ‌های رفع‌شده | 4 (Orders page ×3 + DB truncation) | +| Migration‌های جدید | 1 (RemoveImagePathMaxLength) | +| ستون‌های DB تغییریافته | 9 (nvarchar(500) → nvarchar(max)) | +| Build | 0 Error ✅ (هر ۳ پروژه) | + +--- + +## 🏷 فاز ۸ — یکسان‌سازی فروشگاه عادی و تخفیفی (بهمن ۱۴۰۴) + +> **مستند کامل:** [`totalDoc/ui-modernization/BACKOFFICE-STORE-UNIFICATION.md`](../../totalDoc/ui-modernization/BACKOFFICE-STORE-UNIFICATION.md) + +### ۸.۱ — بازسازی NavMenu ✅ +- ایجاد دو NavGroup مجزا: «فروشگاه عادی» و «فروشگاه تخفیفی» +- حذف «ویرایش دسته‌جمعی» از منو +- انبارداری → گروه مستقل | پکیج‌ها → آیتم مستقل +- **فایل:** `Shared/NavMenu.razor` + +### ۸.۲ — حذف گزارش‌های کوچک از سفارشات ✅ +- حذف کارت‌های آماری (TotalOrders + TotalAmount) و نمودار Bar ارسال +- حذف فیلدها: `_stats`, `_statusChartLabels`, `_statusChartSeries` +- حذف متد `UpdateStats()` و کلاس `OrderStatsViewModel` +- عنوان: «سفارش‌های کاربر» → «لیست سفارشات» +- **فایل‌ها:** `Pages/UserOrder/UserOrderMainPage.razor` + `.razor.cs` + +### ۸.۳ — رفع باگ لیست خالی سفارشات ✅ +- **علت:** `PaymentDate.ToDateTime()` بدون null check → exception ساکت در WASM +- **رفع:** `@if (context.Item.PaymentDate != null)` + fallback "-" +- **فایل:** `Pages/UserOrder/UserOrderMainPage.razor` + +### ۸.۴ — بازنویسی صفحه محصولات تخفیفی ✅ +- تبدیل به `BasePageComponent` (مطابق فروشگاه عادی) +- فیلترهای جدید: وضعیت + موجودی +- ستون‌های جدید: تصویر inline + عنوان truncate + چیپ رنگی موجودی + چیپ وضعیت +- **فایل‌ها:** `Pages/DiscountShop/DiscountProductsMainPage.razor` + `.razor.cs` (بازنویسی کامل) + +### ۸.۵ — بازنویسی صفحه دسته‌بندی‌های تخفیفی ✅ +- تبدیل به `BasePageComponent` (مطابق فروشگاه عادی) +- ستون‌های جدید: نام لاتین، دسته‌بندی والد (resolve شده)، تعداد محصولات، ترتیب +- code-behind جدید (`@code` درون‌خطی → `.razor.cs`) +- **فایل‌ها:** `Pages/DiscountShop/DiscountCategoriesMainPage.razor` + `.razor.cs` (بازنویسی کامل) + +### خلاصه آمار فاز ۸ +| معیار | تعداد | +|---|---| +| فایل‌های بازنویسی‌شده | 4 | +| فایل‌های ویرایش‌شده | 3 | +| باگ‌های رفع‌شده | 2 (PaymentDate null + لیست خالی) | +| Build | 0 Error ✅ | + +--- + +## 🏷 فاز ۷ — پس از اجرای Audit v7.0 (تیر ۱۴۰۴) + +### خلاصه تغییرات +- **۵۷ مورد** از ۵۸ یافته audit اجرا شد (≈98%) +- **تمام ۱۶ مورد بحرانی 🔴** حل شد +- **تمام ۱۸ مورد جزئی 🟢** حل شد +- **فازهای ۱ تا ۶ تکمیل شدند** (به‌جز DayaLoan و Audit Trail که نیاز به بک‌اند دارند) +- **فاز ۷** — Global Search, Notification Bell, NavMenu Badge, Export Excel 4 صفحه جدید +- **۱۳+ فایل جدید** ساخته شد +- **۹ صفحه** ادغام شدند (۱۴ صفحه → ۵ صفحه) +- **Build**: 0 error ✅ + +--- + +## فاز ۷ — Global Search + Notifications + Export All + NavMenu Badge (v7.0) + +### 6.5 — Badge Pending در NavMenu — ✅ +- **`NavMenu.razor`**: اضافه شدن `MudBadge` روی لینک «درخواست‌های برداشت» +- نمایش تعداد درخواست‌های Pending بصورت real-time از gRPC (`CommissionContract.GetWithdrawalRequestsAsync` با `Status=0`) +- fire-and-forget در `OnInitializedAsync` با try/catch silent + +### 6.2 — Global Search در AppBar — ✅ +- **فایل جدید**: `Shared/GlobalSearch.razor` +- `MudAutocomplete` با Debounce 400ms +- دو نوع جستجو: ۱) نام صفحات (۱۵ صفحه اصلی) ۲) کاربران از gRPC (`UserContract.GetAllUserByFilterAsync`) +- Template سفارشی با آیکون + عنوان + زیرنویس +- ناوبری خودکار با `Navigation.NavigateTo` +- اضافه شده در `MainLayout.razor` داخل `` +- CSS در `app.css` — rounded border-radius 24px, compact padding + +### 6.1 — Notification Bell (placeholder) — ✅ +- **`MainLayout.razor`**: اضافه شدن `MudMenu` + `MudBadge` (Dot) + آیکون Notifications +- Dropdown با هدر «اعلان‌ها» + placeholder «اعلان جدیدی وجود ندارد» +- آماده اتصال به بک‌اند — فقط `Visible=true` و populate items + +### 6.3 — Export Excel صفحات جدید — ✅ (۱۰ صفحه کامل) +- **۴ صفحه جدید** اضافه شدند به ۶ صفحه قبلی: + 1. **UserMainPage** — خروجی CSV: شناسه, موبایل, نام, نام خانوادگی, کدملی + 2. **DiscountOrdersMainPage** — خروجی CSV: شماره سفارش, تاریخ, مبلغ کل, تخفیف, قابل پرداخت, تعداد, وضعیت, پرداخت + 3. **ManualPayments** — خروجی CSV: شناسه, شناسه کاربر, نام کاربر, مبلغ, نوع, وضعیت, تاریخ + 4. **InventoryMainPage** — خروجی CSV: شناسه, محصول, انبار, موجودی, رزرو, قابل فروش, حد هشدار, وضعیت +- هر ۴ صفحه: دکمه «خروجی Excel» + `ExportToExcel()` + `EscapeCsv()` + UTF-8 BOM + `jsSaveAsFile` +- فایل‌های code-behind جدید: `ManualPayments.razor.cs`, `DiscountOrdersMainPage.razor.cs` + +--- + +## فاز ۶ — تاریخ شمسی + تاریخچه‌ها + Export Excel (v6.0) + +### تاریخ شمسی یکپارچه (3.6) — ✅ کامل +- **۱۹+ فایل** آپدیت شدند: تمام تاریخ‌ها از فرمت میلادی (`yyyy/MM/dd`) به شمسی تبدیل شدند +- از extension method‌های `DateTimeConverterCL` استفاده شد: + - `.MiladiToJalali()` — فرمت تاریخ فقط (مثال: ۱۴۰۴/۰۴/۱۲) + - `.MiladiToJalaliWithTime()` — فرمت تاریخ و ساعت +- **صفحات اصلاح‌شده شامل**: Club (Members, Statistics, Features, MemberDetailsDialog)، Commission (Dashboard, WeeklyReports, WithdrawalRequests, Payouts, WithdrawalReports)، Network (UserNetworkInfo, BalancesReport, Statistics, NetworkTreeViewer)، UserOrder, Products, Package, Inventory, DiscountShop, Blog, Content, و غیره +- `PropertyColumn Format="yyyy/MM/dd"` → `TemplateColumn` با `.MiladiToJalali()` +- `MudDatePicker DateFormat` تغییر نکرد (قابلیت تقویم شمسی نیاز به کتابخانه جداگانه دارد) + +### تاریخچه عضویت باشگاه (5.7) — ✅ +- **`MemberDetailsDialog.razor`**: تب تاریخچه با فیلدهای صحیح proto: + - ستون‌ها: `Action`, `Created`, `PackageName`, `Reason`, `PerformedBy` + - Request: `PageIndex = 0` (نه PageNumber) + +### تاریخچه تغییرات شبکه (5.8) — ✅ +- **`UserNetworkInfo.razor`**: تب تاریخچه با فیلدهای تخصصی: + - ستون‌ها: `Action`, `Created`, `OldParentId → NewParentId`, `OldNetworkLeg → NewNetworkLeg` (چپ/راست) + - ستون `Reason` و `PerformedBy` اضافه شد + - Request: `PageIndex = 0` + +### لاگ اجرای Worker‌ها (5.6) — ✅ +- در تب WorkerControl از SystemHub قبلاً پیاده‌سازی شده بود + +### Export Excel / CSV (6.3) — ✅ ۶ صفحه +قابلیت خروجی CSV (سازگار با Excel) به ۶ صفحه اصلی اضافه شد: + +| صفحه | فایل(ها) | ستون‌های خروجی | +|---|---|---| +| **Products** (قبلاً موجود) | ProductsMainPage.razor.cs | — | +| **Club Members** | ClubMembers.razor + .razor.cs | شناسه,کاربر,نام,پکیج,کد فعال‌سازی,تاریخ فعال‌سازی,تاریخ انقضا,فعال,منقضی | +| **Withdrawal Requests** | WithdrawalRequests.razor + .razor.cs | شناسه,کاربر,نام,مبلغ,وضعیت,روش,شبا,تاریخ درخواست,تاریخ پردازش,مرجع بانکی | +| **Weekly Reports** | WeeklyReports.razor + .razor.cs | هفته,مبلغ استخر,موجودی‌ها,ارزش,وضعیت,تاریخ محاسبه | +| **User Orders** | UserOrderMainPage.razor + .razor.cs | شناسه,کاربر,نام,مبلغ,وضعیت پرداخت,وضعیت ارسال,روش پرداخت,تاریخ | +| **Stock Movements** | MovementsPage.razor + .razor.cs | شناسه,محصول,نوع,تعداد,قبل,بعد,مرجع,یادداشت,تاریخ | + +**الگوی پیاده‌سازی:** +- دکمه `` با آیکون `FileDownload` در ToolBarContent +- `StringBuilder` → CSV با هدرهای فارسی +- UTF-8 BOM (`Encoding.UTF8.GetPreamble()`) برای نمایش صحیح فارسی در Excel +- `jsSaveAsFile(filename, base64)` از `wwwroot/js/main.js` +- متد `EscapeCsv()` برای مقادیر حاوی کاما/کوتیشن +- تاریخ‌ها در خروجی نیز شمسی هستند + +### فایل‌های جدید (این نسخه) + +| فایل | عملکرد | +|---|---| +| `Pages/Commission/WeeklyReports.razor.cs` | Code-behind برای export (به‌دلیل محدودیت Razor parser با escaped quotes) | + +--- + +## نسخه قبلی — Audit v5.0 (خرداد ۱۴۰۴) + +### تم رنگی یکپارچه +- **`CustomMudTheme.cs`**: تم Primary از `#0380C0` به `#6366f1` (Indigo) تغییر کرد — هماهنگ با FrontOffice +- **`PaletteDark`** اضافه شد: Surface `#1a1a2e`, Background `#16213e`, AppbarBackground `#0f3460` +- **`app.css`**: رنگ loading از `#1b6ec2` به `var(--mud-palette-primary)` تغییر کرد +- **`NavMenu.razor.css`**: رنگ active از `#0380C0` هاردکد به CSS variable تغییر کرد +- **`MainLayout.razor`**: حذف inline style `border: 1px solid #5e4df9` + +### Dark Mode Toggle +- آیکون ماه/آفتاب در AppBar اضافه شد +- `_isDarkMode` state با `MudThemeProvider` اتصال دارد +- تعویض بین `PaletteLight` و `PaletteDark` در CustomMudTheme + +### عنوان اپلیکیشن +- "پنل مدیریت **فرصت**" → "پنل مدیریت **کارا بازار سلامت**" + +--- + +## فاز ۲ — بازطراحی لایوت صفحات + +### BasePageComponent بازنویسی کامل +- **قبل**: فیلتر ثابت سمت راست (20%) + جدول (80%)، ارتفاع 85vh هاردکد +- **بعد**: فیلتر collapsible بالای جدول، فیلدها در `MudGrid` با `MudItem`، responsive +- **۱۳ صفحه** آپدیت شدند: User, Products, Package, Category, UserOrder, UserAddress, UserRole, Role, BlogPost, BlogCategory, Tag, Transactions, Content + +### DataGrid Height یکسان‌سازی +- همه DataGrid‌ها: `Height="calc(100vh - 240px)"` +- **صفحات اصلاح‌شده**: تمام ~33 صفحه دارای DataGrid + +### Pager یکسان‌سازی +- **PageSize**: همه `20, 50, 100` +- **متن فارسی**: `RowsPerPageString="تعداد در صفحه"` و `InfoFormat="سطر {first_item} تا {last_item} از {all_items}"` + +### MaxWidth یکسان‌سازی +- `MainLayout.razor` MudContainer wrapper اضافه شد → MaxWidth یکسان برای همه صفحات +- **۳۱ صفحه**: حذف `MudContainer` تکراری (double nesting) + +### Breadcrumb +- **`Shared/AppBreadcrumb.razor`** ساخته شد +- جداکننده چپ‌به‌راست (`ChevronLeft`) +- نقشه فارسی URL segments (60+ مسیر) +- آخرین آیتم disabled (صفحه فعلی) + +### Login + VerifyCode بازطراحی +- عرض ثابت 35% → responsive `MaxWidth.Small` +- لوگو + برندینگ "کارا بازار سلامت" اضافه شد +- طراحی gradient background + +--- + +## فاز ۲.۵ — پاکسازی ساختاری + +### NavMenu بازسازی کامل +- **لینک مرده `categories-dragdrop`**: حذف شد +- **Transactions**: حذف از NavMenu (صفحه stub خالی) +- **AlertsMonitoring**: حذف از NavMenu (100% mock) +- **WorkerControl**: به SystemHub منتقل شد (قبلاً لینک نداشت) +- **«پیام‌های عمومی»**: از بخش فروشگاه تخفیفی به «مدیریت محتوا» منتقل شد +- **ساختار گروه‌بندی** اصلاح شد: + - کمیسیون و شبکه: NavGroup واضح + - باشگاه مشتریان: اعضا و آمار + فیچرها + - فروشگاه: پکیج‌ها، محصولات (group)، سفارش‌ها، فروشگاه تخفیفی (group) + - مدیریت: کاربران، نقش‌ها، پرداخت دستی، **کیف‌پول (جدید)**، **قراردادها (جدید)** + - محتوا: بلاگ، صفحات سایت، پیام‌های عمومی + - سیستم: مدیریت سیستم، نسخه اپ‌ها + +--- + +## فاز ۳ — UX بهبودها + +### NoRecordsContent (Empty State) +- **۳۳ DataGrid** آپدیت شدند +- پیام: `موردی یافت نشد.` + +### Delete Confirmation با نام آیتم +- **۱۱ صفحه** اصلاح شدند: + - Role → `«{model.Title}»` + - User → `«{model.FirstName} {model.LastName}»` + - Package → `«{model.Title}»` + - UserAddress → `«{model.Title}»` + - UserRole → `شناسه «{model.Id}»` + - UserOrder → `شماره «{model.Id}»` + - Category → `«{model.Title}»` + - Products → `«{model.Title}»` + - DiscountCategories → `«{category?.Title}»` (lookup اضافه شد) + - DiscountProducts → `«{product?.Title}»` (lookup اضافه شد) + - PublicMessages → `«{message?.Title}»` (lookup اضافه شد) + +### User Menu در AppBar +- `MudMenu` جایگزین متن ساده شماره موبایل شد +- آیتم‌ها: نام کاربر (غیرفعال) + خروج +- آیکون `AccountCircle` +- خروج (`signout`) از NavMenu به AppBar منتقل شد + +--- + +## فاز ۳.۵ — ادغام صفحات + +### Dashboard Merge ← `Pages/Index.razor` +- **`Index.razor` + `SystemOverview.razor`** ادغام شدند +- Routes: `/` + `/dashboard/overview` +- بخش‌ها: + - 6 کارت آمار CMS (کاربران، محصولات، پکیج‌ها، دسته‌بندی‌ها، سفارش‌ها، مبلغ پرداخت‌شده) + - آمار کمیسیون (هفته جاری، استخر، موجودی‌ها، وضعیت محاسبه) + - آمار باشگاه (کل/فعال/غیرفعال) + - جدول آخرین ۵ سفارش پرداخت‌شده + - ۶ دکمه Quick Action +- بارگذاری موازی با `Task.WhenAll` + `.ResponseAsync` +- `SystemOverview.razor` **حذف شد** + +### DiscountShopHub ← `Pages/DiscountShop/DiscountShopHub.razor` +- Routes: `/discount-shop`, `/discount-orders`, `/discount-sales-reports` +- ۲ تب: DiscountOrdersMainPage + SalesReports +- انتخاب تب از URL + +### ClubHub ← `Pages/Club/ClubHub.razor` +- Routes: `/club`, `/club/members`, `/club/statistics` +- ۲ تب: ClubMembers + Statistics + +### BlogHub ← `Pages/Blog/BlogHub.razor` +- Routes: `/blog`, `/blog/posts`, `/blog/categories`, `/tags` +- ۳ تب: BlogPostManagementPage + BlogCategoryManagementPage + TagManagementPage + +### SystemHub ← `Pages/SystemManagement/SystemHub.razor` +- Routes: `/system`, `/system/configuration`, `/system/worker-control`, `/system/health` +- ۳ تب: Configuration + WorkerControl + HealthDashboard + +### ۱۰ صفحه — `@page` directive حذف شد +صفحاتی که به hub منتقل شدند دیگر route مستقل ندارند: +DiscountOrdersMainPage, SalesReports, ClubMembers, Statistics, BlogPostManagementPage, BlogCategoryManagementPage, TagManagementPage, Configuration, WorkerControl, HealthDashboard + +--- + +## فاز ۴ — فیکس‌های بیزینسی + +### Dashboard آمار اصلاح شد +- **قبل**: آمار از ۱۰ رکورد اول محاسبه می‌شد (نادرست) +- **بعد**: از `metadata.TotalCount` و API‌های جداگانه استفاده می‌شود + +### ManualPayments — تأیید/رد +- دکمه‌های Approve/Reject وقتی `Status==0` (در انتظار) نمایش داده می‌شوند +- Confirmation dialog قبل از اجرا +- از `ManualPaymentId` (نه `Id`) استفاده می‌شود + +### UserOrder — فیلتر Cancelled +- `لغو شده` اضافه شد + +### WithdrawalRequests — بهبود کامل +- **Pager**: 10/25/50/100 → 20/50/100 +- **`WithdrawalDetailsDialog.razor`** (جدید): نمایش کامل اطلاعات کاربر، درخواست، و بانکی +- **`RejectReasonDialog.razor`** (جدید): ورود دلیل رد با اعتبارسنجی +- ViewDetails: از Snackbar TODO به دیالوگ واقعی تغییر کرد +- RejectRequest: از دلیل هاردکد به دیالوگ custom تغییر کرد + +--- + +## فاز ۵ — صفحات مفقود (CMS-Derived) + +### WalletManagementPage ← `Pages/Wallet/WalletManagementPage.razor` +- Route: `/wallets` +- **تب ۱ — کیف‌پول‌ها**: DataGrid با ServerData، فیلتر UserAutoComplete + - ستون‌ها: شناسه، کاربر، موجودی اصلی، موجودی شبکه، مشاهده تغییرات + - نوع: `GetAllUserWalletByFilterResponseModel` +- **تب ۲ — تاریخچه تغییرات**: DataGrid با ServerData، فیلتر کاربر + نوع (افزایش/کاهش) + - ستون‌ها: شناسه، کیف‌پول، نوع (چیپ رنگی)، تغییر موجودی، موجودی فعلی، تغییر شبکه، موجودی شبکه فعلی، شناسه مرجع، تاریخ + - نوع: `GetAllUserWalletChangeLogByFilterResponseModel` + - فیلدهای proto با typo: `ChangeNerworkValue`, `RefrenceId` + +### UserContractPage ← `Pages/Contract/UserContractPage.razor` +- Route: `/contracts` +- DataGrid با ServerData، فیلتر UserAutoComplete +- ستون‌ها: شناسه، کاربر، قرارداد، کد امضا، لینک PDF، جزئیات +- نوع: `GetAllUserContractByFilterResponseModel` + +### ContractDetailsDialog ← `Pages/Contract/ContractDetailsDialog.razor` +- جدول ساده: شناسه، کاربر، قالب قرارداد، کد امضا، لینک دانلود PDF + +### ClubFeaturesPage ← `Pages/Club/ClubFeaturesPage.razor` +- Route: `/club/features` +- **تب ۱ — فیچرهای تعریف‌شده**: کارت‌های MudPaper با عنوان، توضیحات، وضعیت (فعال/غیرفعال)، ترتیب + - از `ConfigClient.GetClubFeaturesAsync` +- **تب ۲ — فیچرهای کاربران**: DataGrid با فیلتر کاربر، سوئیچ فعال/غیرفعال + - از `ClubClient.GetUserClubFeaturesAsync` + `ToggleUserClubFeatureAsync` + +--- + +## ⚠️ نکات فنی مهم + +### الگوهای Proto +- **فیلتر**: `new GetAllXxxByFilterFilter()` (سطح بالا، بدون `.Types.`) +- **پاسخ لیست**: `GetAllXxxByFilterResponseModel` (نه `GetXxxResponse`) +- **Typo‌ها در proto**: `ChangeNerworkValue` و `RefrenceId` — باید دقیقاً همین‌ها استفاده شوند + +### _Imports.razor — سرویس‌های Global +سرویس‌های زیر از `_Imports.razor` تزریق می‌شوند و نباید در code-behind با `[Inject]` دوباره تعریف شوند: +- `NavigationManager Navigation` +- `ILocalStorageService LocalStorageService` +- `ISnackbar Snackbar` +- `IJSRuntime jsRuntime` +- `IDialogService DialogService` +- `AuthenticationStateProvider` + +### MudBlazor محدودیت‌ها +- `Variant.Flat` وجود ندارد → از `Variant.Text` استفاده شود +- `GutterSize` روی `MudGrid` deprecated است + +--- + +## فاز ۴ (ادامه) — تکمیل فیکس‌های بیزینسی + +### UserSettings — حذف تب‌های جعلی (2.5.5) +- **`UserSettings.razor`**: تب Notifications (۷ تاگل جعلی بدون بک‌اند) → placeholder «به‌زودی فعال می‌شود» با آیکون NotificationsActive +- **`UserSettings.razor`**: تب Security (فرم تغییر رمز + 2FA بدون بک‌اند) → placeholder «به‌زودی فعال می‌شود» با آیکون Lock +- **حذف کد مرده**: ~۱۵ متغیر notification/security + متدهای `SaveNotificationSettings()`, `SaveSecuritySettings()`, `ChangePassword()` + +### HealthDashboard — حذف متریک‌های Mock (2.5.6) +- **`HealthDashboard.razor`**: بخش System Resources (۴ کارت CPU=45.2%, Memory=62.8%, Disk=73.5%, Network) → یک کارت با پیام «مانیتورینگ منابع سیستم در نسخه‌های آینده با اتصال به Prometheus/Grafana فعال خواهد شد» +- **حذف کد مرده**: ۹ متغیر mock (`_cpuUsage`, `_memoryUsage`, etc.) + متد `GetResourceColor()` + +### حذف cursor:pointer زائد (4.10) +- `Style="cursor:pointer;"` از **۱۷ فایل** حذف شد (MudButton/MudIconButton خودشان cursor:pointer دارند) +- شامل: ProductsMainPage, GalleryDialog, Image.razor (base component), RoleMainPage, UserOrderMainPage, PackageMainPage, etc. + +### حذف Console.WriteLine (4.11) +- از **۱۱ فایل** حذف شد: DiscountProductService, DiscountCategoryService, NetworkTreeViewer, UserSettings, CategoryMainPage, UserOrderMainPage, Commission/Dashboard, DiscountProductsMainPage, DiscountCategoryMultiSelectCombo, UserRole/CreateDialog +- **`Commission/Dashboard.razor.cs`**: `using System.Text.Json` هم حذف شد (دیگر استفاده نمی‌شد) + +### DiscountProducts — فیلتر دسته‌بندی (4.7) +- **`DiscountProductsMainPage.razor`**: `@inject IDiscountCategoryService` اضافه شد +- دسته‌بندی‌های فعال از سرویس بارگذاری و در MudSelect نمایش داده می‌شوند +- جایگزینی `@* TODO: Load categories *@` با `@foreach` واقعی + +### DiscountProducts — Items → ServerData (4.8) +- **`DiscountProductsMainPage.razor`**: تبدیل از `Items="@_products"` به `ServerData="LoadServerData"` +- متد `LoadServerData(GridState)` اضافه شد با `PageNumber` و `PageSize` از state +- `Height="calc(100vh - 300px)"` + `FixedHeader="true"` اضافه شد +- Snackbar اطلاع‌رسانی اضافی در هر بارگذاری حذف شد (redundant) + +### UserOrder — فعال‌سازی آمار (4.6) +- **`UserOrderMainPage.razor`**: بخش آمار (MudCard + MudChart) از حالت comment خارج شد +- نمایش تعداد سفارش‌ها + مجموع مبلغ + نمودار Bar وضعیت ارسال + +### UserSettings — persist با localStorage (4.9) +- تب General از قبل با localStorage کار می‌کرد ✅ (فقط تب‌های جعلی حذف شدند) + +--- + +## فاز ۴.۵ — Cross-Navigation + +### لینک نام کاربر → پروفایل (4.5.1, 4.5.2) +- **`UserOrderMainPage.razor`**: ستون `UserFullName` از PropertyColumn به TemplateColumn تبدیل شد — MudLink به `/network/user-info/{UserId}` +- **`UserPayouts.razor`**: نام/شناسه کاربر به MudLink تبدیل شد → `/network/user-info/{UserId}` +- **`WithdrawalRequests.razor`**: نام کاربر به MudLink تبدیل شد → `/network/user-info/{UserId}` + +### لینک محصول ↔ انبار (4.5.3, 4.5.4) — Skip +- صفحه جزئیات محصول وجود ندارد (فقط لیست + دیالوگ ویرایش) +- لینک cross-navigation بدون صفحه مقصد معنادار نیست + +### Extract shared status helpers (3.5.6) — Skip +- بررسی نشان داد هر context مقادیر متفاوتی دارد: + - UserPayouts: status 1 = Success/پرداخت شده + - WithdrawalRequests: status 1 = Info/واریز شده + - PayoutDetailsDialog: فقط ۳ وضعیت (نه ۶) +- استخراج به helper مشترک باعث از دست رفتن معنای domain-specific می‌شود + +--- + +## 📈 آمار تغییرات + +| معیار | تعداد | +|---|---| +| فایل‌های جدید | 11 | +| فایل‌های حذف‌شده | 1 (SystemOverview.razor) | +| فایل‌های ویرایش‌شده | ~65+ | +| DataGrid‌های آپدیت‌شده | 33 | +| Delete confirmation اصلاح‌شده | 11 | +| صفحات ادغام‌شده | 14 → 5 | +| خطاهای build حل‌شده | 9+ | +| Console.WriteLine حذف‌شده | 22+ (از ۱۱ فایل) | +| cursor:pointer حذف‌شده | 17 فایل | +| Cross-link اضافه‌شده | 3 صفحه (UserOrder, UserPayouts, WithdrawalRequests) | diff --git a/cms/CMS-README.md b/cms/CMS-README.md new file mode 100644 index 0000000..829ad70 --- /dev/null +++ b/cms/CMS-README.md @@ -0,0 +1,445 @@ +# CMS Microservice - Network & Club Commission + Inventory Management System + +[![Status](https://img.shields.io/badge/Status-Active%20Development-success)]() +[![Progress](https://img.shields.io/badge/Inventory%20System-Phase%202%20Complete-blue)]() +[![Phase](https://img.shields.io/badge/Next-Business%20Services-orange)]() + +## 📊 Project Status (January 2026) + +### 🏪 Inventory Management System - NEW! +**Progress**: Phase 2 Complete (50%) +**Architecture**: Clean Architecture + CQRS + Repository Pattern + +#### ✅ Completed Phases +1. ✅ **Phase 1: Infrastructure & Domain Layer** + - Domain Entities: `InventoryItem`, `StockMovement`, `Warehouse` + - Domain Enums: `StockMovementType` + - EF Core Configurations with proper indexing + - Database migration applied + +2. ✅ **Phase 2: Repository Pattern & CQRS** + - Repository Interfaces & Implementations + - CQRS Commands (17 commands) + - CQRS Queries (35 queries) + - MediatR Handlers (52 handlers) + +#### 🔄 In Progress +3. 🔄 **Phase 3: Business Services Layer** +4. ⏳ **Phase 4: DTOs & AutoMapper** +5. ⏳ **Phase 5: API Controllers** + +--- + +### 💼 Commission System - Production Ready +**Progress**: 85% Complete +**MVP Status**: ✅ 100% Complete + +#### ✅ Completed Features +- ✅ Binary network tree with automatic placement +- ✅ Club membership (Member/Trial) with commission rates +- ✅ Weekly commission calculation (Lesser Leg algorithm) +- ✅ Background worker with Hangfire +- ✅ Email + SMS notifications (MailKit + Kavenegar) +- ✅ Health check endpoints (Kubernetes-ready) + +### 🟡 Partially Complete +- Phase 10: Withdrawal & Settlement (40%) + - ✅ Commands & Database + - ❌ Payment Gateway Integration + +### ❌ Not Started +- Phase 9: Club Shop & Product Integration (0%) + +--- + +## 🚀 Recent Updates (January 2026) + +### 🏪 Inventory Management System - NEW! ✅ +**Complete CQRS-based inventory management with:** + +#### Domain Layer: +- ✅ `InventoryItem` - Multi-warehouse product tracking with min/max thresholds +- ✅ `StockMovement` - Complete audit trail with 8 movement types +- ✅ `Warehouse` - Multi-location support with default warehouse + +#### Repository Pattern: +- ✅ `IInventoryItemRepository` - 25+ methods for inventory operations +- ✅ `IStockMovementRepository` - Movement tracking & analytics +- ✅ `IWarehouseRepository` - Warehouse management & statistics + +#### CQRS Commands (17 total): +- **Inventory:** Create, Update, Delete, Reserve, Release, Reduce, Increase +- **Movement:** Create, BulkCreate, Delete +- **Warehouse:** Create, Update, Delete, SetDefault, Activate, BulkCreate + +#### CQRS Queries (35 total): +- **Inventory:** GetById, Search, LowStock, OutOfStock, CheckAvailability +- **Movement:** GetHistory, GetByOrder, Search, Analytics, DailyVolume, TopMoving +- **Warehouse:** GetById, Search, GetStats, GetLowStock, GetAllStats + +#### Business Features: +- ✅ Multi-warehouse inventory management +- ✅ Stock reservation system for orders +- ✅ Automatic movement tracking +- ✅ Low stock & out-of-stock alerts +- ✅ Advanced analytics & reporting +- ✅ Bulk operations support +- ✅ Transaction-safe operations + +--- + +### Email & SMS Notifications - COMPLETED ✅ +- ✅ **MailKit 4.14.1** for Email (SMTP with HTML templates) +- ✅ **Kavenegar 1.2.5** for SMS (Iranian SMS gateway) +- ✅ User.Email field added with migration +- ✅ 3 notification types: Commission, Club activation, Errors +- ✅ Persian RTL templates with rich formatting +- ✅ Production configuration guide created + +### Hangfire Job Scheduling - COMPLETED ✅ +- ✅ Dashboard UI at `/hangfire` +- ✅ Cron schedule: Sunday 00:05 UTC +- ✅ SQL Server persistence +- ✅ Manual trigger API endpoints +- ✅ Distributed execution support + +### Infrastructure Enhancements - COMPLETED ✅ +- ✅ Health Check endpoints (`/health`, `/health/ready`, `/health/live`) +- ✅ AlertService (structured logging for Sentry/Slack) +- ✅ Retry logic (Polly 8.5.0 with exponential backoff) +- ✅ WorkerExecutionLog (database audit trail) +- ✅ CurrentUserService (JWT authentication context) + +--- + +## 🏗️ Architecture + +**Clean Architecture** with 4 layers: +``` +CMSMicroservice.Domain/ # Entities, Enums, Interfaces +├── Entities/ +│ ├── InventoryItem.cs # NEW: Inventory tracking +│ ├── StockMovement.cs # NEW: Movement audit +│ └── Warehouse.cs # NEW: Multi-warehouse +├── Enums/ +│ └── StockMovementType.cs # NEW: Movement types + +CMSMicroservice.Application/ # CQRS (Commands, Queries, MediatR) +├── Features/ +│ ├── InventoryItems/ # NEW: Inventory CQRS +│ │ ├── Commands/ +│ │ ├── Queries/ +│ │ └── Handlers/ +│ ├── StockMovements/ # NEW: Movement CQRS +│ │ ├── Commands/ +│ │ ├── Queries/ +│ │ └── Handlers/ +│ └── Warehouses/ # NEW: Warehouse CQRS +│ ├── Commands/ +│ ├── Queries/ +│ └── Handlers/ +└── Common/Interfaces/ + └── Repositories/ # NEW: Repository interfaces + +CMSMicroservice.Infrastructure/ # DbContext, Services, Background Jobs +├── Persistence/ +│ ├── Context/ +│ ├── Configurations/ # NEW: EF Core configs +│ ├── Repositories/ # NEW: Repository implementations +│ └── Migrations/ +└── DependencyInjection.cs # NEW: DI setup + +CMSMicroservice.WebApi/ # gRPC Services, Controllers +CMSMicroservice.Protobuf/ # Protocol Buffers definitions +``` + +**Technology Stack**: +- .NET 9.0 +- Entity Framework Core 9.0.11 +- gRPC + JSON Transcoding +- Hangfire 1.8.22 (Job Scheduling) +- MediatR 13.0.0 (CQRS) +- Polly 8.5.0 (Resilience) +- MailKit 4.14.1 (Email) +- Kavenegar 1.2.5 (SMS) +- SQL Server + +--- + +## 📖 Documentation + +- **[Development Plan](docs/development-plan.md)** - NEW: Inventory system roadmap +- **[Implementation Progress](docs/implementation-progress.md)** - Detailed phase-by-phase progress +- **[Email/SMS Configuration Guide](docs/email-sms-configuration-guide.md)** - Production setup instructions +- **[Balance Calculation Logic](docs/balance-calculation-carryover-logic.md)** - Commission algorithm details +- **[Binary Tree Registration](docs/binary-tree-registration-guide.md)** - Network tree guide +- **[Network Club Commission System](docs/network-club-commission-system-v1.1.md)** - Full system specification + +--- + +## 🏪 Inventory System Usage + +### Create Warehouse +```csharp +await mediator.Send(new CreateWarehouseCommand +{ + Name = "Main Warehouse", + Code = "WH-001", + IsDefault = true, + IsActive = true +}); +``` + +### Create Inventory Item +```csharp +await mediator.Send(new CreateInventoryItemCommand +{ + ProductId = 1, + WarehouseId = 1, + Quantity = 100, + MinQuantity = 10, + MaxQuantity = 1000 +}); +``` + +### Reserve Stock for Order +```csharp +await mediator.Send(new ReserveInventoryCommand +{ + Id = inventoryId, + Quantity = 5, + OrderId = 12345 +}); +``` + +### Check Availability +```csharp +bool available = await mediator.Send( + new CheckInventoryAvailabilityQuery(inventoryId, 10)); +``` + +### Get Low Stock Alerts +```csharp +var lowStock = await mediator.Send(new GetLowStockItemsQuery +{ + WarehouseId = 1, + Count = 50 +}); +``` + +### Get Movement Analytics +```csharp +var summary = await mediator.Send(new GetMovementSummaryQuery +{ + FromDate = DateTime.Now.AddDays(-7), + ToDate = DateTime.Now +}); + +var topProducts = await mediator.Send(new GetTopMovingProductsQuery +{ + FromDate = DateTime.Now.AddDays(-30), + ToDate = DateTime.Now, + Count = 10 +}); +``` + +--- + +## 🚀 Quick Start + +### Prerequisites +- .NET 9.0 SDK +- SQL Server (local or remote) +- (Optional) Gmail account for Email +- (Optional) Kavenegar account for SMS + +### 1. Clone & Build +```bash +cd /home/masoud/Apps/project/FourSat/CMS/src +dotnet build +``` + +### 2. Configure Database +Update `appsettings.json` with your SQL Server connection: +```json +"ConnectionStrings": { + "DefaultConnection": "Server=YOUR_SERVER;Database=Foursat_CMS;..." +} +``` + +### 3. Apply Migrations +```bash +cd CMSMicroservice.WebApi +dotnet ef database update +``` + +### 4. Configure Notifications (Optional) +See [Email/SMS Configuration Guide](docs/email-sms-configuration-guide.md) + +### 5. Run +```bash +dotnet run --urls="http://localhost:5133" +``` + +### 6. Access Endpoints +- **Health**: http://localhost:5133/health +- **Hangfire Dashboard**: http://localhost:5133/hangfire +- **gRPC**: localhost:5133 (HTTP/2) + +--- + +## 🔧 Configuration + +### Email (SMTP) +```json +"Email": { + "Enabled": true, + "SmtpHost": "smtp.gmail.com", + "SmtpPort": 587, + "SmtpUsername": "your-email@gmail.com", + "SmtpPassword": "your-gmail-app-password", + "FromEmail": "noreply@foursat.com", + "FromName": "FourSat CMS", + "EnableSsl": true +} +``` + +### SMS (Kavenegar) +```json +"Sms": { + "Enabled": true, + "Provider": "Kavenegar", + "KavenegarApiKey": "YOUR_API_KEY", + "Sender": "10008663" +} +``` + +### Background Worker +```csharp +// Cron: "5 0 * * 0" = Every Sunday at 00:05 UTC +RecurringJob.AddOrUpdate( + "weekly-commission-calculation", + job => job.ExecuteAsync(CancellationToken.None), + "5 0 * * 0"); +``` + +--- + +## 🧪 Testing + +### Manual Trigger (via API) +```bash +# Trigger weekly calculation immediately +curl -X POST http://localhost:5133/api/admin/trigger-weekly-calculation + +# Trigger recurring job now +curl -X POST http://localhost:5133/api/admin/trigger-recurring-job-now + +# Get recurring jobs status +curl http://localhost:5133/api/admin/recurring-jobs-status +``` + +### Health Checks +```bash +curl http://localhost:5133/health # Overall health +curl http://localhost:5133/health/ready # Readiness probe (K8s) +curl http://localhost:5133/health/live # Liveness probe (K8s) +``` + +--- + +## 📊 What's Remaining? + +### 🏪 Inventory System (Current Focus) +1. **Phase 3: Business Services** (In Progress) + - `IInventoryManagementService` - High-level operations + - `IStockMovementService` - Movement orchestration + - `IWarehouseService` - Warehouse business logic + - `IInventoryReportingService` - Advanced reporting + +2. **Phase 4: DTOs & AutoMapper** (Next) + - Request/Response DTOs + - AutoMapper profiles + - Validation rules + +3. **Phase 5: API Controllers** (Planned) + - `InventoryController` - REST API + - `WarehouseController` - Warehouse management + - `StockMovementController` - Movement tracking + - Swagger documentation + +### 💼 Commission System +1. **Payment Gateway Integration** (Phase 10 - 1 week) + - Daya or Bank Mellat API integration + - IBAN transfer automation + - Admin approval UI in BackOffice + +2. **Production Configuration** (30 minutes) + - Gmail App Password setup + - Kavenegar API key registration + - Update `appsettings.Production.json` + +### Medium Priority +3. **Club Shop Integration** (Phase 9 - 2 weeks) + - Product catalog for club memberships + - Shopping cart integration + - Auto-activation on purchase + +### Low Priority +4. **Testing** (Phase 7 - Postponed) + - Unit tests for business logic + - Integration tests for API + - Load testing for background worker + +### Optional Enhancements +- Redis distributed locks (multi-server deployment) +- Sentry error tracking (API key needed) +- Slack notifications (webhook needed) +- FCM push notifications + +--- + +## 🎯 MVP Features (100% Complete) + +### 💼 Commission System: +✅ Binary network tree with automatic placement +✅ Club membership (Member/Trial) with different commission rates +✅ Weekly commission calculation (Lesser Leg algorithm) +✅ Background worker with Hangfire (cron scheduling) +✅ Balance carryover logic (rollover unused volumes) +✅ MaxWeeklyBalances cap enforcement +✅ Health check endpoints (Kubernetes-ready) +✅ Manual trigger API (admin control) +✅ Email + SMS notifications (MailKit + Kavenegar) +✅ Retry logic with exponential backoff (Polly) +✅ Audit trail (WorkerExecutionLog, History tables) +✅ Structured logging (AlertService for Sentry/Slack) +✅ JWT authentication context (CurrentUserService) + +### 🏪 Inventory System (Phase 2 Complete): +✅ Domain entities (InventoryItem, StockMovement, Warehouse) +✅ Multi-warehouse inventory management +✅ Stock reservation system for orders +✅ 8 movement types with complete audit trail +✅ Repository pattern with 25+ methods per repository +✅ CQRS with 17 commands and 35 queries +✅ 52 MediatR handlers with business logic +✅ Low stock and out-of-stock alerts +✅ Advanced analytics (top products, daily volume) +✅ Bulk operations support +✅ Transaction-safe operations with rollback +✅ DI container configuration + +--- + +## 👥 Team + +**Development**: FourSat Team +**Last Updated**: January 2026 + +--- + +## 📝 License + +Proprietary - FourSat Company +# Multi-remote push enabled diff --git a/deployment/DEPLOYMENT-README.md b/deployment/DEPLOYMENT-README.md new file mode 100644 index 0000000..10b3c13 --- /dev/null +++ b/deployment/DEPLOYMENT-README.md @@ -0,0 +1,161 @@ +# 🚀 FourSat Offline Deployment + +این دایرکتوری شامل scripts و مستندات برای deploy کردن سرویس‌های FourSat **بدون نیاز به اینترنت** است. + +## ⚡ Quick Start + +### گزینه 1: Setup خودکار (پیشنهادی) + +**روی ماشینی با Docker و اینترنت:** + +```bash +cd /home/masoud/Apps/project/FourSat/deployment +./setup-offline-complete.sh +``` + +این اسکریپت: +- ✅ Images را pull می‌کند +- ✅ Export می‌کند به `.tar` +- ✅ به server transfer می‌کند +- ✅ در containerd server import می‌کند +- ✅ تمام! + +### گزینه 2: Setup دستی + +اگر Docker روی این ماشین نیست، مستندات کامل را بخوانید: + +```bash +cat OFFLINE-SETUP-GUIDE.md +``` + +--- + +## 📁 فایل‌های مهم + +### 🎯 اسکریپت‌های اصلی +- **`setup-offline-complete.sh`** ⭐ - Setup کامل خودکار (نیاز به Docker) +- **`export-import-images.sh`** - Export/Import دستی images +- **`OFFLINE-SETUP-GUIDE.md`** 📚 - راهنمای کامل قدم به قدم + +### 📖 مستندات +- **`README.md`** - این فایل +- **`QUICK-REFERENCE.md`** - مرجع سریع commands +- **`DEPLOYMENT-GUIDE.md`** - راهنمای deployment +- **`SERVER-SETUP-GUIDE.md`** - تنظیمات server +- **`CHANGES-SUMMARY.md`** - لیست تغییرات انجام شده +- **`SETUP-INSTRUCTIONS.md`** - دستورالعمل‌های setup + +### 🛠️ اسکریپت‌های کمکی +- `pull-base-images.sh` - Pull کردن base images +- `save-images.sh` - ذخیره images به tar +- `load-images.sh` - بارگذاری images از tar +- `cache-nuget-packages.sh` - Cache کردن NuGet packages +- `build-all-offline.sh` - Build تمام سرویس‌ها offline +- `cleanup.sh` - پاکسازی فایل‌های build +- `test-services.sh` - تست سرویس‌های deploy شده +- `k8s-deploy.sh` - Deploy به Kubernetes +- `k8s-health-check.sh` - بررسی سلامت deployments +- `quick-start.sh` - Setup تعاملی +- `server-cache-images.sh` - Cache images روی server +- `load-cached-images.sh` - بارگذاری cached images +- `verify-cache.sh` - بررسی cache +- `pull-images-to-node.sh` - Pull به Kubernetes node + +--- + +## 🔍 چک‌لیست Setup + +- [ ] **Base images در containerd server** (روی node نه pod) +- [ ] **Workflows بدون proxy** تنظیم شده‌اند +- [ ] **DNS = "0.0.0.0"** برای جلوگیری از دسترسی به اینترنت +- [ ] **DOCKER_BUILDKIT=0** برای استفاده از legacy builder +- [ ] **Test یک workflow** برای اطمینان از کار کردن offline + +--- + +## 🏗️ معماری Deployment + +``` +┌─────────────────────────────────────────┐ +│ Kubernetes Cluster (194.5.195.53) │ +│ │ +│ ┌───────────────────────────────────┐ │ +│ │ Node (containerd) │ │ +│ │ ├─ mcr.microsoft.com/dotnet/* │ │ +│ │ └─ nginx:alpine │ │ +│ └───────────────────────────────────┘ │ +│ ▲ │ +│ │ images available to pods │ +│ │ │ +│ ┌──────┴──────────────────────────┐ │ +│ │ gitea-runner pod │ │ +│ │ ├─ dind (Docker-in-Docker) │ │ +│ │ └─ runner (Gitea Actions) │ │ +│ └─────────────────────────────────┘ │ +└─────────────────────────────────────────┘ +``` + +**کلید موفقیت**: Images باید در **containerd روی node** باشند، نه در pod! + +--- + +## 🐛 عیب‌یابی + +### ❌ Workflow هنوز download می‌کند؟ + +```bash +# بررسی images روی server +ssh root@194.5.195.53 "ctr -n k8s.io images list | grep mcr.microsoft.com" +``` + +اگر خالی است، setup را دوباره اجرا کنید. + +### ❌ Build با error می‌خورد؟ + +```bash +# بررسی logs workflow در Gitea +# اگر "TLS handshake timeout" می‌بینید → DNS هنوز active است +# اگر "image not found" می‌بینید → images در containerd نیستند +``` + +### ❌ Import به containerd کار نمی‌کند? + +```bash +# مطمئن شوید namespace درست است +ssh root@194.5.195.53 "ctr namespaces list" + +# باید k8s.io را ببینید +# برای import همیشه از -n k8s.io استفاده کنید: +ctr -n k8s.io images import /path/to/image.tar +``` + +--- + +## 📞 Support + +مشکل دارید? مستندات کامل را بخوانید: + +```bash +# راهنمای کامل setup offline +cat OFFLINE-SETUP-GUIDE.md + +# مرجع سریع commands +cat QUICK-REFERENCE.md + +# راهنمای deployment +cat DEPLOYMENT-GUIDE.md +``` + +--- + +## ✨ ویژگی‌ها + +- ✅ **کاملاً Offline** - هیچ download در حین build +- ✅ **خودکار** - یک اسکریپت برای setup کامل +- ✅ **مستند شده** - راهنماهای جامع فارسی +- ✅ **تست شده** - روی Kubernetes با k3s +- ✅ **سریع** - build بدون تاخیر network + +--- + +**نوشته شده برای پروژه FourSat** 🛰️ diff --git a/frontoffice/CHANGELOG.md b/frontoffice/CHANGELOG.md new file mode 100644 index 0000000..9a93d3c --- /dev/null +++ b/frontoffice/CHANGELOG.md @@ -0,0 +1,311 @@ +# 📋 تاریخچه تغییرات FrontOffice — کارا بازار سلامت + +> **آخرین بروزرسانی**: اسفند ۱۴۰۴ (فوریه ۲۰۲۶) +> **فریمورک**: Blazor Server + MudBlazor 8.14 + .NET 9 + +--- + +## 🔖 نسخه ۲.۷.۰ — اسفند ۱۴۰۴ (February 17, 2026) + +### ۱. اجبار تخفیف ۱۰۰٪ و حذف اسلایدر + +- **حذف** `MudSlider` و `MudNumericField` از `Checkout.razor` — کاربر دیگه درصد تخفیف انتخاب نمی‌کنه +- **حذف** کامل بخش نمایش موجودی اعتباری +- بکند همیشه حداکثر تخفیف (`MaxDiscountPercent`) رو اعمال می‌کنه + +### ۲. رفع متن Badge تخفیف + +- **مشکل:** Badge روی محصولات "۱۰۰٪ اعتباری" نشون می‌داد — گمراه‌کننده +- **رفع:** نمایش درصد واقعی محصول (مثلاً "۳۰٪ تخفیف") +- **فایل‌ها:** `Products.razor`, `Cart.razor`, `ProductDetail.razor` + +### ۳. نمایش جدول مالیات (VAT) در Checkout + +- جمع کل، تخفیف، مبلغ پس از تخفیف، مالیات ۹٪، مبلغ قابل پرداخت +- استفاده از `VatCalculator` برای محاسبه VAT + +### ۴. نمایش وضعیت پرداخت در سفارشات + +- **فیلد جدید** `payment_status` در proto `discountorder.proto` (v0.0.179) +- **صفحه Orders:** نمایش Chip رنگی بر اساس PaymentStatus (موفق/ناموفق/در انتظار) +- **صفحه OrderDetail:** Alert برای سفارشات ناموفق + دکمه بازگشت + جزئیات وضعیت +- **Helper متدها:** `GetPaymentStatusText()`, `GetPaymentStatusColor()`, `GetDeliveryStatusText()` + +### ۵. فیکس مپینگ PaymentStatus و DeliveryStatus + +- **مشکل:** Domain enum مقادیر متفاوتی از Proto داشت — مستقیم cast می‌شد +- **رفع:** `MapPaymentStatus()` و `MapDeliveryStatus()` در `DiscountOrderService.cs` (WebApi) +- سفارشات ناموفق حالا `DeliveryStatus=Cancelled` دارن (بجای "در حال پردازش") + +### ۶. فیکس Proto به NuGet v0.0.179 + +- `FrontOffice.Main.csproj`: `PackageReference` به `Foursat.CMSMicroservice.Protobuf` v0.0.179 + +--- + +## 🔖 نسخه ۲.۶.۰ — بهمن ۱۴۰۴ (February 16, 2026) + +### ۱. درگاه پرداخت زرین‌پال + +- **یکپارچه‌سازی ZarinPal** — پرداخت مستقیم بدون PYMS واسط +- صفحه checkout فروشگاه اعتباری: ریدایرکت به ZarinPal → callback → تأیید +- صفحه checkout فروشگاه عادی: همان جریان +- پشتیبانی از sandbox و production + +### ۲. جدول PaymentTransaction + +- **Entity جدید** `PaymentTransaction` — ذخیره جزئیات سطح درگاه (Authority, CardPan, CardHash, RefId) +- جدا از جدول Transaction اصلی +- Migration: `AddPaymentTransactionTable` + +### ۳. فیکس نمایش وضعیت پرداخت + +- **مشکل:** سفارشات اعتباری «در انتظار پرداخت» نشان می‌دادند حتی بعد از پرداخت موفق +- **علت:** Mapster نمی‌تونست `PaymentStatus` (enum) رو به `payment_completed` (bool) مپ کنه +- **رفع:** مپینگ دستی در `DiscountOrderService` + +### ۴. فیکس DeliveryStatus + +- **مشکل:** فروشگاه اعتباری بعد از پرداخت `InTransit` ست می‌کرد +- **رفع:** تغییر به `Pending` — ادمین باید وضعیت پست رو مشخص کنه + +### ۵. تغییر به NuGet Package (Docker build fix) + +- `ProjectReference` به CMS Protobuf → `PackageReference` (v0.0.178) +- Docker build context فقط `src/` داره → مسیر `../../../CMS` قابل دسترسی نیست + +--- + +## 🔖 نسخه ۲.۵.۰ — بهمن ۱۴۰۴ + +### ۱. محافظت صفحات نیازمند احراز هویت (Auth Guard) + +**فایل‌های تغییریافته:** +- `Shared/MainLayout.razor.cs` + +**شرح:** +قبلاً هیچ محافظتی در سطح مسیریابی وجود نداشت — کاربر غیرلاگین می‌توانست مستقیماً به `/profile/*`، `/commission/*`، `/cart` و... دسترسی پیدا کند. + +**تغییرات:** +- متد `EnforceAuthGuardAsync()` اضافه شد — در هر تغییر مسیر و اولین بار رندر اجرا می‌شود +- متد `IsProtectedRoute(path)` مسیرهای محافظت‌شده را تشخیص می‌دهد +- کاربر غیرلاگین → ریدایرکت به `/` (صفحه اصلی) + +**مسیرهای محافظت‌شده:** +| گروه | مسیرها | +|---|---| +| پروفایل | `/profile/*` | +| کمیسیون | `/commission/*` | +| شبکه | `/network/*` | +| باشگاه | `/club/*` | +| سبد خرید | `/cart`, `/checkout*`, `/orders`, `/order/*`, `/order-tracking/*` | +| پکیج‌ها | `/my-packages` | +| دروازه | `/my-orders`, `/my-cart` | +| فروشگاه اعتباری | `/discount-store/cart`, `/discount-store/checkout`, `/discount-store/orders`, `/discount-store/order/*` | + +**مسیرهای عمومی:** +`/`, `/register`, `/about`, `/faq`, `/contact`, `/blog/*`, `/packages`, `/package/*`, `/products`, `/product/*`, `/categories`, `/stores`, `/discount-store`, `/discount-store/product/*` + +--- + +### ۲. استخراج کامپوننت PhoneVerifyForm + +**فایل‌های جدید:** +- `Shared/PhoneVerifyForm.razor` +- `Shared/PhoneVerifyForm.razor.cs` + +**فایل‌های تغییریافته:** +- `Shared/AuthDialog.razor` +- `Shared/AuthDialog.razor.cs` + +**شرح:** +فرم تلفن + تایید OTP + کپچا که قبلاً به‌صورت `RenderFragment` با `__builder` مستقیم در `AuthDialog` نوشته شده بود، به کامپوننت مستقل `PhoneVerifyForm` استخراج شد. + +**ساختار قبل:** +``` +AuthDialog.razor + └── @code { PhoneOrVerifyContent() => __builder => { ... } } ← RenderFragment پیچیده +``` + +**ساختار بعد:** +``` +AuthDialog.razor + └── ← کامپوننت مستقل +PhoneVerifyForm.razor ← مارکاپ فرم +PhoneVerifyForm.razor.cs ← پارامترها و فرم رف‌ها +``` + +**پارامترهای PhoneVerifyForm:** + +| پارامتر | نوع | توضیح | +|---|---|---| +| `CurrentStep` | `AuthStep` | مرحله فعلی (Phone / Verify) | +| `PhoneRequest` | `CreateNewOtpTokenRequest` | مدل فرم تلفن | +| `VerifyRequest` | `VerifyOtpTokenRequest` | مدل فرم تایید | +| `CaptchaCode` | `string?` | کد کپچا نمایش‌داده‌شده | +| `CaptchaInput` / `CaptchaInputChanged` | `string?` + `EventCallback` | ورودی کپچا (two-way) | +| `OnRefreshCaptcha` | `EventCallback` | رفرش کپچا | +| `IsBusy` | `bool` | وضعیت بارگذاری | +| `ErrorMessage` / `InfoMessage` | `string?` | پیام‌های خطا/اطلاع | +| `PhoneNumber` | `string?` | شماره تایید‌شده | +| `ResendRemaining` | `int` | ثانیه تا ارسال مجدد | +| `OnChangePhone` / `OnResendOtp` | `EventCallback` | اکشن‌های تایید | + +**نکته مهم — Two-way binding کپچا:** +فیلد کپچا با `Value` + `ValueChanged` بایند شده (نه `@bind-Value`) تا مقدار تایپ‌شده از فرزند به والد برگردد: +```razor + +``` + +**دسترسی به فرم‌ها از والد:** +```csharp +// AuthDialog.razor.cs +var phoneForm = _phoneVerifyForm?.GetPhoneForm(); +var verifyForm = _phoneVerifyForm?.GetVerifyForm(); +``` + +--- + +### ۳. بهبود لایوت مدال ورود (AuthDialog) + +**فایل‌های تغییریافته:** +- `Shared/AuthDialog.razor` +- `Utilities/AuthDialogService.cs` +- `wwwroot/css/site.css` + +**مشکلات قبلی:** +- دیالوگ روی موبایل `FullScreen` بود → فضای خالی بزرگ بین فرم و دکمه‌ها +- `TitleContent` و `DialogActions` جدا → گپ عمودی +- ردیف کپچا با `MudStack Row="true"` → آیتم‌ها عمودی رندر می‌شدند + +**تغییرات:** +1. **حذف FullScreen**: `AuthDialogService` حالا همیشه `MaxWidth.ExtraSmall, FullWidth=true, CloseButton=true` +2. **ادغام محتوا**: آواتار + عنوان + فرم + دکمه‌ها همه داخل `DialogContent` → بدون `TitleContent` و `DialogActions` +3. **کلاس `auth-dialog-wrapper`**: CSS با `.auth-dialog-wrapper .mud-dialog-title { display: none; }` عنوان پیش‌فرض دیالوگ رو مخفی می‌کنه +4. **ردیف کپچا**: از `MudStack Row` به `div.captcha-row` با CSS flex اختصاصی +5. **حالت Inline**: بدون تغییر ساختاری — فقط از `PhoneVerifyForm` استفاده می‌کنه + +**CSS جدید:** +```css +.auth-dialog-wrapper .mud-dialog-title { display: none; } +.auth-dialog-wrapper .mud-dialog-content { padding-bottom: 24px !important; } +.auth-dialog-content { max-width: 400px; margin: 0 auto; } + +.captcha-row { display: flex; align-items: center; gap: 10px; } +.captcha-row > .mud-input-control { flex: 1 1 0; min-width: 0; } +.captcha-row > .mud-paper { flex: 0 0 auto; } +.captcha-row > .mud-button-root { flex: 0 0 auto; } +``` + +--- + +### ۴. صفحه لندینگ — حذف /pricing و اضافه بنر بلاگ + +**فایل‌های تغییریافته:** +- `Pages/Index.razor` +- `wwwroot/css/site.css` + +**تغییرات:** +1. دکمه هیرو «مشاهده پکیج‌ها» → **«آخرین اخبار»** با لینک `/blog` +2. **بنر جدیدترین مطلب** بین هیرو و «سه گام تا شروع» اضافه شد + - تصویر بندانگشتی + عنوان + خلاصه + آیکون شیشه‌ای + - هاور: `translateY(-2px)` + سایه بزرگ‌تر + +**CSS جدید:** +```css +.landing-blog-banner { border: 1px solid var(--mud-palette-divider); transition: ... } +.landing-blog-banner:hover { box-shadow: var(--mud-elevation-4); transform: translateY(-2px); } +.landing-blog-thumb { width: 80px; height: 80px; border-radius: 12px; } +.landing-blog-title { -webkit-line-clamp: 1; font-weight: 600; } +.landing-blog-summary { -webkit-line-clamp: 1; } +``` + +--- + +### ۵. افزایش ارتفاع تکست‌باکس‌ها (Global) + +**فایل تغییریافته:** +- `wwwroot/css/site.css` + +**قبل:** `padding: 10px 14px` +**بعد:** `padding: 14px 14px` + `font-size: 1rem` + +```css +.mud-input-outlined .mud-input-slot { + padding: 14px 14px !important; + font-size: 1rem; +} +``` + +تمام فیلدهای Outlined در کل اپلیکیشن بزرگ‌تر شدند. + +--- + +### ۶. اصلاح RTL فیلدهای ورودی + +**فایل تغییریافته:** +- `wwwroot/css/site.css` + +**مشکل:** فیلدهای `type="tel"` به‌صورت پیش‌فرض مرورگر `direction: ltr` می‌گیرن — لیبل سمت راست ولی placeholder/cursor سمت چپ. + +**اصلاح:** +```css +.mud-input-slot input, +.mud-input-slot textarea { + direction: rtl !important; + text-align: right !important; +} +``` + +--- + +### ۷. اصلاح captcha-box CSS + +**فایل تغییریافته:** +- `wwwroot/css/site.css` + +**قبل:** +```css +.captcha-box { + min-width: 120px; min-height: 56px; + background: linear-gradient(135deg, rgba(123,97,255,.12), rgba(255,140,189,.12)); +} +``` + +**بعد:** +```css +.captcha-box { + min-width: 96px; min-height: 48px; + border-radius: var(--mud-default-borderradius); + background: rgba(99,102,241,.08); + border: 1px solid var(--mud-palette-divider); +} +``` + +--- + +## 📁 نقشه فایل‌ها + +``` +Shared/ +├── AuthDialog.razor ← بازنویسی (کامپوننت PhoneVerifyForm جایگزین RenderFragment) +├── AuthDialog.razor.cs ← بروزرسانی (استفاده از _phoneVerifyForm) +├── PhoneVerifyForm.razor ← ✨ جدید (فرم تلفن + تایید + کپچا) +├── PhoneVerifyForm.razor.cs ← ✨ جدید (پارامترها و فرم رف‌ها) +├── MainLayout.razor.cs ← Auth Guard اضافه شد +Pages/ +├── Index.razor ← /pricing → /blog + بنر بلاگ +Utilities/ +├── AuthDialogService.cs ← حذف FullScreen، ثابت‌سازی سایز +wwwroot/css/ +├── site.css ← captcha-row, auth-dialog, RTL fix, input height +``` + +--- + +## 🔍 وضعیت بیلد + +| تاریخ | خطا | هشدار | توضیح | +|---|---|---|---| +| بهمن ۱۴۰۴ | **۰** | ۱۰۵ | MUD0002 warnings (بی‌خطر — مربوط به MudBlazor analyzer) | diff --git a/frontoffice/UI-UNIFICATION-PLAN.md b/frontoffice/UI-UNIFICATION-PLAN.md new file mode 100644 index 0000000..e43f290 --- /dev/null +++ b/frontoffice/UI-UNIFICATION-PLAN.md @@ -0,0 +1,542 @@ +# 🎨 پلن جامع یکپارچه‌سازی UI/UX — کارا بازار سلامت + +> **تاریخ**: بهمن ۱۴۰۴ +> **وضعیت**: ✅ **تمام ۶ فاز + فاز ۷ (ناوبری و امنیت) تکمیل شد** +> **هدف**: یکپارچه‌سازی طراحی FrontOffice با ۲۰٪ تغییر UX و ۵۰٪ تغییر UI +> **فریمورک**: Blazor Server + MudBlazor 8.14 +> **📋 تاریخچه تغییرات جزئی**: [CHANGELOG.md](CHANGELOG.md) + +--- + +## 📊 خلاصه اجرایی + +| شاخص | وضعیت قبل | وضعیت بعد | +|---|---|---| +| **صفحات کل** | ۴۱ صفحه + ۶ کامپوننت مشترک | ۴۱ صفحه + ۸ کامپوننت مشترک | +| **الگوی PageHeader** | ۱۹ صفحه از ۴۱ | ۳۲+ صفحه ✅ | +| **Inline Style سنگین** | ۱۱ صفحه 🔴 | ≤۲ صفحه (فقط gradient‌های تزئینی) ✅ | +| **Loading State** | ۲ الگوی متفاوت (Circular vs Linear) | `` واحد ✅ | +| **Empty State** | ۴+ الگوی متناقض | `` واحد ✅ | +| **Container Spacing** | ۶ الگوی متناقض | `py-6` استاندارد ✅ | +| **رنگ‌بندی** | رنگ‌های hardcoded در ۸+ صفحه | CSS Variable ✅ | +| **تم پالت** | Primary `#0380C0` (آبی ساده) | Indigo `#6366f1` + Full PaletteDark ✅ | +| **Elevation** | مخلوط ۲/۳/۴ | استاندارد ۰–۲ ✅ | +| **Build** | ۰ خطا | ۰ خطا ✅ | + +### فازها +| فاز | عنوان | وضعیت | +|---|---|---| +| ۱ | زیرساخت دیزاین سیستم | ✅ تکمیل | +| ۲ | صفحات پروفایل | ✅ تکمیل | +| ۳ | صفحات تخصصی | ✅ تکمیل | +| ۴ | بهبود بصری فروشگاه | ✅ تکمیل | +| ۵ | صفحات عمومی | ✅ تکمیل | +| ۶ | پالیش و تست | ✅ تکمیل | +| ۷ | ناوبری، امنیت و بازسازی کامپوننت‌ها | ✅ تکمیل | + +--- + +## 🔍 بخش ۱: تحلیل ضعف‌های جاری + +### ۱.۱ ناسازگاری‌های ساختاری (Structural) + +#### ❌ ۱.۱.۱ — PageHeader دوگانه +**مشکل**: نیمی از صفحات از `` استفاده می‌کنند، نیم دیگر header دستی دارند. + +| از `` استفاده می‌کنند ✅ | Header دستی دارند ❌ | +|---|---| +| Store/* (۸ صفحه) | Profile/* (۷ صفحه) | +| DiscountStore/* (۶ صفحه) | Club/* (۲ صفحه) | +| Gateway/* (۳ صفحه) | Commission/* (۲ صفحه) | +| Package/* (۲ صفحه) | Network/* (۱ صفحه) | +| PackageDetail, Checkout | Blog/*, Index, About, Contact, FAQ | + +**تأثیر**: ظاهر متفاوت دکمه بازگشت، فاصله‌بندی ناهماهنگ + +#### ❌ ۱.۱.۲ — Container MaxWidth متناقض +``` +MaxWidth.Large → اکثر صفحات +MaxWidth.Medium → Personal, Settings, OrderTracking, Blog/Post, Gateway/* +MaxWidth.Small → ChangePassword +ترکیبی (loading≠content) → OrderDetail, ProductDetail, PackageDetail +``` + +**تأثیر**: برخی صفحات پهن‌تر از حد نیاز هستند (مثلاً فرم‌های ساده با Large) + +#### ❌ ۱.۱.۳ — Container Padding متناقض +``` +py-6 → اکثریت (استاندارد) +py-8 → Package/Packages, Package/MyPackages +pa-2 pa-md-6 → Store/Products, DiscountStore/Products +py-6 py-md-10 → Gateway/* +py-4 py-md-6 → DiscountStore/ProductDetail +py-16 سکشنی → Index, About, Contact, FAQ +``` + +**قاعده پیشنهادی**: `py-6` برای صفحات داخلی، section-based برای صفحات عمومی + +--- + +### ۱.۲ ناسازگاری‌های بصری (Visual) + +#### ❌ ۱.۲.۱ — Inline Style سنگین (۱۱ صفحه) + +| صفحه | نمونه مشکل‌دار | +|---|---| +| **Index.razor** | `Style="color:#fff; font-size:clamp(1.6rem,4.5vw,2.4rem);"` | +| **Profile/Index** | `Style="background:rgba(99,102,241,.12);"` | +| **Store/ProductDetail** | `style="width:100%;height:360px;background-image:url(...);"` | +| **PackageDetail** | `Style="background: radial-gradient(600px 280px..."` | +| **Checkout** | `Style="background: radial-gradient(..."` + `Elevation="4"` | +| **Blog/Index** | `Style="color:#fff; font-weight:700;"`, `Style="font-size:3.5rem;"` | +| **Blog/Post** | `Style="width:100%; height:100%;"`, `Style="font-size:4rem;"` | +| **About** | `Style="background: radial-gradient(...);"` | +| **WeeklyBalance** | `Style="background: linear-gradient(135deg, #e8f5e9..."` | +| **Gateway/**** | `Style="background:rgba(16,185,129,.12)..."`, `Style="color:#10b981;"` | +| **DiscountStore/ProductDetail** | `Style="background:rgba(16,185,129,.06)..."` | + +#### ❌ ۱.۲.۲ — رنگ‌های Hardcoded + +| رنگ | استفاده | باید باشد | +|---|---|---| +| `#10b981` | Gateway (سبز فروشگاه) | `var(--ds-color-store)` | +| `#ef4444` | Gateway (قرمز اعتباری) | `var(--ds-color-discount)` | +| `#6366f1`, `#818cf8`, `#a78bfa` | Hero/Banner gradients | `var(--ds-gradient-primary)` | +| `rgba(99,102,241,.12)` | Dashboard backgrounds | `var(--ds-primary-soft)` | +| `rgba(16,185,129,.06)` | Discount product highlights | `var(--ds-success-soft)` | +| `#e8f5e9`, `#c8e6c9` | WeeklyBalance stat cards | `var(--ds-success-gradient)` | + +#### ❌ ۱.۲.۳ — Elevation ناهماهنگ +``` +Elevation="0" → Blog cards (با border) +Elevation="1" → برخی صفحات +Elevation="2" → اکثر صفحات (استاندارد) +Elevation="3" → WeeklyBalance stat cards +Elevation="4" → Checkout.razor +``` + +**قاعده پیشنهادی**: `Elevation="0"` با `border` = کارت‌های اطلاعاتی، `Elevation="2"` = default + +#### ❌ ۱.۲.۴ — Paper Rounding ناهماهنگ +``` +rounded-lg (16px) → اکثریت +rounded-xl (20px) → Index, Profile/Index, Gateway, DiscountStore/ProductDetail +بدون class → design system !important → 12px +``` + +--- + +### ۱.۳ ناسازگاری‌های UX (تجربه کاربری) + +#### ❌ ۱.۳.۱ — Loading State دوگانه +``` +MudProgressCircular → Store/*, DiscountStore/*, Package/*, About, Blog, Addresses +MudProgressLinear → Club/*, Commission/*, Network/*, RegisterWizard +``` + +**مشکل**: کاربر دو تجربه مختلف «در حال بارگذاری» می‌بیند + +#### ❌ ۱.۳.۲ — Empty State ناهماهنگ +``` +MudAlert Severity.Info → Store/Orders, Categories, DiscountStore/Orders +Icon + Text + Button → Addresses, Package/MyPackages, PackageDetail +MudAlert Severity.Warning → WithdrawalRequests +Custom dashed-border paper → Blog/Index +``` + +#### ❌ ۱.۳.۳ — Routing Directive ناهماهنگ +``` +@attribute [Route(RouteConstants...)] → ۳۹ صفحه ✅ +@page "/categories" → Categories.razor ❌ +@page "/blog/{Slug}" → Blog/Post.razor ❌ +``` + +#### ❌ ۱.۳.۴ — PackageDetail Loading/Error بدون Container +Loading و Error state در `PackageDetail.razor` بدون `MudContainer` رندر می‌شوند → محتوا تمام‌عرض نمایش می‌یابد. + +#### ❌ ۱.۳.۵ — تم فعلی کم‌رنگ +```csharp +// CustomMudTheme.cs فعلی +Primary = "#0380C0" // آبی ساده +// بدون Secondary، Tertiary، Info، Warning تعریف‌شده +// بدون PaletteDark +// بدون LayoutProperties +``` + +**مشکلات**: +- فقط Primary تعریف شده، بقیه رنگ‌ها default MudBlazor +- Dark mode بدون palette اختصاصی +- بدون `DefaultBorderRadius`، `AppbarHeight` و غیره +- تناقض بین Primary `#0380C0` و gradient‌های CSS با `#6366f1` + +--- + +## 🎯 بخش ۲: معماری دیزاین سیستم هدف + +### ۲.۱ سلسله‌مراتب صفحات + +``` +┌─────────────────────────────────────────────┐ +│ MainLayout │ +│ ├─ AppBar (fixed, transparent) │ +│ ├─ MudMainContent │ +│ │ ├─ [Public Pages] → Section-based │ +│ │ │ (Index, About, Contact, FAQ, Blog) │ +│ │ └─ [Internal Pages] → Container-based │ +│ │ ├─ │ +│ │ ├─ Content (MudStack/MudGrid) │ +│ │ └─ │ +│ ├─ Footer (hidden on mobile) │ +│ └─ BottomNav (mobile only) │ +└─────────────────────────────────────────────┘ +``` + +### ۲.۲ قواعد واحد (Single Source of Truth) + +| قاعده | مقدار | +|---|---| +| **Container MaxWidth** | `Large` = لیست/گرید, `Medium` = فرم/جزئیات, `Small` = تک‌فرم ساده | +| **Container Spacing** | `py-6` صفحات داخلی, section-based صفحات عمومی | +| **Paper Elevation** | `0` با border = کارت اطلاعاتی, `2` = default | +| **Paper Rounding** | `rounded-lg` = default, `rounded-xl` = hero/banner | +| **Loading State** | `` component واحد | +| **Empty State** | `` component واحد | +| **Page Header** | `` در تمام صفحات داخلی | +| **Content Wrapper** | `MudStack Spacing="3"` بعد از PageHeader | + +### ۲.۳ CSS Variables هدف + +```css +:root { + /* ── Brand Colors ── */ + --ds-brand-primary: #6366f1; /* Indigo — هویت اصلی */ + --ds-brand-secondary: #8b5cf6; /* Purple */ + --ds-brand-accent: #a78bfa; /* Light purple */ + + /* ── Semantic Colors ── */ + --ds-color-store: #10b981; /* فروشگاه عادی */ + --ds-color-discount: #ef4444; /* فروشگاه اعتباری */ + --ds-color-success: #10b981; + --ds-color-warning: #f59e0b; + --ds-color-error: #ef4444; + --ds-color-info: #3b82f6; + + /* ── Soft Backgrounds ── */ + --ds-primary-soft: rgba(99,102,241,.08); + --ds-success-soft: rgba(16,185,129,.08); + --ds-error-soft: rgba(239,68,68,.08); + --ds-warning-soft: rgba(245,158,11,.08); + + /* ── Gradients ── */ + --ds-gradient-primary: linear-gradient(135deg, #6366f1 0%, #818cf8 50%, #a78bfa 100%); + --ds-gradient-store: linear-gradient(135deg, #10b981 0%, #34d399 100%); + --ds-gradient-discount: linear-gradient(135deg, #ef4444 0%, #f97316 50%, #f59e0b 100%); + --ds-gradient-success: linear-gradient(135deg, #d1fae5 0%, #a7f3d0 100%); + + /* ── Spacing (existing) ── */ + --ds-radius-sm: 8px; + --ds-radius-md: 12px; + --ds-radius-lg: 16px; + --ds-radius-xl: 20px; + --ds-transition: 0.2s ease; + --ds-shadow-sm: 0 1px 3px rgba(0,0,0,.06); + --ds-shadow-md: 0 4px 12px rgba(0,0,0,.08); + --ds-shadow-lg: 0 8px 24px rgba(0,0,0,.10); +} +``` + +--- + +## 🚀 بخش ۳: فازبندی اجرا + +### 🔷 فاز ۱ — زیرساخت دیزاین سیستم (UI ~15%) +> **اولویت**: بالا | **ریسک**: پایین | **حجم**: ۶ فایل + +| # | تسک | فایل | نوع تغییر | +|---|---|---|---| +| 1.1 | ارتقاء `CustomMudTheme.cs` — اضافه کردن PaletteDark، LayoutProperties، رنگ‌های Secondary/Tertiary/Info، تغییر Primary به `#6366f1` | `CustomMudTheme.cs` | UI | +| 1.2 | توسعه CSS Variables — اضافه کردن brand colors، semantic colors، soft backgrounds، gradients | `site.css` | UI | +| 1.3 | ساخت `` component واحد | `Shared/LoadingState.razor` (جدید) | UX | +| 1.4 | ساخت `` component واحد | `Shared/EmptyState.razor` (جدید) | UX | +| 1.5 | بهبود `` — اضافه کردن آیکون، subtitle اختیاری | `Shared/PageHeader.razor` | UI | +| 1.6 | اضافه کردن `.page-container` CSS pattern | `site.css` | UI | + +--- + +### 🔷 فاز ۲ — یکپارچه‌سازی صفحات Profile (UI ~10%, UX ~5%) +> **اولویت**: بالا | **ریسک**: پایین | **حجم**: ۹ فایل + +| # | تسک | تغییرات | +|---|---|---| +| 2.1 | `Profile/Personal` → جایگزینی header دستی با `` | UX | +| 2.2 | `Profile/Addresses` → `` + `` + `` | UX | +| 2.3 | `Profile/Wallet` → `` | UX | +| 2.4 | `Profile/Settings` → `` | UX | +| 2.5 | `Profile/Tree` → `` | UX | +| 2.6 | `Profile/WithdrawalRequests` → `` + `` | UX | +| 2.7 | `Profile/ChangePassword` → `` | UX | +| 2.8 | `Profile/Index` (Dashboard) → حذف inline styles، استفاده از CSS Variables | UI | +| 2.9 | `Club/MembershipPage` + `Club/FeaturesPage` → `` + `` | UX | + +--- + +### 🔷 فاز ۳ — یکپارچه‌سازی صفحات تخصصی (UI ~5%, UX ~5%) +> **اولویت**: متوسط | **ریسک**: پایین | **حجم**: ۵ فایل + +| # | تسک | تغییرات | +|---|---|---| +| 3.1 | `Commission/Dashboard` → `` + `` | UX | +| 3.2 | `Commission/WeeklyBalance` → `` + حذف inline gradient styles | UI + UX | +| 3.3 | `Network/NetworkStatistics` → `` + `` | UX | +| 3.4 | `PackageDetail` → wrap loading/error در `MudContainer` | UX bug fix | +| 3.5 | `Checkout` → Elevation=4→2، حذف inline radial-gradient | UI | + +--- + +### 🔷 فاز ۴ — بهبود بصری فروشگاه‌ها (UI ~10%) +> **اولویت**: متوسط | **ریسک**: پایین | **حجم**: ۶ فایل + +| # | تسک | تغییرات | +|---|---|---| +| 4.1 | `Store/Products` → حذف inline hero styles، استفاده از CSS class | UI | +| 4.2 | `Store/ProductDetail` → حذف inline image styles، ساخت `.product-image-main` CSS | UI | +| 4.3 | `DiscountStore/ProductDetail` → حذف hardcoded rgba، استفاده از `--ds-success-soft` | UI | +| 4.4 | `Gateway/*` (۳ صفحه) → حذف hardcoded `#10b981`/`#ef4444`، استفاده از `--ds-color-store`/`--ds-color-discount` | UI | +| 4.5 | یکسان‌سازی Elevation → `0` با border یا `2` | UI | +| 4.6 | یکسان‌سازی Container spacing → `py-6` | UI | + +--- + +### 🔷 فاز ۵ — بهبود صفحات عمومی و بلاگ (UI ~10%) +> **اولویت**: پایین | **ریسک**: پایین | **حجم**: ۷ فایل + +| # | تسک | تغییرات | +|---|---|---| +| 5.1 | `Index.razor` → حذف inline styles از hero، استفاده از CSS class | UI | +| 5.2 | `About.razor` → حذف inline radial-gradient | UI | +| 5.3 | `Contact.razor` → cleanup minor inline styles | UI | +| 5.4 | `FAQ.razor` → cleanup minor inline styles | UI | +| 5.5 | `Blog/Index` → حذف inline hero styles، استفاده از CSS class | UI | +| 5.6 | `Blog/Post` → حذف inline styles از hero image و typography | UI | +| 5.7 | `RegisterWizard` → بهینه‌سازی wizard-section dark mode | UI | + +--- + +### 🔷 فاز ۶ — Polish نهایی و فرآیندی (UX ~10%) +> **اولویت**: پایین | **ریسک**: بسیار پایین | **حجم**: ۴ فایل + تست + +| # | تسک | تغییرات | +|---|---|---| +| 6.1 | Fix routing inconsistency — Categories + Blog/Post | UX | +| 6.2 | MudSnackbar notifications styling | UI | +| 6.3 | Dialog styling consistency (AuthDialog, AddressDialogs) | UI | +| 6.4 | Micro-interactions — button press, card hover, page transition | UI | +| 6.5 | تست کامل Dark Mode در تمام صفحات | UI + QA | +| 6.6 | تست Mobile Responsive در تمام صفحات | UX + QA | + +--- + +## 📈 بخش ۴: جدول تأثیرگذاری + +### تأثیر UI (هدف ~۵۰٪ تغییر) + +| حوزه | تعداد فایل | درصد تأثیر | +|---|---|---| +| Theme + CSS Variables | ۲ | ۱۵% (تأثیر سراسری) | +| حذف Inline Styles | ۱۱ | ۱۵% | +| یکسان‌سازی Elevation/Rounding | ۲۰+ | ۱۰% | +| بهبود رنگ‌بندی (CSS Variables) | ۸ | ۵% | +| Micro-interactions | سراسری | ۵% | +| **جمع** | | **~۵۰%** | + +### تأثیر UX (هدف ~۲۰٪ تغییر) + +| حوزه | تعداد فایل | درصد تأثیر | +|---|---|---| +| PageHeader یکپارچه | ۱۲ صفحه | ۸% | +| LoadingState واحد | ۱۵+ صفحه | ۴% | +| EmptyState واحد | ۸+ صفحه | ۳% | +| Container fixes (PackageDetail) | ۲ | ۲% | +| Routing consistency | ۲ | ۱% | +| Flow improvements | ۲ | ۲% | +| **جمع** | | **~۲۰%** | + +--- + +## 🔧 بخش ۵: مشخصات فنی کامپوننت‌های جدید + +### ۵.۱ LoadingState Component + +```razor +@* Shared/LoadingState.razor *@ + + + @if (!string.IsNullOrWhiteSpace(Message)) + { + @Message + } + + +@code { + [Parameter] public string Message { get; set; } = "در حال بارگذاری..."; +} +``` + +### ۵.۲ EmptyState Component + +```razor +@* Shared/EmptyState.razor *@ + + + @Title + @if (!string.IsNullOrWhiteSpace(Description)) + { + + @Description + + } + @if (!string.IsNullOrWhiteSpace(ActionText)) + { + + @ActionText + + } + + +@code { + [Parameter] public string Icon { get; set; } = Icons.Material.Filled.Inbox; + [Parameter] public string Title { get; set; } = "موردی یافت نشد"; + [Parameter] public string? Description { get; set; } + [Parameter] public string? ActionText { get; set; } + [Parameter] public string? ActionHref { get; set; } + [Parameter] public EventCallback OnAction { get; set; } +} +``` + +### ۵.۳ PageHeader ارتقاء‌یافته + +```razor +@* Shared/PageHeader.razor — ارتقاء‌یافته *@ + + +@code { + [Parameter] public string Title { get; set; } = ""; + [Parameter] public string? Subtitle { get; set; } + [Parameter] public string? BackHref { get; set; } + + [Inject] private IJSRuntime JS { get; set; } = default!; + private async Task GoBack() => await JS.InvokeVoidAsync("history.back"); +} +``` + +--- + +## ✅ بخش ۶: چک‌لیست تکمیل هر فاز + +### فاز ۱ چک‌لیست: +- [ ] `CustomMudTheme.cs` — Primary→`#6366f1`, PaletteDark اضافه شد +- [ ] `site.css` — CSS Variables جدید (brand, semantic, soft, gradient) +- [ ] `Shared/LoadingState.razor` — ساخته و تست شد +- [ ] `Shared/EmptyState.razor` — ساخته و تست شد +- [ ] `Shared/PageHeader.razor` — Subtitle parameter اضافه شد +- [ ] `.page-container` CSS pattern اضافه شد +- [ ] Build: 0 errors ✅ +- [ ] Dark Mode: صحیح ✅ +- [ ] Mobile: صحیح ✅ + +### فاز ۲ چک‌لیست: +- [ ] `Profile/Personal` → `` +- [ ] `Profile/Addresses` → `` + `` + `` +- [ ] `Profile/Wallet` → `` +- [ ] `Profile/Settings` → `` +- [ ] `Profile/Tree` → `` +- [ ] `Profile/WithdrawalRequests` → `` + `` +- [ ] `Profile/ChangePassword` → `` +- [ ] `Profile/Index` → inline styles → CSS +- [ ] `Club/*` → `` + `` +- [ ] Build: 0 errors ✅ + +### فاز ۳ چک‌لیست: +- [ ] `Commission/*` → `` + `` +- [ ] `Network/*` → `` + `` +- [ ] `PackageDetail` → MudContainer wrapper برای loading/error +- [ ] `Checkout` → Elevation fix + inline cleanup +- [ ] `WeeklyBalance` → inline gradient → CSS class +- [ ] Build: 0 errors ✅ + +### فاز ۴ چک‌لیست: +- [ ] `Store/Products` → hero inline → CSS +- [ ] `Store/ProductDetail` → image inline → CSS class +- [ ] `DiscountStore/ProductDetail` → rgba → variable +- [ ] `Gateway/*` → hardcoded → variable +- [ ] Elevation یکسان‌سازی +- [ ] Container spacing یکسان‌سازی +- [ ] Build: 0 errors ✅ + +### فاز ۵ چک‌لیست: +- [ ] `Index.razor` → hero inline cleanup +- [ ] `About.razor` → radial-gradient cleanup +- [ ] `Blog/Index` + `Blog/Post` → inline cleanup +- [ ] `Contact.razor` + `FAQ.razor` → minor cleanup +- [ ] Build: 0 errors ✅ + +### فاز ۶ چک‌لیست: +- [ ] Routing fix (Categories, Blog/Post) +- [ ] MudSnackbar styling +- [ ] Dialog consistency +- [ ] Dark mode full test +- [ ] Mobile responsive full test +- [ ] Build: 0 errors ✅ + +--- + +## 📋 بخش ۷: خلاصه تغییرات در یک نگاه + +``` +فایل‌های تغییر‌یافته: +├── CustomMudTheme.cs [فاز ۱] — ارتقاء کامل تم +├── site.css [فاز ۱-۵] — CSS Variables + class‌های جدید +├── Shared/LoadingState.razor [فاز ۱] — جدید +├── Shared/EmptyState.razor [فاز ۱] — جدید +├── Shared/PageHeader.razor [فاز ۱] — بهبود +├── Profile/* (۷ فایل) [فاز ۲] — PageHeader + LoadingState +├── Profile/Index.razor [فاز ۲] — حذف inline styles +├── Club/* (۲ فایل) [فاز ۲] — PageHeader + LoadingState +├── Commission/* (۲ فایل) [فاز ۳] — PageHeader + LoadingState + cleanup +├── Network/* (۱ فایل) [فاز ۳] — PageHeader + LoadingState +├── PackageDetail.razor [فاز ۳] — Container fix +├── Checkout.razor [فاز ۳] — Elevation + cleanup +├── Store/* (۲ فایل) [فاز ۴] — inline → CSS +├── DiscountStore/ProductDetail [فاز ۴] — rgba → variable +├── Gateway/* (۳ فایل) [فاز ۴] — hardcoded → variable +├── Index.razor [فاز ۵] — hero cleanup +├── About.razor [فاز ۵] — gradient cleanup +├── Blog/* (۲ فایل) [فاز ۵] — inline cleanup +├── Contact.razor + FAQ.razor [فاز ۵] — minor cleanup +└── Categories + Blog/Post [فاز ۶] — routing fix +``` + +**مجموع فایل‌های تأثیرپذیر**: ~۳۵ فایل +**فایل‌های جدید**: ۲ (LoadingState, EmptyState) +**میزان تغییر UI**: ~۵۰٪ +**میزان تغییر UX**: ~۲۰٪ +**ریسک شکست**: پایین (تغییرات تدریجی، build verification در هر فاز) diff --git a/migration/DATAMIGRATION-README.md b/migration/DATAMIGRATION-README.md new file mode 100644 index 0000000..4acc902 --- /dev/null +++ b/migration/DATAMIGRATION-README.md @@ -0,0 +1,425 @@ +# FourSat Data Migration Tool + +## نگاه کلی + +این ابزار برای مهاجرت داده‌های دیتابیس از ساختار قدیمی (Production) به ساختار جدید (Stage) طراحی شده است. + +**ویژگی‌ها:** +- ✅ Queue-based processing با retry logic +- ✅ Error handling - آیتم‌های ناموفق به صف retry می‌روند +- ✅ Logging کامل با Serilog (Console + File) +- ✅ قابلیت توقف/ادامه (Pause/Resume) +- ✅ Table name mapping (مثل Categorys → Categories) +- ✅ Batch processing برای کارایی بهتر +- ✅ Retry با Exponential Backoff +- ✅ Progress tracking + +--- + +## ساختار پروژه + +``` +FourSat.DataMigration/ +├── Program.cs # Entry point با Hosting +├── appsettings.json # تنظیمات (ConnectionStrings, Mappings) +├── Models/ +│ ├── MigrationSettings.cs # تنظیمات migration +│ ├── TableMapping.cs # نگاشت table ها +│ └── MigrationQueueItem.cs # آیتم صف +├── Services/ +│ ├── IMigrationService.cs # Interface +│ ├── MigrationService.cs # سرویس اصلی migration +│ ├── QueueManager.cs # مدیریت صف و retry +│ └── TableMigrator.cs # مهاجرت یک table +└── Logs/ # لاگ فایل‌ها (auto-created) +``` + +--- + +## تنظیمات (`appsettings.json`) + +### 1. ConnectionStrings +```json +{ + "SourceDatabase": "Server=185.252.31.42,2019;Database=Foursat;...", + "TargetDatabase": "Server=194.5.195.53,31433;Database=Foursat;..." +} +``` + +**⚠️ توجه**: حتماً Username و Password را وارد کنید! + +### 2. MigrationSettings +- **BatchSize**: تعداد رکوردهای هر batch (پیشنهاد: 1000) +- **MaxRetryAttempts**: حداکثر تلاش مجدد (5 بار) +- **RetryDelaySeconds**: تأخیر بین retry ها (5 ثانیه) +- **MaxConcurrentTables**: تعداد table های همزمان (3 عدد) +- **EnableDetailedLogging**: لاگ جزئیات (true) +- **SkipEmptyTables**: نادیده گرفتن table های خالی (true) + +### 3. TableMappings +نگاشت نام table قدیمی به جدید (33 جدول): + +```json +{ + "Categorys": "Categories", + "ClubFeatures": "ClubFeatures", + "ClubMembershipHistories": "ClubMembershipHistories", + "ClubMemberships": "ClubMemberships", + "CommissionPayoutHistories": "CommissionPayoutHistories", + "Contracts": "Contracts", + "FactorDetailss": "FactorDetails", + "NetworkMembershipHistories": "NetworkMembershipHistories", + "NetworkWeeklyBalances": "NetworkWeeklyBalances", + "OtpTokens": "OtpTokens", + "Packages": "Packages", + "ProductGalleryss": "ProductGalleries", + "ProductImagess": "ProductImages", + "Productss": "Products", + "PruductCategorys": "ProductCategories", + "PruductTags": "ProductTags", + "Roles": "Roles", + "SystemConfigurationHistories": "SystemConfigurationHistories", + "SystemConfigurations": "SystemConfigurations", + "Tags": "Tags", + "Transactionss": "Transactions", + "UserAddresss": "UserAddresses", + "UserCartss": "UserCarts", + "UserClubFeatures": "UserClubFeatures", + "UserCommissionPayouts": "UserCommissionPayouts", + "UserContracts": "UserContracts", + "UserOrders": "UserOrders", + "UserRoles": "UserRoles", + "Users": "Users", + "UserWalletChangeLogs": "UserWalletChangeLogs", + "UserWallets": "UserWallets", + "WeeklyCommissionPools": "WeeklyCommissionPools", + "WorkerExecutionLogs": "WorkerExecutionLogs" +} +``` + +**چگونه کار می‌کند:** +- اگر table در mapping باشد → از نام جدید استفاده می‌کند +- اگر در mapping نباشد → همان نام را استفاده می‌کند +- اگر table در target نباشد → Log می‌کند و skip می‌کند + +--- + +## نحوه اجرا + +### 1. ویرایش appsettings.json +```bash +cd /home/masoud/Apps/project/FourSat/DataMigration/FourSat.DataMigration +nano appsettings.json +``` + +**تغییرات لازم:** +- ✅ `SourceDatabase`: Username و Password را وارد کنید +- ✅ `TargetDatabase`: Username و Password را وارد کنید +- ✅ `TableMappings`: اگر mapping جدید دارید اضافه کنید + +### 2. Build پروژه +```bash +dotnet build +``` + +### 3. اجرای Migration +```bash +dotnet run +``` + +### 4. مشاهده Logs +```bash +# Real-time console output +# یا +tail -f Logs/migration-20251206.txt +``` + +--- + +## جریان کار (Workflow) + +``` +1. خواندن تنظیمات از appsettings.json + ↓ +2. اتصال به Source و Target databases + ↓ +3. کشف تمام table های Source (CMS schema) + ↓ +4. برای هر table: + ├─ بررسی mapping (قدیمی → جدید) + ├─ تعداد رکوردها را بخواند + ├─ اگر خالی → skip (با log) + ├─ اگر پر → افزودن به Queue + └─ Log: "Table X → Y: N records" + ↓ +5. پردازش Queue: + ├─ تا MaxConcurrentTables همزمان + ├─ هر table در batch ها (BatchSize) + ├─ اگر error → Retry (MaxRetryAttempts) + ├─ اگر بعد از retry fail → Log + Skip + └─ پیشرفت را نمایش بده + ↓ +6. گزارش نهایی: + ├─ تعداد table های موفق + ├─ تعداد table های ناموفق + ├─ جمع رکوردهای migrate شده + └─ مدت زمان کل +``` + +--- + +## Retry Logic + +### استراتژی: +1. **اولین تلاش**: بلافاصله +2. **تلاش 2**: بعد از 5 ثانیه +3. **تلاش 3**: بعد از 10 ثانیه (exponential backoff) +4. **تلاش 4**: بعد از 20 ثانیه +5. **تلاش 5**: بعد از 40 ثانیه + +**اگر همه fail شوند:** +- Log error با جزئیات کامل +- Table را از queue حذف کن +- به table بعدی برو (متوقف نمی‌شود!) + +--- + +## Error Handling + +### خطاهای رایج: + +| خطا | دلیل | راه حل | +|-----|------|--------| +| **Login failed** | Username/Password اشتباه | appsettings.json را بررسی کنید | +| **Table not found** | Table در target وجود ندارد | Migration بزنید یا از mapping صحیح استفاده کنید | +| **Timeout** | Network کند یا batch زیاد | BatchSize را کاهش دهید | +| **Deadlock** | همزمانی بالا | MaxConcurrentTables را کم کنید | +| **Permission denied** | User دسترسی ندارد | سطح دسترسی SQL را بررسی کنید | + +--- + +## مثال خروجی + +``` +[12:30:15 INF] Starting migration... +[12:30:16 INF] Source: 30 tables found +[12:30:16 INF] Mapping: Categorys → Categories +[12:30:16 INF] Mapping: Productss → Products +[12:30:17 INF] Queue: 28 tables added (2 empty skipped) +[12:30:18 INF] Migrating: Categories (6 records) +[12:30:18 INF] Success: Categories (6/6) - 100% +[12:30:19 INF] Migrating: Products (150 records) +[12:30:21 INF] Success: Products (150/150) - 100% +... +[12:35:42 INF] === Migration Complete === +[12:35:42 INF] Success: 28 tables, 45,320 records +[12:35:42 INF] Failed: 0 tables +[12:35:42 INF] Duration: 5 minutes 27 seconds +``` + +--- + +## فایل‌های باقی مانده برای پیاده‌سازی + +### Models/MigrationSettings.cs +```csharp +public class MigrationSettings +{ + public int BatchSize { get; set; } = 1000; + public int MaxRetryAttempts { get; set; } = 5; + public int RetryDelaySeconds { get; set; } = 5; + public int MaxConcurrentTables { get; set; } = 3; + public bool EnableDetailedLogging { get; set; } = true; + public bool SkipEmptyTables { get; set; } = true; +} +``` + +### Models/TableMapping.cs +```csharp +public class TableMapping +{ + public string SourceTable { get; set; } = string.Empty; + public string TargetTable { get; set; } = string.Empty; + public long TotalRecords { get; set; } + public long MigratedRecords { get; set; } + public MigrationStatus Status { get; set; } +} + +public enum MigrationStatus +{ + Pending, + InProgress, + Completed, + Failed, + Retrying +} +``` + +### Models/MigrationQueueItem.cs +```csharp +public class MigrationQueueItem +{ + public string SourceTable { get; set; } = string.Empty; + public string TargetTable { get; set; } = string.Empty; + public long TotalRecords { get; set; } + public int RetryCount { get; set; } + public DateTime? LastAttempt { get; set; } + public string? LastError { get; set; } +} +``` + +### Services/IMigrationService.cs +```csharp +public interface IMigrationService +{ + Task RunAsync(CancellationToken cancellationToken); +} +``` + +### Services/MigrationService.cs +```csharp +public class MigrationService : IMigrationService +{ + // کلاس اصلی که: + // 1. لیست table ها را از source می‌خواند + // 2. QueueManager را راه‌اندازی می‌کند + // 3. TableMigrator ها را همزمان اجرا می‌کند + // 4. Progress و statistics را نمایش می‌دهد +} +``` + +### Program.cs +```csharp +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Serilog; + +var host = Host.CreateDefaultBuilder(args) + .UseSerilog((context, config) => config.ReadFrom.Configuration(context.Configuration)) + .ConfigureServices((context, services) => + { + services.Configure(context.Configuration.GetSection("MigrationSettings")); + services.AddSingleton(); + // Register other services... + }) + .Build(); + +await host.Services.GetRequiredService().RunAsync(CancellationToken.None); +``` + +--- + +## توقف و ادامه (Pause/Resume) + +**نحوه توقف:** +```bash +Ctrl+C # Graceful shutdown +``` + +**نحوه ادامه:** +- هیچ state ذخیره نمی‌شود (stateless) +- دوباره `dotnet run` کنید +- چون `INSERT` استفاده می‌شود، رکوردهای duplicate ایجاد می‌شود +- **پیشنهاد**: قبل از اجرای مجدد، Target را TRUNCATE کنید + +**برای Production:** +- از `MERGE` یا `INSERT IF NOT EXISTS` استفاده کنید +- یک جدول `MigrationState` برای ذخیره پیشرفت ایجاد کنید + +--- + +## نکات امنیتی + +1. **Credentials**: + - ❌ هرگز appsettings.json را commit نکنید + - ✅ از Environment Variables یا User Secrets استفاده کنید + +2. **Network**: + - ✅ از VPN برای اتصال به Production استفاده کنید + - ✅ IP شما در Firewall مجاز باشد + +3. **Permissions**: + - Source: فقط `SELECT` کافی است + - Target: نیاز به `INSERT` دارد + +--- + +## بهینه‌سازی عملکرد + +### برای دیتابیس کوچک (<100K records): +```json +{ + "BatchSize": 5000, + "MaxConcurrentTables": 5 +} +``` + +### برای دیتابیس متوسط (100K-1M): +```json +{ + "BatchSize": 2000, + "MaxConcurrentTables": 3 +} +``` + +### برای دیتابیس بزرگ (>1M): +```json +{ + "BatchSize": 500, + "MaxConcurrentTables": 2 +} +``` + +--- + +## حذف یا خاموش کردن + +### خاموش کردن موقت: +```bash +# فقط اجرا نکنید! +``` + +### حذف کامل: +```bash +cd /home/masoud/Apps/project/FourSat +rm -rf DataMigration/ +``` + +--- + +## لایسنس + +این ابزار موقت برای استفاده داخلی FourSat است. بعد از sync کامل، حذف شود. + +--- + +## سوالات متداول (FAQ) + +**Q: چرا بعضی table ها migrate نمی‌شوند؟** +A: چک کنید: +1. Table در Target وجود دارد؟ +2. Schema match می‌کند؟ +3. Mapping صحیح است؟ + +**Q: چگونه فقط یک table خاص را migrate کنم؟** +A: در کد `MigrationService.cs`، فیلتر اضافه کنید: +```csharp +var tablesToMigrate = allTables.Where(t => t == "Users").ToList(); +``` + +**Q: چگونه از duplicate جلوگیری کنم؟** +A: قبل از اجرا، Target را خالی کنید: +```sql +TRUNCATE TABLE [CMS].[Categories]; +TRUNCATE TABLE [CMS].[Products]; +-- ... +``` + +**Q: آیا می‌توانم بدون توقف سرور اجرا کنم؟** +A: بله، فقط `SELECT` روی Source اجرا می‌شود (ReadOnly). + +--- + +**آخرین بروزرسانی**: December 6, 2025 +**نسخه**: 1.0 +**وضعیت**: آماده برای پیاده‌سازی نهایی