Compare commits
3 Commits
ad31c8be97
...
ce74377012
| Author | SHA1 | Date | |
|---|---|---|---|
| ce74377012 | |||
| 21b8965c10 | |||
| 4ef4bfbeef |
@@ -2,6 +2,7 @@
|
||||
|
||||
> آخرین بروزرسانی: February 17, 2026
|
||||
> ۲۲۰ فایل → ۳۰ فایل (تجمیع ۳ فازی + cleanup نهایی)
|
||||
> آخرین تغییرات: فیکس ZarinPal callback، تخفیف ۱۰۰٪ اجباری، VAT checkout، ExpirePendingOrders، فیکس DeliveryStatus mapping، دیپلوی Production، فیکس CI/CD cross-deploy، ساخت appsettings.Production.json هر ۳ پروژه، فیکس K8S_SERVER، فیکس nginx image path
|
||||
|
||||
---
|
||||
|
||||
@@ -23,6 +24,10 @@
|
||||
| **نقشه نوسازی UI فرانت؟** | [`ui-modernization/UI-MODERNIZATION-PLAN.md`](ui-modernization/UI-MODERNIZATION-PLAN.md) |
|
||||
| **معماری مدیریت فایل و تصاویر؟** | [`cms/FILE-MANAGEMENT-ARCHITECTURE.md`](cms/FILE-MANAGEMENT-ARCHITECTURE.md) |
|
||||
| **فیکس فلوی ثبتنام FrontOffice؟** | [`cms/REGISTRATION-FLOW-FIXES.md`](cms/REGISTRATION-FLOW-FIXES.md) |
|
||||
| **باگ cross-deploy چه بود؟** | [`deployment/CICD-PIPELINE-GUIDE.md`](deployment/CICD-PIPELINE-GUIDE.md) |
|
||||
| **سرور Production کجاست؟** | [`deployment/INFRASTRUCTURE-GUIDE.md`](deployment/INFRASTRUCTURE-GUIDE.md) |
|
||||
| **تنظیمات VAT/مالیات؟** | [`cms/payment-gateway.md`](cms/payment-gateway.md) (بخش ۱۰) |
|
||||
| **سرویس انقضای سفارش؟** | [`cms/payment-gateway.md`](cms/payment-gateway.md) (بخش ۱۱) |
|
||||
| **Audit report کامل BackOffice؟** | [`BackOffice/docs/BACKOFFICE-AUDIT.md`](../BackOffice/docs/BACKOFFICE-AUDIT.md) |
|
||||
|
||||
---
|
||||
@@ -36,6 +41,7 @@
|
||||
| [club-membership-contract-system.md](business/club-membership-contract-system.md) | سیستم قرارداد عضویت: امضا، OTP، رفرش توکن |
|
||||
| [package-purchase-system.md](business/package-purchase-system.md) | ۳ سناریو خرید پکیج: وام دایا، پرداخت دستی، درگاه |
|
||||
| [daya-loan-integration.md](business/daya-loan-integration.md) | یکپارچهسازی وام دایا + جزئیات API + پیادهسازی CMS |
|
||||
| [DISCOUNT-STORE-STATUS.md](business/DISCOUNT-STORE-STATUS.md) | 🔄 وضعیت فروشگاه تخفیفی: تخفیف ۱۰۰٪ اجباری + ZarinPal + VAT + ExpirePendingOrders — Production Deploy ✅ |
|
||||
| [discount-shop-business.md](business/discount-shop-business.md) | فروشگاه تخفیفی: پرداخت ترکیبی، درصد تخفیف، entity design |
|
||||
| [manual-payment-system.md](business/manual-payment-system.md) | پرداخت دستی: کارت به کارت، تأیید ادمین، آپلود FMS |
|
||||
|
||||
@@ -48,7 +54,7 @@
|
||||
| [FRONTOFFICE-CMS-API-COMPATIBILITY.md](cms/FRONTOFFICE-CMS-API-COMPATIBILITY.md) | ماتریس سازگاری API بین FrontOffice و CMS |
|
||||
| [ICURRENTUSERSERVICE-IMPLEMENTATION.md](cms/ICURRENTUSERSERVICE-IMPLEMENTATION.md) | پترن JWT + ICurrentUserService در endpointهای Customer |
|
||||
| [ADMIN-CUSTOMER-SEPARATION-FIX.md](cms/ADMIN-CUSTOMER-SEPARATION-FIX.md) | 🆕 فیکس جداسازی Admin/Customer: حذف JWT fallback از ۸ handler + resolve صریح در ۴ endpoint |
|
||||
| [payment-gateway.md](cms/payment-gateway.md) | IPaymentGatewayService: Mock vs Daya، پیادهسازی payout |
|
||||
| [payment-gateway.md](cms/payment-gateway.md) | 🔄 IPaymentGatewayService: ZarinPal مستقیم + تخفیف ۱۰۰٪ اجباری + VAT + ExpirePendingOrders + فیکس DeliveryStatus mapping + دیپلوی Production |
|
||||
| [payment-architecture-pyms.md](cms/payment-architecture-pyms.md) | معماری PYMS: جریان پرداخت BFF→PYMS→Gateway→CMS |
|
||||
| [chatika-integration.md](cms/chatika-integration.md) | یکپارچهسازی Chatika AI: Hangfire worker، retry logic |
|
||||
| [club-feature-management-services.md](cms/club-feature-management-services.md) | CQRS سرویسهای مدیریت ClubFeature |
|
||||
@@ -65,9 +71,9 @@
|
||||
| فایل | توضیح |
|
||||
|------|-------|
|
||||
| [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، عیبیابی |
|
||||
| [INFRASTRUCTURE-GUIDE.md](deployment/INFRASTRUCTURE-GUIDE.md) | مشخصات سرور، DB credentials، Gitea، وضعیت استقرار |
|
||||
| [SERVER-MIRRORS-CONFIG.md](deployment/SERVER-MIRRORS-CONFIG.md) | تنظیمات mirror: K3s registries.yaml، containerd |
|
||||
| [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 |
|
||||
| [SERVER-MIRRORS-CONFIG.md](deployment/SERVER-MIRRORS-CONFIG.md) | 🔄 تنظیمات mirror: K3s registries.yaml Staging + Production، containerd |
|
||||
| [INGRESS-NGINX-WARNING.md](deployment/INGRESS-NGINX-WARNING.md) | ⚠️ هشدار K3s: مشکل hostNetwork در ingress-nginx |
|
||||
|
||||
## 📂 ui-modernization/ — مستندات نوسازی UI (۳ فایل)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# فروشگاه تخفیفی — وضعیت پیادهسازی و تسکها
|
||||
|
||||
> **تاریخ:** ۱۴۰۴/۱۱/۲۲ (2026-02-11)
|
||||
> **آخرین بروزرسانی:** ۱۴۰۴/۱۱/۲۳
|
||||
> **وضعیت کلی:** بکند کامل ✅ | بکآفیس کامل ✅ | فرانتآفیس کامل ✅
|
||||
> **آخرین بروزرسانی:** ۱۴۰۴/۱۱/۲۸ (2026-02-17)
|
||||
> **وضعیت کلی:** بکند کامل ✅ | بکآفیس کامل ✅ | فرانتآفیس کامل ✅ | Production Deploy ✅
|
||||
|
||||
---
|
||||
|
||||
@@ -162,22 +162,28 @@
|
||||
│ هر محصول: قیمت × تعداد
|
||||
│ تخفیف هر محصول: price × count × maxDiscountPercent / 100
|
||||
│ جمع کل / جمع تخفیف / مبلغ درگاه
|
||||
├─ موجودی تخفیفی کاربر: XXX تومان
|
||||
├─ کاربر تعیین میکند چقدر از تخفیفی استفاده کند (≤ سقف مجاز)
|
||||
├─ مالیات ۹٪ روی مبلغ درگاه
|
||||
├─ مبلغ قابل پرداخت = مبلغ درگاه + مالیات
|
||||
├─ ⚠️ تخفیف اجباری: همیشه حداکثر (MaxDiscountPercent) اعمال میشود
|
||||
└─ [پرداخت]
|
||||
↓
|
||||
PlaceOrder RPC:
|
||||
├─ بررسی موجودی + محاسبه
|
||||
├─ ساخت سفارش (Pending)
|
||||
├─ بررسی موجودی + محاسبه (MaxDiscountPercent اجباری)
|
||||
├─ ساخت سفارش (PaymentStatus=Pending)
|
||||
├─ رزرو موجودی انبار
|
||||
├─ اگر gateway_amount > 0 → payment_url برگردانده میشود
|
||||
├─ اگر gateway_amount > 0 → ZarinPal payment_url
|
||||
└─ اگر gateway_amount = 0 → سفارش مستقیم تکمیل
|
||||
↓
|
||||
ریدایرکت به درگاه (اگر لازم باشد)
|
||||
ریدایرکت به ZarinPal
|
||||
↓
|
||||
CompleteOrderPayment RPC (بعد از callback):
|
||||
├─ success → کسر DiscountBalance + تأیید فروش + ثبت تراکنش
|
||||
└─ failure → آزادسازی رزرو انبار + لغو سفارش
|
||||
Callback → CompleteOrderPayment RPC:
|
||||
├─ success → کسر DiscountBalance + تأیید + PaymentTransaction + DeliveryStatus=Pending
|
||||
└─ failure → آزادسازی رزرو انبار + PaymentStatus=Reject + DeliveryStatus=Cancelled
|
||||
↓
|
||||
ExpirePendingOrdersService (Background):
|
||||
├─ هر ۵ دقیقه چک میکند
|
||||
├─ سفارشات Pending بالای ۳۰ دقیقه → Reject + Cancelled
|
||||
└─ آزادسازی رزرو انبار
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,583 @@
|
||||
# سادهسازی سیستم مدیریت صفحات سایت
|
||||
|
||||
> **تاریخ:** ۱۳۹۶/۱۱/۲۸ (2026-02-17)
|
||||
> **وضعیت:** طرح اولیه — منتظر تأیید
|
||||
> **اولویت:** بالا
|
||||
|
||||
---
|
||||
|
||||
## ۱. خلاصه مسئله
|
||||
|
||||
### وضعیت فعلی (مشکلات)
|
||||
|
||||
سیستم فعلی مدیریت صفحات **بیش از حد انعطافپذیر و پیچیده** طراحی شده:
|
||||
|
||||
| مشکل | توضیح |
|
||||
|-------|--------|
|
||||
| **سیستم عمومی Section/Key** | ادمین باید `SectionKey` رو دقیق تایپ کنه (مثلاً `value-1`, `team-2`). یه اشتباه تایپی باعث میشه فرانت اون بخش رو پیدا نکنه |
|
||||
| **ExtraData بهصورت JSON خام** | اطلاعات تماس (آدرس/تلفن/ایمیل) و شبکههای اجتماعی داخل textarea به JSON خام نوشته میشه — خطاپذیر |
|
||||
| **HTML Editor برای همهچیز** | حتی برای متنهای ساده (عنوان یک Value) از HTML Editor استفاده میشه |
|
||||
| **CRUD نامحدود** | ادمین میتونه صفحات جدید بسازه ولی فرانت فقط `about` و `contact` رو میشناسه |
|
||||
| **لندینگ پیج کاملاً هاردکد** | محتوای لندینگ (Steps, Features, Stats, FAQ, Testimonials) داخل کد C# هاردکد شده و از CMS استفاده نمیکنه |
|
||||
| **صفحه مجوزها وجود نداره** | هیچ صفحهای برای نمایش نمادهای اعتماد و مجوزها نداریم |
|
||||
|
||||
### هدف
|
||||
|
||||
**۴ صفحه مشخص** با **فرمهای اختصاصی** (نه عمومی) در پنل ادمین:
|
||||
|
||||
| # | صفحه | محتوای قابل ویرایش | طراحی |
|
||||
|---|-------|-------------------|--------|
|
||||
| 1 | **لندینگ** | عنوان hero، زیرعنوان، متن دکمهها، عناوین سکشنها، متن مراحل/ویژگیها/سوالات/آمار | **چیدمان ثابت** — فقط متنها قابل تغییر |
|
||||
| 2 | **درباره ما** | عنوان، چشمانداز، مأموریت، ارزشها (عنوان+متن+آیکون)، اعضای تیم (نام+سمت+تصویر) | **چیدمان ثابت** — تعداد ارزشها و اعضا قابل تغییر |
|
||||
| 3 | **تماس با ما** | آدرس، تلفن، ایمیل، ساعات کاری، لینک شبکههای اجتماعی | **چیدمان ثابت** — فقط اطلاعات قابل تغییر |
|
||||
| 4 | **مجوزها** 🆕 | تصاویر مجوزها با عنوان و لینک (نماد اعتماد الکترونیکی و ...) | **ساده و یکپارچه** |
|
||||
|
||||
---
|
||||
|
||||
## ۲. معماری جدید — Structured Page Settings
|
||||
|
||||
### فلسفه طراحی
|
||||
|
||||
```
|
||||
❌ قبلی: Generic Sections + Free-form Keys + Raw JSON
|
||||
✅ جدید: Typed Settings per Page + Structured Forms + Fixed Layout
|
||||
```
|
||||
|
||||
بهجای اینکه هر صفحه N تا Section داشته باشه با Keyهای دلخواه، **هر صفحه یک مدل مشخص** با فیلدهای تایپشده داره.
|
||||
|
||||
### ۲.۱ مدلهای داده جدید (Database)
|
||||
|
||||
#### جدول `SitePageSettings` (جایگزین SitePage + SitePageSection)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ SitePageSettings │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Id : long (PK) │
|
||||
│ PageKey : string(50) [UNIQUE INDEX] │ ← "landing" | "about" | "contact" | "licenses"
|
||||
│ Title : string(200) │
|
||||
│ MetaDescription : string?(300) │
|
||||
│ HeroTitle : string?(200) │
|
||||
│ HeroSubtitle : string?(500) │
|
||||
│ HeroImagePath : string? │
|
||||
│ IsActive : bool │
|
||||
│ SettingsJson : string (JSON Column) │ ← ⭐ Typed JSON per PageKey
|
||||
│ + Audit fields │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### جدول `SitePageImage` (برای مجوزها و تصاویر تیم)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ SitePageImage │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Id : long (PK) │
|
||||
│ SitePageSettingsId : long (FK) │
|
||||
│ ImageGroup : string(50) │ ← "licenses" | "team" | "values"
|
||||
│ Title : string?(200) │
|
||||
│ Subtitle : string?(300) │
|
||||
│ Description : string? │
|
||||
│ ImagePath : string │
|
||||
│ ThumbnailPath : string? │
|
||||
│ LinkUrl : string? │ ← برای مجوزها: لینک به سایت مرجع
|
||||
│ IconName : string?(100) │
|
||||
│ SortOrder : int │
|
||||
│ IsActive : bool │
|
||||
│ + Audit fields │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### SettingsJson — ساختار بهازای هر صفحه
|
||||
|
||||
**Landing (`PageKey = "landing"`):**
|
||||
```json
|
||||
{
|
||||
"heroButtonPrimaryText": "شروع کنید",
|
||||
"heroButtonSecondaryText": "بیشتر بدانید",
|
||||
"steps": [
|
||||
{ "title": "ثبتنام", "description": "...", "iconName": "PersonAdd" }
|
||||
],
|
||||
"features": [
|
||||
{ "title": "پشتیبانی ۲۴/۷", "description": "...", "iconName": "Support" }
|
||||
],
|
||||
"stats": [
|
||||
{ "label": "کاربران فعال", "value": 15000, "suffix": "+" }
|
||||
],
|
||||
"testimonials": [
|
||||
{ "name": "علی محمدی", "role": "کاربر", "text": "...", "rating": 5 }
|
||||
],
|
||||
"faqs": [
|
||||
{ "question": "سوال ۱", "answer": "جواب ۱", "category": "عمومی" }
|
||||
],
|
||||
"featuredBlogEnabled": true,
|
||||
"ctaTitle": "همین الان شروع کنید",
|
||||
"ctaDescription": "...",
|
||||
"ctaButtonText": "ثبتنام رایگان"
|
||||
}
|
||||
```
|
||||
|
||||
**About (`PageKey = "about"`):**
|
||||
```json
|
||||
{
|
||||
"visionTitle": "چشمانداز",
|
||||
"visionText": "...",
|
||||
"missionTitle": "مأموریت",
|
||||
"missionText": "...",
|
||||
"valuesTitle": "ارزشهای ما",
|
||||
"teamTitle": "تیم ما"
|
||||
}
|
||||
```
|
||||
+ `SitePageImage` records با `ImageGroup = "values"` برای ارزشها
|
||||
+ `SitePageImage` records با `ImageGroup = "team"` برای اعضای تیم
|
||||
|
||||
**Contact (`PageKey = "contact"`):**
|
||||
```json
|
||||
{
|
||||
"address": "تهران، ...",
|
||||
"phone": "021-12345678",
|
||||
"email": "info@kbs1.ir",
|
||||
"workingHours": "شنبه تا چهارشنبه ۹ تا ۱۸",
|
||||
"telegramUrl": "https://t.me/...",
|
||||
"instagramUrl": "https://instagram.com/...",
|
||||
"linkedinUrl": "https://linkedin.com/...",
|
||||
"whatsappUrl": "https://wa.me/...",
|
||||
"mapLatitude": 35.6892,
|
||||
"mapLongitude": 51.3890,
|
||||
"formSubjects": ["پشتیبانی فنی", "پیشنهاد همکاری", "سایر"]
|
||||
}
|
||||
```
|
||||
|
||||
**Licenses (`PageKey = "licenses"`):**
|
||||
```json
|
||||
{
|
||||
"pageDescription": "مجوزها و نمادهای اعتماد",
|
||||
"displayStyle": "grid"
|
||||
}
|
||||
```
|
||||
+ `SitePageImage` records با `ImageGroup = "licenses"` — هر مجوز: Title + ImagePath + LinkUrl
|
||||
|
||||
---
|
||||
|
||||
## ۳. تغییرات بهازای هر لایه
|
||||
|
||||
### ۳.۱ دیتابیس (CMS — Entity Framework)
|
||||
|
||||
| عملیات | فایل/محل | توضیح |
|
||||
|--------|----------|--------|
|
||||
| **حذف** | `SitePage` entity | جایگزین با `SitePageSettings` |
|
||||
| **حذف** | `SitePageSection` entity | جایگزین با `SitePageImage` (فقط برای آیتمهای تصویری) |
|
||||
| **ایجاد** | `SitePageSettings.cs` | Entity جدید با `SettingsJson` |
|
||||
| **ایجاد** | `SitePageImage.cs` | Entity جدید برای تصاویر (مجوزها، تیم، ارزشها) |
|
||||
| **تغییر** | `DbContext` — `SitePageConfiguration` | Configuration جدید |
|
||||
| **تغییر** | `SitePageSeedData.cs` | Seed data جدید برای ۴ صفحه |
|
||||
| **Migration** | EF Migration | **Data migration** از ساختار قدیم به جدید |
|
||||
|
||||
### ۳.۲ Proto / gRPC Contract
|
||||
|
||||
| عملیات | توضیح |
|
||||
|--------|--------|
|
||||
| **بازنویسی** | `site_pages.proto` — حذف ۱۰ RPC قبلی، جایگزین با ۴ RPC ساده |
|
||||
|
||||
```protobuf
|
||||
service SitePageSettingsService {
|
||||
// دریافت تنظیمات صفحه با کلید (FrontOffice)
|
||||
rpc GetPageSettings (GetPageSettingsRequest) returns (PageSettingsResponse);
|
||||
|
||||
// ذخیره تنظیمات صفحه (BackOffice — Admin)
|
||||
rpc SavePageSettings (SavePageSettingsRequest) returns (SavePageSettingsResponse);
|
||||
|
||||
// مدیریت تصاویر صفحه (مجوزها، تیم، ارزشها)
|
||||
rpc SavePageImage (SavePageImageRequest) returns (SavePageImageResponse);
|
||||
rpc DeletePageImage (DeletePageImageRequest) returns (DeletePageImageResponse);
|
||||
|
||||
// لیست همه صفحات (BackOffice)
|
||||
rpc GetAllPages (GetAllPagesRequest) returns (GetAllPagesResponse);
|
||||
}
|
||||
```
|
||||
|
||||
### ۳.۳ CMS Backend (Application Layer)
|
||||
|
||||
| عملیات | فایلها | توضیح |
|
||||
|--------|---------|--------|
|
||||
| **حذف** | ۲۲ فایل Command/Query فعلی | CQRS handlers قدیمی |
|
||||
| **ایجاد** | `GetPageSettingsQuery` + Handler | دریافت Settings + Images |
|
||||
| **ایجاد** | `SavePageSettingsCommand` + Handler + Validator | ذخیره JSON با اعتبارسنجی |
|
||||
| **ایجاد** | `SavePageImageCommand` + Handler | آپلود/ویرایش تصویر |
|
||||
| **ایجاد** | `DeletePageImageCommand` + Handler | حذف تصویر |
|
||||
| **ایجاد** | `GetAllPagesQuery` + Handler | لیست صفحات |
|
||||
| **تغییر** | gRPC Service | `SitePageGrpcService` بازنویسی |
|
||||
|
||||
### ۳.۴ FrontOffice (Blazor Server — سمت مشتری)
|
||||
|
||||
| عملیات | فایل | توضیح |
|
||||
|--------|------|--------|
|
||||
| **تغییر** | `SitePageService.cs` | سادهسازی — فقط `GetPageSettings(pageKey)` |
|
||||
| **تغییر** | `Index.razor` + `.cs` | **بزرگترین تغییر:** از هاردکد به CMS-driven. چیدمان ثابت میمونه، فقط متنها از `SettingsJson` خونده میشه |
|
||||
| **تغییر** | `AboutUs.razor` + `.cs` | سادهتر — خواندن مستقیم فیلدهای typed بهجای key-matching |
|
||||
| **تغییر** | `ContactUs.razor` + `.cs` | سادهتر — خواندن مستقیم فیلدها بدون JSON parsing |
|
||||
| **ایجاد** | `Licenses.razor` + `.cs` | 🆕 صفحه جدید مجوزها |
|
||||
|
||||
### ۳.۵ BackOffice (Blazor WASM — پنل ادمین)
|
||||
|
||||
| عملیات | فایل | توضیح |
|
||||
|--------|------|--------|
|
||||
| **حذف** | ۵ فایل Dialog فعلی | `CreateSitePageDialog`, `EditSitePageDialog`, `SitePageSectionsDialog`, `SitePageSectionEditDialog` |
|
||||
| **حذف** | `SitePageManagement.razor` + `.cs` فعلی | جایگزین |
|
||||
| **ایجاد** | `PageSettingsManagement.razor` | صفحه اصلی — لیست ۴ صفحه ثابت |
|
||||
| **ایجاد** | `LandingPageSettings.razor` | 🌟 فرم اختصاصی لندینگ |
|
||||
| **ایجاد** | `AboutPageSettings.razor` | 🌟 فرم اختصاصی دربارهما |
|
||||
| **ایجاد** | `ContactPageSettings.razor` | 🌟 فرم اختصاصی تماس |
|
||||
| **ایجاد** | `LicensesPageSettings.razor` | 🌟 فرم اختصاصی مجوزها |
|
||||
| **تغییر** | `ISitePageService` + Impl | سادهسازی interface |
|
||||
|
||||
---
|
||||
|
||||
## ۴. طراحی UI پنل ادمین (BackOffice)
|
||||
|
||||
### ۴.۱ صفحه اصلی مدیریت صفحات
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ مدیریت صفحات سایت │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ 🏠 │ │ 👥 │ │ 📞 │ │ 🏅 │ │
|
||||
│ │ لندینگ │ │ دربارهما│ │ تماس │ │ مجوزها │ │
|
||||
│ │ │ │ │ │ │ │ │ │
|
||||
│ │ [ویرایش] │ │ [ویرایش] │ │ [ویرایش] │ │ [ویرایش] │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
||||
│ │
|
||||
│ ℹ️ صفحات سایت ثابت هستند و فقط محتوای آنها │
|
||||
│ قابل ویرایش است │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### ۴.۲ فرم ویرایش لندینگ (نمونه)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ ← بازگشت تنظیمات صفحه لندینگ │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ── Hero Section ────────────────────────────────────── │
|
||||
│ عنوان: [_______________________________] │
|
||||
│ زیرعنوان: [_______________________________] │
|
||||
│ تصویر پسزمینه: [📎 انتخاب فایل] │
|
||||
│ متن دکمه اصلی: [_____________] │
|
||||
│ متن دکمه ثانویه:[_____________] │
|
||||
│ │
|
||||
│ ── مراحل (Steps) ───────────────────────────────────── │
|
||||
│ ┌────┬──────────────┬──────────────────┬────────┐ │
|
||||
│ │ # │ عنوان │ توضیح │ آیکون │ │
|
||||
│ ├────┼──────────────┼──────────────────┼────────┤ │
|
||||
│ │ 1 │ [ثبتنام ] │ [در کمتر از...] │ [🔍] │ │
|
||||
│ │ 2 │ [دعوت ] │ [لینک اختصاصی ] │ [🔍] │ │
|
||||
│ │ 3 │ [دریافت ] │ [پاداشهای... ] │ [🔍] │ │
|
||||
│ │ │ │ [+ افزودن مرحله]│ │ │
|
||||
│ └────┴──────────────┴──────────────────┴────────┘ │
|
||||
│ │
|
||||
│ ── ویژگیها (Features) ──────────────────────────────── │
|
||||
│ (مشابه بالا — جدول قابل ویرایش) │
|
||||
│ │
|
||||
│ ── آمار (Stats) ────────────────────────────────────── │
|
||||
│ ┌──────────────┬─────────┬────────┐ │
|
||||
│ │ برچسب │ مقدار │ پسوند │ │
|
||||
│ ├──────────────┼─────────┼────────┤ │
|
||||
│ │ [کاربران ] │ [15000] │ [+] │ │
|
||||
│ └──────────────┴─────────┴────────┘ │
|
||||
│ │
|
||||
│ ── نظرات مشتریان ───────────────────────────────────── │
|
||||
│ (جدول: نام، نقش، متن، امتیاز) │
|
||||
│ │
|
||||
│ ── سوالات متداول (FAQ) ─────────────────────────────── │
|
||||
│ (جدول: سوال، جواب، دستهبندی) │
|
||||
│ │
|
||||
│ ── CTA Banner ──────────────────────────────────────── │
|
||||
│ عنوان: [_______________] │
|
||||
│ توضیح: [_______________] │
|
||||
│ متن دکمه: [_______________] │
|
||||
│ │
|
||||
│ [💾 ذخیره تغییرات] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### ۴.۳ فرم ویرایش تماس با ما
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ ← بازگشت تنظیمات صفحه تماس با ما │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ── اطلاعات تماس ───────────────────────────────────── │
|
||||
│ آدرس: [_______________________________] │
|
||||
│ تلفن: [_______________________________] │
|
||||
│ ایمیل: [_______________________________] │
|
||||
│ ساعات کاری: [_______________________________] │
|
||||
│ │
|
||||
│ ── شبکههای اجتماعی ───────────────────────────────── │
|
||||
│ تلگرام: [_______________________________] │
|
||||
│ اینستاگرام: [_______________________________] │
|
||||
│ لینکدین: [_______________________________] │
|
||||
│ واتساپ: [_______________________________] │
|
||||
│ │
|
||||
│ ── تنظیمات فرم تماس ───────────────────────────────── │
|
||||
│ موضوعات: [پشتیبانی فنی ×] [پیشنهاد همکاری ×] │
|
||||
│ [+ افزودن موضوع] │
|
||||
│ │
|
||||
│ [💾 ذخیره تغییرات] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### ۴.۴ فرم مجوزها (جدید)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ ← بازگشت مدیریت مجوزها و نمادهای اعتماد │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ توضیح صفحه: [_______________________________] │
|
||||
│ │
|
||||
│ ── مجوزها ──────────────────────────────────────────── │
|
||||
│ ┌──────┬──────────────┬─────────────────┬────────────┐ │
|
||||
│ │ تصویر│ عنوان │ لینک │ عملیات │ │
|
||||
│ ├──────┼──────────────┼─────────────────┼────────────┤ │
|
||||
│ │ [🖼] │ [نماد اعتماد]│ [https://...] │ [🗑] [↕] │ │
|
||||
│ │ [🖼] │ [ساماندهی ] │ [https://...] │ [🗑] [↕] │ │
|
||||
│ │ [🖼] │ [مجوز کسب..] │ [https://...] │ [🗑] [↕] │ │
|
||||
│ └──────┴──────────────┴─────────────────┴────────────┘ │
|
||||
│ │
|
||||
│ [+ افزودن مجوز جدید] │
|
||||
│ │
|
||||
│ [💾 ذخیره تغییرات] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ۵. طراحی UI فرانت مشتری (FrontOffice)
|
||||
|
||||
### ۵.۱ صفحه مجوزها (جدید — `/licenses`)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ [Header / Navbar] │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 🏅 مجوزها و نمادهای اعتماد │
|
||||
│ توضیح کوتاه صفحه از CMS │
|
||||
│ │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ [تصویر] │ │ [تصویر] │ │ [تصویر] │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ نماد │ │ ساماندهی │ │ مجوز │ │
|
||||
│ │ اعتماد │ │ │ │ کسبوکار │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||
│ │
|
||||
│ (هر تصویر لینکدار — کلیک = باز شدن سایت مرجع) │
|
||||
│ │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ [Footer] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### ۵.۲ تغییرات سایر صفحات
|
||||
|
||||
- **لندینگ:** بدون تغییر ظاهری — فقط منبع داده از هاردکد به CMS تغییر میکنه
|
||||
- **درباره ما:** بدون تغییر ظاهری — کد سادهتر میشه
|
||||
- **تماس با ما:** بدون تغییر ظاهری — کد سادهتر میشه
|
||||
|
||||
---
|
||||
|
||||
## ۶. Migration Plan — مراحل اجرا
|
||||
|
||||
### فاز ۱: دیتابیس و Backend (CMS)
|
||||
|
||||
```
|
||||
مدت تخمینی: ۱ روز
|
||||
```
|
||||
|
||||
| # | تسک | جزئیات |
|
||||
|---|------|--------|
|
||||
| 1.1 | ایجاد Entityهای جدید | `SitePageSettings`, `SitePageImage` |
|
||||
| 1.2 | ایجاد EF Configuration | Indexes, relationships, JSON column |
|
||||
| 1.3 | نوشتن Migration | `SimplifySitePages` — ایجاد جدولهای جدید |
|
||||
| 1.4 | نوشتن Data Migration | انتقال داده از `SitePage`/`SitePageSection` به ساختار جدید |
|
||||
| 1.5 | Seed Data جدید | ۴ صفحه: landing, about, contact, licenses |
|
||||
| 1.6 | حذف Entityهای قدیمی | بعد از تأیید migration موفق |
|
||||
|
||||
### فاز ۲: Proto و gRPC Service
|
||||
|
||||
```
|
||||
مدت تخمینی: ۰.۵ روز
|
||||
```
|
||||
|
||||
| # | تسک | جزئیات |
|
||||
|---|------|--------|
|
||||
| 2.1 | بازنویسی `site_pages.proto` | ۵ RPC جدید (Get, Save, Image CRUD, List) |
|
||||
| 2.2 | بازنویسی gRPC Service | `SitePageSettingsGrpcService` |
|
||||
| 2.3 | نوشتن CQRS Handlers | ۵ handler جدید |
|
||||
| 2.4 | Validators | اعتبارسنجی SettingsJson بر اساس PageKey |
|
||||
|
||||
### فاز ۳: BackOffice (پنل ادمین)
|
||||
|
||||
```
|
||||
مدت تخمینی: ۱.۵ روز
|
||||
```
|
||||
|
||||
| # | تسک | جزئیات |
|
||||
|---|------|--------|
|
||||
| 3.1 | حذف UI قدیمی | ۵ فایل dialog + management page |
|
||||
| 3.2 | صفحه اصلی | `PageSettingsManagement.razor` — کارتهای ۴ صفحه |
|
||||
| 3.3 | فرم لندینگ | `LandingPageSettings.razor` — فرم با سکشنهای Steps/Features/Stats/FAQ/Testimonials/CTA |
|
||||
| 3.4 | فرم دربارهما | `AboutPageSettings.razor` — Vision/Mission + مدیریت Values & Team |
|
||||
| 3.5 | فرم تماس | `ContactPageSettings.razor` — فیلدهای ساده |
|
||||
| 3.6 | فرم مجوزها | `LicensesPageSettings.razor` — آپلود و مدیریت تصاویر مجوز |
|
||||
| 3.7 | سرویس BackOffice | `ISitePageSettingsService` + Implementation |
|
||||
|
||||
### فاز ۴: FrontOffice (سمت مشتری)
|
||||
|
||||
```
|
||||
مدت تخمینی: ۱ روز
|
||||
```
|
||||
|
||||
| # | تسک | جزئیات |
|
||||
|---|------|--------|
|
||||
| 4.1 | بروزرسانی `SitePageService` | سادهسازی — فقط `GetPageSettings` |
|
||||
| 4.2 | بروزرسانی `Index.razor` | خواندن Steps/Features/Stats/FAQ/Testimonials از CMS |
|
||||
| 4.3 | بروزرسانی `AboutUs.razor` | خواندن مستقیم فیلدها (بدون key-matching) |
|
||||
| 4.4 | بروزرسانی `ContactUs.razor` | خواندن مستقیم فیلدها (بدون JSON parsing) |
|
||||
| 4.5 | ایجاد `Licenses.razor` | 🆕 صفحه جدید مجوزها |
|
||||
| 4.6 | افزودن به Navigation | لینک مجوزها در Footer |
|
||||
|
||||
### فاز ۵: تست و Cleanup
|
||||
|
||||
```
|
||||
مدت تخمینی: ۰.۵ روز
|
||||
```
|
||||
|
||||
| # | تسک | جزئیات |
|
||||
|---|------|--------|
|
||||
| 5.1 | تست E2E | همه ۴ صفحه در FrontOffice |
|
||||
| 5.2 | تست ادمین | ویرایش همه ۴ صفحه از BackOffice |
|
||||
| 5.3 | حذف کدهای قدیمی | فایلهایی که دیگه استفاده نمیشن |
|
||||
| 5.4 | بروزرسانی مستندات | CHANGELOG, INDEX.md |
|
||||
|
||||
---
|
||||
|
||||
## ۷. مقایسه قبل و بعد
|
||||
|
||||
### کاهش پیچیدگی
|
||||
|
||||
| معیار | قبل | بعد | تغییر |
|
||||
|-------|------|------|--------|
|
||||
| RPCهای gRPC | 10 | 5 | -50% |
|
||||
| CQRS Handlers | 10 (22 file) | 5 (~12 file) | -45% |
|
||||
| Entityها | 2 (generic) | 2 (typed) | = |
|
||||
| BackOffice Dialogs | 4 generic | 4 specific | کیفیت↑ |
|
||||
| JSON خام در UI | ✅ بله | ❌ خیر | حذف |
|
||||
| خطای تایپ SectionKey | ✅ ممکن | ❌ غیرممکن | حذف |
|
||||
| لندینگ CMS-driven | ❌ هاردکد | ✅ CMS | بهبود |
|
||||
| صفحه مجوزها | ❌ ندارد | ✅ دارد | 🆕 |
|
||||
|
||||
### تجربه ادمین
|
||||
|
||||
| قبل | بعد |
|
||||
|------|------|
|
||||
| لیست صفحات → انتخاب → مدیریت سکشنها → ویرایش سکشن (4 مرحله) | ۴ کارت → فرم اختصاصی (2 مرحله) |
|
||||
| JSON خام برای اطلاعات تماس | فیلدهای مشخص (آدرس، تلفن، ایمیل) |
|
||||
| HTML Editor برای عنوان ساده | Text field ساده |
|
||||
| امکان ساخت صفحهای که فرانت نمیشناسه | فقط ۴ صفحه مشخص |
|
||||
|
||||
---
|
||||
|
||||
## ۸. ریسکها و ملاحظات
|
||||
|
||||
| ریسک | شدت | راهحل |
|
||||
|------|------|--------|
|
||||
| Data migration از ساختار قدیم | متوسط | Script migration دقیق + بکاپ قبل از اجرا |
|
||||
| Breaking change در Proto | بالا | نسخه جدید Proto NuGet + بروزرسانی هر ۳ پروژه همزمان |
|
||||
| تصاویر موجود (hero, section images) | کم | مسیرها در فایل سیستم ثابت میمونن — فقط reference DB تغییر میکنه |
|
||||
| Backward compatibility | کم | چون ساختار قبلی فقط ۲ صفحه فعال داشت، migration سادهست |
|
||||
|
||||
---
|
||||
|
||||
## ۹. فایلهای تأثیرپذیر (خلاصه)
|
||||
|
||||
### حذف (Delete)
|
||||
```
|
||||
CMS:
|
||||
- Domain/Entities/Content/SitePage.cs
|
||||
- Domain/Entities/Content/SitePageSection.cs
|
||||
- Application/Features/SitePages/* (22 files)
|
||||
- Infrastructure/Persistence/Configurations/SitePageConfiguration.cs
|
||||
- Infrastructure/Persistence/Configurations/SitePageSectionConfiguration.cs
|
||||
|
||||
BackOffice:
|
||||
- Pages/Content/SitePageManagement.razor + .cs
|
||||
- Pages/Content/CreateSitePageDialog.razor + .cs
|
||||
- Pages/Content/EditSitePageDialog.razor + .cs
|
||||
- Pages/Content/SitePageSectionsDialog.razor + .cs
|
||||
- Pages/Content/SitePageSectionEditDialog.razor + .cs
|
||||
```
|
||||
|
||||
### ایجاد (Create)
|
||||
```
|
||||
CMS:
|
||||
- Domain/Entities/Content/SitePageSettings.cs
|
||||
- Domain/Entities/Content/SitePageImage.cs
|
||||
- Application/Features/SitePageSettings/* (~12 files)
|
||||
- Infrastructure/Persistence/Configurations/SitePageSettingsConfiguration.cs
|
||||
- Infrastructure/Persistence/Configurations/SitePageImageConfiguration.cs
|
||||
|
||||
BackOffice:
|
||||
- Pages/Content/PageSettingsManagement.razor + .cs
|
||||
- Pages/Content/LandingPageSettings.razor + .cs
|
||||
- Pages/Content/AboutPageSettings.razor + .cs
|
||||
- Pages/Content/ContactPageSettings.razor + .cs
|
||||
- Pages/Content/LicensesPageSettings.razor + .cs
|
||||
|
||||
FrontOffice:
|
||||
- Pages/Licenses.razor + .cs
|
||||
|
||||
Proto:
|
||||
- site_pages.proto (rewrite)
|
||||
```
|
||||
|
||||
### تغییر (Modify)
|
||||
```
|
||||
CMS:
|
||||
- ApplicationDbContext.cs (DbSets)
|
||||
- SitePageSeedData.cs
|
||||
- SitePageGrpcService.cs
|
||||
|
||||
BackOffice:
|
||||
- Services/ISitePageService.cs → ISitePageSettingsService.cs
|
||||
- Services/SitePageService.cs → SitePageSettingsService.cs
|
||||
- NavMenu (routing)
|
||||
|
||||
FrontOffice:
|
||||
- Services/SitePageService.cs (simplify)
|
||||
- Pages/Index.razor + .cs (CMS-driven)
|
||||
- Pages/AboutUs.razor + .cs (simplify)
|
||||
- Pages/ContactUs.razor + .cs (simplify)
|
||||
- Shared/NavMenu or Footer (add Licenses link)
|
||||
- DI registration
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ۱۰. نتیجهگیری
|
||||
|
||||
این تغییر یک **سادهسازی معماری** هست که:
|
||||
|
||||
1. ✅ پیچیدگی غیرضروری رو حذف میکنه
|
||||
2. ✅ تجربه ادمین رو بهبود میده (فرمهای اختصاصی بهجای فرمهای عمومی)
|
||||
3. ✅ خطاهای انسانی رو کاهش میده (بدون JSON خام و SectionKey تایپی)
|
||||
4. ✅ لندینگ پیج رو CMS-driven میکنه
|
||||
5. ✅ صفحه مجوزها رو اضافه میکنه
|
||||
6. ✅ حجم کد رو ~۳۰٪ کاهش میده
|
||||
|
||||
> **مرحله بعد:** بعد از تأیید این طرح، شروع پیادهسازی از فاز ۱ (دیتابیس)
|
||||
+286
-3
@@ -772,6 +772,289 @@ catch (Exception ex)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2024-12-02
|
||||
**Version**: 1.0
|
||||
**Status**: ✅ Production Ready
|
||||
---
|
||||
|
||||
## 🆕 فاز ۲ — ZarinPal + PaymentTransaction (بهمن ۱۴۰۴)
|
||||
|
||||
### ۴. ZarinPalPaymentService (فعال)
|
||||
|
||||
**Purpose**: درگاه پرداخت مستقیم زرینپال — بدون PYMS واسط
|
||||
|
||||
**Configuration**:
|
||||
```json
|
||||
{
|
||||
"UseRealPaymentGateway": true,
|
||||
"PaymentProvider": "zarinpal",
|
||||
"ZarinPal": {
|
||||
"MerchantId": "6b098fc8-f490-47a1-aac3-1de1a1b84404",
|
||||
"UseSandbox": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**API Endpoints**:
|
||||
|
||||
#### InitiatePayment (درخواست پرداخت)
|
||||
```
|
||||
POST https://sandbox.zarinpal.com/pg/v4/payment/request.json
|
||||
{
|
||||
"merchant_id": "...",
|
||||
"amount": 100000,
|
||||
"description": "خرید پکیج طلایی",
|
||||
"callback_url": "https://cms.se.kbs1.ir/api/payment/callback",
|
||||
"metadata": { "mobile": "09123456789" }
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"data": {
|
||||
"authority": "A00000000000000000000000000123456",
|
||||
"code": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### VerifyPayment (تأیید پرداخت)
|
||||
```
|
||||
POST https://sandbox.zarinpal.com/pg/v4/payment/verify.json
|
||||
{
|
||||
"merchant_id": "...",
|
||||
"authority": "A00000000000000000000000000123456",
|
||||
"amount": 100000
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"data": {
|
||||
"code": 100,
|
||||
"ref_id": 123456789,
|
||||
"card_pan": "6037****1234",
|
||||
"card_hash": "...",
|
||||
"fee_type": "Merchant",
|
||||
"fee": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Sandbox URL**: `https://sandbox.zarinpal.com/pg/StartPay/{Authority}`
|
||||
**Production URL**: `https://zarinpal.com/pg/StartPay/{Authority}`
|
||||
|
||||
**PaymentVerificationResult (بروزشده)**:
|
||||
```csharp
|
||||
public class PaymentVerificationResult
|
||||
{
|
||||
public bool IsSuccess { get; set; }
|
||||
public string RefId { get; set; }
|
||||
public string? TrackingCode { get; set; }
|
||||
public decimal Amount { get; set; }
|
||||
public string? Message { get; set; }
|
||||
public string? CardPan { get; set; } // 🆕 شماره کارت ماسکشده
|
||||
public string? CardHash { get; set; } // 🆕 هش کارت
|
||||
public int? VerificationCode { get; set; } // 🆕 کد تأیید زرینپال
|
||||
}
|
||||
```
|
||||
|
||||
**Service Registration (بروزشده)**:
|
||||
```csharp
|
||||
var paymentProvider = configuration.GetValue<string>("PaymentProvider", "zarinpal");
|
||||
|
||||
if (paymentProvider?.ToLower() == "zarinpal")
|
||||
{
|
||||
services.AddHttpClient<IPaymentGatewayService, ZarinPalPaymentService>();
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### ۵. جدول PaymentTransaction (جداگانه از Transaction)
|
||||
|
||||
**Purpose**: ذخیره جزئیات سطح درگاه — جدا از Transaction entity اصلی
|
||||
|
||||
**Entity**: `Domain/Entities/Payment/PaymentTransaction.cs`
|
||||
|
||||
```csharp
|
||||
public class PaymentTransaction : BaseEntity
|
||||
{
|
||||
public string GatewayProvider { get; set; } // "zarinpal"
|
||||
public string MerchantId { get; set; }
|
||||
public long Amount { get; set; }
|
||||
public string? CallbackUrl { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? Mobile { get; set; }
|
||||
public long? UserId { get; set; }
|
||||
|
||||
// Request
|
||||
public int? RequestStatusCode { get; set; } // 100 = success
|
||||
public string? RequestStatusMessage { get; set; }
|
||||
public string? Authority { get; set; } // ZarinPal authority
|
||||
|
||||
// Verification
|
||||
public bool PaymentStatus { get; set; }
|
||||
public int? VerificationStatusCode { get; set; }
|
||||
public string? VerificationStatusMessage { get; set; }
|
||||
public string? CardHash { get; set; }
|
||||
public string? CardPan { get; set; } // ماسکشده: 6037****1234
|
||||
public long? RefId { get; set; }
|
||||
|
||||
// Relations
|
||||
public long? TransactionId { get; set; }
|
||||
public long? OrderId { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
**Indexes**: Authority, GatewayProvider, UserId, TransactionId, RefId
|
||||
**Migration**: `AddPaymentTransactionTable`
|
||||
|
||||
**جریان کامل پرداخت**:
|
||||
```
|
||||
1. PlaceOrderCommandHandler → InitiatePayment → PaymentTransaction ایجاد (PaymentStatus=false)
|
||||
2. کاربر → ریدایرکت به ZarinPal
|
||||
3. ZarinPal → Callback به /api/payment/callback
|
||||
4. PaymentCallbackController → VerifyPayment → PaymentTransaction بروز (PaymentStatus=true, CardPan, RefId)
|
||||
5. CompleteOrderPaymentCommandHandler → Transaction + Order + Wallet بروز
|
||||
```
|
||||
|
||||
**مصرفکنندهها**:
|
||||
| سرویس | عملیات |
|
||||
|--------|--------|
|
||||
| `PlaceOrderCommandHandler` | ایجاد PaymentTransaction بعد از InitiatePayment |
|
||||
| `PaymentCallbackController` | بروزرسانی بعد از VerifyPayment |
|
||||
| `TransactionsService` | ایجاد/بروزرسانی در CustomerPaymentRequest/Verification |
|
||||
| `PackageService` | ایجاد/بروزرسانی در CustomerPurchasePackage/Verify |
|
||||
|
||||
---
|
||||
|
||||
### ۶. فیکس نمایش وضعیت پرداخت سفارشات تخفیفی
|
||||
|
||||
**مشکل**: `DiscountOrderService.GetOrderById/GetUserOrders` از `Mapster.Adapt<>()` استفاده میکرد. نامها متفاوت بودند:
|
||||
- Domain: `PaymentStatus` (enum: Success=0, Reject=1, Pending=2)
|
||||
- Proto: `payment_completed` (bool)
|
||||
|
||||
Mapster نمیتونست enum رو به bool مپ کنه → همیشه `false` (در انتظار پرداخت).
|
||||
|
||||
**رفع**: جایگزینی Mapster با مپینگ دستی:
|
||||
```csharp
|
||||
PaymentCompleted = result.PaymentStatus == DomainEnums.PaymentStatus.Success
|
||||
```
|
||||
|
||||
### ۷. فیکس DeliveryStatus بعد از پرداخت
|
||||
|
||||
**مشکل**: فروشگاه تخفیفی بعد از پرداخت موفق، `DeliveryStatus = InTransit` (ارسال شده) ست میکرد. ولی فروشگاه عادی `Pending` نگه میداشت.
|
||||
|
||||
**رفع**: هر دو handler (`CompleteOrderPaymentCommandHandler` و `PlaceOrderCommandHandler`) به `DeliveryStatus.Pending` تغییر کردند — ادمین باید وضعیت پستی رو مشخص کنه.
|
||||
|
||||
---
|
||||
|
||||
### ۸. فیکس ZarinPal Callback URL (اسفند ۱۴۰۴)
|
||||
|
||||
**مشکل**: `PurchasePackageCommandHandler` از `yourdomain.com` به صورت hardcode استفاده میکرد.
|
||||
|
||||
**رفع**: خواندن از `IConfiguration`:
|
||||
```csharp
|
||||
var cmsBaseUrl = _configuration["CmsBaseUrl"];
|
||||
var frontOfficeBaseUrl = _configuration["FrontOfficeBaseUrl"];
|
||||
```
|
||||
|
||||
**appsettings.json (Production)**:
|
||||
```json
|
||||
{
|
||||
"CmsBaseUrl": "https://cms.kbs1.ir",
|
||||
"FrontOfficeBaseUrl": "https://foursat.kbs1.ir"
|
||||
}
|
||||
```
|
||||
**appsettings.json (Staging)**:
|
||||
```json
|
||||
{
|
||||
"CmsBaseUrl": "https://cms.se.kbs1.ir",
|
||||
"FrontOfficeBaseUrl": "https://foursat.se.kbs1.ir"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### ۹. اجبار تخفیف ۱۰۰٪ (اسفند ۱۴۰۴)
|
||||
|
||||
**تغییر بیزینسی**: کاربر دیگه نمیتونه درصد تخفیف رو انتخاب کنه — **همیشه حداکثر تخفیف** (MaxDiscountPercent) اعمال میشه.
|
||||
|
||||
**تغییرات CMS (بکند):**
|
||||
- `PlaceOrderCommandHandler`: همیشه `MaxDiscountPercent` محصول استفاده میشه
|
||||
- فیلد `requested_discount_percent` از request نادیده گرفته میشه
|
||||
|
||||
**تغییرات FrontOffice:**
|
||||
- حذف `MudSlider` و `MudNumericField` از `Checkout.razor`
|
||||
- حذف کامل بخش نمایش موجودی تخفیفی
|
||||
- Badge محصولات: نمایش درصد واقعی (مثلاً "۳۰٪ تخفیف") بجای "۱۰۰٪ تخفیفی"
|
||||
|
||||
---
|
||||
|
||||
### ۱۰. نمایش مالیات (VAT) در Checkout (اسفند ۱۴۰۴)
|
||||
|
||||
جدول خلاصه مالی کامل اضافه شد:
|
||||
|
||||
| فیلد | توضیح |
|
||||
|------|-------|
|
||||
| جمع کل | قبل از تخفیف |
|
||||
| تخفیف | مجموع DiscountAmount |
|
||||
| مبلغ پس از تخفیف | بعد از کسر تخفیف |
|
||||
| مالیات ۹٪ | `VatCalculator` روی مبلغ درگاه |
|
||||
| **مبلغ قابل پرداخت** | مبلغ درگاه + مالیات |
|
||||
|
||||
---
|
||||
|
||||
### ۱۱. سرویس Expire سفارشات معلق (اسفند ۱۴۰۴)
|
||||
|
||||
**فایل**: `ExpirePendingOrdersService.cs` — `BackgroundService`
|
||||
|
||||
| تنظیم | مقدار |
|
||||
|-------|-------|
|
||||
| بررسی | هر ۵ دقیقه |
|
||||
| انقضا | بعد از ۳۰ دقیقه `PaymentStatus=Pending` |
|
||||
| عملیات | `PaymentStatus=Reject`, `DeliveryStatus=Cancelled`, آزادسازی رزرو انبار |
|
||||
| ساعت | `DateTime.Now` (نه UtcNow — DB از ساعت محلی استفاده میکنه) |
|
||||
|
||||
---
|
||||
|
||||
### ۱۲. فیکس DeliveryStatus مپینگ (اسفند ۱۴۰۴)
|
||||
|
||||
**مشکل**: Domain `DeliveryStatus.Pending(1)` مستقیم cast به Proto `PROCESSING(1)` میشد → سفارشات failed نشون میدادن "در حال پردازش".
|
||||
|
||||
**راهحل**: `MapDeliveryStatus()` و `MapPaymentStatus()` اضافه شدن:
|
||||
|
||||
| Domain | Proto |
|
||||
|--------|-------|
|
||||
| `PaymentStatus.Success(0)` | `COMPLETED(1)` |
|
||||
| `PaymentStatus.Reject(1)` | `FAILED(2)` |
|
||||
| `PaymentStatus.Pending(2)` | `PENDING(0)` |
|
||||
| `DeliveryStatus.None(0)` | `PENDING(0)` |
|
||||
| `DeliveryStatus.Pending(1)` | `PROCESSING(1)` |
|
||||
| `DeliveryStatus.InTransit(2)` | `SHIPPED(2)` |
|
||||
| `DeliveryStatus.Delivered(3)` | `DELIVERED(3)` |
|
||||
| `DeliveryStatus.Returned/Cancelled(4,5)` | `CANCELLED(4)` |
|
||||
|
||||
+ وقتی پرداخت ناموفقه: `order.DeliveryStatus = DeliveryStatus.Cancelled`
|
||||
|
||||
---
|
||||
|
||||
### ۱۳. استقرار Production (اسفند ۱۴۰۴)
|
||||
|
||||
**Merge از `kub-stage` به `production`** — هر ۳ ریپو:
|
||||
- CMS: ۳ conflict حل شد (workflow, Dockerfile, appsettings)
|
||||
- FrontOffice: ۱ conflict (workflow)
|
||||
- BackOffice: ۲ conflict (workflow, Dockerfile)
|
||||
|
||||
**Migration دیتابیس Production**: ۷ migration اعمال شد:
|
||||
1. `AddDiscountProductImages`
|
||||
2. `AddInventorySystem`
|
||||
3. `u19` + `u20`
|
||||
4. `AddBlogAndContentEntities`
|
||||
5. `RemoveImagePathMaxLength`
|
||||
6. `AddPaymentTransactionTable`
|
||||
|
||||
**ZarinPal در Production**: `UseSandbox: true` → "درگاه فعال نمیباشد" (عمدی)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: February 17, 2026
|
||||
**Version**: 3.0
|
||||
**Proto Version**: 0.0.179
|
||||
**Status**: ✅ ZarinPal Active (Sandbox) + PaymentTransaction + ExpireOrders + Production Deployed
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 🔧 راهنمای CI/CD Pipeline — Gitea Actions + K3s
|
||||
|
||||
> آخرین بروزرسانی: February 11, 2026
|
||||
> آخرین بروزرسانی: February 17, 2026
|
||||
|
||||
---
|
||||
|
||||
@@ -230,6 +230,110 @@ DOCKER_BUILDKIT=0 docker build --network host -t ... .
|
||||
|
||||
---
|
||||
|
||||
### مشکل ۸: `COPY libs/` fails in Docker build (BackOffice)
|
||||
|
||||
**خطا:**
|
||||
```
|
||||
COPY failed: file not found in build context: stat libs/: file does not exist
|
||||
```
|
||||
|
||||
**علت:** Dockerfile خط `COPY ["libs/", "libs/"]` داشت ولی `libs/` خارج از Docker build context (`src/`) بود. قبلاً BFF DLLها استفاده میشدن، ولی حالا از NuGet package مستقیم استفاده میشه.
|
||||
|
||||
**راهحل:**
|
||||
1. حذف `COPY ["libs/", "libs/"]` از Dockerfile
|
||||
2. تغییر `ProjectReference` به `PackageReference` در csproj:
|
||||
```xml
|
||||
<!-- قبل -->
|
||||
<ProjectReference Include="../../../CMS/src/CMSMicroservice.Protobuf/CMSMicroservice.Protobuf.csproj" />
|
||||
<!-- بعد -->
|
||||
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="0.0.178" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### مشکل ۹: ProjectReference خارج از Docker context (FrontOffice/BackOffice)
|
||||
|
||||
**خطا:**
|
||||
```
|
||||
error CS0246: The type or namespace name 'CustomerAddressModel' could not be found
|
||||
```
|
||||
|
||||
**علت:** csproj از `ProjectReference Include="../../../CMS/src/CMSMicroservice.Protobuf/..."` استفاده میکرد. در Docker build context فقط `src/` موجوده → CMS قابل دسترسی نیست.
|
||||
|
||||
**راهحل:**
|
||||
1. بامپ نسخه پروتوباف (`0.0.177` → `0.0.178`)
|
||||
2. `dotnet pack -c Release` و push به Nexus
|
||||
3. تغییر هر دو پروژه (FrontOffice + BackOffice) به `PackageReference`
|
||||
|
||||
```bash
|
||||
# Pack & Push
|
||||
cd CMS/src/CMSMicroservice.Protobuf
|
||||
dotnet pack -c Release
|
||||
dotnet nuget push bin/Release/Foursat.CMSMicroservice.Protobuf.0.0.178.nupkg \
|
||||
--source http://194.5.195.53:32081/repository/foursat-nuget-hosted/index.json \
|
||||
--api-key admin:87zH26nbqT --skip-duplicate
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### مشکل ۱۰: `nginx:alpine` TLS handshake timeout
|
||||
|
||||
**خطا:**
|
||||
```
|
||||
Get "https://registry-1.docker.io/v2/": net/http: TLS handshake timeout
|
||||
```
|
||||
|
||||
**علت:** Dockerfile خط `FROM nginx:alpine` مستقیم از Docker Hub پول میکرد ولی سرور به Docker Hub دسترسی نداره.
|
||||
|
||||
**راهحل:** تغییر به رجیستری لوکال:
|
||||
```dockerfile
|
||||
# قبل
|
||||
FROM nginx:alpine AS final
|
||||
# بعد
|
||||
FROM 194.5.195.53:32082/nginx:alpine AS final
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### مشکل ۱۱: SERVER_PASSWORD secret missing → Permission denied
|
||||
|
||||
**خطا:**
|
||||
```
|
||||
Permission denied, please try again.
|
||||
```
|
||||
|
||||
**علت:** سکرت `SERVER_PASSWORD` در ریپو Gitea تنظیم نشده بود. Pipeline از `sshpass -e` با `${{ secrets.SERVER_PASSWORD }}` برای SSH استفاده میکنه.
|
||||
|
||||
**راهحل:** اضافه کردن سکرت از طریق Gitea API:
|
||||
```bash
|
||||
curl -sk -u "admin:87zH26nbqT" -X PUT \
|
||||
"https://git.se.kbs1.ir/api/v1/repos/admin/BackOffice/actions/secrets/SERVER_PASSWORD" \
|
||||
-H "Content-Type: application/json" -d '{"data":"87zH26nbqT"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### مشکل ۱۲: CMS ingress 502 — backend-protocol: GRPC
|
||||
|
||||
**خطا:** `https://cms.se.kbs1.ir/` → 502 Bad Gateway
|
||||
|
||||
**علت:** CMS ingress annotation `backend-protocol: GRPC` داشت + Kestrel فقط `Http2`. مرورگر HTTP/1.1 میفرسته → nginx نمیتونه به gRPC backend فوروارد کنه.
|
||||
|
||||
**راهحل (دو تغییر):**
|
||||
1. Kestrel protocol → `Http1AndHttp2` (هم gRPC هم REST):
|
||||
```bash
|
||||
kubectl set env deployment/cms Kestrel__EndpointDefaults__Protocols=Http1AndHttp2
|
||||
```
|
||||
2. حذف GRPC annotations از ingress:
|
||||
```bash
|
||||
kubectl annotate ingress cms-ingress nginx.ingress.kubernetes.io/backend-protocol-
|
||||
kubectl annotate ingress cms-ingress nginx.ingress.kubernetes.io/grpc-backend-
|
||||
```
|
||||
|
||||
> ⚠️ FrontOffice از gRPC-Web استفاده میکنه که روی HTTP/1.1 هم کار میکنه.
|
||||
|
||||
---
|
||||
|
||||
## 🔄 تغییرات prod-deploy (قدیم → جدید)
|
||||
|
||||
| مورد | قدیم (prod-deploy) | جدید |
|
||||
@@ -290,7 +394,15 @@ ubuntu-22.04 → docker://docker.gitea.com/runner-images:ubuntu-22.04
|
||||
| Secret | استفاده |
|
||||
|--------|---------|
|
||||
| `REGISTRY_PASSWORD` | پسورد Docker registry (admin) |
|
||||
| `SERVER_PASSWORD` | پسورد SSH سرور (root) |
|
||||
| `SERVER_PASSWORD` | پسورد SSH سرور (root) — ⚠️ باید در هر ۳ ریپو ست بشه |
|
||||
|
||||
> **نکته:** اگر `SERVER_PASSWORD` ست نباشه، مرحله Deploy با `Permission denied` فیل میشه.
|
||||
> با API اضافه کنید:
|
||||
> ```bash
|
||||
> curl -sk -u "admin:PASSWORD" -X PUT \
|
||||
> "https://git.se.kbs1.ir/api/v1/repos/admin/REPO/actions/secrets/SERVER_PASSWORD" \
|
||||
> -H "Content-Type: application/json" -d '{"data":"PASSWORD"}'
|
||||
> ```
|
||||
|
||||
---
|
||||
|
||||
@@ -416,3 +528,151 @@ jobs:
|
||||
kubectl rollout status deployment/<service> --timeout=180s
|
||||
"
|
||||
```
|
||||
---
|
||||
|
||||
## 🐛 باگ بحرانی: Cross-Deployment — Push به Production ریدیپلوی Staging (اسفند ۱۴۰۴)
|
||||
|
||||
### علائم:
|
||||
- Push به برنچ `production` → هم production و هم staging ریدیپلوی شدند
|
||||
- CMS staging pod بعد از push ریستارت شد
|
||||
- Runner log: **۲ تسک CMS** بجای ۱ تسک اجرا شد
|
||||
|
||||
### علت ریشهای:
|
||||
Gitea Act Runner **تمام فایلهای workflow** داخل `.gitea/workflows/` برنچ push شده رو اجرا میکنه — حتی اگه `on.push.branches` برنچ دیگهای باشه. وقتی production push شد، `kub-deploy.yml` (trigger: `kub-stage`) هم اجرا شد و ایمیج `admin/cms:latest` رو با کد production ساخت → staging از `latest` pull کرد → **staging با DB production بالا اومد!**
|
||||
|
||||
### راهحل:
|
||||
حذف workflowهای staging از برنچ production (هر ۳ ریپو):
|
||||
```bash
|
||||
git rm .gitea/workflows/kub-deploy.yml .gitea/workflows/cms-stage.yml # CMS
|
||||
git rm .gitea/workflows/fo-stage.yml .gitea/workflows/kub-deploy.yml # FrontOffice
|
||||
git rm .gitea/workflows/bo-stage.yml .gitea/workflows/kub-deploy.yml # BackOffice
|
||||
```
|
||||
|
||||
> ⚠️ **قانون طلایی:** هر برنچ فقط workflow مربوط به خودش رو داشته باشه.
|
||||
|
||||
---
|
||||
|
||||
## 🐛 مشکل ۱۳: Production deploy ایمیج pull نمیشد
|
||||
|
||||
**علت:** Production K8s از `git.foursat.afrino.co/admin/cms:prod` pull میکرد، ولی CI ایمیج رو به `194.5.195.53:30080` push میکرد.
|
||||
|
||||
**راهحل:**
|
||||
1. اضافه کردن `194.5.195.53:30080` به `/etc/rancher/k3s/registries.yaml` پروداکشن + ریاستارت K3s
|
||||
2. آپدیت deployment image: `kubectl set image deployment/cms cms=194.5.195.53:30080/admin/cms:prod`
|
||||
3. فیکس `prod-deploy.yml`: `K8S_SSH_PASSWORD` → `SERVER_PASSWORD`, `rollout restart` → `set image :sha`
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Production Workflow Template (فعلی)
|
||||
|
||||
```yaml
|
||||
name: Build and Deploy to Production
|
||||
on:
|
||||
push:
|
||||
branches: [production]
|
||||
env:
|
||||
REGISTRY: 194.5.195.53:30080
|
||||
IMAGE_NAME: admin/<service>
|
||||
K8S_SERVER: 45.149.79.127
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: 194.5.195.53:32082/docker-sshpass:latest
|
||||
options: --privileged
|
||||
steps:
|
||||
# ... (Start Docker, Checkout, Login — مشابه staging)
|
||||
- name: Build Docker Image
|
||||
run: |
|
||||
DOCKER_BUILDKIT=0 docker build --network host \
|
||||
-t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \
|
||||
-t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:prod .
|
||||
- name: Push to Registry
|
||||
run: |
|
||||
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
|
||||
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:prod
|
||||
- name: Deploy to Production
|
||||
run: |
|
||||
export SSHPASS="${{ secrets.SERVER_PASSWORD }}"
|
||||
sshpass -e ssh -o StrictHostKeyChecking=no root@${{ env.K8S_SERVER }} "
|
||||
kubectl set image deployment/<svc> <svc>=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
|
||||
kubectl rollout status deployment/<svc> --timeout=300s
|
||||
"
|
||||
```
|
||||
|
||||
> تفاوت staging vs production: staging = tag `latest` + `rollout restart` | production = tag `sha` + `set image`
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ مشخصات دو محیط
|
||||
|
||||
| | Staging | Production |
|
||||
|--|---------|------------|
|
||||
| **سرور** | `194.5.195.53` | `45.149.79.127` |
|
||||
| **DB** | `mssql-svc@Foursat` | `45.149.79.127,31433@KBS` |
|
||||
| **Registry** | `194.5.195.53:30080` (local) | همان staging registry |
|
||||
| **Image Tags** | `:latest` | `:prod` + `:sha` |
|
||||
| **Branch** | `kub-stage` | `production` |
|
||||
| **Domains** | `*.se.kbs1.ir` | `*.kbs1.ir` |
|
||||
|
||||
---
|
||||
|
||||
## 🐛 مشکل ۱۴: K8S_SERVER اشتباه در prod-deploy.yml (CMS + BackOffice)
|
||||
|
||||
**تاریخ:** February 17, 2026
|
||||
**علت:** `K8S_SERVER` در `prod-deploy.yml` CMS و BackOffice هنوز `194.5.195.53` (staging) بود بجای `45.149.79.127` (production).
|
||||
**عارضه:** `kubectl set image` به سرور staging ارسال میشد — deployment production آپدیت نمیشد.
|
||||
|
||||
**فایلهای فیکس شده:**
|
||||
- `CMS/.gitea/workflows/prod-deploy.yml` — `K8S_SERVER: 194.5.195.53` → `45.149.79.127`
|
||||
- `BackOffice/.gitea/workflows/prod-deploy.yml` — `K8S_SERVER: 194.5.195.53` → `45.149.79.127`
|
||||
- FrontOffice قبلاً درست بود ✅
|
||||
|
||||
**فیکس اضافی:** هر دو workflow از `kubectl rollout restart` به `kubectl set image` تغییر کردن تا ایمیج SHA-tagged واقعاً set بشه.
|
||||
|
||||
---
|
||||
|
||||
## 🐛 مشکل ۱۵: نبود appsettings.Production.json — URLهای staging روی production
|
||||
|
||||
**تاریخ:** February 17, 2026
|
||||
**علت:** هیچکدوم از ۳ پروژه `appsettings.Production.json` نداشتن. از طرفی `ASPNETCORE_ENVIRONMENT=Production` ست بود → fallback به `appsettings.json` (که URLهای staging داشت).
|
||||
|
||||
**عارضهها:**
|
||||
- CMS: `CmsBaseUrl=cms.se.kbs1.ir` → ZarinPal callback به staging برمیگشت
|
||||
- CMS: `FrontOfficeBaseUrl=foursat.se.kbs1.ir` → redirect بعد از پرداخت به staging میرفت
|
||||
- FrontOffice: `GwUrl=localhost:32846` → gRPC به هیچجا وصل نمیشد
|
||||
- BackOffice: `GwUrl=localhost:32847` → gRPC به هیچجا وصل نمیشد
|
||||
|
||||
**فایلهای ساخته شده:**
|
||||
|
||||
| پروژه | فایل | محتوای کلیدی |
|
||||
|--------|------|-------------|
|
||||
| CMS | `src/CMSMicroservice.WebApi/appsettings.Production.json` | `CmsBaseUrl=cms.kbs1.ir`, `FrontOfficeBaseUrl=kbs1.ir`, `DB=KBS`, `ZarinPal.UseSandbox=false` |
|
||||
| FrontOffice | `src/FrontOffice.Main/appsettings.Production.json` | `GwUrl=cms.kbs1.ir` |
|
||||
| BackOffice | `src/BackOffice/wwwroot/appsettings.Production.json` | `GwUrl=cms.kbs1.ir` |
|
||||
|
||||
> ⚠️ **نکته:** CMS فایل `appsettings.Production.json` در `.gitignore` هست (`**/ appsettings.Production.json`). با `git add -f` ترک شد. بعد از هر تغییر باید دوباره force add بشه.
|
||||
|
||||
---
|
||||
|
||||
## 🐛 مشکل ۱۶: nginx image path اشتباه در BackOffice Dockerfile (production branch)
|
||||
|
||||
**تاریخ:** February 17, 2026
|
||||
**علت:** Dockerfile روی برنچ `production` از `194.5.195.53:32082/library/nginx:alpine` استفاده میکرد که در رجیستری وجود نداشت. روی `kub-stage` قبلاً فیکس شده بود ولی merge به production این خط رو override کرده بود.
|
||||
|
||||
**ارور CI:**
|
||||
```
|
||||
Step 9/14 : FROM 194.5.195.53:32082/library/nginx:alpine AS final
|
||||
manifest for 194.5.195.53:32082/library/nginx:alpine not found: manifest unknown
|
||||
```
|
||||
|
||||
**رفع:**
|
||||
```dockerfile
|
||||
# قبل (اشتباه)
|
||||
FROM 194.5.195.53:32082/library/nginx:alpine AS final
|
||||
|
||||
# بعد (صحیح)
|
||||
FROM 194.5.195.53:32082/nginx:alpine AS final
|
||||
```
|
||||
|
||||
**نکته:** این فیکس مستقیماً روی برنچ `production` انجام و push شد (کامیت `743403e`).
|
||||
@@ -2,12 +2,23 @@
|
||||
|
||||
## 📌 Server Information
|
||||
|
||||
### سرور Staging
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Server IP | `194.5.195.53` |
|
||||
| SSH Access | `root / 87zH26nbqT` |
|
||||
| Kubernetes | K3s with local-path storage |
|
||||
| ServiceLB | K3s svclb (built-in) |
|
||||
| Domains | `*.se.kbs1.ir` |
|
||||
|
||||
### سرور Production
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Server IP | `45.149.79.127` |
|
||||
| SSH Access | `root / 87zH26nbqT` |
|
||||
| Kubernetes | K3s with local-path storage |
|
||||
| ServiceLB | K3s svclb (built-in) |
|
||||
| Domains | `*.kbs1.ir` |
|
||||
|
||||
---
|
||||
|
||||
@@ -22,13 +33,25 @@
|
||||
| PVC | `mssql-pvc` (10Gi) |
|
||||
|
||||
### Databases:
|
||||
|
||||
#### Staging (194.5.195.53):
|
||||
- `gitea` - Gitea metadata
|
||||
- `Foursat` - Application database
|
||||
- `Foursat` - Application database (staging)
|
||||
- `Hosein` - Application database
|
||||
|
||||
### Connection String:
|
||||
#### Production (45.149.79.127):
|
||||
- `KBS` - Application database (production)
|
||||
|
||||
### Connection Strings:
|
||||
```
|
||||
# Staging
|
||||
Server=mssql-svc,1433;Database=Foursat;User Id=sa;Password=87zH26nbqT;TrustServerCertificate=true
|
||||
|
||||
# Production (appsettings.Production.json)
|
||||
Server=mssql-svc;Database=KBS;User Id=sa;Password=YourStrong@Passw0rd;TrustServerCertificate=True
|
||||
|
||||
# Production (env override — قدیمی، از بیرون cluster)
|
||||
# Server=45.149.79.127,31433;Database=KBS;User Id=sa;Password=YourStrong@Passw0rd;TrustServerCertificate=true
|
||||
```
|
||||
|
||||
---
|
||||
@@ -170,11 +193,13 @@ kubectl logs -f deploy/nexus
|
||||
|
||||
## 🔐 Credentials Summary
|
||||
|
||||
| Service | Username | Password |
|
||||
|---------|----------|----------|
|
||||
| Server SSH | root | 87zH26nbqT |
|
||||
| MSSQL | sa | 87zH26nbqT |
|
||||
| Gitea | admin | (set during install) |
|
||||
| Service | Username | Password | Server |
|
||||
|---------|----------|----------|--------|
|
||||
| Staging SSH | root | 87zH26nbqT | 194.5.195.53 |
|
||||
| Production SSH | root | 87zH26nbqT | 45.149.79.127 |
|
||||
| Staging MSSQL | sa | 87zH26nbqT | mssql-svc:1433 |
|
||||
| Production MSSQL | sa | YourStrong@Passw0rd | 45.149.79.127:31433 |
|
||||
| Gitea | admin | (set during install) | 194.5.195.53 |
|
||||
|
||||
---
|
||||
|
||||
@@ -218,7 +243,42 @@ curl -s http://194.5.195.53:32082/v2/_catalog
|
||||
|
||||
---
|
||||
|
||||
*Last Updated: 2025-01-18*
|
||||
---
|
||||
|
||||
## 🔧 CMS Ingress & Kestrel Protocol (بروزشده: February 2026)
|
||||
|
||||
### تنظیمات Kestrel:
|
||||
| متغیر | مقدار قبلی | مقدار فعلی |
|
||||
|--------|-----------|------------|
|
||||
| `Kestrel__EndpointDefaults__Protocols` | `Http2` | `Http1AndHttp2` |
|
||||
|
||||
> با `Http1AndHttp2` هم gRPC (HTTP/2) و هم REST/HTTP (HTTP/1.1) روی یک پورت کار میکنن.
|
||||
|
||||
### تنظیمات Ingress CMS:
|
||||
| Annotation | مقدار قبلی | مقدار فعلی |
|
||||
|-----------|-----------|------------|
|
||||
| `backend-protocol` | `GRPC` | حذف شد |
|
||||
| `grpc-backend` | `true` | حذف شد |
|
||||
| `ssl-redirect` | `true` | `true` |
|
||||
| `cert-manager.io/cluster-issuer` | `letsencrypt-prod` | `letsencrypt-prod` |
|
||||
|
||||
> ⚠️ FrontOffice از gRPC-Web استفاده میکنه که روی HTTP/1.1 هم کار میکنه — نیازی به annotation GRPC نیست.
|
||||
|
||||
### NuGet Package (Proto):
|
||||
| پکیج | نسخه | رجیستری |
|
||||
|-------|-------|--------|
|
||||
| `Foursat.CMSMicroservice.Protobuf` | `0.0.179` | Nexus (`foursat-nuget-hosted`) |
|
||||
|
||||
### Gitea Secrets (هر ۳ ریپو):
|
||||
| Secret | CMS | FrontOffice | BackOffice |
|
||||
|--------|-----|-------------|------------|
|
||||
| `REGISTRY_PASSWORD` | ✅ | ✅ | ✅ |
|
||||
| `SERVER_PASSWORD` | ✅ | ✅ | ✅ |
|
||||
| `KUBECONFIG` | ✅ | ✅ | ✅ |
|
||||
|
||||
---
|
||||
|
||||
*Last Updated: February 17, 2026*
|
||||
|
||||
|
||||
---
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
# Server Mirrors Configuration
|
||||
|
||||
**Server:** 194.5.195.53
|
||||
**Date:** 2026-01-29
|
||||
**Staging Server:** 194.5.195.53
|
||||
**Production Server:** 45.149.79.127
|
||||
**Date:** 2026-02-17
|
||||
|
||||
---
|
||||
|
||||
## 1. Docker Registry Mirrors (K3s)
|
||||
|
||||
فایل: `/etc/rancher/k3s/registries.yaml`
|
||||
### Staging — `/etc/rancher/k3s/registries.yaml` (194.5.195.53)
|
||||
|
||||
### ترتیب Pull کردن ایمیجها:
|
||||
1. **Nexus** (194.5.195.53:32082) - لوکال
|
||||
@@ -66,6 +67,55 @@ configs:
|
||||
systemctl restart k3s
|
||||
```
|
||||
|
||||
### Production — `/etc/rancher/k3s/registries.yaml` (45.149.79.127)
|
||||
|
||||
Production server از staging registry ها pull میکنه:
|
||||
|
||||
```yaml
|
||||
mirrors:
|
||||
"docker.io":
|
||||
endpoint:
|
||||
- "http://194.5.195.53:32082"
|
||||
- "https://docker.arvancloud.ir"
|
||||
- "https://registry-1.docker.io"
|
||||
"194.5.195.53:32082":
|
||||
endpoint:
|
||||
- "http://194.5.195.53:32082"
|
||||
"194.5.195.53:30080":
|
||||
endpoint:
|
||||
- "http://194.5.195.53:30080"
|
||||
"git.foursat.afrino.co":
|
||||
endpoint:
|
||||
- "https://git.foursat.afrino.co"
|
||||
"git.se.kbs1.ir":
|
||||
endpoint:
|
||||
- "https://git.se.kbs1.ir"
|
||||
|
||||
configs:
|
||||
"194.5.195.53:32082":
|
||||
auth:
|
||||
username: admin
|
||||
password: 87zH26nbqT
|
||||
"194.5.195.53:30080":
|
||||
auth:
|
||||
username: admin
|
||||
password: 87zH26nbqT
|
||||
"git.foursat.afrino.co":
|
||||
auth:
|
||||
username: admin
|
||||
password: 87zH26nbqT
|
||||
tls:
|
||||
insecure_skip_verify: true
|
||||
"git.se.kbs1.ir":
|
||||
auth:
|
||||
username: admin
|
||||
password: 87zH26nbqT
|
||||
tls:
|
||||
insecure_skip_verify: true
|
||||
```
|
||||
|
||||
> ⚠️ Production از `194.5.195.53:30080` (Gitea container registry) برای pull ایمیجهای CI/CD استفاده میکنه.
|
||||
|
||||
---
|
||||
|
||||
## 2. APT Package Mirrors (Ubuntu 24.04 Noble)
|
||||
|
||||
Reference in New Issue
Block a user