Complete FrontOffice BFF to CMS Migration
- Migrated all 9 services from FrontOffice.BFF to CMS architecture - Enhanced user.proto with 7 additional Customer API endpoints: * UpdateCustomerProfile, GetCustomerProfile * ChangeCustomerPassword with validation * GetCustomerReferrals with commission stats * UploadCustomerAvatar with file validation * GetCustomerSettings, UpdateCustomerSettings - All services now support Customer endpoints with /Customer/ prefix - Mock implementations with realistic Persian data - Fixed namespace conflicts and compilation issues - Comprehensive testing completed for all endpoints - Services migrated: Categories, City, UserCarts, Products, UserWallet, Transaction, UserOrder, Package, User (enhanced)
This commit is contained in:
@@ -8,6 +8,7 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Linq;
|
||||
using Serilog.Core;
|
||||
using Serilog;
|
||||
using System.Reflection;
|
||||
@@ -17,18 +18,19 @@ using CMSMicroservice.WebApi.Common.Behaviours;
|
||||
using Hangfire;
|
||||
using Hangfire.SqlServer;
|
||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||
using System.IO;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
// Configure Kestrel to support both HTTP/1.1 and HTTP/2
|
||||
builder.WebHost.ConfigureKestrel(options =>
|
||||
{
|
||||
builder.WebHost.ConfigureKestrel(options =>
|
||||
// Enable both HTTP/1.1 and HTTP/2 for all endpoints
|
||||
options.ConfigureEndpointDefaults(listenOptions =>
|
||||
{
|
||||
// Setup a HTTP/2 endpoint without TLS.
|
||||
options.ListenLocalhost(5000, o => o.Protocols =
|
||||
HttpProtocols.Http2);
|
||||
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
|
||||
});
|
||||
}
|
||||
});
|
||||
var levelSwitch = new LoggingLevelSwitch();
|
||||
|
||||
// Read Seq configuration from appsettings.json
|
||||
@@ -102,15 +104,76 @@ builder.Services.AddCors(options =>
|
||||
builder.Services.AddGrpcSwagger();
|
||||
builder.Services.AddSwaggerGen(c =>
|
||||
{
|
||||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "gRPC transcoding", Version = "v1" });
|
||||
c.CustomSchemaIds(type=>type.ToString());
|
||||
// CMS Core Services Documentation
|
||||
c.SwaggerDoc("cms", new OpenApiInfo
|
||||
{
|
||||
Title = "FourSat CMS - Core Services",
|
||||
Version = "v1",
|
||||
Description = "Core CMS microservice APIs - Internal business logic and data management",
|
||||
Contact = new OpenApiContact
|
||||
{
|
||||
Name = "FourSat Development Team",
|
||||
Email = "dev@foursat.com"
|
||||
}
|
||||
});
|
||||
|
||||
// Admin API Documentation (BFF)
|
||||
c.SwaggerDoc("admin", new OpenApiInfo
|
||||
{
|
||||
Title = "FourSat CMS - Admin BFF",
|
||||
Version = "v1",
|
||||
Description = "Admin Backend-for-Frontend API - User Management, Products, Commission, Network, Reports",
|
||||
Contact = new OpenApiContact
|
||||
{
|
||||
Name = "FourSat Development Team",
|
||||
Email = "dev@foursat.com"
|
||||
}
|
||||
});
|
||||
|
||||
// Customer API Documentation (BFF)
|
||||
c.SwaggerDoc("customer", new OpenApiInfo
|
||||
{
|
||||
Title = "FourSat CMS - Customer BFF",
|
||||
Version = "v1",
|
||||
Description = "Customer Backend-for-Frontend API - Profile, Shop, Commission, Network Statistics",
|
||||
Contact = new OpenApiContact
|
||||
{
|
||||
Name = "FourSat Development Team",
|
||||
Email = "dev@foursat.com"
|
||||
}
|
||||
});
|
||||
|
||||
// Unified API Documentation (All endpoints)
|
||||
c.SwaggerDoc("unified", new OpenApiInfo
|
||||
{
|
||||
Title = "FourSat CMS - Unified API",
|
||||
Version = "v1",
|
||||
Description = "Complete API Documentation - All Core, Admin & Customer endpoints in one place"
|
||||
});
|
||||
|
||||
c.CustomSchemaIds(type => type.ToString());
|
||||
|
||||
// Resolve conflicting actions for Swagger
|
||||
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
|
||||
|
||||
// Include XML documentation for gRPC services
|
||||
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||
if (File.Exists(xmlPath))
|
||||
{
|
||||
c.IncludeXmlComments(xmlPath);
|
||||
}
|
||||
|
||||
// Security Definition
|
||||
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
|
||||
{
|
||||
In = ParameterLocation.Header,
|
||||
Description = "Please insert JWT with Bearer into field",
|
||||
Name = "Authorization",
|
||||
Type = SecuritySchemeType.ApiKey
|
||||
Description = "Please insert JWT with Bearer into field (Format: Bearer {token})",
|
||||
Name = "Authorization",
|
||||
Type = SecuritySchemeType.ApiKey,
|
||||
Scheme = "Bearer"
|
||||
});
|
||||
|
||||
c.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||
{
|
||||
{
|
||||
@@ -125,7 +188,96 @@ builder.Services.AddSwaggerGen(c =>
|
||||
new string[] { }
|
||||
}
|
||||
});
|
||||
|
||||
// Group endpoints by functionality
|
||||
c.TagActionsBy(api =>
|
||||
{
|
||||
var serviceName = api.ActionDescriptor.RouteValues?["controller"] ??
|
||||
GetGrpcServiceName(api.RelativePath);
|
||||
|
||||
// Define service categories for better organization
|
||||
return serviceName switch
|
||||
{
|
||||
var name when name.Contains("User") => new[] { "👤 User Management" },
|
||||
var name when name.Contains("Product") => new[] { "📦 Product Catalog" },
|
||||
var name when name.Contains("Category") => new[] { "🗂️ Categories" },
|
||||
var name when name.Contains("Commission") => new[] { "💰 Commission & Earnings" },
|
||||
var name when name.Contains("Network") => new[] { "🌐 Network & Binary Tree" },
|
||||
var name when name.Contains("Club") => new[] { "🏆 Club Management" },
|
||||
var name when name.Contains("Discount") => new[] { "🏷️ Discount Shop" },
|
||||
var name when name.Contains("Order") => new[] { "🛒 Orders & Shopping" },
|
||||
var name when name.Contains("Payment") => new[] { "💳 Payments & Transactions" },
|
||||
var name when name.Contains("Inventory") => new[] { "📋 Inventory Management" },
|
||||
var name when name.Contains("Health") => new[] { "🔧 System Health" },
|
||||
var name when name.Contains("Configuration") => new[] { "⚙️ Configuration" },
|
||||
var name when name.Contains("Admin") => new[] { "👑 Administration" },
|
||||
_ => new[] { $"📋 {serviceName}" }
|
||||
};
|
||||
});
|
||||
|
||||
c.DocInclusionPredicate((docName, apiDesc) =>
|
||||
{
|
||||
// Get service name from both REST controllers and gRPC services
|
||||
var controllerName = apiDesc.ActionDescriptor.RouteValues?["controller"] ?? "";
|
||||
var grpcServiceName = GetGrpcServiceName(apiDesc.RelativePath);
|
||||
var serviceName = !string.IsNullOrEmpty(controllerName) ? controllerName : grpcServiceName;
|
||||
|
||||
return docName switch
|
||||
{
|
||||
"cms" => IsCoreService(serviceName),
|
||||
"admin" => IsAdminService(serviceName),
|
||||
"customer" => IsCustomerService(serviceName),
|
||||
"unified" => true, // Show all endpoints
|
||||
_ => true
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// Helper functions for gRPC service name extraction and categorization
|
||||
static string GetGrpcServiceName(string? relativePath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(relativePath)) return "";
|
||||
|
||||
var segments = relativePath.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
||||
return segments.Length > 0 ? segments[0] : "";
|
||||
}
|
||||
|
||||
static bool IsCoreService(string serviceName)
|
||||
{
|
||||
var coreServices = new[]
|
||||
{
|
||||
"Health", "Configuration", "OtpToken", "Contract", "AppVersion"
|
||||
};
|
||||
|
||||
return coreServices.Any(core => serviceName.Contains(core, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
static bool IsAdminService(string serviceName)
|
||||
{
|
||||
var adminServices = new[]
|
||||
{
|
||||
"Admin", "Role", "UserRole", "ManualPayment", "Inventory",
|
||||
"Tag", "ProductTag", "ProductGalleries", "ProductImages",
|
||||
"DiscountOrder", "FactorDetails", "Products", "ProductCategory",
|
||||
"Category", "DiscountCategory", "DiscountProduct"
|
||||
};
|
||||
|
||||
return adminServices.Any(admin => serviceName.Contains(admin, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
static bool IsCustomerService(string serviceName)
|
||||
{
|
||||
var customerServices = new[]
|
||||
{
|
||||
"User", "UserAddress", "Commission", "NetworkMembership",
|
||||
"ClubMembership", "UserOrder", "UserWallet", "UserCarts",
|
||||
"DiscountShoppingCart", "City", "Package", "Transactions",
|
||||
"UserContract", "UserWalletChangeLog"
|
||||
};
|
||||
|
||||
return customerServices.Any(customer => serviceName.Contains(customer, StringComparison.OrdinalIgnoreCase)) &&
|
||||
!IsAdminService(serviceName); // Exclude admin services
|
||||
}
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
@@ -169,6 +321,9 @@ app.UseCors("AllowAll");
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
// Enable static files for Swagger custom CSS
|
||||
app.UseStaticFiles();
|
||||
|
||||
// Map Health Check endpoints
|
||||
app.MapHealthChecks("/health");
|
||||
app.MapHealthChecks("/health/ready", new Microsoft.AspNetCore.Diagnostics.HealthChecks.HealthCheckOptions
|
||||
@@ -194,7 +349,32 @@ app.MapGet("/", () => "Communication with gRPC endpoints must be made through a
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c =>
|
||||
{
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
|
||||
// CMS Core Services
|
||||
c.SwaggerEndpoint("/swagger/cms/swagger.json", "🔧 CMS Core Services");
|
||||
|
||||
// Admin BFF
|
||||
c.SwaggerEndpoint("/swagger/admin/swagger.json", "👑 Admin BFF");
|
||||
|
||||
// Customer BFF
|
||||
c.SwaggerEndpoint("/swagger/customer/swagger.json", "👥 Customer BFF");
|
||||
|
||||
// Unified API (All endpoints)
|
||||
c.SwaggerEndpoint("/swagger/unified/swagger.json", "🌐 Unified API (All)");
|
||||
|
||||
// UI Customization
|
||||
c.DocumentTitle = "FourSat CMS API Documentation";
|
||||
c.RoutePrefix = "swagger"; // Available at /swagger
|
||||
|
||||
// Default to CMS core view
|
||||
c.DefaultModelExpandDepth(2);
|
||||
c.DefaultModelsExpandDepth(-1);
|
||||
c.DocExpansion(Swashbuckle.AspNetCore.SwaggerUI.DocExpansion.None);
|
||||
c.EnableFilter();
|
||||
c.EnableDeepLinking();
|
||||
c.EnableValidator();
|
||||
|
||||
// Custom CSS
|
||||
c.InjectStylesheet("/swagger-ui/custom.css");
|
||||
});
|
||||
|
||||
// Configure Hangfire Dashboard
|
||||
|
||||
Reference in New Issue
Block a user