docs: consolidate 53 files into 15 structured files in 3 folders

- business/ (5): club-commission, payment, ecommerce, membership, content
- technical/ (5): cms-arch, ui, deployment, migration, api
- overview/ (5): flowcharts, index, changelog, glossary, roadmap
- Removed all old folders: backoffice, cms, deployment, docs, frontoffice, migration, ui-modernization, business (old)
- Updated internal links with relative folder paths
This commit is contained in:
masoodafar-web
2026-02-18 22:29:37 +03:30
parent d7c32dab2a
commit efff5e9cd5
71 changed files with 3632 additions and 32267 deletions
+262
View File
@@ -0,0 +1,262 @@
# ⚙️ معماری CMS و زیرساخت فنی
> **منابع ادغام‌شده:** `CMS-README.md`, `ICURRENTUSERSERVICE-IMPLEMENTATION.md`, `FILE-MANAGEMENT-ARCHITECTURE.md`, `FRONTOFFICE-CMS-API-COMPATIBILITY.md`, `BFF-REMOVAL-PLAN.md`, `system-constants.md`
> **آخرین بروزرسانی:** اسفند ۱۴۰۴
---
## ۱. Stack فنی
| لایه | تکنولوژی | نسخه |
|------|----------|------|
| **Runtime** | .NET | 9.0 |
| **ORM** | Entity Framework Core | 9.0 |
| **Communication** | gRPC (Protobuf) | v3 |
| **Pattern** | CQRS + MediatR | — |
| **Database** | SQL Server (MSSQL) | 2022-CU16 |
| **Job Scheduler** | Hangfire | — |
| **Auth** | JWT Bearer + Identity | — |
| **API Gateway** | حذف‌شده (Direct gRPC) | — |
---
## ۲. معماری لایه‌ای CMS
```
┌──────────────────────────────────────────────────────┐
│ Presentation Layer │
│ FrontOffice (Blazor Server) ←─gRPC─→ CMS │
│ BackOffice (Blazor WASM) ←─gRPC─→ CMS │
├──────────────────────────────────────────────────────┤
│ Application Layer │
│ Commands (MediatR IRequest<T>) │
│ Queries (MediatR IRequest<T>) │
│ Validators (FluentValidation) │
│ Handlers (IRequestHandler<TReq, TRes>) │
├──────────────────────────────────────────────────────┤
│ Domain Layer │
│ Entities, Enums, Value Objects │
│ Domain Events, Interfaces │
├──────────────────────────────────────────────────────┤
│ Infrastructure Layer │
│ EF Core DbContext (CMSDbContext) │
│ Repositories, External Services │
│ Hangfire Jobs, File Storage │
├──────────────────────────────────────────────────────┤
│ Database │
│ SQL Server — Schema: [CMS] │
└──────────────────────────────────────────────────────┘
```
---
## ۳. CQRS با MediatR
### ۳.۱ ساختار فولدرها
```
CMS/src/
├── CMSMicroservice/
│ ├── Features/
│ │ ├── Products/
│ │ │ ├── Commands/
│ │ │ │ ├── CreateProductCommand.cs
│ │ │ │ └── CreateProductCommandHandler.cs
│ │ │ ├── Queries/
│ │ │ │ ├── GetProductsQuery.cs
│ │ │ │ └── GetProductsQueryHandler.cs
│ │ │ └── Validators/
│ │ │ └── CreateProductCommandValidator.cs
│ │ ├── Orders/
│ │ ├── Users/
│ │ ├── Club/
│ │ ├── Payment/
│ │ └── Blog/
│ ├── Services/
│ │ ├── gRPC/ ← gRPC service implementations
│ │ ├── Background/ ← Hangfire jobs
│ │ └── External/ ← ZarinPal, Kavenegar, Daya, Chatika
│ ├── Infrastructure/
│ │ ├── Persistence/ ← DbContext, Migrations
│ │ └── Identity/ ← JWT, Claims, ICurrentUserService
│ └── Protos/ ← .proto files
```
### ۳.۲ مثال Command
```csharp
// Command
public record CreateProductCommand(
string Name, string Description, decimal Price,
Guid CategoryId, string ImageUrl
) : IRequest<Guid>;
// Handler
public class CreateProductCommandHandler
: IRequestHandler<CreateProductCommand, Guid>
{
private readonly CMSDbContext _db;
public async Task<Guid> Handle(
CreateProductCommand request, CancellationToken ct)
{
var product = new Product { /* map fields */ };
_db.Products.Add(product);
// Auto-create inventory record
_db.Inventories.Add(new Inventory { ProductId = product.Id });
await _db.SaveChangesAsync(ct);
return product.Id;
}
}
```
---
## ۴. gRPC Services
### ۴.۱ لیست سرویس‌ها
| سرویس | proto | متدهای اصلی |
|--------|-------|-------------|
| `ProductService` | product.proto | GetProducts, GetProduct, Create, Update, Delete |
| `OrderService` | order.proto | CreateOrder, GetOrders, UpdateStatus |
| `UserService` | user.proto | Register, Login, GetProfile, UpdateProfile |
| `ClubService` | club.proto | GetNetworkTree, GetBalance, AcceptContract |
| `PaymentService` | payment.proto | CreatePayment, VerifyPayment |
| `BlogService` | blog.proto | GetPosts, GetPost, Create, Update |
| `InventoryService` | inventory.proto | GetInventory, UpdateStock |
| `FileService` | file.proto | Upload, Download, Delete |
| `SitePageService` | sitepage.proto | GetPage, SaveSettings |
| `CategoryService` | category.proto | GetCategories, Create, Update |
| `SystemConfigService` | config.proto | GetConfig, UpdateConfig |
### ۴.۲ PaginationState (مشترک)
```protobuf
message PaginationState {
int32 skip = 1;
int32 take = 2;
}
```
**Namespace صحیح:**
```csharp
using CMSMicroservice.Protobuf.Protos.PaginationState;
// ⚠️ نه: CMSMicroservice.Protobuf.Protos.PublicMessages.PaginationState
```
---
## ۵. Database
### ۵.۱ اتصال
```
Staging: Server=194.5.195.53; Database=FourSatCMS; Schema=CMS
Production: Server=45.149.79.127; Database=FourSatCMS; Schema=CMS
Engine: MSSQL 2022-CU16, Collation=Arabic_CI_AS
```
### ۵.۲ جداول اصلی
| جدول | توضیح | رکوردهای تقریبی |
|------|--------|----------------|
| Users | کاربران | ~5K |
| Products | محصولات | ~200 |
| Categories | دسته‌بندی‌ها | ~30 |
| Orders | سفارشات | ~2K |
| Inventories | موجودی | ~200 |
| BlogPosts | پست‌های بلاگ | ~50 |
| SitePages | صفحات سایت | ~10 |
| UserClubMemberships | عضویت باشگاه | ~500 |
| UserContracts | قراردادها | ~500 |
| NetworkNodes | نودهای درخت باینری | ~500 |
| Transactions | تراکنش‌ها | ~5K |
| SystemConfigurations | تنظیمات | ~30 |
| ChatMessages | پیام‌های چاتیکا | ~1K |
### ۵.۳ Stored Procedures
| SP | کاربرد |
|----|--------|
| `SP_GetNetworkTree` | بازگشتی — استخراج درخت باینری |
| `sp_CalculateWeeklyBalances` | محاسبه بالانس هفتگی هر عضو |
| `sp_CalculateWeeklyCommissionPool` | توزیع Pool هفتگی |
---
## ۶. حذف BFF / Gateway
### ۶.۱ قبل vs بعد
```
قبل:
FrontOffice → BFF (REST) → CMS (gRPC)
BackOffice → BFF (REST) → CMS (gRPC)
بعد (فعلی):
FrontOffice → CMS (gRPC مستقیم)
BackOffice → CMS (gRPC مستقیم)
مزایا:
✅ حذف لایه واسط → کاهش latency
✅ حذف maintenance اضافی
✅ Type-safe از proto تا UI
✅ کاهش ۱ سرویس در deployment
```
### ۶.۲ سازگاری API
```
FrontOffice Service Layer:
• ProductService.cs → gRPC client wrapper
• OrderService.cs → gRPC client wrapper
• UserService.cs → gRPC client wrapper
هر Service:
• Constructor: inject GrpcChannel
• Methods: wrap gRPC calls + map to DTOs
• Error handling: try/catch RpcException
```
---
## ۷. Hangfire Jobs
| Job | فرکانس | کاربرد |
|-----|---------|--------|
| `DayaLoanProcessorJob` | هر ۱۵ دقیقه | پردازش درخواست‌های وام |
| `WeeklyCommissionJob` | هفتگی (شنبه ۰۰:۰۰) | محاسبه و توزیع کمیسیون |
| `ChatikaJob` | هر ۵ دقیقه | همگام‌سازی پیام‌های AI |
| `InventorySyncJob` | هر ساعت | ایجاد رکوردهای موجودی گمشده |
---
## ۸. پیکربندی
### ۸.۱ appsettings.json ساختار
```json
{
"ConnectionStrings": {
"DefaultConnection": "Server=...;Database=FourSatCMS"
},
"Jwt": {
"Secret": "***",
"Issuer": "FourSat",
"ExpiryMinutes": 1440
},
"Grpc": {
"CmsUrl": "https://localhost:5001"
},
"Hangfire": {
"DashboardPath": "/hangfire",
"WorkerCount": 4
},
"Kavenegar": { "ApiKey": "***" },
"ZarinPal": { "MerchantId": "***" },
"DayaLoan": { "UseMock": true }
}
```
+252
View File
@@ -0,0 +1,252 @@
# 🖥️ BackOffice و FrontOffice — معماری UI
> **منابع ادغام‌شده:** `BACKOFFICE-ARCHITECTURE.md`, `BACKOFFICE-STORE-UNIFICATION.md`, `UI-MODERNIZATION-PLAN.md`, `UI-UNIFICATION-PLAN.md`, `PHASE-1-COMPLETE.md`, `PHASE-3-COMPLETE.md`, `PRODUCT-IMAGES-SQUARE.md`
> **آخرین بروزرسانی:** اسفند ۱۴۰۴
---
## ۱. Stack مشترک
| آیتم | BackOffice | FrontOffice |
|------|-----------|-------------|
| **Framework** | Blazor WebAssembly | Blazor Server |
| **UI Library** | MudBlazor v8 | MudBlazor v8 |
| **ارتباط با CMS** | gRPC (مستقیم) | gRPC (مستقیم) |
| **احراز هویت** | JWT Bearer | JWT Bearer |
| **Hosting** | Static files (nginx) | Kestrel server |
| **Target** | ادمین‌ها | کاربران نهایی |
---
## ۲. معماری BackOffice
### ۲.۱ ساختار فولدرها
```
BackOffice/src/BackOffice/
├── Layout/
│ ├── MainLayout.razor ← Sidebar + AppBar
│ └── NavMenu.razor ← منوی ناوبری
├── Pages/
│ ├── Dashboard/
│ ├── Products/
│ │ ├── ProductList.razor
│ │ ├── ProductList.razor.cs ← code-behind
│ │ ├── ProductEdit.razor
│ │ └── ProductEdit.razor.cs
│ ├── Orders/
│ ├── Users/
│ ├── Club/
│ ├── Blog/
│ ├── Inventory/
│ ├── SitePages/
│ │ └── {PageType}Editor.razor ← Shopify-style typed editors
│ └── Settings/
├── Services/
│ ├── ProductService.cs ← gRPC client wrapper
│ ├── OrderService.cs
│ ├── UserService.cs
│ └── ...
├── Shared/
│ ├── AppImage.razor ← کامپوننت تصویر مشترک (1:1)
│ ├── ConfirmDialog.razor
│ └── LoadingIndicator.razor
└── wwwroot/
```
### ۲.۲ الگوی Code-Behind
```csharp
// ProductList.razor.cs
public partial class ProductList : ComponentBase
{
[Inject] private IProductService ProductService { get; set; }
[Inject] private ISnackbar Snackbar { get; set; }
private List<ProductDto> _products = new();
private bool _isLoading = true;
protected override async Task OnInitializedAsync()
{
await LoadProducts();
}
private async Task LoadProducts()
{
_isLoading = true;
try {
_products = await ProductService.GetProductsAsync();
} catch (RpcException ex) {
Snackbar.Add($"خطا: {ex.Status.Detail}", Severity.Error);
}
_isLoading = false;
}
}
```
---
## ۳. معماری FrontOffice
### ۳.۱ ساختار فولدرها
```
FrontOffice/src/FrontOffice/
├── Layout/
│ ├── MainLayout.razor ← Header + Footer
│ └── AuthLayout.razor ← Login/Register pages
├── Pages/
│ ├── Home.razor
│ ├── Landing.razor ← انیمیشن‌دار
│ ├── Store/
│ │ ├── Products.razor ← Lazy loading (12 per page)
│ │ ├── Products.razor.cs
│ │ ├── ProductDetail.razor
│ │ └── Cart.razor
│ ├── DiscountStore/
│ │ ├── Products.razor ← Lazy loading + hybrid payment
│ │ ├── Products.razor.cs
│ │ └── Cart.razor
│ ├── Club/
│ │ ├── Dashboard.razor ← داشبورد باشگاه
│ │ ├── NetworkTree.razor ← نمای درخت
│ │ └── Contract.razor ← امضای قرارداد
│ ├── Blog/
│ ├── Auth/
│ │ ├── Login.razor
│ │ └── Register.razor
│ └── About.razor, Contact.razor, ...
├── Services/
│ ├── ProductService.cs ← با GetProductsPagedAsync
│ ├── ClubService.cs
│ └── ...
└── Shared/
├── AppImage.razor
├── ProductCard.razor ← مشترک بین Store و DiscountStore
└── LoadMoreButton.razor
```
---
## ۴. UI Modernization — فازها
### ۴.۱ نقشه فازها
| فاز | عنوان | شامل | وضعیت |
|------|--------|-------|--------|
| **Phase 1** | پایه MudBlazor v8 | ارتقا MudBlazor، Layout اصلی | ✅ 100% |
| **Phase 2** | صفحات محصول | Card grid، فیلتر، جزئیات | ✅ 100% |
| **Phase 3** | فروشگاه تخفیفی | UI DiscountStore + hybrid pay | ✅ 100% |
| **Phase 4** | باشگاه | داشبورد، درخت، قرارداد | ✅ 100% |
| **Phase 5** | محتوا | بلاگ، Site Pages | ✅ 100% |
| **Phase 6** | نهایی‌سازی | تصاویر 1:1، lazy load، landing fix | ✅ 100% |
| **Phase 7** | موبایل | Responsive، PWA، Bottom nav | ⬜ 0% |
### ۴.۲ جزئیات Phase 1-6 (تکمیل‌شده)
```
✅ Phase 1: ارتقا MudBlazor v7→v8, AppBar, Drawer, Theme
✅ Phase 2: ProductCard (1:1), CategoryFilter, MudGrid
✅ Phase 3: DiscountStore pages, HybridPayment component
✅ Phase 4: NetworkTree visualization, Contract modal
✅ Phase 5: Blog pagination, SitePageEditors (Shopify)
✅ Phase 6: AppImage shared, lazy load, counter animation fix
```
---
## ۵. یکپارچه‌سازی فروشگاه (Store Unification)
### ۵.۱ کامپوننت‌های مشترک
```razor
@* AppImage.razor — مشترک بین همه پروژه‌ها *@
<MudImage
Src="@ImageUrl"
Alt="@Alt"
ObjectFit="ObjectFit.Cover"
Style="aspect-ratio: 1/1; width: 100%;"
loading="lazy" />
@code {
[Parameter] public string? ImageUrl { get; set; }
[Parameter] public string Alt { get; set; } = "";
}
```
### ۵.۲ تغییرات BackOffice
| صفحه | قبل | بعد |
|------|------|------|
| Product List | `<img>` ساده | `<AppImage>` مربعی |
| Product Edit | فرم ساده | MudForm + Validation |
| Inventory | بدون Autocomplete | با MudAutocomplete |
| SitePages | جدول Settings | Typed Editors |
---
## ۶. تم و استایل
### ۶.۱ MudBlazor Theme
```csharp
var theme = new MudTheme {
PaletteLight = new PaletteLight {
Primary = "#1976D2",
Secondary = "#FF9800",
Background = "#F5F5F5",
Surface = "#FFFFFF",
AppbarBackground = "#1976D2"
},
Typography = new Typography {
Default = new DefaultTypography {
FontFamily = new[] { "Vazirmatn", "Roboto", "sans-serif" }
}
}
};
```
### ۶.۲ RTL Support
```css
/* wwwroot/css/app.css */
body { direction: rtl; font-family: 'Vazirmatn', sans-serif; }
.mud-drawer--open-responsive-lg-left { right: 0; left: auto; }
```
---
## ۷. ناوبری Auth-Aware (FrontOffice)
```csharp
// MainLayout.razor.cs
@inject AuthenticationStateProvider AuthState
var authState = await AuthState.GetAuthenticationStateAsync();
var user = authState.User;
if (user.Identity?.IsAuthenticated == true) {
var isClub = user.HasClaim("IsClubMember", "true");
// Show: Dashboard, Store, DiscountStore (if club), Profile
} else {
// Show: Landing, Store, Register, Login
}
```
---
## ۸. خلاصه وضعیت
| ماژول | وضعیت | درصد |
|-------|--------|------|
| BackOffice MudBlazor v8 | ✅ | 100% |
| FrontOffice MudBlazor v8 | ✅ | 100% |
| Code-behind pattern | ✅ | 100% |
| AppImage component | ✅ | 100% |
| Lazy loading | ✅ | 100% |
| Store Unification | ✅ | 100% |
| SitePage Typed Editors | ✅ | 100% |
| RTL Support | ✅ | 100% |
| Mobile Responsive (Phase 7) | ⬜ | 0% |
| Dark Mode | ⬜ | 0% |
| PWA | ⬜ | 0% |
+340
View File
@@ -0,0 +1,340 @@
# 🚀 استقرار، CI/CD و زیرساخت
> **منابع ادغام‌شده:** `CICD-PIPELINE-GUIDE.md`, `DEPLOYMENT-README.md`, `INFRASTRUCTURE-GUIDE.md`, `INGRESS-NGINX-WARNING.md`, `OFFLINE-DEPLOYMENT-GUIDE.md`, `SERVER-MIRRORS-CONFIG.md`
> **آخرین بروزرسانی:** اسفند ۱۴۰۴
---
## ۱. سرورها
| سرور | IP | نقش | منابع |
|------|-----|------|--------|
| **Staging** | 194.5.195.53 | توسعه + تست | 4 CPU, 8GB RAM |
| **Production** | 45.149.79.127 | محیط نهایی | 4 CPU, 16GB RAM |
| **Git** | git.se.kbs1.ir | Gitea (مخازن کد) | — |
| **Registry** | داخلی | Docker Registry / Nexus | — |
---
## ۲. Docker و Container
### ۲.۱ سرویس‌ها
```yaml
# docker-compose.yml (production)
services:
cms:
image: foursat/cms:latest
ports: ["5001:5001"] # gRPC
environment:
- ConnectionStrings__Default=Server=db;Database=FourSatCMS
- ASPNETCORE_ENVIRONMENT=Production
depends_on: [db]
backoffice:
image: foursat/backoffice:latest
ports: ["5002:80"] # Static Blazor WASM
frontoffice:
image: foursat/frontoffice:latest
ports: ["5003:5003"] # Blazor Server
db:
image: mcr.microsoft.com/mssql/server:2022-CU16-ubuntu-22.04
ports: ["1433:1433"]
volumes: ["sqldata:/var/opt/mssql"]
nexus: # NuGet + Docker registry
image: sonatype/nexus3
ports: ["8081:8081"]
volumes:
sqldata:
```
### ۲.۲ Dockerfile (CMS)
```dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app
EXPOSE 5001
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY ["CMSMicroservice/CMSMicroservice.csproj", "CMSMicroservice/"]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM base AS final
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "CMSMicroservice.dll"]
```
---
## ۳. Kubernetes
### ۳.۱ Manifests ساختار
```
deployment/k8s-manifests/
├── cms-deployment.yaml
├── cms-service.yaml
├── backoffice-deployment.yaml
├── backoffice-service.yaml
├── frontoffice-deployment.yaml
├── frontoffice-service.yaml
├── db-statefulset.yaml
├── db-service.yaml
├── ingress.yaml
├── configmap.yaml
└── secrets.yaml
```
### ۳.۲ مثال Deployment
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: cms
namespace: foursat
spec:
replicas: 2
selector:
matchLabels:
app: cms
template:
spec:
containers:
- name: cms
image: foursat/cms:latest
ports:
- containerPort: 5001
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
grpc:
port: 5001
initialDelaySeconds: 15
readinessProbe:
grpc:
port: 5001
```
### ۳.۳ Ingress
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: foursat-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
spec:
rules:
- host: foursat.ir
http:
paths:
- path: /
backend:
service:
name: frontoffice
port: { number: 5003 }
- path: /admin
backend:
service:
name: backoffice
port: { number: 80 }
```
> ⚠️ **هشدار:** Ingress-nginx نسخه‌های قبل از 1.9.0 مشکل امنیتی CVE-2023-5044 دارند. حتماً بروزرسانی کنید.
---
## ۴. CI/CD Pipeline
### ۴.۱ Gitea Actions Workflow
```yaml
name: Build and Deploy
on:
push:
branches: [kub-stage, production]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Restore
run: dotnet restore
- name: Build
run: dotnet build --no-restore -c Release
- name: Test
run: dotnet test --no-build -c Release
- name: Docker Build & Push
run: |
docker build -t $REGISTRY/foursat/cms:${{ github.sha }} .
docker push $REGISTRY/foursat/cms:${{ github.sha }}
- name: Deploy to K8s
if: github.ref == 'refs/heads/production'
run: |
kubectl set image deployment/cms cms=$REGISTRY/foursat/cms:${{ github.sha }}
```
### ۴.۲ شاخه‌ها
| شاخه | محیط | Deploy |
|------|------|--------|
| `kub-stage` | Staging (194.5.195.53) | Auto |
| `production` | Production (45.149.79.127) | Manual trigger |
| `main` | — | Development only |
---
## ۵. استقرار آفلاین (Offline Deployment)
### ۵.۱ فلوی آماده‌سازی
```
سرور اینترنت‌دار:
1. pull-base-images.sh → دانلود Docker images
2. cache-nuget-packages.sh → دانلود NuGet packages
3. save-images.sh → ذخیره تصاویر به tar
4. بسته‌بندی همه فایل‌ها
انتقال فیزیکی (USB/HDD):
tar files + nuget packages + k8s manifests
سرور آفلاین:
1. load-images.sh → بارگذاری تصاویر
2. setup-nexus-complete.sh → راه‌اندازی Nexus (NuGet proxy)
3. build-all-offline.sh → بیلد با Nexus محلی
4. k8s-deploy.sh → استقرار در Kubernetes
```
### ۵.۲ اسکریپت‌های کلیدی
| اسکریپت | کاربرد |
|----------|--------|
| `pull-base-images.sh` | دانلود ۱۵+ Docker image پایه |
| `save-images.sh` | Export به tar (4-8 GB) |
| `load-images.sh` | Import از tar به Docker |
| `cache-nuget-packages.sh` | دانلود NuGet offline |
| `setup-nexus-complete.sh` | راه‌اندازی NuGet proxy |
| `build-all-offline.sh` | بیلد بدون اینترنت |
| `k8s-deploy.sh` | Deploy تمام سرویس‌ها |
| `k8s-health-check.sh` | بررسی سلامت سرویس‌ها |
---
## ۶. Nexus Repository Manager
### ۶.۱ نقش
```
Nexus (داخلی):
├── NuGet proxy → cache.nuget.org packages
├── NuGet hosted → بسته‌های proto داخلی
├── Docker proxy → cache Docker Hub images
└── Docker hosted → تصاویر داخلی FourSat
```
### ۶.۲ NuGet.config
```xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nexus" value="http://localhost:8081/repository/nuget-group/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>
```
---
## ۷. Mirror و Cache
### ۷.۱ Docker Mirror
```json
// /etc/docker/daemon.json
{
"registry-mirrors": [
"https://mirror.gcr.io",
"https://docker.arvancloud.ir"
],
"insecure-registries": [
"localhost:8082"
]
}
```
### ۷.۲ NuGet Mirror
```
Primary: nuget.org
Fallback: Nexus local proxy
Proto packages: BaGet (internal) at http://localhost:5555
```
---
## ۸. Proto Packages (NuGet)
### ۸.۱ فلوی بسته‌بندی
```
CMS/src/Protos/*.proto
pack-protos.sh → dotnet pack → .nupkg
push to BaGet/Nexus
BackOffice + FrontOffice → dotnet restore → مصرف proto
```
### ۸.۲ نام بسته
```xml
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="1.0.x" />
```
---
## ۹. مانیتورینگ و Health Check
```bash
# k8s-health-check.sh
kubectl get pods -n foursat
kubectl top pods -n foursat
kubectl logs deployment/cms -n foursat --tail=50
# تست سرویس‌ها
grpcurl -plaintext localhost:5001 list # لیست سرویس‌ها
grpcurl -plaintext localhost:5001 grpc.health.v1.Health/Check # Health
curl http://localhost:5002/index.html # BackOffice
curl http://localhost:5003/ # FrontOffice
```
+230
View File
@@ -0,0 +1,230 @@
# 🔄 مهاجرت داده، BFF و Gateway
> **منابع ادغام‌شده:** `BACKOFFICE-BFF-MIGRATION.md`, `customer-facing-capabilities-codex.md`, `DATA-TABLE-MAPPINGS.md`, `DATAMIGRATION-README.md`, `FRONTOFFICE-TO-CMS-MIGRATION.md`, `GATEWAY-REMOVAL-MIGRATION-PLAN.md`, `MIGRATION-PROGRESS.md`
> **آخرین بروزرسانی:** اسفند ۱۴۰۴
---
## ۱. تاریخچه مهاجرت‌ها
```
Timeline:
▸ فاز ۱: FrontOffice REST → CMS gRPC (مستقیم)
▸ فاز ۲: BackOffice REST → CMS gRPC (مستقیم)
▸ فاز ۳: حذف BFF/Gateway
▸ فاز ۴: حذف API Gateway (Ocelot)
▸ فاز ۵: یکپارچه‌سازی Proto packages
▸ فاز ۶: Data migration از سیستم قدیم
```
---
## ۲. حذف BFF (Backend-for-Frontend)
### ۲.۱ قبل
```
FrontOffice ──HTTP/REST──→ BFF ──gRPC──→ CMS
BackOffice ──HTTP/REST──→ BFF ──gRPC──→ CMS
BFF مسئولیت‌ها:
• تبدیل REST↔gRPC
• Aggregation
• Auth proxy
• Rate limiting
```
### ۲.۲ بعد (فعلی)
```
FrontOffice ──gRPC──→ CMS (مستقیم)
BackOffice ──gRPC──→ CMS (مستقیم)
مزایا:
✅ حذف ۱ سرویس از deployment
✅ کاهش ~50ms latency per request
✅ Type-safety از proto تا UI
✅ ساده‌سازی debug و logging
✅ کاهش maintenance cost
```
### ۲.۳ مراحل مهاجرت
```
مرحله ۱: ایجاد gRPC client wrappers در FrontOffice
ProductService.cs → _client.GetProductsAsync(request)
OrderService.cs → _client.GetOrdersAsync(request)
...
مرحله ۲: جایگزینی HttpClient با GrpcChannel
services.AddGrpcClient<ProductServiceClient>(o => {
o.Address = new Uri(config["Grpc:CmsUrl"]);
});
مرحله ۳: حذف BFF project
- حذف BFF از solution
- حذف BFF از docker-compose
- حذف BFF از K8s manifests
مرحله ۴: تست end-to-end
- تست هر صفحه FrontOffice
- تست هر صفحه BackOffice
- Performance benchmark
```
---
## ۳. حذف API Gateway (Ocelot)
### ۳.۱ قبل
```
Client → nginx → Ocelot Gateway → { CMS, BFF, FileService }
URL routing, rate limiting, auth
```
### ۳.۲ بعد
```
Client → nginx → Ingress → { CMS, BackOffice, FrontOffice }
Path-based routing in Ingress
```
### ۳.۳ دلایل حذف
```
✅ Ocelot maintenance burden → حذف
✅ K8s Ingress → routing بومی
✅ Let's Encrypt → TLS بومی
✅ gRPC → type-safe بدون نیاز به gateway
```
---
## ۴. FrontOffice to CMS Migration
### ۴.۱ Service Mapping
| FrontOffice Service | BFF Endpoint (حذف‌شده) | CMS gRPC Service |
|--------------------|-----------------------|-------------------|
| `ProductService` | `GET /api/products` | `ProductService.GetProducts` |
| `OrderService` | `POST /api/orders` | `OrderService.CreateOrder` |
| `UserService` | `POST /api/auth/login` | `UserService.Login` |
| `ClubService` | `GET /api/club/tree` | `ClubService.GetNetworkTree` |
| `BlogService` | `GET /api/blog/posts` | `BlogService.GetPosts` |
| `PaymentService` | `POST /api/payment/create` | `PaymentService.CreatePayment` |
| `FileService` | `POST /api/files/upload` | `FileService.Upload` |
| `SitePageService` | `GET /api/pages/{type}` | `SitePageService.GetPage` |
### ۴.۲ DTO Mapping
```
BFF DTOs (حذف‌شده) → Proto Messages (فعلی)
ProductDto → ProductMessage
OrderDto → OrderMessage
UserDto → UserMessage
Proto-generated classes مستقیم در UI استفاده می‌شوند
یا به local DTOs map می‌شوند (برای UI-specific fields)
```
---
## ۵. Data Migration (سیستم قدیم → جدید)
### ۵.۱ پروژه DataMigration
```
DataMigration/
├── FourSat.DataMigration/ ← Console app
│ ├── Program.cs
│ ├── Migrators/
│ │ ├── UserMigrator.cs
│ │ ├── ProductMigrator.cs
│ │ ├── OrderMigrator.cs
│ │ └── ClubMigrator.cs
│ └── Mappings/
│ └── TableMappings.cs
└── FourSat.GeographySeeder/ ← Seed geography data
├── Program.cs
└── Data/
├── provinces.json
└── cities.json
```
### ۵.۲ Data Table Mappings
| جدول مبدأ (قدیم) | جدول مقصد (CMS) | نکات |
|------------------|-----------------|------|
| `dbo.Users` | `CMS.Users` | PhoneNumber as primary identifier |
| `dbo.Products` | `CMS.Products` | ImageUrl migration needed |
| `dbo.Orders` | `CMS.Orders` | Status enum remapping |
| `dbo.Categories` | `CMS.Categories` | Hierarchical → ParentId |
| `dbo.NetworkTree` | `CMS.NetworkNodes` | Binary tree reconstruction |
| `dbo.Wallets` | `CMS.UserWalletBalances` | ۳ wallet types split |
| `dbo.Transactions` | `CMS.Transactions` | Type enum remapping |
| `dbo.Memberships` | `CMS.UserClubMemberships` | + Contract creation |
### ۵.۳ SQL Scripts مهاجرت
| اسکریپت | کاربرد |
|----------|--------|
| `MigrateUsersToClubMembership.sql` | انتقال همه کاربران |
| `MigrateSpecificUsersToClubMembership.sql` | انتقال انتخابی |
| `ChargeUserWallets.sql` | شارژ اولیه کیف‌پول‌ها |
| `AddIsActiveToUserClubFeatures.sql` | افزودن فیلد IsActive |
| `SeedSitePages.sql` | داده اولیه صفحات سایت |
| `SystemConfigurations.sql` | مقادیر پیش‌فرض تنظیمات |
| `populate-weekly-commission-pools.sql` | داده تاریخی Pool |
| `update_products_price_10_percent.sql` | افزایش قیمت ۱۰% |
---
## ۶. Geography Seeder
```
FourSat.GeographySeeder:
• ۳۱ استان
• ~۱۲۰۰ شهر
• منبع: دیتای رسمی تقسیمات کشوری
• فرمت: JSON → EF Core Seed
استفاده:
dotnet run --project FourSat.GeographySeeder
```
---
## ۷. Customer-Facing Capabilities Codex
### ۷.۱ خلاصه (بزرگ‌ترین سند — ۵,۳۰۰ خط)
این سند شامل مستندسازی کامل تمام قابلیت‌های کاربرمحور سیستم است:
| بخش | محتوا |
|------|--------|
| **User Journey** | فلوی کامل از ثبت‌نام تا خرید |
| **Store Features** | لیست محصول، فیلتر، سبد، پرداخت |
| **Club Features** | عضویت، درخت، کمیسیون، قرارداد |
| **Content** | بلاگ، صفحات، SEO |
| **Admin Features** | مدیریت محصول، سفارش، کاربر |
| **Integration** | Chatika، ZarinPal، Kavenegar، Daya |
| **Mobile** | Responsive، PWA (planned) |
---
## ۸. وضعیت مهاجرت
| مهاجرت | وضعیت | درصد |
|--------|--------|------|
| FrontOffice BFF → gRPC | ✅ | 100% |
| BackOffice BFF → gRPC | ✅ | 100% |
| API Gateway حذف | ✅ | 100% |
| Data Migration (Users) | ✅ | 100% |
| Data Migration (Products) | ✅ | 100% |
| Data Migration (Orders) | ✅ | 100% |
| Data Migration (Club/Network) | ✅ | 100% |
| Geography Seeder | ✅ | 100% |
| Proto package unification | ✅ | 100% |
+329
View File
@@ -0,0 +1,329 @@
# 🔌 API، Protobuf و یکپارچه‌سازی خارجی
> **منابع ادغام‌شده:** `FRONTOFFICE-CMS-API-COMPATIBILITY.md`, `REMAINING-TASKS.md`, `chatika-integration.md`, `payment-gateway.md`, `club-feature-management-services.md`
> **آخرین بروزرسانی:** اسفند ۱۴۰۴
---
## ۱. معماری ارتباطات
```
┌──────────────────────────────────────────────────────────────────┐
│ External Services │
│ ┌─────────┐ ┌──────────┐ ┌─────────┐ ┌─────────┐ │
│ │ ZarinPal│ │ Kavenegar│ │ DayaLoan│ │ Chatika │ │
│ │ (IPG) │ │ (SMS) │ │ (Loan) │ │ (AI) │ │
│ └────┬────┘ └────┬─────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │ │
│ ┌────▼───────────▼────────────▼────────────▼────┐ │
│ │ CMS Microservice │ │
│ │ (gRPC Server + Hangfire + EF Core) │ │
│ └────────────────┬───────────────────────────────┘ │
│ │ gRPC (Protobuf v3) │
│ ┌───────────┼───────────┐ │
│ ┌────▼────┐ ┌────▼────┐ │
│ │BackOffice│ │FrontOffice│ │
│ │(Blazor │ │(Blazor │ │
│ │ WASM) │ │ Server) │ │
│ └─────────┘ └──────────┘ │
└──────────────────────────────────────────────────────────────────┘
```
---
## ۲. gRPC Proto Definitions
### ۲.۱ لیست کامل سرویس‌ها
```protobuf
// ===== product.proto =====
service ProductService {
rpc GetProducts (GetProductsRequest) returns (GetProductsResponse);
rpc GetProductById (GetProductByIdRequest) returns (ProductMessage);
rpc CreateProduct (CreateProductRequest) returns (CreateProductResponse);
rpc UpdateProduct (UpdateProductRequest) returns (UpdateProductResponse);
rpc DeleteProduct (DeleteProductRequest) returns (Empty);
rpc GetProductsPaged (GetProductsPagedRequest) returns (GetProductsPagedResponse);
}
// ===== order.proto =====
service OrderService {
rpc CreateOrder (CreateOrderRequest) returns (CreateOrderResponse);
rpc GetOrders (GetOrdersRequest) returns (GetOrdersResponse);
rpc GetOrderById (GetOrderByIdRequest) returns (OrderMessage);
rpc UpdateOrderStatus (UpdateOrderStatusRequest) returns (Empty);
}
// ===== user.proto =====
service UserService {
rpc Register (RegisterRequest) returns (AuthResponse);
rpc Login (LoginRequest) returns (AuthResponse);
rpc GetProfile (GetProfileRequest) returns (UserProfileMessage);
rpc UpdateProfile (UpdateProfileRequest) returns (Empty);
rpc SendOtp (SendOtpRequest) returns (SendOtpResponse);
rpc VerifyOtp (VerifyOtpRequest) returns (VerifyOtpResponse);
}
// ===== club.proto =====
service ClubService {
rpc GetNetworkTree (GetNetworkTreeRequest) returns (NetworkTreeResponse);
rpc GetBalance (GetBalanceRequest) returns (BalanceResponse);
rpc ReadContract (ReadContractRequest) returns (ContractResponse);
rpc RequestContractOtp (RequestOtpRequest) returns (OtpResponse);
rpc VerifyContractOtp (VerifyOtpRequest) returns (VerifyOtpResponse);
rpc AcceptContract (AcceptContractRequest) returns (AcceptContractResponse);
rpc GetClubFeatures (GetFeaturesRequest) returns (FeaturesResponse);
}
// ===== payment.proto =====
service PaymentService {
rpc CreatePayment (CreatePaymentRequest) returns (CreatePaymentResponse);
rpc VerifyPayment (VerifyPaymentRequest) returns (VerifyPaymentResponse);
rpc GetPaymentStatus (PaymentStatusRequest) returns (PaymentStatusResponse);
}
// ===== blog.proto =====
service BlogService {
rpc GetPosts (GetPostsRequest) returns (GetPostsResponse);
rpc GetPostBySlug (GetPostBySlugRequest) returns (BlogPostMessage);
rpc CreatePost (CreatePostRequest) returns (CreatePostResponse);
rpc UpdatePost (UpdatePostRequest) returns (Empty);
rpc DeletePost (DeletePostRequest) returns (Empty);
}
// ===== inventory.proto =====
service InventoryService {
rpc GetInventory (GetInventoryRequest) returns (InventoryMessage);
rpc UpdateStock (UpdateStockRequest) returns (Empty);
rpc GetAllInventories (GetAllRequest) returns (InventoryListResponse);
}
// ===== sitepage.proto =====
service SitePageService {
rpc GetPage (GetPageRequest) returns (SitePageMessage);
rpc SaveSettings (SaveSettingsRequest) returns (Empty);
rpc GetAllPages (Empty) returns (PageListResponse);
}
// ===== file.proto =====
service FileService {
rpc Upload (stream UploadRequest) returns (UploadResponse);
rpc Download (DownloadRequest) returns (stream DownloadResponse);
rpc Delete (DeleteFileRequest) returns (Empty);
}
// ===== category.proto =====
service CategoryService {
rpc GetCategories (GetCategoriesRequest) returns (CategoryListResponse);
rpc CreateCategory (CreateCategoryRequest) returns (CreateCategoryResponse);
rpc UpdateCategory (UpdateCategoryRequest) returns (Empty);
}
// ===== config.proto =====
service SystemConfigService {
rpc GetConfig (GetConfigRequest) returns (ConfigResponse);
rpc UpdateConfig (UpdateConfigRequest) returns (Empty);
rpc GetAllConfigs (Empty) returns (ConfigListResponse);
}
```
### ۲.۲ Shared Messages
```protobuf
// ===== common.proto =====
message PaginationState {
int32 skip = 1;
int32 take = 2;
}
message PaginatedResponse {
int32 totalCount = 1;
int32 pageSize = 2;
int32 currentPage = 3;
}
message Empty {}
```
---
## ۳. External Service Integration
### ۳.۱ ZarinPal (پرداخت)
```csharp
public class ZarinPalService : IPaymentGateway
{
// Config
private readonly string _merchantId;
private readonly bool _isSandbox;
// Endpoints
const string PAYMENT_URL = "https://api.zarinpal.com/pg/v4/payment/request.json";
const string VERIFY_URL = "https://api.zarinpal.com/pg/v4/payment/verify.json";
const string SANDBOX_URL = "https://sandbox.zarinpal.com/pg/v4/payment/request.json";
// Flow
// 1. CreatePayment → Authority token
// 2. Redirect → https://www.zarinpal.com/pg/StartPay/{Authority}
// 3. Callback → VerifyPayment(Authority, Amount)
// 4. Result → RefID (reference number)
}
```
### ۳.۲ Kavenegar (SMS)
```csharp
public class KavenegarService : ISmsService
{
// Templates
const string OTP_TEMPLATE = "verify-foursat";
const string CONTRACT_TEMPLATE = "contract-verify";
const string WELCOME_TEMPLATE = "club-welcome";
// Rate Limiting
// ۱ SMS per phone per 60 seconds
// ۵ SMS per phone per hour
// ۲۰ SMS per phone per day
public async Task SendOtpAsync(string phone, string code)
{
await _api.VerifyLookup(phone, code, OTP_TEMPLATE);
}
}
```
### ۳.۳ Daya Loan (وام)
```csharp
public class DayaLoanService : ILoanService
{
// Hangfire job — هر ۱۵ دقیقه
// Polly retry: 3 attempts, exponential backoff (2s, 4s, 8s)
// Mock mode for staging (auto-approve)
public async Task<LoanResult> RequestLoanAsync(Guid userId, decimal amount)
{
if (_options.UseMock)
return LoanResult.Approved(amount);
var response = await _httpClient.PostAsync(
$"{_baseUrl}/api/loans/request",
new { UserId = userId, Amount = amount });
return MapResponse(response);
}
}
```
### ۳.۴ Chatika (AI)
```csharp
public class ChatikaService : IAiChatService
{
// Hangfire job — هر ۵ دقیقه
// Polly retry: 3 attempts
// Only for active club members
public async Task<string> GetResponseAsync(string userMessage)
{
var response = await _httpClient.PostAsync(
$"{_baseUrl}/api/chat",
new { Message = userMessage });
return response.Content.ReadAsStringAsync();
}
}
```
---
## ۴. API Compatibility Layer
### ۴.۱ FrontOffice Service Pattern
```csharp
// هر سرویس در FrontOffice یک wrapper بر gRPC client است
public class ProductService : IProductService
{
private readonly ProductServiceClient _client;
public ProductService(ProductServiceClient client)
{
_client = client;
}
public async Task<ProductListResult> GetProductsPagedAsync(
int skip, int take, Guid? categoryId = null, string? search = null)
{
try
{
var request = new GetProductsPagedRequest {
Pagination = new PaginationState { Skip = skip, Take = take },
CategoryId = categoryId?.ToString() ?? "",
SearchTerm = search ?? ""
};
var response = await _client.GetProductsPagedAsync(request);
return new ProductListResult(
response.Products.Select(MapToDto).ToList(),
response.TotalCount);
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.Unavailable)
{
// CMS is down — show cached data or error
throw new ServiceUnavailableException("CMS service unavailable");
}
}
}
```
### ۴.۲ Error Handling
| gRPC Status | HTTP Equivalent | Handling |
|------------|-----------------|----------|
| `OK` | 200 | Return data |
| `NotFound` | 404 | Show "not found" message |
| `InvalidArgument` | 400 | Show validation errors |
| `Unauthenticated` | 401 | Redirect to login |
| `PermissionDenied` | 403 | Show "access denied" |
| `Unavailable` | 503 | Show "service down" |
| `Internal` | 500 | Show generic error |
---
## ۵. Proto Package Distribution
```
CMS/src/Protos/*.proto
pack-protos.sh
Foursat.CMSMicroservice.Protobuf.nupkg (v1.0.x)
Push to BaGet (http://localhost:5555) or Nexus
BackOffice: <PackageReference Include="Foursat.CMSMicroservice.Protobuf" />
FrontOffice: <PackageReference Include="Foursat.CMSMicroservice.Protobuf" />
```
---
## ۶. Remaining Tasks / Integration Gaps
| آیتم | اولویت | وضعیت |
|------|---------|--------|
| Product Bundle API | Medium | ⬜ Proto + Handler needed |
| Manual Payment API | Low | ⬜ Design only |
| SignalR for Chatika | Low | ⬜ Replace polling |
| File upload streaming | Done | ✅ |
| Blog search | Done | ✅ |
| Inventory autocomplete | Done | ✅ |
| Lazy load pagination | Done | ✅ |
| Rate limiting (API level) | Medium | ⬜ |
| API versioning | Low | ⬜ |