10 KiB
Session Log - December 20, 2025
خلاصه Session
این session شامل رفع چندین باگ در صفحات BackOffice و فعالسازی قابلیتهای Products بود.
1. فیکس صفحه /network/balances
مشکل
ValidationException هنگام لود صفحه بالانسهای هفتگی
علت
Mapster mapping برای تبدیل GetUserWeeklyBalancesRequest به GetUserWeeklyBalancesQuery وجود نداشت.
راهحل
اضافه کردن mapping در CommissionProfile.cs:
// File: BackOffice.BFF/src/BackOffice.BFF.WebApi/Common/Mappings/CommissionProfile.cs
config.NewConfig<GetUserWeeklyBalancesRequest, GetUserWeeklyBalancesQuery>()
.Map(dest => dest.PaginationState, src => src.PaginationState);
2. فیکس صفحه /club/members
مشکل
صفحه لود میشد ولی هیچ دادهای نمایش نمیداد
علت
Mapster mappings در CMS و BFF برای GetAllClubMemberships وجود نداشتند.
راهحل
ایجاد ClubMembershipProfile.cs در هر دو لایه:
CMS/src/CMSMicroservice.WebApi/Common/Mappings/ClubMembershipProfile.cs (NEW):
public class ClubMembershipProfile : IRegister
{
void IRegister.Register(TypeAdapterConfig config)
{
// GetAllClubMemberships mappings
config.NewConfig<GetAllClubMembershipsRequest, GetAllClubMembershipsQuery>()
.Map(dest => dest.PaginationState, src => src.PaginationState)
.Map(dest => dest.Filter, src => src.Filter);
config.NewConfig<GetAllClubMembershipsResponseDto, GetAllClubMembershipsResponse>()
.MapWith(src => new GetAllClubMembershipsResponse
{
MetaData = src.MetaData != null ? new CMSMicroservice.Protobuf.Common.MetaData
{
PageIndex = src.MetaData.PageIndex,
TotalPages = src.MetaData.TotalPages,
TotalCount = src.MetaData.TotalCount
} : null,
Models = { src.Models?.Select(...) ?? Enumerable.Empty<...>() }
});
}
}
BackOffice.BFF/src/BackOffice.BFF.WebApi/Common/Mappings/ClubMembershipProfile.cs (REWRITTEN):
- Mapping از BFF Proto به Query
- Mapping از CMS Response به BFF Proto Response
- استفاده از alias imports برای disambiguation
3. فیکس صفحه /club/statistics
مشکل
Status(StatusCode="Unimplemented", Detail="Method cms.ClubMembershipContract/GetClubStatistics is unimplemented")
علت
متد GetClubStatistics در BFF Service override نشده بود.
راهحل
1. اضافه کردن override در ClubMembershipService.cs:
public override async Task<GetClubStatisticsResponse> GetClubStatistics(
GetClubStatisticsRequest request, ServerCallContext context)
{
return await _dispatchRequestToCQRS.Handle<GetClubStatisticsRequest, GetClubStatisticsQuery, GetClubStatisticsResponse>(request, context);
}
2. اضافه کردن mappings در CMS ClubMembershipProfile:
config.NewConfig<GetClubStatisticsRequest, GetClubStatisticsQuery>();
config.NewConfig<GetClubStatisticsResponseDto, GetClubStatisticsResponse>()
.MapWith(src => new GetClubStatisticsResponse
{
TotalMembers = src.TotalMembers,
ActiveMembers = src.ActiveMembers,
// ... سایر فیلدها
PackageDistribution = { src.PackageDistribution?.Select(...) },
MonthlyTrend = { src.MonthlyTrend?.Select(...) }
});
3. اضافه کردن mappings در BFF ClubMembershipProfile:
- Mapping از BFF Proto به Query
- Mapping از CMS Response DTO به BFF Proto Response
4. فعالسازی قابلیتهای Products
مشکل
همه دکمههای صفحه محصولات "در حال توسعه" نشان میدادند
علت
کدهای دیالوگها comment شده بودند با TODO markers.
راهحل
Uncomment کردن کدها در ProductsMainPage.razor.cs:
فایل: BackOffice/src/BackOffice/Pages/Products/ProductsMainPage.razor.cs
// ✅ CreateNew() - فعال شد
public async Task CreateNew()
{
var dialog = await DialogService.ShowAsync<CreateDialog>("افزودن محصول",
new DialogParameters<CreateDialog> { { x => x.Model, new CreateNewProductsRequest() } },
new DialogOptions { CloseButton = true, FullWidth = true, MaxWidth = MaxWidth.Small });
// ...
}
// ✅ Update() - فعال شد
public async Task Update(DataModel model)
{
var parameters = new DialogParameters<UpdateDialog> { { x => x.Model, model.Adapt<UpdateProductsRequest>() } };
var dialog = await DialogService.ShowAsync<UpdateDialog>("ویرایش محصول", parameters, ...);
// ...
}
// ✅ OpenGallery() - فعال شد
public async Task OpenGallery(DataModel model)
{
var parameters = new DialogParameters<GalleryDialog>
{
{ x => x.ProductId, model.Id },
{ x => x.ProductTitle, model.Title }
};
await DialogService.ShowAsync<GalleryDialog>("گالری تصاویر", parameters, ...);
}
// ✅ OpenTagAssignment() - فعال شد
public async Task OpenTagAssignment(DataModel model)
{
var parameters = new DialogParameters<AssignTagsDialog>
{
{ x => x.ProductId, model.Id },
{ x => x.ProductTitle, model.Title }
};
await DialogService.ShowAsync<AssignTagsDialog>("مدیریت تگهای محصول", parameters, ...);
}
Using statement uncomment شد:
using BackOffice.Pages.Tag.Components; // برای AssignTagsDialog
5. اضافه کردن فیلد "تعداد موجودی" به Products
نیاز
نمایش و ویرایش تعداد موجودی محصول در فرمها و لیست
تغییرات
1. فرمهای دیالوگ (CreateDialog.razor & UpdateDialog.razor):
<MudStack Row="true" AlignItems="AlignItems.Center">
<MudItem xs="6">
<MudNumericField T="int" HideSpinButtons="true" @bind-Value="Model.Discount"
Disabled="_isLoading" Label="تخفیف (%)" Variant="Variant.Outlined" Margin="Margin.Dense" />
</MudItem>
<MudItem xs="6">
<MudNumericField T="int" HideSpinButtons="true" @bind-Value="Model.RemainingCount"
Disabled="_isLoading" Label="تعداد موجودی" Variant="Variant.Outlined" Margin="Margin.Dense" />
</MudItem>
</MudStack>
2. ستون جدید در لیست (ProductsMainPage.razor):
<TemplateColumn Title="موجودی" CellStyle="text-wrap: nowrap;">
<CellTemplate>
@if (context.Item.RemainingCount <= 0)
{
<MudChip T="string" Color="Color.Error" Size="Size.Small">ناموجود</MudChip>
}
else if (context.Item.RemainingCount < 10)
{
<MudChip T="string" Color="Color.Warning" Size="Size.Small">@context.Item.RemainingCount</MudChip>
}
else
{
<MudChip T="string" Color="Color.Success" Size="Size.Small">@context.Item.RemainingCount</MudChip>
}
</CellTemplate>
</TemplateColumn>
3. اضافه کردن فیلد به BFF Commands (فیکس مهم!):
مشکل: فیلد RemainingCount در BFF Application Commands نبود و باعث میشد مقدار ارسال/دریافت نشه.
CreateNewProductsCommand.cs:
public int Discount { get; init; }
public int Rate { get; init; }
public int RemainingCount { get; init; } // ← اضافه شد
public ImageFileModel ImageFile { get; init; }
UpdateProductsCommand.cs:
public int Discount { get; init; }
public int Rate { get; init; }
public int RemainingCount { get; init; } // ← اضافه شد
public string ImagePath { get; init; }
لیست کامل فایلهای تغییر یافته
BackOffice.BFF
| فایل | نوع تغییر | توضیح |
|---|---|---|
WebApi/Common/Mappings/CommissionProfile.cs |
MODIFIED | اضافه شدن mapping برای GetUserWeeklyBalances |
WebApi/Common/Mappings/ClubMembershipProfile.cs |
REWRITTEN | Mappings کامل برای ClubMembership |
WebApi/Services/ClubMembershipService.cs |
MODIFIED | اضافه شدن GetClubStatistics override |
Application/ProductsCQ/Commands/CreateNewProducts/CreateNewProductsCommand.cs |
MODIFIED | اضافه شدن RemainingCount |
Application/ProductsCQ/Commands/UpdateProducts/UpdateProductsCommand.cs |
MODIFIED | اضافه شدن RemainingCount |
CMS
| فایل | نوع تغییر | توضیح |
|---|---|---|
WebApi/Common/Mappings/ClubMembershipProfile.cs |
NEW | Mappings برای ClubMembership |
BackOffice UI
| فایل | نوع تغییر | توضیح |
|---|---|---|
Pages/Products/ProductsMainPage.razor.cs |
MODIFIED | فعالسازی CreateNew, Update, OpenGallery, OpenTagAssignment |
Pages/Products/ProductsMainPage.razor |
MODIFIED | اضافه شدن ستون موجودی |
Pages/Products/Components/CreateDialog.razor |
MODIFIED | اضافه شدن فیلد موجودی |
Pages/Products/Components/UpdateDialog.razor |
MODIFIED | اضافه شدن فیلد موجودی |
نکات فنی مهم
1. Mapster با Proto Types
برای proto types که immutable هستند، باید از MapWith استفاده کرد:
config.NewConfig<SourceDto, ProtoResponse>()
.MapWith(src => new ProtoResponse
{
Field1 = src.Field1,
RepeatedField = { src.List?.Select(...) ?? Enumerable.Empty<...>() }
});
2. Alias Imports برای Proto Disambiguation
وقتی دو proto با اسم یکسان داریم:
using BffProtos = BackOffice.BFF.ClubMembership.Protobuf.Protos.ClubMembership;
using CmsProtos = CMSMicroservice.Protobuf.Protos.ClubMembership;
3. Null-Safe MetaData Mapping
MetaData = src.MetaData != null ? new MetaData
{
PageIndex = src.MetaData.PageIndex,
TotalPages = src.MetaData.TotalPages,
TotalCount = src.MetaData.TotalCount
} : null
Build Status پایان Session
BackOffice.BFF: ✅ Build succeeded (0 errors)
CMS: ✅ Build succeeded (0 errors)
BackOffice UI: ✅ Build succeeded (0 errors)