diff --git a/BuildFlow.slnx b/BuildFlow.slnx
index 23b4b38..7068979 100644
--- a/BuildFlow.slnx
+++ b/BuildFlow.slnx
@@ -18,6 +18,11 @@
+
+
+
+
+
diff --git a/src/BuildFlow.Host/BuildFlow.Host.csproj b/src/BuildFlow.Host/BuildFlow.Host.csproj
index 348bbba..e35448b 100644
--- a/src/BuildFlow.Host/BuildFlow.Host.csproj
+++ b/src/BuildFlow.Host/BuildFlow.Host.csproj
@@ -17,6 +17,8 @@
+
+
diff --git a/src/BuildFlow.Host/BuildFlowHostModule.cs b/src/BuildFlow.Host/BuildFlowHostModule.cs
index 0f290ed..3aab9ca 100644
--- a/src/BuildFlow.Host/BuildFlowHostModule.cs
+++ b/src/BuildFlow.Host/BuildFlowHostModule.cs
@@ -1,6 +1,9 @@
using BuildFlow.Host.Configuration;
using BuildFlow.Host.Hubs;
-using BuildFlow.Host.Services;
+using BuildFlow.Host.Services.BackgroundServices;
+using BuildFlow.Host.Services.Integration;
+using BuildFlow.Host.Services.Notifications;
+using BuildFlow.Host.Services.Users;
using FastEndpoints.Swagger;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
@@ -12,6 +15,8 @@ using File.Infrastructure;
using IM.Application;
using IM.Domain.Common;
using IM.Infrastructure;
+using BuildFlow.Platform.Application;
+using BuildFlow.Platform.Infrastructure.Persistence;
using Volo.Abp;
using Volo.Abp.Modularity;
using Workflow.Application;
@@ -26,6 +31,7 @@ namespace BuildFlow.Host;
[DependsOn(
typeof(BuildFlow.Application.RAGApplicationModule),
typeof(BuildFlow.Infrastructure.RAGInfrastructureModule),
+ typeof(PlatformApplicationModule),
typeof(FileApplicationModule),
typeof(FileInfrastructureModule),
typeof(IMApplicationModule),
@@ -88,7 +94,7 @@ public class BuildFlowHostModule : AbpModule
services.AddHostedService();
// 消息中心通知分发器(仅 rag 用)
- services.AddScoped();
+ services.AddScoped();
// 进程内文件存储:覆盖 rag 原有的 HTTP 版 FileStorageClient(后注册者胜出)
services.AddScoped();
@@ -96,6 +102,12 @@ public class BuildFlowHostModule : AbpModule
// JWT 认证 + CORS:使用共享内核扩展方法(消除重复的认证/跨域配置)
services.AddSharedJwtAuthentication(config);
services.AddSharedCors();
+
+ // 响应包裹中间件配置:文件下载为二进制流式响应,必须绕过 JSON 包裹与 MemoryStream 缓冲
+ services.Configure(opts =>
+ {
+ opts.PassthroughPrefixes.Add("/api/files/download");
+ });
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
diff --git a/src/BuildFlow.Host/Configuration/NotificationConfiguration.cs b/src/BuildFlow.Host/Configuration/NotificationConfiguration.cs
index 3acfa15..7b58785 100644
--- a/src/BuildFlow.Host/Configuration/NotificationConfiguration.cs
+++ b/src/BuildFlow.Host/Configuration/NotificationConfiguration.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Host.Services;
+using BuildFlow.Host.Services.Users;
using Workflow.Application.Notifications;
using Workflow.Application.Scheduler;
diff --git a/src/BuildFlow.Host/Endpoints/file/Buckets/CreateBucketEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Buckets/CreateBucketEndpoint.cs
index be2486c..d3d7998 100644
--- a/src/BuildFlow.Host/Endpoints/file/Buckets/CreateBucketEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Buckets/CreateBucketEndpoint.cs
@@ -5,6 +5,7 @@ namespace BuildFlow.Host.Endpoints.file.Buckets;
/// 创建存储桶端点。POST /api/buckets,按名称创建存储桶。
+[Authorize]
public class CreateBucketEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Post("/buckets");
diff --git a/src/BuildFlow.Host/Endpoints/file/Buckets/DeleteBucketEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Buckets/DeleteBucketEndpoint.cs
index 194c320..5351e60 100644
--- a/src/BuildFlow.Host/Endpoints/file/Buckets/DeleteBucketEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Buckets/DeleteBucketEndpoint.cs
@@ -5,6 +5,7 @@ namespace BuildFlow.Host.Endpoints.file.Buckets;
/// 删除存储桶端点。DELETE /api/buckets,按名称删除存储桶。
+[Authorize]
public class DeleteBucketEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Delete("/buckets");
diff --git a/src/BuildFlow.Host/Endpoints/file/Files/CheckFileEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Files/CheckFileEndpoint.cs
index f3d3405..c795d00 100644
--- a/src/BuildFlow.Host/Endpoints/file/Files/CheckFileEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Files/CheckFileEndpoint.cs
@@ -5,6 +5,7 @@ using MediatR;
namespace BuildFlow.Host.Endpoints.file.Files;
/// 秒传预检端点。POST /api/files/check,按哈希查同用户已存在文件。
+[Authorize]
public class CheckFileEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Post("/files/check");
diff --git a/src/BuildFlow.Host/Endpoints/file/Files/DeleteFileEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Files/DeleteFileEndpoint.cs
index 36c7bbb..44dd2fc 100644
--- a/src/BuildFlow.Host/Endpoints/file/Files/DeleteFileEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Files/DeleteFileEndpoint.cs
@@ -5,6 +5,7 @@ namespace BuildFlow.Host.Endpoints.file.Files;
/// 删除文件端点。DELETE /api/files/delete,按对象键删除文件。
+[Authorize]
public class DeleteFileEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Delete("/files/delete");
diff --git a/src/BuildFlow.Host/Endpoints/file/Files/GetFileContentEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Files/GetFileContentEndpoint.cs
index 8f12021..46b2742 100644
--- a/src/BuildFlow.Host/Endpoints/file/Files/GetFileContentEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Files/GetFileContentEndpoint.cs
@@ -6,6 +6,7 @@ namespace BuildFlow.Host.Endpoints.file.Files;
/// 文件内容端点。GET /api/files/content,返回文件文本内容。
+[Authorize]
public class GetFileContentEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Get("/files/content");
diff --git a/src/BuildFlow.Host/Endpoints/file/Files/GetFilePreviewEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Files/GetFilePreviewEndpoint.cs
index 7ecb179..d028ef8 100644
--- a/src/BuildFlow.Host/Endpoints/file/Files/GetFilePreviewEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Files/GetFilePreviewEndpoint.cs
@@ -6,6 +6,7 @@ namespace BuildFlow.Host.Endpoints.file.Files;
/// 文件预览端点。GET /api/files/preview,返回预签名预览 URL。
+[Authorize]
public class GetFilePreviewEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Get("/files/preview");
diff --git a/src/BuildFlow.Host/Endpoints/file/Files/GetOfficePreviewEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Files/GetOfficePreviewEndpoint.cs
new file mode 100644
index 0000000..4ed4433
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/file/Files/GetOfficePreviewEndpoint.cs
@@ -0,0 +1,21 @@
+using File.Application.Features.Files.DTOs;
+using File.Application.Features.Files.Queries;
+using MediatR;
+
+namespace BuildFlow.Host.Endpoints.file.Files;
+
+///
+/// Office/PDF 文档在线预览端点。GET /api/files/office-preview,
+/// 返回 KKFileView 预览地址,前端 window.open 打开即可渲染 Office 文档。
+///
+[Authorize]
+public class GetOfficePreviewEndpoint(IMediator mediator) : Endpoint
+{
+ public override void Configure() => Get("/files/office-preview");
+
+ public override async Task HandleAsync(GetOfficePreviewRequest req, CancellationToken ct)
+ {
+ var result = await mediator.Send(new GetOfficePreviewQuery(req.BucketName, req.ObjectKey), ct);
+ await Send.OkAsync(result, ct);
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/file/Files/GetOfficePreviewRequest.cs b/src/BuildFlow.Host/Endpoints/file/Files/GetOfficePreviewRequest.cs
new file mode 100644
index 0000000..061dfdd
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/file/Files/GetOfficePreviewRequest.cs
@@ -0,0 +1,8 @@
+namespace BuildFlow.Host.Endpoints.file.Files;
+
+/// Office/PDF 文档预览请求。以查询参数指定存储桶与对象键。
+public class GetOfficePreviewRequest
+{
+ [QueryParam] public string BucketName { get; init; } = default!;
+ [QueryParam] public string ObjectKey { get; init; } = default!;
+}
diff --git a/src/BuildFlow.Host/Endpoints/file/Files/ListFilesEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Files/ListFilesEndpoint.cs
index 4158cd1..a178686 100644
--- a/src/BuildFlow.Host/Endpoints/file/Files/ListFilesEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Files/ListFilesEndpoint.cs
@@ -6,6 +6,7 @@ namespace BuildFlow.Host.Endpoints.file.Files;
/// 列举文件端点。GET /api/files/list,支持前缀与分页查询。
+[Authorize]
public class ListFilesEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Get("/files/list");
diff --git a/src/BuildFlow.Host/Endpoints/file/Files/UploadFileEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Files/UploadFileEndpoint.cs
index d7d78a8..9511943 100644
--- a/src/BuildFlow.Host/Endpoints/file/Files/UploadFileEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Files/UploadFileEndpoint.cs
@@ -6,6 +6,7 @@ namespace BuildFlow.Host.Endpoints.file.Files;
/// 上传文件端点。POST /api/files/upload,支持 multipart 文件上传。
+[Authorize]
public class UploadFileEndpoint(IMediator mediator) : Endpoint
{
public override void Configure()
diff --git a/src/BuildFlow.Host/Endpoints/file/Folders/CreateFolderEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Folders/CreateFolderEndpoint.cs
index 138d97b..3ff960a 100644
--- a/src/BuildFlow.Host/Endpoints/file/Folders/CreateFolderEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Folders/CreateFolderEndpoint.cs
@@ -6,6 +6,7 @@ namespace BuildFlow.Host.Endpoints.file.Folders;
/// 创建文件夹端点。POST /api/folders。
+[Authorize]
public class CreateFolderEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Post("/folders");
diff --git a/src/BuildFlow.Host/Endpoints/file/Folders/DeleteFolderEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Folders/DeleteFolderEndpoint.cs
index 806d2e0..85ba15a 100644
--- a/src/BuildFlow.Host/Endpoints/file/Folders/DeleteFolderEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Folders/DeleteFolderEndpoint.cs
@@ -5,6 +5,7 @@ namespace BuildFlow.Host.Endpoints.file.Folders;
/// 删除文件夹端点。DELETE /api/folders/{Id}。
+[Authorize]
public class DeleteFolderEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Delete("/folders/{Id}");
diff --git a/src/BuildFlow.Host/Endpoints/file/Folders/GetFolderEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Folders/GetFolderEndpoint.cs
index d49d4c0..18cad1a 100644
--- a/src/BuildFlow.Host/Endpoints/file/Folders/GetFolderEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Folders/GetFolderEndpoint.cs
@@ -5,6 +5,7 @@ namespace BuildFlow.Host.Endpoints.file.Folders;
/// 获取文件夹详情端点。GET /api/folders/{Id}。
+[Authorize]
public class GetFolderEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Get("/folders/{Id}");
diff --git a/src/BuildFlow.Host/Endpoints/file/Folders/MoveFileEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Folders/MoveFileEndpoint.cs
index 7b83a9c..319fb4d 100644
--- a/src/BuildFlow.Host/Endpoints/file/Folders/MoveFileEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Folders/MoveFileEndpoint.cs
@@ -5,6 +5,7 @@ namespace BuildFlow.Host.Endpoints.file.Folders;
/// 移动文件到目标文件夹端点。POST /api/files/{Id}/move。
+[Authorize]
public class MoveFileEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Post("/files/{Id}/move");
diff --git a/src/BuildFlow.Host/Endpoints/file/Folders/RenameFolderEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Folders/RenameFolderEndpoint.cs
index 0f718e8..b5275c1 100644
--- a/src/BuildFlow.Host/Endpoints/file/Folders/RenameFolderEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Folders/RenameFolderEndpoint.cs
@@ -6,6 +6,7 @@ namespace BuildFlow.Host.Endpoints.file.Folders;
/// 重命名文件夹端点。PUT /api/folders/{Id}。
+[Authorize]
public class RenameFolderEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Put("/folders/{Id}");
diff --git a/src/BuildFlow.Host/Endpoints/file/Folders/UploadToFolderEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Folders/UploadToFolderEndpoint.cs
index 5bde33a..b739115 100644
--- a/src/BuildFlow.Host/Endpoints/file/Folders/UploadToFolderEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Folders/UploadToFolderEndpoint.cs
@@ -6,6 +6,7 @@ namespace BuildFlow.Host.Endpoints.file.Folders;
/// 上传文件到指定文件夹端点。POST /api/folders/{FolderId}/files。
+[Authorize]
public class UploadToFolderEndpoint(IMediator mediator) : Endpoint
{
public override void Configure()
diff --git a/src/BuildFlow.Host/Endpoints/file/Multipart/AbortMultipartEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Multipart/AbortMultipartEndpoint.cs
index 8ddadcb..4ca157e 100644
--- a/src/BuildFlow.Host/Endpoints/file/Multipart/AbortMultipartEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Multipart/AbortMultipartEndpoint.cs
@@ -5,6 +5,7 @@ namespace BuildFlow.Host.Endpoints.file.Multipart;
/// 中止分片上传端点。POST /api/files/multipart/abort。
+[Authorize]
public class AbortMultipartEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Post("/files/multipart/abort");
diff --git a/src/BuildFlow.Host/Endpoints/file/Multipart/CompleteMultipartEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Multipart/CompleteMultipartEndpoint.cs
index 38fc1a8..f751c20 100644
--- a/src/BuildFlow.Host/Endpoints/file/Multipart/CompleteMultipartEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Multipart/CompleteMultipartEndpoint.cs
@@ -6,6 +6,7 @@ namespace BuildFlow.Host.Endpoints.file.Multipart;
/// 完成分片上传端点。POST /api/files/multipart/complete。
+[Authorize]
public class CompleteMultipartEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Post("/files/multipart/complete");
diff --git a/src/BuildFlow.Host/Endpoints/file/Multipart/InitMultipartEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Multipart/InitMultipartEndpoint.cs
index fea6579..86d137a 100644
--- a/src/BuildFlow.Host/Endpoints/file/Multipart/InitMultipartEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Multipart/InitMultipartEndpoint.cs
@@ -6,6 +6,7 @@ namespace BuildFlow.Host.Endpoints.file.Multipart;
/// 初始化分片上传端点。POST /api/files/multipart/init。
+[Authorize]
public class InitMultipartEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Post("/files/multipart/init");
diff --git a/src/BuildFlow.Host/Endpoints/file/Multipart/ListPartsEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Multipart/ListPartsEndpoint.cs
index ad70ff4..67a9c69 100644
--- a/src/BuildFlow.Host/Endpoints/file/Multipart/ListPartsEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Multipart/ListPartsEndpoint.cs
@@ -8,6 +8,7 @@ namespace BuildFlow.Host.Endpoints.file.Multipart;
/// 查询分片上传已传分片清单端点。GET /api/files/multipart/parts?upload_id=xxx。
/// 断点续传恢复点:前端续传前调用,据此跳过已传 partNumber。
///
+[Authorize]
public class ListPartsEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Get("/files/multipart/parts");
diff --git a/src/BuildFlow.Host/Endpoints/file/Multipart/UploadPartEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Multipart/UploadPartEndpoint.cs
index 7ed10e9..e90e349 100644
--- a/src/BuildFlow.Host/Endpoints/file/Multipart/UploadPartEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Multipart/UploadPartEndpoint.cs
@@ -6,6 +6,7 @@ namespace BuildFlow.Host.Endpoints.file.Multipart;
/// 上传单个分片端点。PUT /api/files/multipart/part。
+[Authorize]
public class UploadPartEndpoint(IMediator mediator) : Endpoint
{
public override void Configure()
diff --git a/src/BuildFlow.Host/Endpoints/file/Shares/CreateShareEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Shares/CreateShareEndpoint.cs
index e6cf0f5..5ec67a4 100644
--- a/src/BuildFlow.Host/Endpoints/file/Shares/CreateShareEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Shares/CreateShareEndpoint.cs
@@ -6,6 +6,7 @@ namespace BuildFlow.Host.Endpoints.file.Shares;
/// 创建分享链接端点。POST /api/share。
+[Authorize]
public class CreateShareEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Post("/share");
diff --git a/src/BuildFlow.Host/Endpoints/file/Shares/DeleteShareEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Shares/DeleteShareEndpoint.cs
index b5b174c..cc5e532 100644
--- a/src/BuildFlow.Host/Endpoints/file/Shares/DeleteShareEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/file/Shares/DeleteShareEndpoint.cs
@@ -5,6 +5,7 @@ namespace BuildFlow.Host.Endpoints.file.Shares;
/// 删除分享端点。DELETE /api/share/{Id}。
+[Authorize]
public class DeleteShareEndpoint(IMediator mediator) : Endpoint
{
public override void Configure() => Delete("/share/{Id}");
diff --git a/src/BuildFlow.Host/Endpoints/rag/Auth/ChangePasswordEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/ChangePasswordEndpoint.cs
similarity index 89%
rename from src/BuildFlow.Host/Endpoints/rag/Auth/ChangePasswordEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Auth/ChangePasswordEndpoint.cs
index f9ebbc1..55ce463 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Auth/ChangePasswordEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Auth/ChangePasswordEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Infrastructure.Persistence;
+using BuildFlow.Platform.Infrastructure.Persistence;
using BuildFlow.Shared.Domain.Common;
namespace BuildFlow.Host.Endpoints.rag.Auth;
@@ -7,7 +7,7 @@ namespace BuildFlow.Host.Endpoints.rag.Auth;
/// 修改当前用户密码。验证旧密码后更新为新密码。
/// POST /api/user/change-password
///
-public class ChangePasswordEndpoint(RagDbContext db, ICurrentUserContext userContext)
+public class ChangePasswordEndpoint(PlatformDbContext db, ICurrentUserContext userContext)
: Endpoint
{
public override void Configure()
diff --git a/src/BuildFlow.Host/Endpoints/rag/Auth/ChangePasswordRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/ChangePasswordRequest.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Auth/ChangePasswordRequest.cs
rename to src/BuildFlow.Host/Endpoints/platform/Auth/ChangePasswordRequest.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Auth/GetAccessCodesEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/GetAccessCodesEndpoint.cs
similarity index 93%
rename from src/BuildFlow.Host/Endpoints/rag/Auth/GetAccessCodesEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Auth/GetAccessCodesEndpoint.cs
index 968a55c..a164bf6 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Auth/GetAccessCodesEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Auth/GetAccessCodesEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Auth.Queries;
+using BuildFlow.Platform.Application.Auth.Queries;
using BuildFlow.Shared.Domain.Common;
using MediatR;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Auth/GetCurrentUserEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/GetCurrentUserEndpoint.cs
similarity index 94%
rename from src/BuildFlow.Host/Endpoints/rag/Auth/GetCurrentUserEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Auth/GetCurrentUserEndpoint.cs
index dc65e9b..a399bf9 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Auth/GetCurrentUserEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Auth/GetCurrentUserEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Auth.Queries;
+using BuildFlow.Platform.Application.Auth.Queries;
using BuildFlow.Shared.Domain.Common;
using MediatR;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Auth/LoginEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/LoginEndpoint.cs
similarity index 91%
rename from src/BuildFlow.Host/Endpoints/rag/Auth/LoginEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Auth/LoginEndpoint.cs
index 3a72a70..623a5a2 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Auth/LoginEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Auth/LoginEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Auth.Commands;
-using BuildFlow.Application.Auth.DTOs;
+using BuildFlow.Platform.Application.Auth.Commands;
+using BuildFlow.Platform.Application.Auth.DTOs;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Auth;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Auth/LoginRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/LoginRequestValidator.cs
similarity index 93%
rename from src/BuildFlow.Host/Endpoints/rag/Auth/LoginRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Auth/LoginRequestValidator.cs
index 479d97d..987bbbc 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Auth/LoginRequestValidator.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Auth/LoginRequestValidator.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Auth.DTOs;
+using BuildFlow.Platform.Application.Auth.DTOs;
namespace BuildFlow.Host.Endpoints.rag.Auth;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Auth/LogoutEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/LogoutEndpoint.cs
similarity index 94%
rename from src/BuildFlow.Host/Endpoints/rag/Auth/LogoutEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Auth/LogoutEndpoint.cs
index c6fb444..323410b 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Auth/LogoutEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Auth/LogoutEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Auth.Commands;
+using BuildFlow.Platform.Application.Auth.Commands;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Auth;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Auth/RefreshTokenEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/RefreshTokenEndpoint.cs
similarity index 96%
rename from src/BuildFlow.Host/Endpoints/rag/Auth/RefreshTokenEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Auth/RefreshTokenEndpoint.cs
index 11550b6..c75a1d9 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Auth/RefreshTokenEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Auth/RefreshTokenEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Auth.Commands;
+using BuildFlow.Platform.Application.Auth.Commands;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Auth;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Auth/RegisterEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/RegisterEndpoint.cs
similarity index 85%
rename from src/BuildFlow.Host/Endpoints/rag/Auth/RegisterEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Auth/RegisterEndpoint.cs
index 584a890..25cf80e 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Auth/RegisterEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Auth/RegisterEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Auth.Commands;
-using BuildFlow.Application.Auth.DTOs;
+using BuildFlow.Platform.Application.Auth.Commands;
+using BuildFlow.Platform.Application.Auth.DTOs;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Auth;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Auth/RegisterRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/RegisterRequestValidator.cs
similarity index 93%
rename from src/BuildFlow.Host/Endpoints/rag/Auth/RegisterRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Auth/RegisterRequestValidator.cs
index 1b69a12..ef20364 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Auth/RegisterRequestValidator.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Auth/RegisterRequestValidator.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Auth.DTOs;
+using BuildFlow.Platform.Application.Auth.DTOs;
namespace BuildFlow.Host.Endpoints.rag.Auth;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Auth/RevokeTokenEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/RevokeTokenEndpoint.cs
similarity index 84%
rename from src/BuildFlow.Host/Endpoints/rag/Auth/RevokeTokenEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Auth/RevokeTokenEndpoint.cs
index 4c086da..459ac9d 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Auth/RevokeTokenEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Auth/RevokeTokenEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Auth.Commands;
-using BuildFlow.Application.Auth.DTOs;
+using BuildFlow.Platform.Application.Auth.Commands;
+using BuildFlow.Platform.Application.Auth.DTOs;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Auth;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Auth/RevokeTokenRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/RevokeTokenRequestValidator.cs
similarity index 88%
rename from src/BuildFlow.Host/Endpoints/rag/Auth/RevokeTokenRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Auth/RevokeTokenRequestValidator.cs
index 1e2f33a..abd2614 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Auth/RevokeTokenRequestValidator.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Auth/RevokeTokenRequestValidator.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Auth.DTOs;
+using BuildFlow.Platform.Application.Auth.DTOs;
namespace BuildFlow.Host.Endpoints.rag.Auth;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Auth/UpdateProfileEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/UpdateProfileEndpoint.cs
similarity index 89%
rename from src/BuildFlow.Host/Endpoints/rag/Auth/UpdateProfileEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Auth/UpdateProfileEndpoint.cs
index 22f3541..f19828d 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Auth/UpdateProfileEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Auth/UpdateProfileEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Auth.Commands;
-using BuildFlow.Application.Auth.Queries;
+using BuildFlow.Platform.Application.Auth.Commands;
+using BuildFlow.Platform.Application.Auth.Queries;
using BuildFlow.Shared.Domain.Common;
using MediatR;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Auth/UpdateProfileRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/UpdateProfileRequest.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Auth/UpdateProfileRequest.cs
rename to src/BuildFlow.Host/Endpoints/platform/Auth/UpdateProfileRequest.cs
diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/CreateMenuEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/CreateMenuEndpoint.cs
new file mode 100644
index 0000000..a0ee9e3
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Menus/CreateMenuEndpoint.cs
@@ -0,0 +1,41 @@
+using BuildFlow.Platform.Application.Menus.Commands;
+using BuildFlow.Platform.Application.Menus.DTOs;
+using MediatR;
+
+namespace BuildFlow.Host.Endpoints.rag.Menus;
+
+///
+/// 创建菜单端点。
+///
+public class CreateMenuEndpoint(IMediator mediator) : Endpoint
+{
+ public override void Configure()
+ {
+ Post("/menus");
+ Permissions("menu:create");
+ }
+
+ public override async Task HandleAsync(CreateMenuRequest req, CancellationToken ct)
+ {
+ var result = await mediator.Send(new CreateMenuCommand
+ {
+ ParentId = req.ParentId,
+ Name = req.Name,
+ Path = req.Path,
+ Component = req.Component,
+ Redirect = req.Redirect,
+ Title = req.Title,
+ Icon = req.Icon,
+ ActiveIcon = req.ActiveIcon,
+ Order = req.Order,
+ HideInMenu = req.HideInMenu,
+ KeepAlive = req.KeepAlive,
+ AffixTab = req.AffixTab,
+ Link = req.Link,
+ NoBasicLayout = req.NoBasicLayout,
+ MenuVisibleWithForbidden = req.MenuVisibleWithForbidden,
+ Authority = req.Authority,
+ }, ct);
+ await Send.ResponseAsync(result, 201, ct);
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/CreateMenuRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/CreateMenuRequestValidator.cs
new file mode 100644
index 0000000..448e25f
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Menus/CreateMenuRequestValidator.cs
@@ -0,0 +1,27 @@
+using BuildFlow.Platform.Application.Menus.DTOs;
+
+namespace BuildFlow.Host.Endpoints.rag.Menus;
+
+///
+/// 创建菜单请求校验。
+///
+public class CreateMenuRequestValidator : Validator
+{
+ public CreateMenuRequestValidator()
+ {
+ RuleFor(x => x.Name).NotEmpty().WithMessage("菜单路由名称不能为空")
+ .MaximumLength(100).WithMessage("菜单路由名称长度不能超过 100 个字符");
+ RuleFor(x => x.Path).NotEmpty().WithMessage("路由路径不能为空")
+ .MaximumLength(200).WithMessage("路由路径长度不能超过 200 个字符");
+ RuleFor(x => x.Title).NotEmpty().WithMessage("菜单标题不能为空")
+ .MaximumLength(100).WithMessage("菜单标题长度不能超过 100 个字符");
+ When(x => x.Component is not null, () =>
+ {
+ RuleFor(x => x.Component!).MaximumLength(200).WithMessage("组件路径长度不能超过 200 个字符");
+ });
+ When(x => x.Authority is not null, () =>
+ {
+ RuleFor(x => x.Authority!).MaximumLength(200).WithMessage("Authority 长度不能超过 200 个字符");
+ });
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpoint.cs
new file mode 100644
index 0000000..eb0ed9f
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpoint.cs
@@ -0,0 +1,22 @@
+using BuildFlow.Platform.Application.Menus.Commands;
+using MediatR;
+
+namespace BuildFlow.Host.Endpoints.rag.Menus;
+
+///
+/// 删除菜单端点。
+///
+public class DeleteMenuEndpoint(IMediator mediator) : Endpoint
+{
+ public override void Configure()
+ {
+ Delete("/menus/{Id}");
+ Permissions("menu:delete");
+ }
+
+ public override async Task HandleAsync(DeleteMenuEndpointRequest req, CancellationToken ct)
+ {
+ await mediator.Send(new DeleteMenuCommand(req.Id), ct);
+ await Send.OkAsync(true, ct);
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpointRequest.cs
new file mode 100644
index 0000000..398efb8
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpointRequest.cs
@@ -0,0 +1,6 @@
+namespace BuildFlow.Host.Endpoints.rag.Menus;
+
+///
+/// 删除菜单请求体。携带路由 Id。
+///
+public record DeleteMenuEndpointRequest(Guid Id);
diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpointRequestValidator.cs
new file mode 100644
index 0000000..47918be
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpointRequestValidator.cs
@@ -0,0 +1,12 @@
+namespace BuildFlow.Host.Endpoints.rag.Menus;
+
+///
+/// 删除菜单请求校验。
+///
+public class DeleteMenuEndpointRequestValidator : Validator
+{
+ public DeleteMenuEndpointRequestValidator()
+ {
+ RuleFor(x => x.Id).NotEmpty().WithMessage("菜单 ID 不能为空");
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/rag/Menus/GetAllMenusEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/GetAllMenusEndpoint.cs
similarity index 85%
rename from src/BuildFlow.Host/Endpoints/rag/Menus/GetAllMenusEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Menus/GetAllMenusEndpoint.cs
index 3121111..f82e60a 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Menus/GetAllMenusEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Menus/GetAllMenusEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Menus.DTOs;
-using BuildFlow.Application.Menus.Queries;
+using BuildFlow.Platform.Application.Menus.DTOs;
+using BuildFlow.Platform.Application.Menus.Queries;
using BuildFlow.Shared.Domain.Common;
using MediatR;
diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuByIdEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuByIdEndpoint.cs
new file mode 100644
index 0000000..c4ae6d8
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuByIdEndpoint.cs
@@ -0,0 +1,23 @@
+using BuildFlow.Platform.Application.Menus.DTOs;
+using BuildFlow.Platform.Application.Menus.Queries;
+using MediatR;
+
+namespace BuildFlow.Host.Endpoints.rag.Menus;
+
+///
+/// 按主键查询单个菜单端点。
+///
+public class GetMenuByIdEndpoint(IMediator mediator) : Endpoint
+{
+ public override void Configure()
+ {
+ Get("/menus/{Id}");
+ Permissions("menu:read");
+ }
+
+ public override async Task HandleAsync(GetMenuByIdRequest req, CancellationToken ct)
+ {
+ var result = await mediator.Send(new GetMenuByIdQuery(req.Id), ct);
+ await Send.OkAsync(result, ct);
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuByIdRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuByIdRequest.cs
new file mode 100644
index 0000000..fb5b4d1
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuByIdRequest.cs
@@ -0,0 +1,6 @@
+namespace BuildFlow.Host.Endpoints.rag.Menus;
+
+///
+/// 按主键查询菜单请求体。携带路由 Id。
+///
+public record GetMenuByIdRequest(Guid Id);
diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuByIdRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuByIdRequestValidator.cs
new file mode 100644
index 0000000..274c1b2
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuByIdRequestValidator.cs
@@ -0,0 +1,12 @@
+namespace BuildFlow.Host.Endpoints.rag.Menus;
+
+///
+/// 按主键查询菜单请求校验。
+///
+public class GetMenuByIdRequestValidator : Validator
+{
+ public GetMenuByIdRequestValidator()
+ {
+ RuleFor(x => x.Id).NotEmpty().WithMessage("菜单 ID 不能为空");
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuTreeEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuTreeEndpoint.cs
new file mode 100644
index 0000000..057a575
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuTreeEndpoint.cs
@@ -0,0 +1,23 @@
+using BuildFlow.Platform.Application.Menus.DTOs;
+using BuildFlow.Platform.Application.Menus.Queries;
+using MediatR;
+
+namespace BuildFlow.Host.Endpoints.rag.Menus;
+
+///
+/// 菜单管理树端点。返回全部菜单,不做角色过滤,供管理端展示。
+///
+public class GetMenuTreeEndpoint(IMediator mediator) : EndpointWithoutRequest>
+{
+ public override void Configure()
+ {
+ Get("/menu/tree");
+ Permissions("menu:read");
+ }
+
+ public override async Task HandleAsync(CancellationToken ct)
+ {
+ var tree = await mediator.Send(new GetMenuTreeQuery(), ct);
+ await Send.OkAsync(tree, ct);
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/UpdateMenuEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/UpdateMenuEndpoint.cs
new file mode 100644
index 0000000..9dc6da6
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Menus/UpdateMenuEndpoint.cs
@@ -0,0 +1,42 @@
+using BuildFlow.Platform.Application.Menus.Commands;
+using BuildFlow.Platform.Application.Menus.DTOs;
+using MediatR;
+
+namespace BuildFlow.Host.Endpoints.rag.Menus;
+
+///
+/// 更新菜单端点。
+///
+public class UpdateMenuEndpoint(IMediator mediator) : Endpoint
+{
+ public override void Configure()
+ {
+ Put("/menus/{Id}");
+ Permissions("menu:update");
+ }
+
+ public override async Task HandleAsync(UpdateMenuEndpointRequest req, CancellationToken ct)
+ {
+ var result = await mediator.Send(new UpdateMenuCommand
+ {
+ Id = req.Id,
+ ParentId = req.ParentId,
+ Name = req.Name,
+ Path = req.Path,
+ Component = req.Component,
+ Redirect = req.Redirect,
+ Title = req.Title,
+ Icon = req.Icon,
+ ActiveIcon = req.ActiveIcon,
+ Order = req.Order,
+ HideInMenu = req.HideInMenu,
+ KeepAlive = req.KeepAlive,
+ AffixTab = req.AffixTab,
+ Link = req.Link,
+ NoBasicLayout = req.NoBasicLayout,
+ MenuVisibleWithForbidden = req.MenuVisibleWithForbidden,
+ Authority = req.Authority,
+ }, ct);
+ await Send.OkAsync(result, ct);
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/UpdateMenuEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/UpdateMenuEndpointRequest.cs
new file mode 100644
index 0000000..f33d17c
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Menus/UpdateMenuEndpointRequest.cs
@@ -0,0 +1,23 @@
+namespace BuildFlow.Host.Endpoints.rag.Menus;
+
+///
+/// 更新菜单请求体。携带路由 Id。
+///
+public record UpdateMenuEndpointRequest(
+ Guid Id,
+ Guid? ParentId,
+ string? Name,
+ string? Path,
+ string? Component,
+ string? Redirect,
+ string? Title,
+ string? Icon,
+ string? ActiveIcon,
+ int? Order,
+ bool? HideInMenu,
+ bool? KeepAlive,
+ bool? AffixTab,
+ string? Link,
+ bool? NoBasicLayout,
+ bool? MenuVisibleWithForbidden,
+ string? Authority);
diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/UpdateMenuEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/UpdateMenuEndpointRequestValidator.cs
new file mode 100644
index 0000000..ea2737c
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Menus/UpdateMenuEndpointRequestValidator.cs
@@ -0,0 +1,20 @@
+namespace BuildFlow.Host.Endpoints.rag.Menus;
+
+///
+/// 更新菜单请求校验。
+///
+public class UpdateMenuEndpointRequestValidator : Validator
+{
+ public UpdateMenuEndpointRequestValidator()
+ {
+ RuleFor(x => x.Id).NotEmpty().WithMessage("菜单 ID 不能为空");
+ When(x => x.Name is not null, () =>
+ {
+ RuleFor(x => x.Name!).MaximumLength(100).WithMessage("菜单路由名称长度不能超过 100 个字符");
+ });
+ When(x => x.Path is not null, () =>
+ {
+ RuleFor(x => x.Path!).MaximumLength(200).WithMessage("路由路径长度不能超过 200 个字符");
+ });
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/rag/Notifications/GetNotificationsEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/GetNotificationsEndpoint.cs
similarity index 86%
rename from src/BuildFlow.Host/Endpoints/rag/Notifications/GetNotificationsEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Notifications/GetNotificationsEndpoint.cs
index 2a77a29..2a4d58e 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Notifications/GetNotificationsEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Notifications/GetNotificationsEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Notifications.DTOs;
-using BuildFlow.Application.Notifications.Queries;
+using BuildFlow.Platform.Application.Notifications.DTOs;
+using BuildFlow.Platform.Application.Notifications.Queries;
using BuildFlow.Shared.Domain.Common;
using MediatR;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Notifications/GetNotificationsRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/GetNotificationsRequest.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Notifications/GetNotificationsRequest.cs
rename to src/BuildFlow.Host/Endpoints/platform/Notifications/GetNotificationsRequest.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Notifications/GetNotificationsRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/GetNotificationsRequestValidator.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Notifications/GetNotificationsRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Notifications/GetNotificationsRequestValidator.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Notifications/GetUnreadNotificationCountEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/GetUnreadNotificationCountEndpoint.cs
similarity index 91%
rename from src/BuildFlow.Host/Endpoints/rag/Notifications/GetUnreadNotificationCountEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Notifications/GetUnreadNotificationCountEndpoint.cs
index 9ee1a11..2197afe 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Notifications/GetUnreadNotificationCountEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Notifications/GetUnreadNotificationCountEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Notifications.Queries;
+using BuildFlow.Platform.Application.Notifications.Queries;
using BuildFlow.Shared.Domain.Common;
using MediatR;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Notifications/MarkAllNotificationsReadEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/MarkAllNotificationsReadEndpoint.cs
similarity index 91%
rename from src/BuildFlow.Host/Endpoints/rag/Notifications/MarkAllNotificationsReadEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Notifications/MarkAllNotificationsReadEndpoint.cs
index de267c2..bf923ec 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Notifications/MarkAllNotificationsReadEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Notifications/MarkAllNotificationsReadEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Notifications.Commands;
+using BuildFlow.Platform.Application.Notifications.Commands;
using BuildFlow.Shared.Domain.Common;
using MediatR;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Notifications/MarkNotificationReadEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/MarkNotificationReadEndpoint.cs
similarity index 92%
rename from src/BuildFlow.Host/Endpoints/rag/Notifications/MarkNotificationReadEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Notifications/MarkNotificationReadEndpoint.cs
index 699c4fe..6707852 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Notifications/MarkNotificationReadEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Notifications/MarkNotificationReadEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Notifications.Commands;
+using BuildFlow.Platform.Application.Notifications.Commands;
using BuildFlow.Shared.Domain.Common;
using MediatR;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Notifications/NotificationEndpointsExtensions.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/NotificationEndpointsExtensions.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Notifications/NotificationEndpointsExtensions.cs
rename to src/BuildFlow.Host/Endpoints/platform/Notifications/NotificationEndpointsExtensions.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Notifications/PublishNotificationEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/PublishNotificationEndpoint.cs
similarity index 92%
rename from src/BuildFlow.Host/Endpoints/rag/Notifications/PublishNotificationEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Notifications/PublishNotificationEndpoint.cs
index 0ec763f..07f0a01 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Notifications/PublishNotificationEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Notifications/PublishNotificationEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Notifications.Commands;
+using BuildFlow.Platform.Application.Notifications.Commands;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Notifications;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Notifications/PublishNotificationRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/PublishNotificationRequest.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Notifications/PublishNotificationRequest.cs
rename to src/BuildFlow.Host/Endpoints/platform/Notifications/PublishNotificationRequest.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Notifications/PublishNotificationRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/PublishNotificationRequestValidator.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Notifications/PublishNotificationRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Notifications/PublishNotificationRequestValidator.cs
diff --git a/src/BuildFlow.Host/Endpoints/platform/Permissions/CreatePermissionEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Permissions/CreatePermissionEndpoint.cs
new file mode 100644
index 0000000..131e2db
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Permissions/CreatePermissionEndpoint.cs
@@ -0,0 +1,24 @@
+using BuildFlow.Platform.Application.Permissions.Commands;
+using BuildFlow.Platform.Application.Permissions.DTOs;
+using MediatR;
+
+namespace BuildFlow.Host.Endpoints.rag.Permissions;
+
+///
+/// 创建权限端点。
+///
+public class CreatePermissionEndpoint(IMediator mediator) : Endpoint
+{
+ public override void Configure()
+ {
+ Post("/permissions");
+ Permissions("permission:create");
+ }
+
+ public override async Task HandleAsync(CreatePermissionRequest req, CancellationToken ct)
+ {
+ var result = await mediator.Send(
+ new CreatePermissionCommand(req.Name, req.Code, req.Description, req.Group), ct);
+ await Send.ResponseAsync(result, 201, ct);
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/platform/Permissions/CreatePermissionRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Permissions/CreatePermissionRequestValidator.cs
new file mode 100644
index 0000000..756732d
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Permissions/CreatePermissionRequestValidator.cs
@@ -0,0 +1,28 @@
+using BuildFlow.Platform.Application.Permissions.DTOs;
+
+namespace BuildFlow.Host.Endpoints.rag.Permissions;
+
+///
+/// 创建权限请求校验。
+///
+public class CreatePermissionRequestValidator : Validator
+{
+ public CreatePermissionRequestValidator()
+ {
+ RuleFor(x => x.Name)
+ .NotEmpty().WithMessage("权限名称不能为空")
+ .Length(2, 50).WithMessage("权限名称长度 2-50 个字符");
+ RuleFor(x => x.Code)
+ .NotEmpty().WithMessage("权限编码不能为空")
+ .Matches(@"^[a-z][a-z0-9-]*(:[a-z][a-z0-9-]*)+$")
+ .WithMessage("权限编码格式应为 resource:action,且仅小写字母、数字、连字符");
+ When(x => x.Description is not null, () =>
+ {
+ RuleFor(x => x.Description!).MaximumLength(500).WithMessage("权限描述长度不能超过 500 个字符");
+ });
+ When(x => x.Group is not null, () =>
+ {
+ RuleFor(x => x.Group!).MaximumLength(50).WithMessage("权限分组长度不能超过 50 个字符");
+ });
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/platform/Permissions/DeletePermissionEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Permissions/DeletePermissionEndpoint.cs
new file mode 100644
index 0000000..054eaef
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Permissions/DeletePermissionEndpoint.cs
@@ -0,0 +1,22 @@
+using BuildFlow.Platform.Application.Permissions.Commands;
+using MediatR;
+
+namespace BuildFlow.Host.Endpoints.rag.Permissions;
+
+///
+/// 删除权限端点。
+///
+public class DeletePermissionEndpoint(IMediator mediator) : Endpoint
+{
+ public override void Configure()
+ {
+ Delete("/permissions/{Id}");
+ Permissions("permission:delete");
+ }
+
+ public override async Task HandleAsync(DeletePermissionEndpointRequest req, CancellationToken ct)
+ {
+ await mediator.Send(new DeletePermissionCommand(req.Id), ct);
+ await Send.OkAsync(true, ct);
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/platform/Permissions/DeletePermissionEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Permissions/DeletePermissionEndpointRequest.cs
new file mode 100644
index 0000000..703e12d
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Permissions/DeletePermissionEndpointRequest.cs
@@ -0,0 +1,6 @@
+namespace BuildFlow.Host.Endpoints.rag.Permissions;
+
+///
+/// 删除权限请求体。携带路由 Id。
+///
+public record DeletePermissionEndpointRequest(Guid Id);
diff --git a/src/BuildFlow.Host/Endpoints/platform/Permissions/DeletePermissionEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Permissions/DeletePermissionEndpointRequestValidator.cs
new file mode 100644
index 0000000..ab54761
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Permissions/DeletePermissionEndpointRequestValidator.cs
@@ -0,0 +1,12 @@
+namespace BuildFlow.Host.Endpoints.rag.Permissions;
+
+///
+/// 删除权限请求校验。
+///
+public class DeletePermissionEndpointRequestValidator : Validator
+{
+ public DeletePermissionEndpointRequestValidator()
+ {
+ RuleFor(x => x.Id).NotEmpty().WithMessage("权限 ID 不能为空");
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/platform/Permissions/GetPermissionByIdEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Permissions/GetPermissionByIdEndpoint.cs
new file mode 100644
index 0000000..2bcce7e
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Permissions/GetPermissionByIdEndpoint.cs
@@ -0,0 +1,23 @@
+using BuildFlow.Platform.Application.Permissions.DTOs;
+using BuildFlow.Platform.Application.Permissions.Queries;
+using MediatR;
+
+namespace BuildFlow.Host.Endpoints.rag.Permissions;
+
+///
+/// 按主键查询单个权限端点。
+///
+public class GetPermissionByIdEndpoint(IMediator mediator) : Endpoint
+{
+ public override void Configure()
+ {
+ Get("/permissions/{Id}");
+ Permissions("permission:read");
+ }
+
+ public override async Task HandleAsync(GetPermissionByIdRequest req, CancellationToken ct)
+ {
+ var result = await mediator.Send(new GetPermissionByIdQuery(req.Id), ct);
+ await Send.OkAsync(result, ct);
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/platform/Permissions/GetPermissionByIdRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Permissions/GetPermissionByIdRequest.cs
new file mode 100644
index 0000000..b27bb4e
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Permissions/GetPermissionByIdRequest.cs
@@ -0,0 +1,6 @@
+namespace BuildFlow.Host.Endpoints.rag.Permissions;
+
+///
+/// 按主键查询权限请求体。携带路由 Id。
+///
+public record GetPermissionByIdRequest(Guid Id);
diff --git a/src/BuildFlow.Host/Endpoints/platform/Permissions/GetPermissionByIdRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Permissions/GetPermissionByIdRequestValidator.cs
new file mode 100644
index 0000000..2ec7f7f
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Permissions/GetPermissionByIdRequestValidator.cs
@@ -0,0 +1,12 @@
+namespace BuildFlow.Host.Endpoints.rag.Permissions;
+
+///
+/// 按主键查询权限请求校验。
+///
+public class GetPermissionByIdRequestValidator : Validator
+{
+ public GetPermissionByIdRequestValidator()
+ {
+ RuleFor(x => x.Id).NotEmpty().WithMessage("权限 ID 不能为空");
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/rag/Permissions/GetPermissionListEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Permissions/GetPermissionListEndpoint.cs
similarity index 85%
rename from src/BuildFlow.Host/Endpoints/rag/Permissions/GetPermissionListEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Permissions/GetPermissionListEndpoint.cs
index fe1c976..399b503 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Permissions/GetPermissionListEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Permissions/GetPermissionListEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Permissions.DTOs;
-using BuildFlow.Application.Permissions.Queries;
+using BuildFlow.Platform.Application.Permissions.DTOs;
+using BuildFlow.Platform.Application.Permissions.Queries;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Permissions;
diff --git a/src/BuildFlow.Host/Endpoints/platform/Permissions/UpdatePermissionEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Permissions/UpdatePermissionEndpoint.cs
new file mode 100644
index 0000000..233de64
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Permissions/UpdatePermissionEndpoint.cs
@@ -0,0 +1,24 @@
+using BuildFlow.Platform.Application.Permissions.Commands;
+using BuildFlow.Platform.Application.Permissions.DTOs;
+using MediatR;
+
+namespace BuildFlow.Host.Endpoints.rag.Permissions;
+
+///
+/// 更新权限端点。编码不可改。
+///
+public class UpdatePermissionEndpoint(IMediator mediator) : Endpoint
+{
+ public override void Configure()
+ {
+ Put("/permissions/{Id}");
+ Permissions("permission:update");
+ }
+
+ public override async Task HandleAsync(UpdatePermissionEndpointRequest req, CancellationToken ct)
+ {
+ var result = await mediator.Send(
+ new UpdatePermissionCommand(req.Id, req.Name, req.Description, req.Group), ct);
+ await Send.OkAsync(result, ct);
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/platform/Permissions/UpdatePermissionEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Permissions/UpdatePermissionEndpointRequest.cs
new file mode 100644
index 0000000..759a087
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Permissions/UpdatePermissionEndpointRequest.cs
@@ -0,0 +1,6 @@
+namespace BuildFlow.Host.Endpoints.rag.Permissions;
+
+///
+/// 更新权限请求体。携带路由 Id。
+///
+public record UpdatePermissionEndpointRequest(Guid Id, string? Name, string? Description, string? Group);
diff --git a/src/BuildFlow.Host/Endpoints/platform/Permissions/UpdatePermissionEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Permissions/UpdatePermissionEndpointRequestValidator.cs
new file mode 100644
index 0000000..bd18c25
--- /dev/null
+++ b/src/BuildFlow.Host/Endpoints/platform/Permissions/UpdatePermissionEndpointRequestValidator.cs
@@ -0,0 +1,24 @@
+namespace BuildFlow.Host.Endpoints.rag.Permissions;
+
+///
+/// 更新权限请求校验。
+///
+public class UpdatePermissionEndpointRequestValidator : Validator
+{
+ public UpdatePermissionEndpointRequestValidator()
+ {
+ RuleFor(x => x.Id).NotEmpty().WithMessage("权限 ID 不能为空");
+ When(x => x.Name is not null, () =>
+ {
+ RuleFor(x => x.Name!).Length(2, 50).WithMessage("权限名称长度 2-50 个字符");
+ });
+ When(x => x.Description is not null, () =>
+ {
+ RuleFor(x => x.Description!).MaximumLength(500).WithMessage("权限描述长度不能超过 500 个字符");
+ });
+ When(x => x.Group is not null, () =>
+ {
+ RuleFor(x => x.Group!).MaximumLength(50).WithMessage("权限分组长度不能超过 50 个字符");
+ });
+ }
+}
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/AssignPermissionsEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpoint.cs
similarity index 86%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/AssignPermissionsEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpoint.cs
index d48faa9..b93f158 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Roles/AssignPermissionsEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Roles.Commands;
-using BuildFlow.Application.Roles.DTOs;
+using BuildFlow.Platform.Application.Roles.Commands;
+using BuildFlow.Platform.Application.Roles.DTOs;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Roles;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/AssignPermissionsEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpointRequest.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/AssignPermissionsEndpointRequest.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpointRequest.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/AssignPermissionsEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpointRequestValidator.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/AssignPermissionsEndpointRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpointRequestValidator.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/CreateRoleEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/CreateRoleEndpoint.cs
similarity index 85%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/CreateRoleEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/CreateRoleEndpoint.cs
index 2c215c8..32c3280 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Roles/CreateRoleEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Roles/CreateRoleEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Roles.Commands;
-using BuildFlow.Application.Roles.DTOs;
+using BuildFlow.Platform.Application.Roles.Commands;
+using BuildFlow.Platform.Application.Roles.DTOs;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Roles;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/CreateRoleRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/CreateRoleRequestValidator.cs
similarity index 93%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/CreateRoleRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/CreateRoleRequestValidator.cs
index 60e59e1..e62beb0 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Roles/CreateRoleRequestValidator.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Roles/CreateRoleRequestValidator.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Roles.DTOs;
+using BuildFlow.Platform.Application.Roles.DTOs;
namespace BuildFlow.Host.Endpoints.rag.Roles;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/DeleteRoleEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/DeleteRoleEndpoint.cs
similarity index 91%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/DeleteRoleEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/DeleteRoleEndpoint.cs
index e29c86c..c052483 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Roles/DeleteRoleEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Roles/DeleteRoleEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Roles.Commands;
+using BuildFlow.Platform.Application.Roles.Commands;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Roles;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/DeleteRoleEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/DeleteRoleEndpointRequest.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/DeleteRoleEndpointRequest.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/DeleteRoleEndpointRequest.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/DeleteRoleEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/DeleteRoleEndpointRequestValidator.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/DeleteRoleEndpointRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/DeleteRoleEndpointRequestValidator.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/GetRoleByIdEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/GetRoleByIdEndpoint.cs
similarity index 84%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/GetRoleByIdEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/GetRoleByIdEndpoint.cs
index bce56ae..9bdb7f8 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Roles/GetRoleByIdEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Roles/GetRoleByIdEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Roles.DTOs;
-using BuildFlow.Application.Roles.Queries;
+using BuildFlow.Platform.Application.Roles.DTOs;
+using BuildFlow.Platform.Application.Roles.Queries;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Roles;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/GetRoleByIdRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/GetRoleByIdRequest.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/GetRoleByIdRequest.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/GetRoleByIdRequest.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/GetRoleByIdRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/GetRoleByIdRequestValidator.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/GetRoleByIdRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/GetRoleByIdRequestValidator.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/GetRoleListEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/GetRoleListEndpoint.cs
similarity index 83%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/GetRoleListEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/GetRoleListEndpoint.cs
index 5e7f941..f543d6e 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Roles/GetRoleListEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Roles/GetRoleListEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Roles.DTOs;
-using BuildFlow.Application.Roles.Queries;
+using BuildFlow.Platform.Application.Roles.DTOs;
+using BuildFlow.Platform.Application.Roles.Queries;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Roles;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/UpdateRoleEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpoint.cs
similarity index 85%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/UpdateRoleEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpoint.cs
index e6f3fdc..b876fe3 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Roles/UpdateRoleEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Roles.Commands;
-using BuildFlow.Application.Roles.DTOs;
+using BuildFlow.Platform.Application.Roles.Commands;
+using BuildFlow.Platform.Application.Roles.DTOs;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Roles;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/UpdateRoleEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpointRequest.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/UpdateRoleEndpointRequest.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpointRequest.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Roles/UpdateRoleEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpointRequestValidator.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Roles/UpdateRoleEndpointRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpointRequestValidator.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/AssignRolesEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Users/AssignRolesEndpoint.cs
similarity index 85%
rename from src/BuildFlow.Host/Endpoints/rag/Users/AssignRolesEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/AssignRolesEndpoint.cs
index dc8317c..1dfd7ef 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Users/AssignRolesEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Users/AssignRolesEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Users.Commands;
-using BuildFlow.Application.Users.DTOs;
+using BuildFlow.Platform.Application.Users.Commands;
+using BuildFlow.Platform.Application.Users.DTOs;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Users;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/AssignRolesEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Users/AssignRolesEndpointRequest.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Users/AssignRolesEndpointRequest.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/AssignRolesEndpointRequest.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/AssignRolesEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Users/AssignRolesEndpointRequestValidator.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Users/AssignRolesEndpointRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/AssignRolesEndpointRequestValidator.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/CreateUserEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Users/CreateUserEndpoint.cs
similarity index 86%
rename from src/BuildFlow.Host/Endpoints/rag/Users/CreateUserEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/CreateUserEndpoint.cs
index a6e9ef0..3108c68 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Users/CreateUserEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Users/CreateUserEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Users.Commands;
-using BuildFlow.Application.Users.DTOs;
+using BuildFlow.Platform.Application.Users.Commands;
+using BuildFlow.Platform.Application.Users.DTOs;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Users;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/CreateUserRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Users/CreateUserRequestValidator.cs
similarity index 93%
rename from src/BuildFlow.Host/Endpoints/rag/Users/CreateUserRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/CreateUserRequestValidator.cs
index 04b30ca..d516bae 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Users/CreateUserRequestValidator.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Users/CreateUserRequestValidator.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Users.DTOs;
+using BuildFlow.Platform.Application.Users.DTOs;
namespace BuildFlow.Host.Endpoints.rag.Users;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/DeleteUserEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Users/DeleteUserEndpoint.cs
similarity index 91%
rename from src/BuildFlow.Host/Endpoints/rag/Users/DeleteUserEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/DeleteUserEndpoint.cs
index a6ac870..f06fb79 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Users/DeleteUserEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Users/DeleteUserEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Application.Users.Commands;
+using BuildFlow.Platform.Application.Users.Commands;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Users;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/DeleteUserEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Users/DeleteUserEndpointRequest.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Users/DeleteUserEndpointRequest.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/DeleteUserEndpointRequest.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/DeleteUserEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Users/DeleteUserEndpointRequestValidator.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Users/DeleteUserEndpointRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/DeleteUserEndpointRequestValidator.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/GetUserByIdEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Users/GetUserByIdEndpoint.cs
similarity index 84%
rename from src/BuildFlow.Host/Endpoints/rag/Users/GetUserByIdEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/GetUserByIdEndpoint.cs
index 35fc2e2..186bd38 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Users/GetUserByIdEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Users/GetUserByIdEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Users.DTOs;
-using BuildFlow.Application.Users.Queries;
+using BuildFlow.Platform.Application.Users.DTOs;
+using BuildFlow.Platform.Application.Users.Queries;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Users;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/GetUserByIdRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Users/GetUserByIdRequest.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Users/GetUserByIdRequest.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/GetUserByIdRequest.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/GetUserByIdRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Users/GetUserByIdRequestValidator.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Users/GetUserByIdRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/GetUserByIdRequestValidator.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/GetUserListEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Users/GetUserListEndpoint.cs
similarity index 84%
rename from src/BuildFlow.Host/Endpoints/rag/Users/GetUserListEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/GetUserListEndpoint.cs
index 725125f..bc1db37 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Users/GetUserListEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Users/GetUserListEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Users.DTOs;
-using BuildFlow.Application.Users.Queries;
+using BuildFlow.Platform.Application.Users.DTOs;
+using BuildFlow.Platform.Application.Users.Queries;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Users;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/GetUserListRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Users/GetUserListRequest.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Users/GetUserListRequest.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/GetUserListRequest.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/UpdateUserEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpoint.cs
similarity index 85%
rename from src/BuildFlow.Host/Endpoints/rag/Users/UpdateUserEndpoint.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpoint.cs
index 91cfca1..b9b8eaa 100644
--- a/src/BuildFlow.Host/Endpoints/rag/Users/UpdateUserEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpoint.cs
@@ -1,5 +1,5 @@
-using BuildFlow.Application.Users.Commands;
-using BuildFlow.Application.Users.DTOs;
+using BuildFlow.Platform.Application.Users.Commands;
+using BuildFlow.Platform.Application.Users.DTOs;
using MediatR;
namespace BuildFlow.Host.Endpoints.rag.Users;
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/UpdateUserEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpointRequest.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Users/UpdateUserEndpointRequest.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpointRequest.cs
diff --git a/src/BuildFlow.Host/Endpoints/rag/Users/UpdateUserEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpointRequestValidator.cs
similarity index 100%
rename from src/BuildFlow.Host/Endpoints/rag/Users/UpdateUserEndpointRequestValidator.cs
rename to src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpointRequestValidator.cs
diff --git a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Applications/CreateBuildFlowApplicationEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Applications/CreateBuildFlowApplicationEndpoint.cs
index e63902b..1bb5589 100644
--- a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Applications/CreateBuildFlowApplicationEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Applications/CreateBuildFlowApplicationEndpoint.cs
@@ -21,4 +21,4 @@ public class CreateBuildFlowApplicationEndpoint(IMediator mediator)
ct);
await Send.ResponseAsync(result, 201, ct);
}
-}
+}
\ No newline at end of file
diff --git a/src/BuildFlow.Host/Endpoints/workflow/Notification/GetNotificationsEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/Notification/GetNotificationsEndpoint.cs
index a1581d4..c519f95 100644
--- a/src/BuildFlow.Host/Endpoints/workflow/Notification/GetNotificationsEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/workflow/Notification/GetNotificationsEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Host.Services;
+using BuildFlow.Host.Services.Users;
using BuildFlow.Shared.Domain.Common;
using MediatR;
using Workflow.Application.Common;
diff --git a/src/BuildFlow.Host/Endpoints/workflow/Notification/GetUnreadNotificationCountEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/Notification/GetUnreadNotificationCountEndpoint.cs
index 1ad1805..7a9f000 100644
--- a/src/BuildFlow.Host/Endpoints/workflow/Notification/GetUnreadNotificationCountEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/workflow/Notification/GetUnreadNotificationCountEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Host.Services;
+using BuildFlow.Host.Services.Users;
using BuildFlow.Shared.Domain.Common;
using MediatR;
using Workflow.Application.Features.Notifications;
diff --git a/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkAllNotificationsReadEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkAllNotificationsReadEndpoint.cs
index 6dba92c..8251d25 100644
--- a/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkAllNotificationsReadEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkAllNotificationsReadEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Host.Services;
+using BuildFlow.Host.Services.Users;
using BuildFlow.Shared.Domain.Common;
using MediatR;
using Workflow.Application.Features.Notifications;
diff --git a/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkNotificationReadEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkNotificationReadEndpoint.cs
index 8cba561..308f0e0 100644
--- a/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkNotificationReadEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkNotificationReadEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Host.Services;
+using BuildFlow.Host.Services.Users;
using BuildFlow.Shared.Domain.Common;
using MediatR;
using Workflow.Application.Features.Notifications;
diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/WithdrawWorkflowInstanceEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/WithdrawWorkflowInstanceEndpoint.cs
index b437a0d..8e570a8 100644
--- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/WithdrawWorkflowInstanceEndpoint.cs
+++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/WithdrawWorkflowInstanceEndpoint.cs
@@ -1,4 +1,4 @@
-using BuildFlow.Host.Services;
+using BuildFlow.Host.Services.Users;
using BuildFlow.Shared.Domain.Common;
using MediatR;
using Workflow.Application.Features.WorkflowInstances.Commands;
diff --git a/src/BuildFlow.Host/Program.cs b/src/BuildFlow.Host/Program.cs
index 7b2b4ec..bda3422 100644
--- a/src/BuildFlow.Host/Program.cs
+++ b/src/BuildFlow.Host/Program.cs
@@ -44,6 +44,7 @@ using (var scope = app.Services.CreateScope())
// 各模块 DbContext 自动 Migrate(有 migration 的)或 EnsureCreated(无 migration 的)
// rag/workflow 均有未提交的模型变更(PendingModelChanges),已在模块注册时抑制该警告
await MigrateDbAsync(sp);
+ await MigrateDbAsync(sp);
await MigrateDbAsync(sp);
await MigrateDbAsync(sp);
await MigrateDbAsync(sp, suppressPendingChanges: true);
@@ -59,16 +60,12 @@ using (var scope = app.Services.CreateScope())
// seed 数据
try
{
- var ragDb = sp.GetRequiredService();
- if (!ragDb.Users.Any())
- await BuildFlow.Infrastructure.Persistence.SeedData.SeedAsync(ragDb);
- // 菜单种子独立执行:SeedMenusAsync 内部已按 Id 幂等补种(缺失才插),
- // 必须始终调用——否则升级新增菜单时已有 menus 数据会卡在「库非空」跳过逻辑里拿不到新项。
- await BuildFlow.Infrastructure.Persistence.SeedData.SeedMenusAsync(ragDb);
+ // 平台种子(权限/角色/用户/菜单)——用 PlatformDbContext
+ var platformDb = sp.GetRequiredService();
+ await BuildFlow.Platform.Infrastructure.Persistence.SeedData.SeedAsync(platformDb);
+ // workflow 种子(组件注册)
var wfDb = sp.GetRequiredService();
- // 组件注册是基础设施、按 Id 幂等补插,必须始终执行——否则数据库已有流程定义时
- // (!WorkflowDefinitions.Any() 为 false)会连带跳过组件注册,导致新组件永不入库。
await SeedData.SeedAsync(wfDb);
}
catch (Exception ex) { Console.WriteLine($"[warn] Seed 跳过: {ex.Message}"); }
diff --git a/src/BuildFlow.Host/Services/TimeoutSchedulerService.cs b/src/BuildFlow.Host/Services/BackgroundServices/TimeoutSchedulerService.cs
similarity index 97%
rename from src/BuildFlow.Host/Services/TimeoutSchedulerService.cs
rename to src/BuildFlow.Host/Services/BackgroundServices/TimeoutSchedulerService.cs
index 28b23e8..03caaec 100644
--- a/src/BuildFlow.Host/Services/TimeoutSchedulerService.cs
+++ b/src/BuildFlow.Host/Services/BackgroundServices/TimeoutSchedulerService.cs
@@ -2,7 +2,7 @@ using Microsoft.Extensions.Options;
using Workflow.Application.Notifications;
using Workflow.Application.Scheduler;
-namespace BuildFlow.Host.Services;
+namespace BuildFlow.Host.Services.BackgroundServices;
///
/// 超时任务调度器:后台 HostedService 壳,周期性调用 OverdueTaskProcessor 扫描逾期任务。
diff --git a/src/BuildFlow.Host/Services/WebhookDispatcherService.cs b/src/BuildFlow.Host/Services/BackgroundServices/WebhookDispatcherService.cs
similarity index 99%
rename from src/BuildFlow.Host/Services/WebhookDispatcherService.cs
rename to src/BuildFlow.Host/Services/BackgroundServices/WebhookDispatcherService.cs
index f9c8bfc..29bbfa8 100644
--- a/src/BuildFlow.Host/Services/WebhookDispatcherService.cs
+++ b/src/BuildFlow.Host/Services/BackgroundServices/WebhookDispatcherService.cs
@@ -4,7 +4,7 @@ using Workflow.Application.Notifications;
using Workflow.Domain.Entities;
using Workflow.Infrastructure.Persistence;
-namespace BuildFlow.Host.Services;
+namespace BuildFlow.Host.Services.BackgroundServices;
///
/// Webhook 后台投递服务:轮询 wf_webhook_deliveries 中 status=pending 且到下次重试时间的记录,
diff --git a/src/BuildFlow.Host/Services/InProcessFileStorageClient.cs b/src/BuildFlow.Host/Services/Integration/InProcessFileStorageClient.cs
similarity index 83%
rename from src/BuildFlow.Host/Services/InProcessFileStorageClient.cs
rename to src/BuildFlow.Host/Services/Integration/InProcessFileStorageClient.cs
index dc06fa9..d277cdc 100644
--- a/src/BuildFlow.Host/Services/InProcessFileStorageClient.cs
+++ b/src/BuildFlow.Host/Services/Integration/InProcessFileStorageClient.cs
@@ -3,7 +3,7 @@ using BuildFlow.Domain.Interfaces;
using File.Application.Features.Files.Commands;
using File.Application.Features.Files.Queries;
-namespace BuildFlow.Host;
+namespace BuildFlow.Host.Services.Integration;
///
/// 进程内文件存储实现,替代 rag-backend 原有的 HTTP 版 FileStorageClient。
@@ -36,9 +36,8 @@ public class InProcessFileStorageClient(IMediator mediator) : IFileStorageClient
CancellationToken ct = default)
{
// 通过 MediatR 查询调用 file 模块的 DownloadFileQueryHandler。
- // 注意:DownloadFileQuery 把对象 buffer 成 byte[](file 模块的查询契约),这里包成 MemoryStream 还原成 Stream。
- // 文档处理场景下文件多为 MB 级,内存拷贝可接受;如需真正的流式,可在 file 模块加一个返回 Stream 的查询。
+ // DownloadFileQuery 现在直接返回 S3 原始流(不再 buffer 成 byte[]),此处原样透传。
var result = await mediator.Send(new DownloadFileQuery(bucket, objectKey), ct);
- return new MemoryStream(result.Data);
+ return result.Stream;
}
}
diff --git a/src/BuildFlow.Host/Services/InProcessUserInfoService.cs b/src/BuildFlow.Host/Services/Integration/InProcessUserInfoService.cs
similarity index 85%
rename from src/BuildFlow.Host/Services/InProcessUserInfoService.cs
rename to src/BuildFlow.Host/Services/Integration/InProcessUserInfoService.cs
index d7b3942..7ee3c37 100644
--- a/src/BuildFlow.Host/Services/InProcessUserInfoService.cs
+++ b/src/BuildFlow.Host/Services/Integration/InProcessUserInfoService.cs
@@ -1,13 +1,13 @@
using MediatR;
-using BuildFlow.Application.Users.Queries;
+using BuildFlow.Platform.Application.Users.Queries;
using IM.Domain.Common;
-namespace BuildFlow.Host;
+namespace BuildFlow.Host.Services.Integration;
///
/// 进程内用户信息查询实现,替代 IM 原有的 gRPC 版 AuthGrpcClientService。
/// 通过 MediatR 查询调用 rag 模块的 处理器,
-/// 而非直接注入 RagDbContext——这样 im 模块对 rag 的依赖从「直接引用 DbContext」
+/// 而非直接注入 PlatformDbContext——这样 im 模块对 rag 的依赖从「直接引用 DbContext」
/// 降级为「发 MediatR 消息」,实现模块间解耦。im 只依赖消息契约,不感知 rag 的数据访问实现。
///
/// 容错策略与 gRPC 版一致:查询失败返回空字典,避免 IM 核心链路因数据库抖动而整体不可用。
@@ -24,7 +24,7 @@ public class InProcessUserInfoService(IMediator mediator) : IUserInfoService
try
{
- // 通过 MediatR 查询调用 rag 模块的 GetUserNamesQueryHandler(它内部查 RagDbContext.Users)
+ // 通过 MediatR 查询调用 rag 模块的 GetUserNamesQueryHandler(它内部查 PlatformDbContext.Users)
var names = await mediator.Send(new GetUserNamesQuery(idList), ct);
// rag 的 User 无 Avatar 字段(gRPC 服务端也返回 Avatar=""),故头像恒为 null
diff --git a/src/BuildFlow.Host/Services/SignalRNotificationDispatcher.cs b/src/BuildFlow.Host/Services/Notifications/SignalRNotificationDispatcher.cs
similarity index 90%
rename from src/BuildFlow.Host/Services/SignalRNotificationDispatcher.cs
rename to src/BuildFlow.Host/Services/Notifications/SignalRNotificationDispatcher.cs
index 5f30826..ba13a28 100644
--- a/src/BuildFlow.Host/Services/SignalRNotificationDispatcher.cs
+++ b/src/BuildFlow.Host/Services/Notifications/SignalRNotificationDispatcher.cs
@@ -1,9 +1,9 @@
-using BuildFlow.Application.Notifications;
-using BuildFlow.Domain.Entities;
+using BuildFlow.Platform.Application.Notifications;
+using BuildFlow.Platform.Domain.Entities;
using BuildFlow.Host.Hubs;
using Microsoft.AspNetCore.SignalR;
-namespace BuildFlow.Host.Services;
+namespace BuildFlow.Host.Services.Notifications;
///
/// 基于 SignalR 的通知分发实现。把已落库的通知按接收人推送到对应分组(user:{id}),
diff --git a/src/BuildFlow.Host/Services/SeedData.IM.cs b/src/BuildFlow.Host/Services/SeedData.IM.cs
deleted file mode 100644
index 5d9e5ce..0000000
--- a/src/BuildFlow.Host/Services/SeedData.IM.cs
+++ /dev/null
@@ -1,278 +0,0 @@
-using IM.Domain.Entities;
-using IM.Domain.Enums;
-using IM.Infrastructure.Mongo;
-using IM.Infrastructure.Persistence;
-using MongoDB.Driver;
-using Group = IM.Domain.Entities.Group;
-
-namespace BuildFlow.Host.Services;
-
-///
-/// IM 模块种子数据。初始化演示用的测试群组与成员关系。
-///
-public static class SeedData
-{
- // Mock 用户(AdminId 匹配 rag-backend JWT 中的 sub claim)
- private static readonly Guid AdminId = Guid.Parse("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11");
- private static readonly Guid User1Id = Guid.Parse("30000000-0000-0000-0000-000000000002");
- private static readonly Guid User2Id = Guid.Parse("30000000-0000-0000-0000-000000000003");
- private static readonly Guid User3Id = Guid.Parse("30000000-0000-0000-0000-000000000004");
-
- public static async Task SeedAsync(IServiceProvider serviceProvider)
- {
- using var scope = serviceProvider.CreateScope();
- var db = scope.ServiceProvider.GetRequiredService();
- var mongoDb = scope.ServiceProvider.GetRequiredService();
-
- // 检查是否已有 seed 数据(通过固定 ID 检测)
- var existingCount = await db.Conversations.CountAsync();
- if (existingCount > 0)
- {
- Console.WriteLine($"SeedData: 清除旧数据 ({existingCount} 条会话)...");
- db.GroupMembers.RemoveRange(db.GroupMembers);
- db.Groups.RemoveRange(db.Groups);
- db.ConversationParticipants.RemoveRange(db.ConversationParticipants);
- db.Conversations.RemoveRange(db.Conversations);
- await db.SaveChangesAsync();
-
- // 清除 MongoDB 旧消息
- await mongoDb.Messages.DeleteManyAsync(FilterDefinition.Empty);
- }
-
- var now = DateTime.UtcNow;
- var systemUser = "system";
-
- // ===== 1. 私聊会话:Admin ↔ User1 =====
- var privateConv1 = new Conversation
- {
- Id = Guid.NewGuid(),
- Type = ConversationType.Private,
- LastMessageContent = "项目进展如何?",
- LastMessageAt = now.AddMinutes(-30),
- CreatedBy = systemUser, CreatedAt = now.AddDays(-3),
- UpdatedBy = systemUser, UpdatedAt = now.AddMinutes(-30),
- OperatorIP = "127.0.0.1"
- };
-
- privateConv1.Participants =
- [
- new ConversationParticipant
- {
- ConversationId = privateConv1.Id, UserId = AdminId,
- JoinedAt = now.AddDays(-3), UnreadCount = 0,
- CreatedBy = systemUser, CreatedAt = now.AddDays(-3),
- UpdatedBy = systemUser, UpdatedAt = now.AddMinutes(-30)
- },
- new ConversationParticipant
- {
- ConversationId = privateConv1.Id, UserId = User1Id,
- JoinedAt = now.AddDays(-3), UnreadCount = 2,
- CreatedBy = systemUser, CreatedAt = now.AddDays(-3),
- UpdatedBy = systemUser, UpdatedAt = now.AddMinutes(-30)
- }
- ];
-
- // ===== 2. 私聊会话:Admin ↔ User2 =====
- var privateConv2 = new Conversation
- {
- Id = Guid.NewGuid(),
- Type = ConversationType.Private,
- LastMessageContent = "下午有空讨论一下技术方案吗?",
- LastMessageAt = now.AddHours(-2),
- CreatedBy = systemUser, CreatedAt = now.AddDays(-1),
- UpdatedBy = systemUser, UpdatedAt = now.AddHours(-2),
- OperatorIP = "127.0.0.1"
- };
-
- privateConv2.Participants =
- [
- new ConversationParticipant
- {
- ConversationId = privateConv2.Id, UserId = AdminId,
- JoinedAt = now.AddDays(-1), UnreadCount = 1,
- CreatedBy = systemUser, CreatedAt = now.AddDays(-1),
- UpdatedBy = systemUser, UpdatedAt = now.AddHours(-2)
- },
- new ConversationParticipant
- {
- ConversationId = privateConv2.Id, UserId = User2Id,
- JoinedAt = now.AddDays(-1), UnreadCount = 0,
- CreatedBy = systemUser, CreatedAt = now.AddDays(-1),
- UpdatedBy = systemUser, UpdatedAt = now.AddHours(-2)
- }
- ];
-
- // ===== 3. 群聊会话:项目组 =====
- var groupConv = new Conversation
- {
- Id = Guid.NewGuid(),
- Type = ConversationType.Group,
- LastMessageContent = "[图片]",
- LastMessageAt = now.AddMinutes(-10),
- CreatedBy = systemUser, CreatedAt = now.AddDays(-5),
- UpdatedBy = systemUser, UpdatedAt = now.AddMinutes(-10),
- OperatorIP = "127.0.0.1"
- };
-
- var group = new Group
- {
- Id = Guid.NewGuid(),
- ConversationId = groupConv.Id,
- Name = "RAG 项目组",
- Description = "RAG 全栈项目开发讨论",
- OwnerId = AdminId,
- MaxMembers = 500,
- CreatedBy = systemUser, CreatedAt = now.AddDays(-5),
- UpdatedBy = systemUser, UpdatedAt = now.AddMinutes(-10),
- OperatorIP = "127.0.0.1"
- };
-
- group.Members =
- [
- new GroupMember
- {
- GroupId = group.Id, UserId = AdminId, Role = GroupMemberRole.Owner,
- JoinedAt = now.AddDays(-5),
- CreatedBy = systemUser, CreatedAt = now.AddDays(-5),
- UpdatedBy = systemUser, UpdatedAt = now.AddDays(-5)
- },
- new GroupMember
- {
- GroupId = group.Id, UserId = User1Id, Role = GroupMemberRole.Admin,
- JoinedAt = now.AddDays(-5),
- CreatedBy = systemUser, CreatedAt = now.AddDays(-5),
- UpdatedBy = systemUser, UpdatedAt = now.AddDays(-5)
- },
- new GroupMember
- {
- GroupId = group.Id, UserId = User2Id, Role = GroupMemberRole.Member,
- JoinedAt = now.AddDays(-4),
- CreatedBy = systemUser, CreatedAt = now.AddDays(-4),
- UpdatedBy = systemUser, UpdatedAt = now.AddDays(-4)
- },
- new GroupMember
- {
- GroupId = group.Id, UserId = User3Id, Role = GroupMemberRole.Member,
- JoinedAt = now.AddDays(-3),
- CreatedBy = systemUser, CreatedAt = now.AddDays(-3),
- UpdatedBy = systemUser, UpdatedAt = now.AddDays(-3)
- }
- ];
-
- groupConv.Participants =
- [
- new ConversationParticipant
- {
- ConversationId = groupConv.Id, UserId = AdminId,
- JoinedAt = now.AddDays(-5), UnreadCount = 3,
- CreatedBy = systemUser, CreatedAt = now.AddDays(-5),
- UpdatedBy = systemUser, UpdatedAt = now.AddMinutes(-10)
- },
- new ConversationParticipant
- {
- ConversationId = groupConv.Id, UserId = User1Id,
- JoinedAt = now.AddDays(-5), UnreadCount = 1,
- CreatedBy = systemUser, CreatedAt = now.AddDays(-5),
- UpdatedBy = systemUser, UpdatedAt = now.AddMinutes(-10)
- },
- new ConversationParticipant
- {
- ConversationId = groupConv.Id, UserId = User2Id,
- JoinedAt = now.AddDays(-4), UnreadCount = 5,
- CreatedBy = systemUser, CreatedAt = now.AddDays(-4),
- UpdatedBy = systemUser, UpdatedAt = now.AddMinutes(-10)
- },
- new ConversationParticipant
- {
- ConversationId = groupConv.Id, UserId = User3Id,
- JoinedAt = now.AddDays(-3), UnreadCount = 0,
- CreatedBy = systemUser, CreatedAt = now.AddDays(-3),
- UpdatedBy = systemUser, UpdatedAt = now.AddMinutes(-10)
- }
- ];
-
- groupConv.Group = group;
-
- db.Conversations.AddRange(privateConv1, privateConv2, groupConv);
- db.Groups.Add(group);
- await db.SaveChangesAsync();
-
- // ===== MongoDB 消息 =====
- var messages = new List();
-
- // 私聊1 消息
- AddMessages(messages, privateConv1.Id, [
- (AdminId, "小赵", MessageContentType.Text, "你好,项目进展如何?", now.AddDays(-3).AddHours(1)),
- (User1Id, "张三", MessageContentType.Text, "还在开发中,预计下周完成", now.AddDays(-3).AddHours(1).AddMinutes(2)),
- (User1Id, "张三", MessageContentType.Text, "后端 API 已经基本完成了", now.AddDays(-3).AddHours(1).AddMinutes(3)),
- (AdminId, "小赵", MessageContentType.Text, "太好了,前端这边也快了", now.AddDays(-3).AddHours(1).AddMinutes(5)),
- (AdminId, "小赵", MessageContentType.Emoji, "👍", now.AddDays(-2).AddHours(3)),
- (User1Id, "张三", MessageContentType.Text, "今天完成了用户模块的对接", now.AddDays(-1).AddHours(5)),
- (AdminId, "小赵", MessageContentType.Text, "项目进展如何?", now.AddMinutes(-30)),
- ]);
-
- // 私聊2 消息
- AddMessages(messages, privateConv2.Id, [
- (User2Id, "李四", MessageContentType.Text, "Hi,我是新加入的李四", now.AddDays(-1).AddHours(1)),
- (AdminId, "小赵", MessageContentType.Text, "欢迎欢迎!", now.AddDays(-1).AddHours(1).AddMinutes(1)),
- (User2Id, "李四", MessageContentType.Emoji, "🎉", now.AddDays(-1).AddHours(1).AddMinutes(2)),
- (User2Id, "李四", MessageContentType.Text, "下午有空讨论一下技术方案吗?", now.AddHours(-2)),
- ]);
-
- // 群聊消息
- AddMessages(messages, groupConv.Id, [
- (AdminId, "小赵", MessageContentType.Text, "大家好,这是我们的项目讨论群", now.AddDays(-5)),
- (User1Id, "张三", MessageContentType.Text, "收到!", now.AddDays(-5).AddMinutes(1)),
- (User2Id, "李四", MessageContentType.Text, "好的,以后在这里讨论", now.AddDays(-5).AddMinutes(2)),
- (AdminId, "小赵", MessageContentType.Text, "先同步一下目前的项目进度", now.AddDays(-4)),
- (AdminId, "小赵", MessageContentType.Text, "1. 后端 Auth 模块已完成\n2. 前端框架搭建完成\n3. 文件系统服务基础功能已上线", now.AddDays(-4).AddMinutes(1)),
- (User1Id, "张三", MessageContentType.Text, "看起来进展很顺利", now.AddDays(-4).AddMinutes(3)),
- (User3Id, "王五", MessageContentType.Emoji, "💪", now.AddDays(-3).AddHours(2)),
- (User2Id, "李四", MessageContentType.Text, "我这边 IM 系统的设计文档写好了", now.AddDays(-2)),
- (AdminId, "小赵", MessageContentType.Text, "不错,我们 review 一下", now.AddDays(-2).AddMinutes(10)),
- (User1Id, "张三", MessageContentType.Text, "我看了,整体架构很清晰", now.AddDays(-2).AddMinutes(15)),
- (User3Id, "王五", MessageContentType.Text, "MongoDB 存消息这个方案挺好的", now.AddDays(-1).AddHours(3)),
- (User2Id, "李四", MessageContentType.Text, "是的,读扩散模式对群聊场景很合适", now.AddDays(-1).AddHours(3).AddMinutes(2)),
- (AdminId, "小赵", MessageContentType.Text, "那就定这个方案,开始实现", now.AddDays(-1).AddHours(3).AddMinutes(5)),
- (User1Id, "张三", MessageContentType.Text, "SignalR Hub 的设计也很简洁", now.AddHours(-5)),
- (AdminId, "小赵", MessageContentType.Text, "对,保持简单,后续有需求再扩展", now.AddHours(-5).AddMinutes(1)),
- (User3Id, "王五", MessageContentType.Text, "前端聊天页面需要支持表情选择器吗?", now.AddMinutes(-30)),
- (AdminId, "小赵", MessageContentType.Text, "先做基础的文本和表情,后面再加选择器", now.AddMinutes(-30).AddMinutes(1)),
- (User2Id, "李四", MessageContentType.Text, "了解了", now.AddMinutes(-20)),
- (User1Id, "张三", MessageContentType.Text, "我来负责前端这块", now.AddMinutes(-15)),
- (AdminId, "小赵", MessageContentType.System, "小赵 创建了群聊「RAG 项目组」", now.AddMinutes(-10)),
- ]);
-
- // 更新 Conversation LastMessageId
- privateConv1.LastMessageId = messages.Last(m => m.ConversationId == privateConv1.Id).Id;
- privateConv2.LastMessageId = messages.Last(m => m.ConversationId == privateConv2.Id).Id;
- groupConv.LastMessageId = messages.Last(m => m.ConversationId == groupConv.Id).Id;
- await db.SaveChangesAsync();
-
- if (messages.Count > 0)
- {
- await mongoDb.Messages.InsertManyAsync(messages);
- }
-
- Console.WriteLine($"SeedData: 插入 {3} 个会话, {group.Members.Count} 个群成员, {messages.Count} 条消息");
- }
-
- private static void AddMessages(
- List list,
- Guid conversationId,
- (Guid SenderId, string SenderName, MessageContentType Type, string Content, DateTime Time)[] items)
- {
- foreach (var (senderId, senderName, type, content, time) in items)
- {
- list.Add(new MessageDocument
- {
- ConversationId = conversationId,
- SenderId = senderId,
- SenderName = senderName,
- ContentType = type,
- Content = content,
- CreatedAt = time
- });
- }
- }
-}
diff --git a/src/BuildFlow.Host/Services/CurrentUserContext.cs b/src/BuildFlow.Host/Services/Users/CurrentUserContext.cs
similarity index 97%
rename from src/BuildFlow.Host/Services/CurrentUserContext.cs
rename to src/BuildFlow.Host/Services/Users/CurrentUserContext.cs
index 3d3146b..0d85995 100644
--- a/src/BuildFlow.Host/Services/CurrentUserContext.cs
+++ b/src/BuildFlow.Host/Services/Users/CurrentUserContext.cs
@@ -2,7 +2,7 @@ using System.Security.Claims;
using BuildFlow.Shared.Domain.Common;
using Microsoft.IdentityModel.JsonWebTokens;
-namespace BuildFlow.Host.Services;
+namespace BuildFlow.Host.Services.Users;
///
/// 基于 HttpContext 的当前用户上下文实现。从已认证的 JWT claims 中读取用户 ID
diff --git a/src/BuildFlow.Host/Services/CurrentUserContextExtensions.cs b/src/BuildFlow.Host/Services/Users/CurrentUserContextExtensions.cs
similarity index 94%
rename from src/BuildFlow.Host/Services/CurrentUserContextExtensions.cs
rename to src/BuildFlow.Host/Services/Users/CurrentUserContextExtensions.cs
index 015b569..b9e766d 100644
--- a/src/BuildFlow.Host/Services/CurrentUserContextExtensions.cs
+++ b/src/BuildFlow.Host/Services/Users/CurrentUserContextExtensions.cs
@@ -1,6 +1,6 @@
using BuildFlow.Shared.Domain.Common;
-namespace BuildFlow.Host.Services;
+namespace BuildFlow.Host.Services.Users;
///
/// work-flow 业务层适配扩展:审计字段已迁移为 string(内核 ICurrentUserContext.UserId),
diff --git a/src/BuildFlow.Host/Services/SystemUserContext.cs b/src/BuildFlow.Host/Services/Users/SystemUserContext.cs
similarity index 95%
rename from src/BuildFlow.Host/Services/SystemUserContext.cs
rename to src/BuildFlow.Host/Services/Users/SystemUserContext.cs
index 01a052d..a580446 100644
--- a/src/BuildFlow.Host/Services/SystemUserContext.cs
+++ b/src/BuildFlow.Host/Services/Users/SystemUserContext.cs
@@ -1,6 +1,6 @@
using BuildFlow.Shared.Domain.Common;
-namespace BuildFlow.Host.Services;
+namespace BuildFlow.Host.Services.Users;
///
/// 系统身份上下文:供后台调度器(TimeoutSchedulerService / WebhookDispatcherService)等
diff --git a/src/BuildFlow.Host/appsettings.json b/src/BuildFlow.Host/appsettings.json
index 89a8e06..cf45417 100644
--- a/src/BuildFlow.Host/appsettings.json
+++ b/src/BuildFlow.Host/appsettings.json
@@ -26,7 +26,8 @@
"Rag": "rag",
"File": "file_system",
"Im": "im_system",
- "Workflow": "workflow"
+ "Workflow": "workflow",
+ "Platform": "platform"
},
"RabbitMq": {
"Host": "43.134.235.58",
@@ -40,6 +41,9 @@
"SecretKey": "REDACTED_S3_SECRET",
"Region": "us-east-1"
},
+ "KkFileView": {
+ "BaseUrl": "http://localhost:8012"
+ },
"Jwt": {
"RequireHttps": false,
"SigningKey": "REDACTED_JWT_SIGNING_KEY_MIN_32_CHARS!!",
diff --git a/src/modules/file/Application/Features/Files/DTOs/OfficePreviewResult.cs b/src/modules/file/Application/Features/Files/DTOs/OfficePreviewResult.cs
new file mode 100644
index 0000000..a8dafaf
--- /dev/null
+++ b/src/modules/file/Application/Features/Files/DTOs/OfficePreviewResult.cs
@@ -0,0 +1,7 @@
+namespace File.Application.Features.Files.DTOs;
+
+///
+/// Office/PDF 文档在线预览结果。返回 KKFileView 可直接打开的预览地址。
+/// 地址由 S3 预签名 URL 经 Base64 编码后拼入 KKFileView 的 onlinePreview 接口构成。
+///
+public record OfficePreviewResult(string PreviewUrl);
diff --git a/src/modules/file/Application/Features/Files/Handlers/GetOfficePreviewQueryHandler.cs b/src/modules/file/Application/Features/Files/Handlers/GetOfficePreviewQueryHandler.cs
new file mode 100644
index 0000000..353f804
--- /dev/null
+++ b/src/modules/file/Application/Features/Files/Handlers/GetOfficePreviewQueryHandler.cs
@@ -0,0 +1,30 @@
+using File.Application.Features.Files.DTOs;
+using File.Application.Features.Files.Queries;
+using File.Infrastructure.Storage;
+using MediatR;
+using Microsoft.Extensions.Options;
+
+namespace File.Application.Features.Files.Handlers;
+
+///
+/// Office/PDF 文档预览查询处理器。生成 S3 预签名 URL(1 小时有效),
+/// 按 KKFileView 约定 Base64 编码后拼成 onlinePreview 地址返回。
+///
+public class GetOfficePreviewQueryHandler(IS3StorageService s3, IOptions kkOptions)
+ : IRequestHandler
+{
+ /// Office 文档预签名有效期较短(1 小时),降低链接泄露风险。
+ private static readonly TimeSpan PreviewExpiry = TimeSpan.FromHours(1);
+
+ public async Task Handle(GetOfficePreviewQuery req, CancellationToken ct)
+ {
+ var presignedUrl = await s3.GeneratePresignedUrlAsync(req.BucketName, req.ObjectKey, PreviewExpiry, ct);
+
+ // KKFileView onlinePreview 约定:url 参数为 Base64 编码的文件直链
+ var encoded = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(presignedUrl));
+ var baseUrl = kkOptions.Value.BaseUrl.TrimEnd('/');
+ var previewUrl = $"{baseUrl}/onlinePreview?url={encoded}";
+
+ return new OfficePreviewResult(previewUrl);
+ }
+}
diff --git a/src/modules/file/Application/Features/Files/Queries/GetOfficePreviewQuery.cs b/src/modules/file/Application/Features/Files/Queries/GetOfficePreviewQuery.cs
new file mode 100644
index 0000000..3bfb325
--- /dev/null
+++ b/src/modules/file/Application/Features/Files/Queries/GetOfficePreviewQuery.cs
@@ -0,0 +1,10 @@
+using File.Application.Features.Files.DTOs;
+using MediatR;
+
+namespace File.Application.Features.Files.Queries;
+
+///
+/// 获取 Office/PDF 文档在线预览地址查询。
+/// 生成 S3 预签名 URL 后拼装为 KKFileView 预览链接,供前端 window.open 打开。
+///
+public record GetOfficePreviewQuery(string BucketName, string ObjectKey) : IRequest;
diff --git a/src/modules/file/Infrastructure/FileInfrastructureModule.cs b/src/modules/file/Infrastructure/FileInfrastructureModule.cs
index f858eaa..0066300 100644
--- a/src/modules/file/Infrastructure/FileInfrastructureModule.cs
+++ b/src/modules/file/Infrastructure/FileInfrastructureModule.cs
@@ -37,5 +37,8 @@ public class FileInfrastructureModule : AbpModule
var options = sp.GetRequiredService>().Value;
return new S3StorageService(Options.Create(options));
});
+
+ // KKFileView 在线预览服务配置(Office/PDF 文档预览,生成预览地址时读取)
+ services.Configure(config.GetSection(KkFileViewOptions.SectionName));
}
}
diff --git a/src/modules/file/Infrastructure/Storage/KkFileViewOptions.cs b/src/modules/file/Infrastructure/Storage/KkFileViewOptions.cs
new file mode 100644
index 0000000..60b2e30
--- /dev/null
+++ b/src/modules/file/Infrastructure/Storage/KkFileViewOptions.cs
@@ -0,0 +1,13 @@
+namespace File.Infrastructure.Storage;
+
+///
+/// KKFileView 在线预览服务配置,从 appsettings.json 的 KkFileView 节读取。
+/// KKFileView 是开源文档预览服务,支持 Office/PDF/图片等 30+ 格式。
+///
+public class KkFileViewOptions
+{
+ public const string SectionName = "KkFileView";
+
+ /// KKFileView 服务基地址,如 http://localhost:8012。
+ public string BaseUrl { get; set; } = default!;
+}
diff --git a/src/modules/rag/Application/Auth/Commands/LoginCommand.cs b/src/modules/platform/Application/Auth/Commands/LoginCommand.cs
similarity index 64%
rename from src/modules/rag/Application/Auth/Commands/LoginCommand.cs
rename to src/modules/platform/Application/Auth/Commands/LoginCommand.cs
index 6c8f3c4..2fa3d4e 100644
--- a/src/modules/rag/Application/Auth/Commands/LoginCommand.cs
+++ b/src/modules/platform/Application/Auth/Commands/LoginCommand.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Auth.DTOs;
+using BuildFlow.Platform.Application.Auth.DTOs;
-namespace BuildFlow.Application.Auth.Commands;
+namespace BuildFlow.Platform.Application.Auth.Commands;
///
diff --git a/src/modules/rag/Application/Auth/Commands/LogoutCommand.cs b/src/modules/platform/Application/Auth/Commands/LogoutCommand.cs
similarity index 74%
rename from src/modules/rag/Application/Auth/Commands/LogoutCommand.cs
rename to src/modules/platform/Application/Auth/Commands/LogoutCommand.cs
index cb05fbd..6593372 100644
--- a/src/modules/rag/Application/Auth/Commands/LogoutCommand.cs
+++ b/src/modules/platform/Application/Auth/Commands/LogoutCommand.cs
@@ -1,6 +1,6 @@
using MediatR;
-namespace BuildFlow.Application.Auth.Commands;
+namespace BuildFlow.Platform.Application.Auth.Commands;
///
diff --git a/src/modules/rag/Application/Auth/Commands/RefreshTokenCommand.cs b/src/modules/platform/Application/Auth/Commands/RefreshTokenCommand.cs
similarity index 64%
rename from src/modules/rag/Application/Auth/Commands/RefreshTokenCommand.cs
rename to src/modules/platform/Application/Auth/Commands/RefreshTokenCommand.cs
index 5523f83..141bc7c 100644
--- a/src/modules/rag/Application/Auth/Commands/RefreshTokenCommand.cs
+++ b/src/modules/platform/Application/Auth/Commands/RefreshTokenCommand.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Auth.DTOs;
+using BuildFlow.Platform.Application.Auth.DTOs;
-namespace BuildFlow.Application.Auth.Commands;
+namespace BuildFlow.Platform.Application.Auth.Commands;
///
diff --git a/src/modules/rag/Application/Auth/Commands/RegisterCommand.cs b/src/modules/platform/Application/Auth/Commands/RegisterCommand.cs
similarity index 77%
rename from src/modules/rag/Application/Auth/Commands/RegisterCommand.cs
rename to src/modules/platform/Application/Auth/Commands/RegisterCommand.cs
index 2622fa2..8919709 100644
--- a/src/modules/rag/Application/Auth/Commands/RegisterCommand.cs
+++ b/src/modules/platform/Application/Auth/Commands/RegisterCommand.cs
@@ -1,6 +1,6 @@
using MediatR;
-namespace BuildFlow.Application.Auth.Commands;
+namespace BuildFlow.Platform.Application.Auth.Commands;
///
diff --git a/src/modules/rag/Application/Auth/Commands/RevokeTokenCommand.cs b/src/modules/platform/Application/Auth/Commands/RevokeTokenCommand.cs
similarity index 76%
rename from src/modules/rag/Application/Auth/Commands/RevokeTokenCommand.cs
rename to src/modules/platform/Application/Auth/Commands/RevokeTokenCommand.cs
index 954880e..5cc4125 100644
--- a/src/modules/rag/Application/Auth/Commands/RevokeTokenCommand.cs
+++ b/src/modules/platform/Application/Auth/Commands/RevokeTokenCommand.cs
@@ -1,6 +1,6 @@
using MediatR;
-namespace BuildFlow.Application.Auth.Commands;
+namespace BuildFlow.Platform.Application.Auth.Commands;
///
diff --git a/src/modules/rag/Application/Auth/Commands/UpdateProfileCommand.cs b/src/modules/platform/Application/Auth/Commands/UpdateProfileCommand.cs
similarity index 78%
rename from src/modules/rag/Application/Auth/Commands/UpdateProfileCommand.cs
rename to src/modules/platform/Application/Auth/Commands/UpdateProfileCommand.cs
index c7effca..3a0df7f 100644
--- a/src/modules/rag/Application/Auth/Commands/UpdateProfileCommand.cs
+++ b/src/modules/platform/Application/Auth/Commands/UpdateProfileCommand.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Auth.Queries;
+using BuildFlow.Platform.Application.Auth.Queries;
-namespace BuildFlow.Application.Auth.Commands;
+namespace BuildFlow.Platform.Application.Auth.Commands;
///
/// 更新当前用户个人资料(姓名、头像、简介)。
diff --git a/src/modules/rag/Application/Auth/DTOs/LoginRequest.cs b/src/modules/platform/Application/Auth/DTOs/LoginRequest.cs
similarity index 69%
rename from src/modules/rag/Application/Auth/DTOs/LoginRequest.cs
rename to src/modules/platform/Application/Auth/DTOs/LoginRequest.cs
index 75f9448..454df37 100644
--- a/src/modules/rag/Application/Auth/DTOs/LoginRequest.cs
+++ b/src/modules/platform/Application/Auth/DTOs/LoginRequest.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Auth.DTOs;
+namespace BuildFlow.Platform.Application.Auth.DTOs;
///
/// 登录请求体。
diff --git a/src/modules/rag/Application/Auth/DTOs/RefreshTokenRequest.cs b/src/modules/platform/Application/Auth/DTOs/RefreshTokenRequest.cs
similarity index 69%
rename from src/modules/rag/Application/Auth/DTOs/RefreshTokenRequest.cs
rename to src/modules/platform/Application/Auth/DTOs/RefreshTokenRequest.cs
index c9c4ca1..d5ed8a0 100644
--- a/src/modules/rag/Application/Auth/DTOs/RefreshTokenRequest.cs
+++ b/src/modules/platform/Application/Auth/DTOs/RefreshTokenRequest.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Auth.DTOs;
+namespace BuildFlow.Platform.Application.Auth.DTOs;
///
/// 刷新令牌请求体。
diff --git a/src/modules/rag/Application/Auth/DTOs/RegisterRequest.cs b/src/modules/platform/Application/Auth/DTOs/RegisterRequest.cs
similarity index 72%
rename from src/modules/rag/Application/Auth/DTOs/RegisterRequest.cs
rename to src/modules/platform/Application/Auth/DTOs/RegisterRequest.cs
index 47ecdb0..0a6ee94 100644
--- a/src/modules/rag/Application/Auth/DTOs/RegisterRequest.cs
+++ b/src/modules/platform/Application/Auth/DTOs/RegisterRequest.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Auth.DTOs;
+namespace BuildFlow.Platform.Application.Auth.DTOs;
///
/// 注册请求体。
diff --git a/src/modules/rag/Application/Auth/DTOs/RevokeTokenRequest.cs b/src/modules/platform/Application/Auth/DTOs/RevokeTokenRequest.cs
similarity index 69%
rename from src/modules/rag/Application/Auth/DTOs/RevokeTokenRequest.cs
rename to src/modules/platform/Application/Auth/DTOs/RevokeTokenRequest.cs
index 7d71dd6..3992e80 100644
--- a/src/modules/rag/Application/Auth/DTOs/RevokeTokenRequest.cs
+++ b/src/modules/platform/Application/Auth/DTOs/RevokeTokenRequest.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Auth.DTOs;
+namespace BuildFlow.Platform.Application.Auth.DTOs;
///
/// 吊销令牌请求体。
diff --git a/src/modules/rag/Application/Auth/DTOs/TokenResponse.cs b/src/modules/platform/Application/Auth/DTOs/TokenResponse.cs
similarity index 73%
rename from src/modules/rag/Application/Auth/DTOs/TokenResponse.cs
rename to src/modules/platform/Application/Auth/DTOs/TokenResponse.cs
index a639f04..642decf 100644
--- a/src/modules/rag/Application/Auth/DTOs/TokenResponse.cs
+++ b/src/modules/platform/Application/Auth/DTOs/TokenResponse.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Auth.DTOs;
+namespace BuildFlow.Platform.Application.Auth.DTOs;
///
/// 令牌响应体。
diff --git a/src/modules/rag/Application/Auth/Handlers/GetAccessCodesQueryHandler.cs b/src/modules/platform/Application/Auth/Handlers/GetAccessCodesQueryHandler.cs
similarity index 73%
rename from src/modules/rag/Application/Auth/Handlers/GetAccessCodesQueryHandler.cs
rename to src/modules/platform/Application/Auth/Handlers/GetAccessCodesQueryHandler.cs
index 18e70d8..9ed595a 100644
--- a/src/modules/rag/Application/Auth/Handlers/GetAccessCodesQueryHandler.cs
+++ b/src/modules/platform/Application/Auth/Handlers/GetAccessCodesQueryHandler.cs
@@ -1,14 +1,14 @@
using BuildFlow.Shared.Domain.Exceptions;
using MediatR;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Auth.Queries;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Auth.Queries;
-namespace BuildFlow.Application.Auth.Handlers;
+namespace BuildFlow.Platform.Application.Auth.Handlers;
///
/// GetAccessCodes查询处理器。执行业务校验后持久化。
///
-public class GetAccessCodesQueryHandler(RagDbContext db) : IRequestHandler>
+public class GetAccessCodesQueryHandler(PlatformDbContext db) : IRequestHandler>
{
public async Task> Handle(GetAccessCodesQuery request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Auth/Handlers/GetCurrentUserQueryHandler.cs b/src/modules/platform/Application/Auth/Handlers/GetCurrentUserQueryHandler.cs
similarity index 77%
rename from src/modules/rag/Application/Auth/Handlers/GetCurrentUserQueryHandler.cs
rename to src/modules/platform/Application/Auth/Handlers/GetCurrentUserQueryHandler.cs
index 9a6ce0e..0ddd6e6 100644
--- a/src/modules/rag/Application/Auth/Handlers/GetCurrentUserQueryHandler.cs
+++ b/src/modules/platform/Application/Auth/Handlers/GetCurrentUserQueryHandler.cs
@@ -1,14 +1,14 @@
using BuildFlow.Shared.Domain.Exceptions;
using MediatR;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Auth.Queries;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Auth.Queries;
-namespace BuildFlow.Application.Auth.Handlers;
+namespace BuildFlow.Platform.Application.Auth.Handlers;
///
/// GetCurrent用户查询处理器。执行业务校验后持久化。
///
-public class GetCurrentUserQueryHandler(RagDbContext db) : IRequestHandler
+public class GetCurrentUserQueryHandler(PlatformDbContext db) : IRequestHandler
{
public async Task Handle(GetCurrentUserQuery request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Auth/Handlers/LoginCommandHandler.cs b/src/modules/platform/Application/Auth/Handlers/LoginCommandHandler.cs
similarity index 93%
rename from src/modules/rag/Application/Auth/Handlers/LoginCommandHandler.cs
rename to src/modules/platform/Application/Auth/Handlers/LoginCommandHandler.cs
index 80b480e..793afe3 100644
--- a/src/modules/rag/Application/Auth/Handlers/LoginCommandHandler.cs
+++ b/src/modules/platform/Application/Auth/Handlers/LoginCommandHandler.cs
@@ -6,17 +6,17 @@ using System.Text;
using MediatR;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
-using BuildFlow.Application.Auth.DTOs;
-using BuildFlow.Domain.Entities;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Auth.Commands;
+using BuildFlow.Platform.Application.Auth.DTOs;
+using BuildFlow.Platform.Domain.Entities;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Auth.Commands;
-namespace BuildFlow.Application.Auth.Handlers;
+namespace BuildFlow.Platform.Application.Auth.Handlers;
///
/// 登录Command处理器。执行业务校验后持久化。
///
-public class LoginCommandHandler(RagDbContext db, IConfiguration config) : IRequestHandler
+public class LoginCommandHandler(PlatformDbContext db, IConfiguration config) : IRequestHandler
{
// 进程内登录失败计数器(未持久化,重启即清零)。键统一小写化,避免大小写差异绕过锁定。
private static readonly Dictionary LoginAttempts = new();
diff --git a/src/modules/rag/Application/Auth/Handlers/LogoutCommandHandler.cs b/src/modules/platform/Application/Auth/Handlers/LogoutCommandHandler.cs
similarity index 69%
rename from src/modules/rag/Application/Auth/Handlers/LogoutCommandHandler.cs
rename to src/modules/platform/Application/Auth/Handlers/LogoutCommandHandler.cs
index 248d0f8..09e295c 100644
--- a/src/modules/rag/Application/Auth/Handlers/LogoutCommandHandler.cs
+++ b/src/modules/platform/Application/Auth/Handlers/LogoutCommandHandler.cs
@@ -1,13 +1,13 @@
using MediatR;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Auth.Commands;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Auth.Commands;
-namespace BuildFlow.Application.Auth.Handlers;
+namespace BuildFlow.Platform.Application.Auth.Handlers;
///
/// 登出Command处理器。执行业务校验后持久化。
///
-public class LogoutCommandHandler(RagDbContext db) : IRequestHandler
+public class LogoutCommandHandler(PlatformDbContext db) : IRequestHandler
{
public async Task Handle(LogoutCommand request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Auth/Handlers/RefreshTokenCommandHandler.cs b/src/modules/platform/Application/Auth/Handlers/RefreshTokenCommandHandler.cs
similarity index 88%
rename from src/modules/rag/Application/Auth/Handlers/RefreshTokenCommandHandler.cs
rename to src/modules/platform/Application/Auth/Handlers/RefreshTokenCommandHandler.cs
index 1f1e43a..53c5d4a 100644
--- a/src/modules/rag/Application/Auth/Handlers/RefreshTokenCommandHandler.cs
+++ b/src/modules/platform/Application/Auth/Handlers/RefreshTokenCommandHandler.cs
@@ -5,16 +5,16 @@ using System.Text;
using MediatR;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
-using BuildFlow.Application.Auth.DTOs;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Auth.Commands;
+using BuildFlow.Platform.Application.Auth.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Auth.Commands;
-namespace BuildFlow.Application.Auth.Handlers;
+namespace BuildFlow.Platform.Application.Auth.Handlers;
///
/// 刷新令牌Command处理器。执行业务校验后持久化。
///
-public class RefreshTokenCommandHandler(RagDbContext db, IConfiguration config) : IRequestHandler
+public class RefreshTokenCommandHandler(PlatformDbContext db, IConfiguration config) : IRequestHandler
{
public async Task Handle(RefreshTokenCommand request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Auth/Handlers/RegisterCommandHandler.cs b/src/modules/platform/Application/Auth/Handlers/RegisterCommandHandler.cs
similarity index 79%
rename from src/modules/rag/Application/Auth/Handlers/RegisterCommandHandler.cs
rename to src/modules/platform/Application/Auth/Handlers/RegisterCommandHandler.cs
index 1b88b6d..a10c767 100644
--- a/src/modules/rag/Application/Auth/Handlers/RegisterCommandHandler.cs
+++ b/src/modules/platform/Application/Auth/Handlers/RegisterCommandHandler.cs
@@ -1,15 +1,15 @@
using BuildFlow.Shared.Domain.Exceptions;
using MediatR;
-using BuildFlow.Domain.Entities;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Auth.Commands;
+using BuildFlow.Platform.Domain.Entities;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Auth.Commands;
-namespace BuildFlow.Application.Auth.Handlers;
+namespace BuildFlow.Platform.Application.Auth.Handlers;
///
/// 注册Command处理器。执行业务校验后持久化。
///
-public class RegisterCommandHandler(RagDbContext db) : IRequestHandler
+public class RegisterCommandHandler(PlatformDbContext db) : IRequestHandler
{
public async Task Handle(RegisterCommand request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Auth/Handlers/RevokeTokenCommandHandler.cs b/src/modules/platform/Application/Auth/Handlers/RevokeTokenCommandHandler.cs
similarity index 66%
rename from src/modules/rag/Application/Auth/Handlers/RevokeTokenCommandHandler.cs
rename to src/modules/platform/Application/Auth/Handlers/RevokeTokenCommandHandler.cs
index 7dfa671..ff0b4a9 100644
--- a/src/modules/rag/Application/Auth/Handlers/RevokeTokenCommandHandler.cs
+++ b/src/modules/platform/Application/Auth/Handlers/RevokeTokenCommandHandler.cs
@@ -1,14 +1,14 @@
using BuildFlow.Shared.Domain.Exceptions;
using MediatR;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Auth.Commands;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Auth.Commands;
-namespace BuildFlow.Application.Auth.Handlers;
+namespace BuildFlow.Platform.Application.Auth.Handlers;
///
/// 吊销令牌Command处理器。执行业务校验后持久化。
///
-public class RevokeTokenCommandHandler(RagDbContext db) : IRequestHandler
+public class RevokeTokenCommandHandler(PlatformDbContext db) : IRequestHandler
{
public async Task Handle(RevokeTokenCommand request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Auth/Handlers/UpdateProfileCommandHandler.cs b/src/modules/platform/Application/Auth/Handlers/UpdateProfileCommandHandler.cs
similarity index 83%
rename from src/modules/rag/Application/Auth/Handlers/UpdateProfileCommandHandler.cs
rename to src/modules/platform/Application/Auth/Handlers/UpdateProfileCommandHandler.cs
index 9318a16..f13d7b0 100644
--- a/src/modules/rag/Application/Auth/Handlers/UpdateProfileCommandHandler.cs
+++ b/src/modules/platform/Application/Auth/Handlers/UpdateProfileCommandHandler.cs
@@ -1,15 +1,15 @@
using MediatR;
-using BuildFlow.Application.Auth.Queries;
-using BuildFlow.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Auth.Queries;
+using BuildFlow.Platform.Infrastructure.Persistence;
using BuildFlow.Shared.Domain.Exceptions;
-using BuildFlow.Application.Auth.Commands;
+using BuildFlow.Platform.Application.Auth.Commands;
-namespace BuildFlow.Application.Auth.Handlers;
+namespace BuildFlow.Platform.Application.Auth.Handlers;
///
/// 更新个人资料处理器:只更新 RealName/Avatar/Description,其他字段不动。
///
-public class UpdateProfileCommandHandler(RagDbContext db)
+public class UpdateProfileCommandHandler(PlatformDbContext db)
: IRequestHandler
{
public async Task Handle(UpdateProfileCommand request, CancellationToken ct)
diff --git a/src/modules/rag/Application/Auth/Queries/CurrentUserInfo.cs b/src/modules/platform/Application/Auth/Queries/CurrentUserInfo.cs
similarity index 84%
rename from src/modules/rag/Application/Auth/Queries/CurrentUserInfo.cs
rename to src/modules/platform/Application/Auth/Queries/CurrentUserInfo.cs
index 6c8305a..f886808 100644
--- a/src/modules/rag/Application/Auth/Queries/CurrentUserInfo.cs
+++ b/src/modules/platform/Application/Auth/Queries/CurrentUserInfo.cs
@@ -1,4 +1,4 @@
-namespace BuildFlow.Application.Auth.Queries;
+namespace BuildFlow.Platform.Application.Auth.Queries;
///
/// 当前用户信息(前端 getUserInfoApi 用)。
diff --git a/src/modules/rag/Application/Auth/Queries/GetAccessCodesQuery.cs b/src/modules/platform/Application/Auth/Queries/GetAccessCodesQuery.cs
similarity index 77%
rename from src/modules/rag/Application/Auth/Queries/GetAccessCodesQuery.cs
rename to src/modules/platform/Application/Auth/Queries/GetAccessCodesQuery.cs
index 04605a9..dad3831 100644
--- a/src/modules/rag/Application/Auth/Queries/GetAccessCodesQuery.cs
+++ b/src/modules/platform/Application/Auth/Queries/GetAccessCodesQuery.cs
@@ -1,6 +1,6 @@
using MediatR;
-namespace BuildFlow.Application.Auth.Queries;
+namespace BuildFlow.Platform.Application.Auth.Queries;
///
diff --git a/src/modules/rag/Application/Auth/Queries/GetCurrentUserQuery.cs b/src/modules/platform/Application/Auth/Queries/GetCurrentUserQuery.cs
similarity index 77%
rename from src/modules/rag/Application/Auth/Queries/GetCurrentUserQuery.cs
rename to src/modules/platform/Application/Auth/Queries/GetCurrentUserQuery.cs
index eb978ba..997b8e0 100644
--- a/src/modules/rag/Application/Auth/Queries/GetCurrentUserQuery.cs
+++ b/src/modules/platform/Application/Auth/Queries/GetCurrentUserQuery.cs
@@ -1,6 +1,6 @@
using MediatR;
-namespace BuildFlow.Application.Auth.Queries;
+namespace BuildFlow.Platform.Application.Auth.Queries;
///
diff --git a/src/modules/rag/Application/Auth/Validators/LoginCommandValidator.cs b/src/modules/platform/Application/Auth/Validators/LoginCommandValidator.cs
similarity index 85%
rename from src/modules/rag/Application/Auth/Validators/LoginCommandValidator.cs
rename to src/modules/platform/Application/Auth/Validators/LoginCommandValidator.cs
index 022b974..28b3732 100644
--- a/src/modules/rag/Application/Auth/Validators/LoginCommandValidator.cs
+++ b/src/modules/platform/Application/Auth/Validators/LoginCommandValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Auth.Commands;
+using BuildFlow.Platform.Application.Auth.Commands;
-namespace BuildFlow.Application.Auth.Validators;
+namespace BuildFlow.Platform.Application.Auth.Validators;
///
/// 登录Command的请求校验器(FluentValidation)。
diff --git a/src/modules/rag/Application/Auth/Validators/LogoutCommandValidator.cs b/src/modules/platform/Application/Auth/Validators/LogoutCommandValidator.cs
similarity index 74%
rename from src/modules/rag/Application/Auth/Validators/LogoutCommandValidator.cs
rename to src/modules/platform/Application/Auth/Validators/LogoutCommandValidator.cs
index 5b37fc9..59ff084 100644
--- a/src/modules/rag/Application/Auth/Validators/LogoutCommandValidator.cs
+++ b/src/modules/platform/Application/Auth/Validators/LogoutCommandValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Auth.Commands;
+using BuildFlow.Platform.Application.Auth.Commands;
-namespace BuildFlow.Application.Auth.Validators;
+namespace BuildFlow.Platform.Application.Auth.Validators;
///
/// 登出Command的请求校验器(FluentValidation)。
diff --git a/src/modules/rag/Application/Auth/Validators/RefreshTokenCommandValidator.cs b/src/modules/platform/Application/Auth/Validators/RefreshTokenCommandValidator.cs
similarity index 76%
rename from src/modules/rag/Application/Auth/Validators/RefreshTokenCommandValidator.cs
rename to src/modules/platform/Application/Auth/Validators/RefreshTokenCommandValidator.cs
index ca1efb0..8414651 100644
--- a/src/modules/rag/Application/Auth/Validators/RefreshTokenCommandValidator.cs
+++ b/src/modules/platform/Application/Auth/Validators/RefreshTokenCommandValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Auth.Commands;
+using BuildFlow.Platform.Application.Auth.Commands;
-namespace BuildFlow.Application.Auth.Validators;
+namespace BuildFlow.Platform.Application.Auth.Validators;
///
/// 刷新令牌Command的请求校验器(FluentValidation)。
diff --git a/src/modules/rag/Application/Auth/Validators/RegisterCommandValidator.cs b/src/modules/platform/Application/Auth/Validators/RegisterCommandValidator.cs
similarity index 86%
rename from src/modules/rag/Application/Auth/Validators/RegisterCommandValidator.cs
rename to src/modules/platform/Application/Auth/Validators/RegisterCommandValidator.cs
index c2d1efe..7b499f2 100644
--- a/src/modules/rag/Application/Auth/Validators/RegisterCommandValidator.cs
+++ b/src/modules/platform/Application/Auth/Validators/RegisterCommandValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Auth.Commands;
+using BuildFlow.Platform.Application.Auth.Commands;
-namespace BuildFlow.Application.Auth.Validators;
+namespace BuildFlow.Platform.Application.Auth.Validators;
///
/// 注册Command的请求校验器(FluentValidation)。
diff --git a/src/modules/rag/Application/Auth/Validators/RevokeTokenCommandValidator.cs b/src/modules/platform/Application/Auth/Validators/RevokeTokenCommandValidator.cs
similarity index 76%
rename from src/modules/rag/Application/Auth/Validators/RevokeTokenCommandValidator.cs
rename to src/modules/platform/Application/Auth/Validators/RevokeTokenCommandValidator.cs
index d972262..4f69355 100644
--- a/src/modules/rag/Application/Auth/Validators/RevokeTokenCommandValidator.cs
+++ b/src/modules/platform/Application/Auth/Validators/RevokeTokenCommandValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Auth.Commands;
+using BuildFlow.Platform.Application.Auth.Commands;
-namespace BuildFlow.Application.Auth.Validators;
+namespace BuildFlow.Platform.Application.Auth.Validators;
///
/// 吊销令牌Command的请求校验器(FluentValidation)。
diff --git a/src/modules/platform/Application/Common/ValidationBehavior.cs b/src/modules/platform/Application/Common/ValidationBehavior.cs
new file mode 100644
index 0000000..ad5baa3
--- /dev/null
+++ b/src/modules/platform/Application/Common/ValidationBehavior.cs
@@ -0,0 +1,28 @@
+using FluentValidation;
+using MediatR;
+
+namespace BuildFlow.Platform.Application.Common;
+
+///
+/// MediatR 管线行为:在 Handler 执行前自动运行所有匹配的 FluentValidation 校验器。
+/// 任一校验失败即抛 ValidationException(被 GlobalExceptionMiddleware 映射为 400),
+/// 使业务 Handler 内无需重复写校验代码,统一在管线层拦截非法请求。
+///
+public class ValidationBehavior(IEnumerable> validators)
+ : IPipelineBehavior where TRequest : IRequest
+{
+ public async Task Handle(TRequest request, RequestHandlerDelegate next,
+ CancellationToken cancellationToken)
+ {
+ if (validators.Any())
+ {
+ var context = new ValidationContext(request);
+ var results = await Task.WhenAll(validators.Select(v => v.ValidateAsync(context, cancellationToken)));
+ var failures = results.SelectMany(r => r.Errors).Where(f => f != null).ToList();
+ if (failures.Count != 0)
+ throw new ValidationException(failures);
+ }
+
+ return await next();
+ }
+}
diff --git a/src/modules/platform/Application/GlobalUsings.cs b/src/modules/platform/Application/GlobalUsings.cs
new file mode 100644
index 0000000..a5ee52f
--- /dev/null
+++ b/src/modules/platform/Application/GlobalUsings.cs
@@ -0,0 +1,2 @@
+// 全局 using:Handler 普遍使用 EF Core 异步查询扩展方法
+global using Microsoft.EntityFrameworkCore;
diff --git a/src/modules/platform/Application/Menus/Commands/CreateMenuCommand.cs b/src/modules/platform/Application/Menus/Commands/CreateMenuCommand.cs
new file mode 100644
index 0000000..5f95c2e
--- /dev/null
+++ b/src/modules/platform/Application/Menus/Commands/CreateMenuCommand.cs
@@ -0,0 +1,27 @@
+using MediatR;
+using BuildFlow.Platform.Application.Menus.DTOs;
+
+namespace BuildFlow.Platform.Application.Menus.Commands;
+
+///
+/// 创建菜单命令。
+///
+public record CreateMenuCommand : IRequest
+{
+ public Guid? ParentId { get; init; }
+ public string Name { get; init; } = default!;
+ public string Path { get; init; } = default!;
+ public string? Component { get; init; }
+ public string? Redirect { get; init; }
+ public string Title { get; init; } = default!;
+ public string? Icon { get; init; }
+ public string? ActiveIcon { get; init; }
+ public int Order { get; init; }
+ public bool HideInMenu { get; init; }
+ public bool? KeepAlive { get; init; }
+ public bool? AffixTab { get; init; }
+ public string? Link { get; init; }
+ public bool NoBasicLayout { get; init; }
+ public bool MenuVisibleWithForbidden { get; init; }
+ public string? Authority { get; init; }
+}
diff --git a/src/modules/platform/Application/Menus/Commands/DeleteMenuCommand.cs b/src/modules/platform/Application/Menus/Commands/DeleteMenuCommand.cs
new file mode 100644
index 0000000..25976aa
--- /dev/null
+++ b/src/modules/platform/Application/Menus/Commands/DeleteMenuCommand.cs
@@ -0,0 +1,8 @@
+using MediatR;
+
+namespace BuildFlow.Platform.Application.Menus.Commands;
+
+///
+/// 删除菜单命令。有子菜单时拒绝删除,避免误删整个子树。
+///
+public record DeleteMenuCommand(Guid Id) : IRequest;
diff --git a/src/modules/platform/Application/Menus/Commands/UpdateMenuCommand.cs b/src/modules/platform/Application/Menus/Commands/UpdateMenuCommand.cs
new file mode 100644
index 0000000..cbdeea8
--- /dev/null
+++ b/src/modules/platform/Application/Menus/Commands/UpdateMenuCommand.cs
@@ -0,0 +1,28 @@
+using MediatR;
+using BuildFlow.Platform.Application.Menus.DTOs;
+
+namespace BuildFlow.Platform.Application.Menus.Commands;
+
+///
+/// 更新菜单命令。支持部分字段更新。
+///
+public record UpdateMenuCommand : IRequest
+{
+ public Guid Id { get; init; }
+ public Guid? ParentId { get; init; }
+ public string? Name { get; init; }
+ public string? Path { get; init; }
+ public string? Component { get; init; }
+ public string? Redirect { get; init; }
+ public string? Title { get; init; }
+ public string? Icon { get; init; }
+ public string? ActiveIcon { get; init; }
+ public int? Order { get; init; }
+ public bool? HideInMenu { get; init; }
+ public bool? KeepAlive { get; init; }
+ public bool? AffixTab { get; init; }
+ public string? Link { get; init; }
+ public bool? NoBasicLayout { get; init; }
+ public bool? MenuVisibleWithForbidden { get; init; }
+ public string? Authority { get; init; }
+}
diff --git a/src/modules/platform/Application/Menus/DTOs/CreateMenuRequest.cs b/src/modules/platform/Application/Menus/DTOs/CreateMenuRequest.cs
new file mode 100644
index 0000000..fca9829
--- /dev/null
+++ b/src/modules/platform/Application/Menus/DTOs/CreateMenuRequest.cs
@@ -0,0 +1,22 @@
+namespace BuildFlow.Platform.Application.Menus.DTOs;
+
+///
+/// 创建菜单请求体。
+///
+public record CreateMenuRequest(
+ Guid? ParentId,
+ string Name,
+ string Path,
+ string? Component,
+ string? Redirect,
+ string Title,
+ string? Icon,
+ string? ActiveIcon,
+ int Order,
+ bool HideInMenu,
+ bool? KeepAlive,
+ bool? AffixTab,
+ string? Link,
+ bool NoBasicLayout,
+ bool MenuVisibleWithForbidden,
+ string? Authority);
diff --git a/src/modules/platform/Application/Menus/DTOs/MenuDto.cs b/src/modules/platform/Application/Menus/DTOs/MenuDto.cs
new file mode 100644
index 0000000..92b663a
--- /dev/null
+++ b/src/modules/platform/Application/Menus/DTOs/MenuDto.cs
@@ -0,0 +1,24 @@
+namespace BuildFlow.Platform.Application.Menus.DTOs;
+
+///
+/// 菜单扁平 DTO,用于管理端增删改查与列表展示。
+/// 区别于 MenuRouteDto:包含全部管理字段(ParentId/Authority 等),不做角色过滤,非树形。
+///
+public record MenuDto(
+ Guid Id,
+ Guid? ParentId,
+ string Name,
+ string Path,
+ string? Component,
+ string? Redirect,
+ string Title,
+ string? Icon,
+ string? ActiveIcon,
+ int Order,
+ bool HideInMenu,
+ bool? KeepAlive,
+ bool? AffixTab,
+ string? Link,
+ bool NoBasicLayout,
+ bool MenuVisibleWithForbidden,
+ string? Authority);
diff --git a/src/modules/rag/Application/Menus/DTOs/MenuMetaDto.cs b/src/modules/platform/Application/Menus/DTOs/MenuMetaDto.cs
similarity index 94%
rename from src/modules/rag/Application/Menus/DTOs/MenuMetaDto.cs
rename to src/modules/platform/Application/Menus/DTOs/MenuMetaDto.cs
index f1532af..2ac8a4e 100644
--- a/src/modules/rag/Application/Menus/DTOs/MenuMetaDto.cs
+++ b/src/modules/platform/Application/Menus/DTOs/MenuMetaDto.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Menus.DTOs;
+namespace BuildFlow.Platform.Application.Menus.DTOs;
///
/// 菜单Meta展示 DTO。
diff --git a/src/modules/rag/Application/Menus/DTOs/MenuRouteDto.cs b/src/modules/platform/Application/Menus/DTOs/MenuRouteDto.cs
similarity index 88%
rename from src/modules/rag/Application/Menus/DTOs/MenuRouteDto.cs
rename to src/modules/platform/Application/Menus/DTOs/MenuRouteDto.cs
index 5d485ac..ca94643 100644
--- a/src/modules/rag/Application/Menus/DTOs/MenuRouteDto.cs
+++ b/src/modules/platform/Application/Menus/DTOs/MenuRouteDto.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Menus.DTOs;
+namespace BuildFlow.Platform.Application.Menus.DTOs;
///
/// 菜单Route展示 DTO。
diff --git a/src/modules/platform/Application/Menus/DTOs/MenuTreeNodeDto.cs b/src/modules/platform/Application/Menus/DTOs/MenuTreeNodeDto.cs
new file mode 100644
index 0000000..844c19e
--- /dev/null
+++ b/src/modules/platform/Application/Menus/DTOs/MenuTreeNodeDto.cs
@@ -0,0 +1,11 @@
+namespace BuildFlow.Platform.Application.Menus.DTOs;
+
+///
+/// 菜单管理树节点。扁平 MenuDto 包装为带 Children 的树,供管理端 Tree 展示。
+/// 不过滤角色,返回全部菜单。
+///
+public record MenuTreeNodeDto
+{
+ public required MenuDto Menu { get; init; }
+ public List Children { get; init; } = [];
+}
diff --git a/src/modules/platform/Application/Menus/DTOs/UpdateMenuRequest.cs b/src/modules/platform/Application/Menus/DTOs/UpdateMenuRequest.cs
new file mode 100644
index 0000000..0824550
--- /dev/null
+++ b/src/modules/platform/Application/Menus/DTOs/UpdateMenuRequest.cs
@@ -0,0 +1,22 @@
+namespace BuildFlow.Platform.Application.Menus.DTOs;
+
+///
+/// 更新菜单请求体。Name 为路由 name,更新后需前端刷新路由。
+///
+public record UpdateMenuRequest(
+ Guid? ParentId,
+ string? Name,
+ string? Path,
+ string? Component,
+ string? Redirect,
+ string? Title,
+ string? Icon,
+ string? ActiveIcon,
+ int? Order,
+ bool? HideInMenu,
+ bool? KeepAlive,
+ bool? AffixTab,
+ string? Link,
+ bool? NoBasicLayout,
+ bool? MenuVisibleWithForbidden,
+ string? Authority);
diff --git a/src/modules/platform/Application/Menus/Handlers/CreateMenuCommandHandler.cs b/src/modules/platform/Application/Menus/Handlers/CreateMenuCommandHandler.cs
new file mode 100644
index 0000000..bc03ef7
--- /dev/null
+++ b/src/modules/platform/Application/Menus/Handlers/CreateMenuCommandHandler.cs
@@ -0,0 +1,52 @@
+using BuildFlow.Shared.Domain.Exceptions;
+using MediatR;
+using BuildFlow.Platform.Application.Menus.DTOs;
+using BuildFlow.Platform.Domain.Entities;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Menus.Commands;
+
+namespace BuildFlow.Platform.Application.Menus.Handlers;
+
+///
+/// 创建菜单命令处理器。校验路由 name 唯一与父菜单存在性。
+///
+public class CreateMenuCommandHandler(PlatformDbContext db) : IRequestHandler
+{
+ public async Task Handle(CreateMenuCommand request, CancellationToken ct)
+ {
+ // 路由 name 全局唯一,避免前端路由冲突。
+ if (await db.Menus.AnyAsync(m => m.Name == request.Name, ct))
+ throw new BusinessException("菜单路由名称已存在");
+
+ // 若指定父菜单,必须真实存在(软删除的也视为不存在)。
+ if (request.ParentId is not null
+ && !await db.Menus.AnyAsync(m => m.Id == request.ParentId.Value, ct))
+ {
+ throw new NotFoundException("父菜单不存在");
+ }
+
+ var menu = new Menu
+ {
+ ParentId = request.ParentId,
+ Name = request.Name,
+ Path = request.Path,
+ Component = request.Component,
+ Redirect = request.Redirect,
+ Title = request.Title,
+ Icon = request.Icon,
+ ActiveIcon = request.ActiveIcon,
+ Order = request.Order,
+ HideInMenu = request.HideInMenu,
+ KeepAlive = request.KeepAlive,
+ AffixTab = request.AffixTab,
+ Link = request.Link,
+ NoBasicLayout = request.NoBasicLayout,
+ MenuVisibleWithForbidden = request.MenuVisibleWithForbidden,
+ Authority = request.Authority,
+ };
+ await db.Menus.AddAsync(menu, ct);
+ await db.SaveChangesAsync(ct);
+
+ return MenuHandlerMapping.ToDto(menu);
+ }
+}
diff --git a/src/modules/platform/Application/Menus/Handlers/DeleteMenuCommandHandler.cs b/src/modules/platform/Application/Menus/Handlers/DeleteMenuCommandHandler.cs
new file mode 100644
index 0000000..5224513
--- /dev/null
+++ b/src/modules/platform/Application/Menus/Handlers/DeleteMenuCommandHandler.cs
@@ -0,0 +1,26 @@
+using BuildFlow.Shared.Domain.Exceptions;
+using MediatR;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Menus.Commands;
+
+namespace BuildFlow.Platform.Application.Menus.Handlers;
+
+///
+/// 删除菜单命令处理器。存在子菜单时拒绝,要求先清理子菜单。
+/// 不使用 EF 的级联删除,避免误删整棵子树。
+///
+public class DeleteMenuCommandHandler(PlatformDbContext db) : IRequestHandler
+{
+ public async Task Handle(DeleteMenuCommand request, CancellationToken ct)
+ {
+ var menu = await db.Menus.FirstOrDefaultAsync(m => m.Id == request.Id, ct)
+ ?? throw new NotFoundException("菜单不存在");
+
+ if (await db.Menus.AnyAsync(m => m.ParentId == request.Id, ct))
+ throw new BusinessException("存在子菜单,请先删除子菜单");
+
+ db.Menus.Remove(menu); // ISoftDelete -> AuditInterceptor 软删除
+ await db.SaveChangesAsync(ct);
+ return Unit.Value;
+ }
+}
diff --git a/src/modules/rag/Application/Menus/Handlers/GetAllMenusQueryHandler.cs b/src/modules/platform/Application/Menus/Handlers/GetAllMenusQueryHandler.cs
similarity index 89%
rename from src/modules/rag/Application/Menus/Handlers/GetAllMenusQueryHandler.cs
rename to src/modules/platform/Application/Menus/Handlers/GetAllMenusQueryHandler.cs
index e78b532..2ab7944 100644
--- a/src/modules/rag/Application/Menus/Handlers/GetAllMenusQueryHandler.cs
+++ b/src/modules/platform/Application/Menus/Handlers/GetAllMenusQueryHandler.cs
@@ -1,14 +1,14 @@
using MediatR;
-using BuildFlow.Application.Menus.DTOs;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Menus.Queries;
+using BuildFlow.Platform.Application.Menus.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Menus.Queries;
-namespace BuildFlow.Application.Menus.Handlers;
+namespace BuildFlow.Platform.Application.Menus.Handlers;
///
/// GetAll菜单s查询处理器。执行业务校验后持久化。
///
-public class GetAllMenusQueryHandler(RagDbContext db) : IRequestHandler>
+public class GetAllMenusQueryHandler(PlatformDbContext db) : IRequestHandler>
{
public async Task> Handle(GetAllMenusQuery request, CancellationToken ct)
{
diff --git a/src/modules/platform/Application/Menus/Handlers/GetMenuByIdQueryHandler.cs b/src/modules/platform/Application/Menus/Handlers/GetMenuByIdQueryHandler.cs
new file mode 100644
index 0000000..64bf380
--- /dev/null
+++ b/src/modules/platform/Application/Menus/Handlers/GetMenuByIdQueryHandler.cs
@@ -0,0 +1,20 @@
+using BuildFlow.Shared.Domain.Exceptions;
+using MediatR;
+using BuildFlow.Platform.Application.Menus.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Menus.Queries;
+
+namespace BuildFlow.Platform.Application.Menus.Handlers;
+
+///
+/// 按主键查询单个菜单处理器。
+///
+public class GetMenuByIdQueryHandler(PlatformDbContext db) : IRequestHandler
+{
+ public async Task Handle(GetMenuByIdQuery request, CancellationToken ct)
+ {
+ var menu = await db.Menus.FirstOrDefaultAsync(m => m.Id == request.Id, ct)
+ ?? throw new NotFoundException("菜单不存在");
+ return MenuHandlerMapping.ToDto(menu);
+ }
+}
diff --git a/src/modules/platform/Application/Menus/Handlers/GetMenuTreeQueryHandler.cs b/src/modules/platform/Application/Menus/Handlers/GetMenuTreeQueryHandler.cs
new file mode 100644
index 0000000..d0b4035
--- /dev/null
+++ b/src/modules/platform/Application/Menus/Handlers/GetMenuTreeQueryHandler.cs
@@ -0,0 +1,30 @@
+using MediatR;
+using BuildFlow.Platform.Application.Menus.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Menus.Queries;
+
+namespace BuildFlow.Platform.Application.Menus.Handlers;
+
+///
+/// 菜单管理树查询处理器。返回全部菜单,按 Order 排序递归构建树。
+///
+public class GetMenuTreeQueryHandler(PlatformDbContext db) : IRequestHandler>
+{
+ public async Task> Handle(GetMenuTreeQuery request, CancellationToken ct)
+ {
+ var menus = await db.Menus.OrderBy(m => m.Order).ToListAsync(ct);
+ return BuildTree(menus, null);
+ }
+
+ private static List BuildTree(List menus, Guid? parentId)
+ {
+ return menus
+ .Where(m => m.ParentId == parentId)
+ .Select(m => new MenuTreeNodeDto
+ {
+ Menu = MenuHandlerMapping.ToDto(m),
+ Children = BuildTree(menus, m.Id),
+ })
+ .ToList();
+ }
+}
diff --git a/src/modules/platform/Application/Menus/Handlers/MenuHandlerMapping.cs b/src/modules/platform/Application/Menus/Handlers/MenuHandlerMapping.cs
new file mode 100644
index 0000000..d6a00c8
--- /dev/null
+++ b/src/modules/platform/Application/Menus/Handlers/MenuHandlerMapping.cs
@@ -0,0 +1,28 @@
+using BuildFlow.Platform.Application.Menus.DTOs;
+
+namespace BuildFlow.Platform.Application.Menus.Handlers;
+
+///
+/// Menu 实体到 MenuDto 的手动映射,供各 Menu handler 复用。
+///
+internal static class MenuHandlerMapping
+{
+ public static MenuDto ToDto(Domain.Entities.Menu m) => new(
+ m.Id,
+ m.ParentId,
+ m.Name,
+ m.Path,
+ m.Component,
+ m.Redirect,
+ m.Title,
+ m.Icon,
+ m.ActiveIcon,
+ m.Order,
+ m.HideInMenu,
+ m.KeepAlive,
+ m.AffixTab,
+ m.Link,
+ m.NoBasicLayout,
+ m.MenuVisibleWithForbidden,
+ m.Authority);
+}
diff --git a/src/modules/platform/Application/Menus/Handlers/UpdateMenuCommandHandler.cs b/src/modules/platform/Application/Menus/Handlers/UpdateMenuCommandHandler.cs
new file mode 100644
index 0000000..e360f71
--- /dev/null
+++ b/src/modules/platform/Application/Menus/Handlers/UpdateMenuCommandHandler.cs
@@ -0,0 +1,56 @@
+using BuildFlow.Shared.Domain.Exceptions;
+using MediatR;
+using BuildFlow.Platform.Application.Menus.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Menus.Commands;
+
+namespace BuildFlow.Platform.Application.Menus.Handlers;
+
+///
+/// 更新菜单命令处理器。若改 name 需校验唯一;改 ParentId 需防自引用。
+///
+public class UpdateMenuCommandHandler(PlatformDbContext db) : IRequestHandler
+{
+ public async Task Handle(UpdateMenuCommand request, CancellationToken ct)
+ {
+ var menu = await db.Menus.FirstOrDefaultAsync(m => m.Id == request.Id, ct)
+ ?? throw new NotFoundException("菜单不存在");
+
+ // 更新 name 时校验全局唯一(排除自身)。
+ if (request.Name is not null && request.Name != menu.Name
+ && await db.Menus.AnyAsync(m => m.Name == request.Name && m.Id != request.Id, ct))
+ {
+ throw new BusinessException("菜单路由名称已存在");
+ }
+
+ // 防止把父菜单指向自身,造成自引用环。
+ if (request.ParentId is not null && request.ParentId == request.Id)
+ throw new BusinessException("不能将菜单的父级指向自身");
+
+ if (request.ParentId.HasValue
+ && !await db.Menus.AnyAsync(m => m.Id == request.ParentId.Value, ct))
+ {
+ throw new NotFoundException("父菜单不存在");
+ }
+
+ if (request.ParentId is not null) menu.ParentId = request.ParentId;
+ if (request.Name is not null) menu.Name = request.Name;
+ if (request.Path is not null) menu.Path = request.Path;
+ if (request.Component is not null) menu.Component = request.Component;
+ if (request.Redirect is not null) menu.Redirect = request.Redirect;
+ if (request.Title is not null) menu.Title = request.Title;
+ if (request.Icon is not null) menu.Icon = request.Icon;
+ if (request.ActiveIcon is not null) menu.ActiveIcon = request.ActiveIcon;
+ if (request.Order is not null) menu.Order = request.Order.Value;
+ if (request.HideInMenu is not null) menu.HideInMenu = request.HideInMenu.Value;
+ if (request.KeepAlive is not null) menu.KeepAlive = request.KeepAlive;
+ if (request.AffixTab is not null) menu.AffixTab = request.AffixTab;
+ if (request.Link is not null) menu.Link = request.Link;
+ if (request.NoBasicLayout is not null) menu.NoBasicLayout = request.NoBasicLayout.Value;
+ if (request.MenuVisibleWithForbidden is not null) menu.MenuVisibleWithForbidden = request.MenuVisibleWithForbidden.Value;
+ if (request.Authority is not null) menu.Authority = request.Authority;
+
+ await db.SaveChangesAsync(ct);
+ return MenuHandlerMapping.ToDto(menu);
+ }
+}
diff --git a/src/modules/rag/Application/Menus/Queries/GetAllMenusQuery.cs b/src/modules/platform/Application/Menus/Queries/GetAllMenusQuery.cs
similarity index 64%
rename from src/modules/rag/Application/Menus/Queries/GetAllMenusQuery.cs
rename to src/modules/platform/Application/Menus/Queries/GetAllMenusQuery.cs
index ac01afe..bac3906 100644
--- a/src/modules/rag/Application/Menus/Queries/GetAllMenusQuery.cs
+++ b/src/modules/platform/Application/Menus/Queries/GetAllMenusQuery.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Menus.DTOs;
+using BuildFlow.Platform.Application.Menus.DTOs;
-namespace BuildFlow.Application.Menus.Queries;
+namespace BuildFlow.Platform.Application.Menus.Queries;
///
diff --git a/src/modules/platform/Application/Menus/Queries/GetMenuByIdQuery.cs b/src/modules/platform/Application/Menus/Queries/GetMenuByIdQuery.cs
new file mode 100644
index 0000000..0b7d22f
--- /dev/null
+++ b/src/modules/platform/Application/Menus/Queries/GetMenuByIdQuery.cs
@@ -0,0 +1,9 @@
+using MediatR;
+using BuildFlow.Platform.Application.Menus.DTOs;
+
+namespace BuildFlow.Platform.Application.Menus.Queries;
+
+///
+/// 按主键查询单个菜单。
+///
+public record GetMenuByIdQuery(Guid Id) : IRequest;
diff --git a/src/modules/platform/Application/Menus/Queries/GetMenuTreeQuery.cs b/src/modules/platform/Application/Menus/Queries/GetMenuTreeQuery.cs
new file mode 100644
index 0000000..fdebe26
--- /dev/null
+++ b/src/modules/platform/Application/Menus/Queries/GetMenuTreeQuery.cs
@@ -0,0 +1,9 @@
+using MediatR;
+using BuildFlow.Platform.Application.Menus.DTOs;
+
+namespace BuildFlow.Platform.Application.Menus.Queries;
+
+///
+/// 查询菜单管理树。返回全部菜单,不做角色过滤。
+///
+public record GetMenuTreeQuery : IRequest>;
diff --git a/src/modules/platform/Application/Menus/Validators/CreateMenuCommandValidator.cs b/src/modules/platform/Application/Menus/Validators/CreateMenuCommandValidator.cs
new file mode 100644
index 0000000..2ace4b9
--- /dev/null
+++ b/src/modules/platform/Application/Menus/Validators/CreateMenuCommandValidator.cs
@@ -0,0 +1,32 @@
+using FluentValidation;
+using BuildFlow.Platform.Application.Menus.Commands;
+
+namespace BuildFlow.Platform.Application.Menus.Validators;
+
+///
+/// 创建菜单命令校验。
+///
+public class CreateMenuCommandValidator : AbstractValidator
+{
+ public CreateMenuCommandValidator()
+ {
+ RuleFor(x => x.Name).NotEmpty().WithMessage("菜单路由名称不能为空")
+ .MaximumLength(100).WithMessage("菜单路由名称长度不能超过 100 个字符");
+ RuleFor(x => x.Path).NotEmpty().WithMessage("路由路径不能为空")
+ .MaximumLength(200).WithMessage("路由路径长度不能超过 200 个字符");
+ RuleFor(x => x.Title).NotEmpty().WithMessage("菜单标题不能为空")
+ .MaximumLength(100).WithMessage("菜单标题长度不能超过 100 个字符");
+ When(x => x.Component is not null, () =>
+ {
+ RuleFor(x => x.Component!).MaximumLength(200).WithMessage("组件路径长度不能超过 200 个字符");
+ });
+ When(x => x.Icon is not null, () =>
+ {
+ RuleFor(x => x.Icon!).MaximumLength(100).WithMessage("图标长度不能超过 100 个字符");
+ });
+ When(x => x.Authority is not null, () =>
+ {
+ RuleFor(x => x.Authority!).MaximumLength(200).WithMessage("Authority 长度不能超过 200 个字符");
+ });
+ }
+}
diff --git a/src/modules/rag/Application/Menus/Validators/GetAllMenusQueryValidator.cs b/src/modules/platform/Application/Menus/Validators/GetAllMenusQueryValidator.cs
similarity index 75%
rename from src/modules/rag/Application/Menus/Validators/GetAllMenusQueryValidator.cs
rename to src/modules/platform/Application/Menus/Validators/GetAllMenusQueryValidator.cs
index a30014e..1152a3d 100644
--- a/src/modules/rag/Application/Menus/Validators/GetAllMenusQueryValidator.cs
+++ b/src/modules/platform/Application/Menus/Validators/GetAllMenusQueryValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Menus.Queries;
+using BuildFlow.Platform.Application.Menus.Queries;
-namespace BuildFlow.Application.Menus.Validators;
+namespace BuildFlow.Platform.Application.Menus.Validators;
///
/// GetAll菜单s查询的请求校验器(FluentValidation)。
diff --git a/src/modules/platform/Application/Menus/Validators/UpdateMenuCommandValidator.cs b/src/modules/platform/Application/Menus/Validators/UpdateMenuCommandValidator.cs
new file mode 100644
index 0000000..0f705e1
--- /dev/null
+++ b/src/modules/platform/Application/Menus/Validators/UpdateMenuCommandValidator.cs
@@ -0,0 +1,27 @@
+using FluentValidation;
+using BuildFlow.Platform.Application.Menus.Commands;
+
+namespace BuildFlow.Platform.Application.Menus.Validators;
+
+///
+/// 更新菜单命令校验。
+///
+public class UpdateMenuCommandValidator : AbstractValidator
+{
+ public UpdateMenuCommandValidator()
+ {
+ RuleFor(x => x.Id).NotEmpty().WithMessage("菜单 ID 不能为空");
+ When(x => x.Name is not null, () =>
+ {
+ RuleFor(x => x.Name!).MaximumLength(100).WithMessage("菜单路由名称长度不能超过 100 个字符");
+ });
+ When(x => x.Path is not null, () =>
+ {
+ RuleFor(x => x.Path!).MaximumLength(200).WithMessage("路由路径长度不能超过 200 个字符");
+ });
+ When(x => x.Title is not null, () =>
+ {
+ RuleFor(x => x.Title!).MaximumLength(100).WithMessage("菜单标题长度不能超过 100 个字符");
+ });
+ }
+}
diff --git a/src/modules/rag/Application/Notifications/Commands/MarkAllNotificationsReadCommand.cs b/src/modules/platform/Application/Notifications/Commands/MarkAllNotificationsReadCommand.cs
similarity index 75%
rename from src/modules/rag/Application/Notifications/Commands/MarkAllNotificationsReadCommand.cs
rename to src/modules/platform/Application/Notifications/Commands/MarkAllNotificationsReadCommand.cs
index 814a213..9bc9759 100644
--- a/src/modules/rag/Application/Notifications/Commands/MarkAllNotificationsReadCommand.cs
+++ b/src/modules/platform/Application/Notifications/Commands/MarkAllNotificationsReadCommand.cs
@@ -1,6 +1,6 @@
using MediatR;
-namespace BuildFlow.Application.Notifications.Commands;
+namespace BuildFlow.Platform.Application.Notifications.Commands;
///
/// MarkAll通知sRead命令。封装写操作入参与意图。
diff --git a/src/modules/rag/Application/Notifications/Commands/MarkNotificationReadCommand.cs b/src/modules/platform/Application/Notifications/Commands/MarkNotificationReadCommand.cs
similarity index 76%
rename from src/modules/rag/Application/Notifications/Commands/MarkNotificationReadCommand.cs
rename to src/modules/platform/Application/Notifications/Commands/MarkNotificationReadCommand.cs
index 624a753..4a7312b 100644
--- a/src/modules/rag/Application/Notifications/Commands/MarkNotificationReadCommand.cs
+++ b/src/modules/platform/Application/Notifications/Commands/MarkNotificationReadCommand.cs
@@ -1,6 +1,6 @@
using MediatR;
-namespace BuildFlow.Application.Notifications.Commands;
+namespace BuildFlow.Platform.Application.Notifications.Commands;
///
diff --git a/src/modules/rag/Application/Notifications/Commands/PublishNotificationCommand.cs b/src/modules/platform/Application/Notifications/Commands/PublishNotificationCommand.cs
similarity index 85%
rename from src/modules/rag/Application/Notifications/Commands/PublishNotificationCommand.cs
rename to src/modules/platform/Application/Notifications/Commands/PublishNotificationCommand.cs
index e2effdb..1c97b2a 100644
--- a/src/modules/rag/Application/Notifications/Commands/PublishNotificationCommand.cs
+++ b/src/modules/platform/Application/Notifications/Commands/PublishNotificationCommand.cs
@@ -1,6 +1,6 @@
using MediatR;
-namespace BuildFlow.Application.Notifications.Commands;
+namespace BuildFlow.Platform.Application.Notifications.Commands;
///
diff --git a/src/modules/rag/Application/Notifications/DTOs/NotificationDtos.cs b/src/modules/platform/Application/Notifications/DTOs/NotificationDtos.cs
similarity index 85%
rename from src/modules/rag/Application/Notifications/DTOs/NotificationDtos.cs
rename to src/modules/platform/Application/Notifications/DTOs/NotificationDtos.cs
index 9a86fc1..9707b23 100644
--- a/src/modules/rag/Application/Notifications/DTOs/NotificationDtos.cs
+++ b/src/modules/platform/Application/Notifications/DTOs/NotificationDtos.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Notifications.DTOs;
+namespace BuildFlow.Platform.Application.Notifications.DTOs;
///
diff --git a/src/modules/rag/Application/Notifications/DTOs/PagedResult.cs b/src/modules/platform/Application/Notifications/DTOs/PagedResult.cs
similarity index 69%
rename from src/modules/rag/Application/Notifications/DTOs/PagedResult.cs
rename to src/modules/platform/Application/Notifications/DTOs/PagedResult.cs
index 4ea7688..cebbbcf 100644
--- a/src/modules/rag/Application/Notifications/DTOs/PagedResult.cs
+++ b/src/modules/platform/Application/Notifications/DTOs/PagedResult.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Notifications.DTOs;
+namespace BuildFlow.Platform.Application.Notifications.DTOs;
///
/// PagedResult。
diff --git a/src/modules/rag/Application/Notifications/Handlers/GetNotificationsQueryHandler.cs b/src/modules/platform/Application/Notifications/Handlers/GetNotificationsQueryHandler.cs
similarity index 79%
rename from src/modules/rag/Application/Notifications/Handlers/GetNotificationsQueryHandler.cs
rename to src/modules/platform/Application/Notifications/Handlers/GetNotificationsQueryHandler.cs
index 82927fa..8cc2d6c 100644
--- a/src/modules/rag/Application/Notifications/Handlers/GetNotificationsQueryHandler.cs
+++ b/src/modules/platform/Application/Notifications/Handlers/GetNotificationsQueryHandler.cs
@@ -1,14 +1,14 @@
using MediatR;
-using BuildFlow.Application.Notifications.DTOs;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Notifications.Queries;
+using BuildFlow.Platform.Application.Notifications.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Notifications.Queries;
-namespace BuildFlow.Application.Notifications.Handlers;
+namespace BuildFlow.Platform.Application.Notifications.Handlers;
///
/// Get通知s查询处理器。执行业务校验后持久化。
///
-public class GetNotificationsQueryHandler(RagDbContext db)
+public class GetNotificationsQueryHandler(PlatformDbContext db)
: IRequestHandler>
{
public async Task> Handle(GetNotificationsQuery request, CancellationToken ct)
diff --git a/src/modules/rag/Application/Notifications/Handlers/GetUnreadNotificationCountQueryHandler.cs b/src/modules/platform/Application/Notifications/Handlers/GetUnreadNotificationCountQueryHandler.cs
similarity index 61%
rename from src/modules/rag/Application/Notifications/Handlers/GetUnreadNotificationCountQueryHandler.cs
rename to src/modules/platform/Application/Notifications/Handlers/GetUnreadNotificationCountQueryHandler.cs
index e3ae676..6614106 100644
--- a/src/modules/rag/Application/Notifications/Handlers/GetUnreadNotificationCountQueryHandler.cs
+++ b/src/modules/platform/Application/Notifications/Handlers/GetUnreadNotificationCountQueryHandler.cs
@@ -1,13 +1,13 @@
using MediatR;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Notifications.Queries;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Notifications.Queries;
-namespace BuildFlow.Application.Notifications.Handlers;
+namespace BuildFlow.Platform.Application.Notifications.Handlers;
///
/// GetUnread通知Count查询处理器。执行业务校验后持久化。
///
-public class GetUnreadNotificationCountQueryHandler(RagDbContext db)
+public class GetUnreadNotificationCountQueryHandler(PlatformDbContext db)
: IRequestHandler
{
public async Task Handle(GetUnreadNotificationCountQuery request, CancellationToken ct)
diff --git a/src/modules/rag/Application/Notifications/Handlers/MarkAllNotificationsReadCommandHandler.cs b/src/modules/platform/Application/Notifications/Handlers/MarkAllNotificationsReadCommandHandler.cs
similarity index 72%
rename from src/modules/rag/Application/Notifications/Handlers/MarkAllNotificationsReadCommandHandler.cs
rename to src/modules/platform/Application/Notifications/Handlers/MarkAllNotificationsReadCommandHandler.cs
index 7acdc55..76fd504 100644
--- a/src/modules/rag/Application/Notifications/Handlers/MarkAllNotificationsReadCommandHandler.cs
+++ b/src/modules/platform/Application/Notifications/Handlers/MarkAllNotificationsReadCommandHandler.cs
@@ -1,13 +1,13 @@
using MediatR;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Notifications.Commands;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Notifications.Commands;
-namespace BuildFlow.Application.Notifications.Handlers;
+namespace BuildFlow.Platform.Application.Notifications.Handlers;
///
/// MarkAll通知sReadCommand处理器。执行业务校验后持久化。
///
-public class MarkAllNotificationsReadCommandHandler(RagDbContext db)
+public class MarkAllNotificationsReadCommandHandler(PlatformDbContext db)
: IRequestHandler
{
public async Task Handle(MarkAllNotificationsReadCommand request, CancellationToken ct)
diff --git a/src/modules/rag/Application/Notifications/Handlers/MarkNotificationReadCommandHandler.cs b/src/modules/platform/Application/Notifications/Handlers/MarkNotificationReadCommandHandler.cs
similarity index 76%
rename from src/modules/rag/Application/Notifications/Handlers/MarkNotificationReadCommandHandler.cs
rename to src/modules/platform/Application/Notifications/Handlers/MarkNotificationReadCommandHandler.cs
index 5a12b73..a49abe8 100644
--- a/src/modules/rag/Application/Notifications/Handlers/MarkNotificationReadCommandHandler.cs
+++ b/src/modules/platform/Application/Notifications/Handlers/MarkNotificationReadCommandHandler.cs
@@ -1,13 +1,13 @@
using MediatR;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Notifications.Commands;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Notifications.Commands;
-namespace BuildFlow.Application.Notifications.Handlers;
+namespace BuildFlow.Platform.Application.Notifications.Handlers;
///
/// Mark通知ReadCommand处理器。执行业务校验后持久化。
///
-public class MarkNotificationReadCommandHandler(RagDbContext db)
+public class MarkNotificationReadCommandHandler(PlatformDbContext db)
: IRequestHandler
{
public async Task Handle(MarkNotificationReadCommand request, CancellationToken ct)
diff --git a/src/modules/rag/Application/Notifications/Handlers/PublishNotificationCommandHandler.cs b/src/modules/platform/Application/Notifications/Handlers/PublishNotificationCommandHandler.cs
similarity index 89%
rename from src/modules/rag/Application/Notifications/Handlers/PublishNotificationCommandHandler.cs
rename to src/modules/platform/Application/Notifications/Handlers/PublishNotificationCommandHandler.cs
index 3b1d124..630c36a 100644
--- a/src/modules/rag/Application/Notifications/Handlers/PublishNotificationCommandHandler.cs
+++ b/src/modules/platform/Application/Notifications/Handlers/PublishNotificationCommandHandler.cs
@@ -1,15 +1,15 @@
using MediatR;
-using BuildFlow.Domain.Entities;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Notifications.Commands;
+using BuildFlow.Platform.Domain.Entities;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Notifications.Commands;
-namespace BuildFlow.Application.Notifications.Handlers;
+namespace BuildFlow.Platform.Application.Notifications.Handlers;
///
/// Publish通知Command处理器。执行业务校验后持久化。
///
public class PublishNotificationCommandHandler(
- RagDbContext db,
+ PlatformDbContext db,
INotificationDispatcher dispatcher) : IRequestHandler
{
public async Task Handle(PublishNotificationCommand request, CancellationToken ct)
diff --git a/src/modules/rag/Application/Notifications/INotificationDispatcher.cs b/src/modules/platform/Application/Notifications/INotificationDispatcher.cs
similarity index 84%
rename from src/modules/rag/Application/Notifications/INotificationDispatcher.cs
rename to src/modules/platform/Application/Notifications/INotificationDispatcher.cs
index ca45a15..ba60ebc 100644
--- a/src/modules/rag/Application/Notifications/INotificationDispatcher.cs
+++ b/src/modules/platform/Application/Notifications/INotificationDispatcher.cs
@@ -1,6 +1,6 @@
-using BuildFlow.Domain.Entities;
+using BuildFlow.Platform.Domain.Entities;
-namespace BuildFlow.Application.Notifications;
+namespace BuildFlow.Platform.Application.Notifications;
///
/// 通知分发器抽象。职责:把已落库的通知实时推送给接收人(如 SignalR)。
diff --git a/src/modules/rag/Application/Notifications/Queries/GetNotificationsQuery.cs b/src/modules/platform/Application/Notifications/Queries/GetNotificationsQuery.cs
similarity index 69%
rename from src/modules/rag/Application/Notifications/Queries/GetNotificationsQuery.cs
rename to src/modules/platform/Application/Notifications/Queries/GetNotificationsQuery.cs
index 9e965e3..9dd27e3 100644
--- a/src/modules/rag/Application/Notifications/Queries/GetNotificationsQuery.cs
+++ b/src/modules/platform/Application/Notifications/Queries/GetNotificationsQuery.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Notifications.DTOs;
+using BuildFlow.Platform.Application.Notifications.DTOs;
-namespace BuildFlow.Application.Notifications.Queries;
+namespace BuildFlow.Platform.Application.Notifications.Queries;
///
diff --git a/src/modules/rag/Application/Notifications/Queries/GetUnreadNotificationCountQuery.cs b/src/modules/platform/Application/Notifications/Queries/GetUnreadNotificationCountQuery.cs
similarity index 76%
rename from src/modules/rag/Application/Notifications/Queries/GetUnreadNotificationCountQuery.cs
rename to src/modules/platform/Application/Notifications/Queries/GetUnreadNotificationCountQuery.cs
index fe8e7c3..90cc937 100644
--- a/src/modules/rag/Application/Notifications/Queries/GetUnreadNotificationCountQuery.cs
+++ b/src/modules/platform/Application/Notifications/Queries/GetUnreadNotificationCountQuery.cs
@@ -1,6 +1,6 @@
using MediatR;
-namespace BuildFlow.Application.Notifications.Queries;
+namespace BuildFlow.Platform.Application.Notifications.Queries;
///
/// GetUnread通知Count查询。封装读操作入参与过滤条件。
diff --git a/src/modules/platform/Application/Permissions/Commands/CreatePermissionCommand.cs b/src/modules/platform/Application/Permissions/Commands/CreatePermissionCommand.cs
new file mode 100644
index 0000000..2612650
--- /dev/null
+++ b/src/modules/platform/Application/Permissions/Commands/CreatePermissionCommand.cs
@@ -0,0 +1,10 @@
+using MediatR;
+using BuildFlow.Platform.Application.Permissions.DTOs;
+
+namespace BuildFlow.Platform.Application.Permissions.Commands;
+
+///
+/// 创建权限命令。校验编码唯一性后写入权限表。
+///
+public record CreatePermissionCommand(string Name, string Code, string? Description, string? Group)
+ : IRequest;
diff --git a/src/modules/platform/Application/Permissions/Commands/DeletePermissionCommand.cs b/src/modules/platform/Application/Permissions/Commands/DeletePermissionCommand.cs
new file mode 100644
index 0000000..dcc3b31
--- /dev/null
+++ b/src/modules/platform/Application/Permissions/Commands/DeletePermissionCommand.cs
@@ -0,0 +1,8 @@
+using MediatR;
+
+namespace BuildFlow.Platform.Application.Permissions.Commands;
+
+///
+/// 删除权限命令。同时清理角色-权限关联,软删除权限本身。
+///
+public record DeletePermissionCommand(Guid Id) : IRequest;
diff --git a/src/modules/platform/Application/Permissions/Commands/UpdatePermissionCommand.cs b/src/modules/platform/Application/Permissions/Commands/UpdatePermissionCommand.cs
new file mode 100644
index 0000000..abbe825
--- /dev/null
+++ b/src/modules/platform/Application/Permissions/Commands/UpdatePermissionCommand.cs
@@ -0,0 +1,10 @@
+using MediatR;
+using BuildFlow.Platform.Application.Permissions.DTOs;
+
+namespace BuildFlow.Platform.Application.Permissions.Commands;
+
+///
+/// 更新权限命令。支持部分字段更新,编码不可改。
+///
+public record UpdatePermissionCommand(Guid Id, string? Name, string? Description, string? Group)
+ : IRequest;
diff --git a/src/modules/platform/Application/Permissions/DTOs/CreatePermissionRequest.cs b/src/modules/platform/Application/Permissions/DTOs/CreatePermissionRequest.cs
new file mode 100644
index 0000000..30ebeff
--- /dev/null
+++ b/src/modules/platform/Application/Permissions/DTOs/CreatePermissionRequest.cs
@@ -0,0 +1,6 @@
+namespace BuildFlow.Platform.Application.Permissions.DTOs;
+
+///
+/// 创建权限请求体。
+///
+public record CreatePermissionRequest(string Name, string Code, string? Description, string? Group);
diff --git a/src/modules/rag/Application/Permissions/DTOs/PermissionDtos.cs b/src/modules/platform/Application/Permissions/DTOs/PermissionDtos.cs
similarity index 72%
rename from src/modules/rag/Application/Permissions/DTOs/PermissionDtos.cs
rename to src/modules/platform/Application/Permissions/DTOs/PermissionDtos.cs
index 4dceb53..3d23984 100644
--- a/src/modules/rag/Application/Permissions/DTOs/PermissionDtos.cs
+++ b/src/modules/platform/Application/Permissions/DTOs/PermissionDtos.cs
@@ -1,4 +1,4 @@
-namespace BuildFlow.Application.Permissions.DTOs;
+namespace BuildFlow.Platform.Application.Permissions.DTOs;
///
/// 权限展示 DTO。
diff --git a/src/modules/platform/Application/Permissions/DTOs/UpdatePermissionRequest.cs b/src/modules/platform/Application/Permissions/DTOs/UpdatePermissionRequest.cs
new file mode 100644
index 0000000..1773dcd
--- /dev/null
+++ b/src/modules/platform/Application/Permissions/DTOs/UpdatePermissionRequest.cs
@@ -0,0 +1,6 @@
+namespace BuildFlow.Platform.Application.Permissions.DTOs;
+
+///
+/// 更新权限请求体。编码不可更新。
+///
+public record UpdatePermissionRequest(string? Name, string? Description, string? Group);
diff --git a/src/modules/platform/Application/Permissions/Handlers/CreatePermissionCommandHandler.cs b/src/modules/platform/Application/Permissions/Handlers/CreatePermissionCommandHandler.cs
new file mode 100644
index 0000000..2f5f50b
--- /dev/null
+++ b/src/modules/platform/Application/Permissions/Handlers/CreatePermissionCommandHandler.cs
@@ -0,0 +1,33 @@
+using BuildFlow.Shared.Domain.Exceptions;
+using MediatR;
+using BuildFlow.Platform.Application.Permissions.DTOs;
+using BuildFlow.Platform.Domain.Entities;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Permissions.Commands;
+
+namespace BuildFlow.Platform.Application.Permissions.Handlers;
+
+///
+/// 创建权限命令处理器。编码唯一性校验后写入。
+///
+public class CreatePermissionCommandHandler(PlatformDbContext db)
+ : IRequestHandler
+{
+ public async Task Handle(CreatePermissionCommand request, CancellationToken ct)
+ {
+ if (await db.Permissions.AnyAsync(p => p.Code == request.Code, ct))
+ throw new BusinessException("权限编码已存在");
+
+ var permission = new Permission
+ {
+ Name = request.Name,
+ Code = request.Code,
+ Description = request.Description,
+ Group = request.Group,
+ };
+ await db.Permissions.AddAsync(permission, ct);
+ await db.SaveChangesAsync(ct);
+
+ return new PermissionDto(permission.Id, permission.Name, permission.Code, permission.Description, permission.Group);
+ }
+}
diff --git a/src/modules/platform/Application/Permissions/Handlers/DeletePermissionCommandHandler.cs b/src/modules/platform/Application/Permissions/Handlers/DeletePermissionCommandHandler.cs
new file mode 100644
index 0000000..f853d2f
--- /dev/null
+++ b/src/modules/platform/Application/Permissions/Handlers/DeletePermissionCommandHandler.cs
@@ -0,0 +1,27 @@
+using BuildFlow.Shared.Domain.Exceptions;
+using MediatR;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Permissions.Commands;
+
+namespace BuildFlow.Platform.Application.Permissions.Handlers;
+
+///
+/// 删除权限命令处理器。先清理角色-权限关联,再软删除权限,避免外键孤儿。
+///
+public class DeletePermissionCommandHandler(PlatformDbContext db)
+ : IRequestHandler
+{
+ public async Task Handle(DeletePermissionCommand request, CancellationToken ct)
+ {
+ var permission = await db.Permissions.FirstOrDefaultAsync(p => p.Id == request.Id, ct)
+ ?? throw new NotFoundException("权限不存在");
+
+ // 先解除已分配该权限的所有角色关联,避免删除后角色仍持失效权限。
+ var links = db.RolePermissions.Where(rp => rp.PermissionId == request.Id);
+ db.RolePermissions.RemoveRange(links);
+
+ db.Permissions.Remove(permission); // ISoftDelete -> AuditInterceptor 软删除
+ await db.SaveChangesAsync(ct);
+ return Unit.Value;
+ }
+}
diff --git a/src/modules/platform/Application/Permissions/Handlers/GetPermissionByIdQueryHandler.cs b/src/modules/platform/Application/Permissions/Handlers/GetPermissionByIdQueryHandler.cs
new file mode 100644
index 0000000..cbdffd5
--- /dev/null
+++ b/src/modules/platform/Application/Permissions/Handlers/GetPermissionByIdQueryHandler.cs
@@ -0,0 +1,23 @@
+using BuildFlow.Shared.Domain.Exceptions;
+using MediatR;
+using BuildFlow.Platform.Application.Permissions.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Permissions.Queries;
+
+namespace BuildFlow.Platform.Application.Permissions.Handlers;
+
+///
+/// 按主键查询单个权限处理器。
+///
+public class GetPermissionByIdQueryHandler(PlatformDbContext db)
+ : IRequestHandler
+{
+ public async Task Handle(GetPermissionByIdQuery request, CancellationToken ct)
+ {
+ return await db.Permissions
+ .Where(p => p.Id == request.Id)
+ .Select(p => new PermissionDto(p.Id, p.Name, p.Code, p.Description, p.Group))
+ .FirstOrDefaultAsync(ct)
+ ?? throw new NotFoundException("权限不存在");
+ }
+}
diff --git a/src/modules/rag/Application/Permissions/Handlers/GetPermissionListQueryHandler.cs b/src/modules/platform/Application/Permissions/Handlers/GetPermissionListQueryHandler.cs
similarity index 52%
rename from src/modules/rag/Application/Permissions/Handlers/GetPermissionListQueryHandler.cs
rename to src/modules/platform/Application/Permissions/Handlers/GetPermissionListQueryHandler.cs
index eb86217..361b567 100644
--- a/src/modules/rag/Application/Permissions/Handlers/GetPermissionListQueryHandler.cs
+++ b/src/modules/platform/Application/Permissions/Handlers/GetPermissionListQueryHandler.cs
@@ -1,14 +1,14 @@
using MediatR;
-using BuildFlow.Application.Permissions.DTOs;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Permissions.Queries;
+using BuildFlow.Platform.Application.Permissions.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Permissions.Queries;
-namespace BuildFlow.Application.Permissions.Handlers;
+namespace BuildFlow.Platform.Application.Permissions.Handlers;
///
/// Get权限List查询处理器。执行业务校验后持久化。
///
-public class GetPermissionListQueryHandler(RagDbContext db) : IRequestHandler>
+public class GetPermissionListQueryHandler(PlatformDbContext db) : IRequestHandler>
{
public async Task> Handle(GetPermissionListQuery request, CancellationToken ct)
{
diff --git a/src/modules/platform/Application/Permissions/Handlers/UpdatePermissionCommandHandler.cs b/src/modules/platform/Application/Permissions/Handlers/UpdatePermissionCommandHandler.cs
new file mode 100644
index 0000000..05fc56e
--- /dev/null
+++ b/src/modules/platform/Application/Permissions/Handlers/UpdatePermissionCommandHandler.cs
@@ -0,0 +1,27 @@
+using BuildFlow.Shared.Domain.Exceptions;
+using MediatR;
+using BuildFlow.Platform.Application.Permissions.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Permissions.Commands;
+
+namespace BuildFlow.Platform.Application.Permissions.Handlers;
+
+///
+/// 更新权限命令处理器。编码不可改,其余字段按需更新。
+///
+public class UpdatePermissionCommandHandler(PlatformDbContext db)
+ : IRequestHandler
+{
+ public async Task Handle(UpdatePermissionCommand request, CancellationToken ct)
+ {
+ var permission = await db.Permissions.FirstOrDefaultAsync(p => p.Id == request.Id, ct)
+ ?? throw new NotFoundException("权限不存在");
+
+ if (request.Name is not null) permission.Name = request.Name;
+ if (request.Description is not null) permission.Description = request.Description;
+ if (request.Group is not null) permission.Group = request.Group;
+ await db.SaveChangesAsync(ct);
+
+ return new PermissionDto(permission.Id, permission.Name, permission.Code, permission.Description, permission.Group);
+ }
+}
diff --git a/src/modules/platform/Application/Permissions/Queries/GetPermissionByIdQuery.cs b/src/modules/platform/Application/Permissions/Queries/GetPermissionByIdQuery.cs
new file mode 100644
index 0000000..a776b39
--- /dev/null
+++ b/src/modules/platform/Application/Permissions/Queries/GetPermissionByIdQuery.cs
@@ -0,0 +1,9 @@
+using MediatR;
+using BuildFlow.Platform.Application.Permissions.DTOs;
+
+namespace BuildFlow.Platform.Application.Permissions.Queries;
+
+///
+/// 按主键查询单个权限。
+///
+public record GetPermissionByIdQuery(Guid Id) : IRequest;
diff --git a/src/modules/rag/Application/Permissions/Queries/GetPermissionListQuery.cs b/src/modules/platform/Application/Permissions/Queries/GetPermissionListQuery.cs
similarity index 61%
rename from src/modules/rag/Application/Permissions/Queries/GetPermissionListQuery.cs
rename to src/modules/platform/Application/Permissions/Queries/GetPermissionListQuery.cs
index cdddc6e..fe0418e 100644
--- a/src/modules/rag/Application/Permissions/Queries/GetPermissionListQuery.cs
+++ b/src/modules/platform/Application/Permissions/Queries/GetPermissionListQuery.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Permissions.DTOs;
+using BuildFlow.Platform.Application.Permissions.DTOs;
-namespace BuildFlow.Application.Permissions.Queries;
+namespace BuildFlow.Platform.Application.Permissions.Queries;
///
diff --git a/src/modules/platform/Application/Permissions/Validators/CreatePermissionCommandValidator.cs b/src/modules/platform/Application/Permissions/Validators/CreatePermissionCommandValidator.cs
new file mode 100644
index 0000000..4be6a0c
--- /dev/null
+++ b/src/modules/platform/Application/Permissions/Validators/CreatePermissionCommandValidator.cs
@@ -0,0 +1,26 @@
+using FluentValidation;
+using BuildFlow.Platform.Application.Permissions.Commands;
+
+namespace BuildFlow.Platform.Application.Permissions.Validators;
+
+///
+/// 创建权限命令校验。
+///
+public class CreatePermissionCommandValidator : AbstractValidator
+{
+ public CreatePermissionCommandValidator()
+ {
+ RuleFor(x => x.Name).NotEmpty().WithMessage("权限名称不能为空")
+ .Length(2, 50).WithMessage("权限名称长度 2-50 个字符");
+ RuleFor(x => x.Code).NotEmpty().WithMessage("权限编码不能为空")
+ .Matches(@"^[a-z][a-z0-9-]*(:[a-z][a-z0-9-]*)+$").WithMessage("权限编码格式应为 resource:action,且仅小写字母、数字、连字符");
+ When(x => x.Description is not null, () =>
+ {
+ RuleFor(x => x.Description!).MaximumLength(500).WithMessage("权限描述长度不能超过 500 个字符");
+ });
+ When(x => x.Group is not null, () =>
+ {
+ RuleFor(x => x.Group!).MaximumLength(50).WithMessage("权限分组长度不能超过 50 个字符");
+ });
+ }
+}
diff --git a/src/modules/platform/Application/Permissions/Validators/UpdatePermissionCommandValidator.cs b/src/modules/platform/Application/Permissions/Validators/UpdatePermissionCommandValidator.cs
new file mode 100644
index 0000000..e9fa99a
--- /dev/null
+++ b/src/modules/platform/Application/Permissions/Validators/UpdatePermissionCommandValidator.cs
@@ -0,0 +1,27 @@
+using FluentValidation;
+using BuildFlow.Platform.Application.Permissions.Commands;
+
+namespace BuildFlow.Platform.Application.Permissions.Validators;
+
+///
+/// 更新权限命令校验。
+///
+public class UpdatePermissionCommandValidator : AbstractValidator
+{
+ public UpdatePermissionCommandValidator()
+ {
+ RuleFor(x => x.Id).NotEmpty().WithMessage("权限 ID 不能为空");
+ When(x => x.Name is not null, () =>
+ {
+ RuleFor(x => x.Name!).Length(2, 50).WithMessage("权限名称长度 2-50 个字符");
+ });
+ When(x => x.Description is not null, () =>
+ {
+ RuleFor(x => x.Description!).MaximumLength(500).WithMessage("权限描述长度不能超过 500 个字符");
+ });
+ When(x => x.Group is not null, () =>
+ {
+ RuleFor(x => x.Group!).MaximumLength(50).WithMessage("权限分组长度不能超过 50 个字符");
+ });
+ }
+}
diff --git a/src/modules/platform/Application/Platform.Application.csproj b/src/modules/platform/Application/Platform.Application.csproj
new file mode 100644
index 0000000..0d16ba1
--- /dev/null
+++ b/src/modules/platform/Application/Platform.Application.csproj
@@ -0,0 +1,18 @@
+
+
+ net10.0
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/modules/platform/Application/PlatformApplicationModule.cs b/src/modules/platform/Application/PlatformApplicationModule.cs
new file mode 100644
index 0000000..71ea589
--- /dev/null
+++ b/src/modules/platform/Application/PlatformApplicationModule.cs
@@ -0,0 +1,21 @@
+using BuildFlow.Platform.Application.Common;
+using BuildFlow.Platform.Infrastructure;
+using FluentValidation;
+using MediatR;
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.Modularity;
+
+namespace BuildFlow.Platform.Application;
+
+/// 平台基础能力应用层模块。注册 MediatR + FluentValidation。
+[DependsOn(typeof(PlatformInfrastructureModule))]
+public class PlatformApplicationModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ var services = context.Services;
+ services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(PlatformApplicationModule).Assembly));
+ services.AddValidatorsFromAssembly(typeof(PlatformApplicationModule).Assembly);
+ services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
+ }
+}
diff --git a/src/modules/rag/Application/Roles/Commands/AssignPermissionsCommand.cs b/src/modules/platform/Application/Roles/Commands/AssignPermissionsCommand.cs
similarity index 66%
rename from src/modules/rag/Application/Roles/Commands/AssignPermissionsCommand.cs
rename to src/modules/platform/Application/Roles/Commands/AssignPermissionsCommand.cs
index d84a6e4..0726405 100644
--- a/src/modules/rag/Application/Roles/Commands/AssignPermissionsCommand.cs
+++ b/src/modules/platform/Application/Roles/Commands/AssignPermissionsCommand.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Roles.DTOs;
+using BuildFlow.Platform.Application.Roles.DTOs;
-namespace BuildFlow.Application.Roles.Commands;
+namespace BuildFlow.Platform.Application.Roles.Commands;
///
diff --git a/src/modules/rag/Application/Roles/Commands/CreateRoleCommand.cs b/src/modules/platform/Application/Roles/Commands/CreateRoleCommand.cs
similarity index 64%
rename from src/modules/rag/Application/Roles/Commands/CreateRoleCommand.cs
rename to src/modules/platform/Application/Roles/Commands/CreateRoleCommand.cs
index 53a4421..c7df055 100644
--- a/src/modules/rag/Application/Roles/Commands/CreateRoleCommand.cs
+++ b/src/modules/platform/Application/Roles/Commands/CreateRoleCommand.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Roles.DTOs;
+using BuildFlow.Platform.Application.Roles.DTOs;
-namespace BuildFlow.Application.Roles.Commands;
+namespace BuildFlow.Platform.Application.Roles.Commands;
///
diff --git a/src/modules/rag/Application/Roles/Commands/DeleteRoleCommand.cs b/src/modules/platform/Application/Roles/Commands/DeleteRoleCommand.cs
similarity index 74%
rename from src/modules/rag/Application/Roles/Commands/DeleteRoleCommand.cs
rename to src/modules/platform/Application/Roles/Commands/DeleteRoleCommand.cs
index f620872..9a030f7 100644
--- a/src/modules/rag/Application/Roles/Commands/DeleteRoleCommand.cs
+++ b/src/modules/platform/Application/Roles/Commands/DeleteRoleCommand.cs
@@ -1,6 +1,6 @@
using MediatR;
-namespace BuildFlow.Application.Roles.Commands;
+namespace BuildFlow.Platform.Application.Roles.Commands;
///
diff --git a/src/modules/rag/Application/Roles/Commands/UpdateRoleCommand.cs b/src/modules/platform/Application/Roles/Commands/UpdateRoleCommand.cs
similarity index 65%
rename from src/modules/rag/Application/Roles/Commands/UpdateRoleCommand.cs
rename to src/modules/platform/Application/Roles/Commands/UpdateRoleCommand.cs
index 28673c9..448fafc 100644
--- a/src/modules/rag/Application/Roles/Commands/UpdateRoleCommand.cs
+++ b/src/modules/platform/Application/Roles/Commands/UpdateRoleCommand.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Roles.DTOs;
+using BuildFlow.Platform.Application.Roles.DTOs;
-namespace BuildFlow.Application.Roles.Commands;
+namespace BuildFlow.Platform.Application.Roles.Commands;
///
diff --git a/src/modules/rag/Application/Roles/DTOs/AssignPermissionsRequest.cs b/src/modules/platform/Application/Roles/DTOs/AssignPermissionsRequest.cs
similarity index 70%
rename from src/modules/rag/Application/Roles/DTOs/AssignPermissionsRequest.cs
rename to src/modules/platform/Application/Roles/DTOs/AssignPermissionsRequest.cs
index 58c3e91..88941dd 100644
--- a/src/modules/rag/Application/Roles/DTOs/AssignPermissionsRequest.cs
+++ b/src/modules/platform/Application/Roles/DTOs/AssignPermissionsRequest.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Roles.DTOs;
+namespace BuildFlow.Platform.Application.Roles.DTOs;
///
/// Assign权限s请求体。
diff --git a/src/modules/rag/Application/Roles/DTOs/CreateRoleRequest.cs b/src/modules/platform/Application/Roles/DTOs/CreateRoleRequest.cs
similarity index 70%
rename from src/modules/rag/Application/Roles/DTOs/CreateRoleRequest.cs
rename to src/modules/platform/Application/Roles/DTOs/CreateRoleRequest.cs
index 31fe615..6617248 100644
--- a/src/modules/rag/Application/Roles/DTOs/CreateRoleRequest.cs
+++ b/src/modules/platform/Application/Roles/DTOs/CreateRoleRequest.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Roles.DTOs;
+namespace BuildFlow.Platform.Application.Roles.DTOs;
///
/// Create角色请求体。
diff --git a/src/modules/rag/Application/Roles/DTOs/RoleDtos.cs b/src/modules/platform/Application/Roles/DTOs/RoleDtos.cs
similarity index 76%
rename from src/modules/rag/Application/Roles/DTOs/RoleDtos.cs
rename to src/modules/platform/Application/Roles/DTOs/RoleDtos.cs
index 0e95edf..df41b51 100644
--- a/src/modules/rag/Application/Roles/DTOs/RoleDtos.cs
+++ b/src/modules/platform/Application/Roles/DTOs/RoleDtos.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Roles.DTOs;
+namespace BuildFlow.Platform.Application.Roles.DTOs;
///
diff --git a/src/modules/rag/Application/Roles/DTOs/UpdateRoleRequest.cs b/src/modules/platform/Application/Roles/DTOs/UpdateRoleRequest.cs
similarity index 70%
rename from src/modules/rag/Application/Roles/DTOs/UpdateRoleRequest.cs
rename to src/modules/platform/Application/Roles/DTOs/UpdateRoleRequest.cs
index f5f78c5..dcfed19 100644
--- a/src/modules/rag/Application/Roles/DTOs/UpdateRoleRequest.cs
+++ b/src/modules/platform/Application/Roles/DTOs/UpdateRoleRequest.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Roles.DTOs;
+namespace BuildFlow.Platform.Application.Roles.DTOs;
///
/// Update角色请求体。
diff --git a/src/modules/rag/Application/Roles/Handlers/AssignPermissionsCommandHandler.cs b/src/modules/platform/Application/Roles/Handlers/AssignPermissionsCommandHandler.cs
similarity index 77%
rename from src/modules/rag/Application/Roles/Handlers/AssignPermissionsCommandHandler.cs
rename to src/modules/platform/Application/Roles/Handlers/AssignPermissionsCommandHandler.cs
index b34fd76..c3ceb83 100644
--- a/src/modules/rag/Application/Roles/Handlers/AssignPermissionsCommandHandler.cs
+++ b/src/modules/platform/Application/Roles/Handlers/AssignPermissionsCommandHandler.cs
@@ -1,16 +1,16 @@
using BuildFlow.Shared.Domain.Exceptions;
using MediatR;
-using BuildFlow.Application.Roles.DTOs;
-using BuildFlow.Domain.Entities;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Roles.Commands;
+using BuildFlow.Platform.Application.Roles.DTOs;
+using BuildFlow.Platform.Domain.Entities;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Roles.Commands;
-namespace BuildFlow.Application.Roles.Handlers;
+namespace BuildFlow.Platform.Application.Roles.Handlers;
///
/// Assign权限sCommand处理器。执行业务校验后持久化。
///
-public class AssignPermissionsCommandHandler(RagDbContext db) : IRequestHandler
+public class AssignPermissionsCommandHandler(PlatformDbContext db) : IRequestHandler
{
public async Task Handle(AssignPermissionsCommand request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Roles/Handlers/CreateRoleCommandHandler.cs b/src/modules/platform/Application/Roles/Handlers/CreateRoleCommandHandler.cs
similarity index 64%
rename from src/modules/rag/Application/Roles/Handlers/CreateRoleCommandHandler.cs
rename to src/modules/platform/Application/Roles/Handlers/CreateRoleCommandHandler.cs
index b76e1d6..345f193 100644
--- a/src/modules/rag/Application/Roles/Handlers/CreateRoleCommandHandler.cs
+++ b/src/modules/platform/Application/Roles/Handlers/CreateRoleCommandHandler.cs
@@ -1,16 +1,16 @@
using BuildFlow.Shared.Domain.Exceptions;
using MediatR;
-using BuildFlow.Application.Roles.DTOs;
-using BuildFlow.Domain.Entities;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Roles.Commands;
+using BuildFlow.Platform.Application.Roles.DTOs;
+using BuildFlow.Platform.Domain.Entities;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Roles.Commands;
-namespace BuildFlow.Application.Roles.Handlers;
+namespace BuildFlow.Platform.Application.Roles.Handlers;
///
/// Create角色Command处理器。执行业务校验后持久化。
///
-public class CreateRoleCommandHandler(RagDbContext db) : IRequestHandler
+public class CreateRoleCommandHandler(PlatformDbContext db) : IRequestHandler
{
public async Task Handle(CreateRoleCommand request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Roles/Handlers/DeleteRoleCommandHandler.cs b/src/modules/platform/Application/Roles/Handlers/DeleteRoleCommandHandler.cs
similarity index 65%
rename from src/modules/rag/Application/Roles/Handlers/DeleteRoleCommandHandler.cs
rename to src/modules/platform/Application/Roles/Handlers/DeleteRoleCommandHandler.cs
index 96a2f5f..b161fb6 100644
--- a/src/modules/rag/Application/Roles/Handlers/DeleteRoleCommandHandler.cs
+++ b/src/modules/platform/Application/Roles/Handlers/DeleteRoleCommandHandler.cs
@@ -1,14 +1,14 @@
using BuildFlow.Shared.Domain.Exceptions;
using MediatR;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Roles.Commands;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Roles.Commands;
-namespace BuildFlow.Application.Roles.Handlers;
+namespace BuildFlow.Platform.Application.Roles.Handlers;
///
/// Delete角色Command处理器。执行业务校验后持久化。
///
-public class DeleteRoleCommandHandler(RagDbContext db) : IRequestHandler
+public class DeleteRoleCommandHandler(PlatformDbContext db) : IRequestHandler
{
public async Task Handle(DeleteRoleCommand request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Roles/Handlers/GetRoleByIdQueryHandler.cs b/src/modules/platform/Application/Roles/Handlers/GetRoleByIdQueryHandler.cs
similarity index 67%
rename from src/modules/rag/Application/Roles/Handlers/GetRoleByIdQueryHandler.cs
rename to src/modules/platform/Application/Roles/Handlers/GetRoleByIdQueryHandler.cs
index 97d0ece..a834b48 100644
--- a/src/modules/rag/Application/Roles/Handlers/GetRoleByIdQueryHandler.cs
+++ b/src/modules/platform/Application/Roles/Handlers/GetRoleByIdQueryHandler.cs
@@ -1,15 +1,15 @@
using BuildFlow.Shared.Domain.Exceptions;
using MediatR;
-using BuildFlow.Application.Roles.DTOs;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Roles.Queries;
+using BuildFlow.Platform.Application.Roles.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Roles.Queries;
-namespace BuildFlow.Application.Roles.Handlers;
+namespace BuildFlow.Platform.Application.Roles.Handlers;
///
/// Get角色ById查询处理器。执行业务校验后持久化。
///
-public class GetRoleByIdQueryHandler(RagDbContext db) : IRequestHandler
+public class GetRoleByIdQueryHandler(PlatformDbContext db) : IRequestHandler
{
public async Task Handle(GetRoleByIdQuery request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Roles/Handlers/GetRoleListQueryHandler.cs b/src/modules/platform/Application/Roles/Handlers/GetRoleListQueryHandler.cs
similarity index 62%
rename from src/modules/rag/Application/Roles/Handlers/GetRoleListQueryHandler.cs
rename to src/modules/platform/Application/Roles/Handlers/GetRoleListQueryHandler.cs
index 9101cc3..bc33e09 100644
--- a/src/modules/rag/Application/Roles/Handlers/GetRoleListQueryHandler.cs
+++ b/src/modules/platform/Application/Roles/Handlers/GetRoleListQueryHandler.cs
@@ -1,14 +1,14 @@
using MediatR;
-using BuildFlow.Application.Roles.DTOs;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Roles.Queries;
+using BuildFlow.Platform.Application.Roles.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Roles.Queries;
-namespace BuildFlow.Application.Roles.Handlers;
+namespace BuildFlow.Platform.Application.Roles.Handlers;
///
/// Get角色List查询处理器。执行业务校验后持久化。
///
-public class GetRoleListQueryHandler(RagDbContext db) : IRequestHandler>
+public class GetRoleListQueryHandler(PlatformDbContext db) : IRequestHandler>
{
public async Task> Handle(GetRoleListQuery request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Roles/Handlers/UpdateRoleCommandHandler.cs b/src/modules/platform/Application/Roles/Handlers/UpdateRoleCommandHandler.cs
similarity index 72%
rename from src/modules/rag/Application/Roles/Handlers/UpdateRoleCommandHandler.cs
rename to src/modules/platform/Application/Roles/Handlers/UpdateRoleCommandHandler.cs
index 4720e8a..9c13726 100644
--- a/src/modules/rag/Application/Roles/Handlers/UpdateRoleCommandHandler.cs
+++ b/src/modules/platform/Application/Roles/Handlers/UpdateRoleCommandHandler.cs
@@ -1,15 +1,15 @@
using BuildFlow.Shared.Domain.Exceptions;
using MediatR;
-using BuildFlow.Application.Roles.DTOs;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Roles.Commands;
+using BuildFlow.Platform.Application.Roles.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Roles.Commands;
-namespace BuildFlow.Application.Roles.Handlers;
+namespace BuildFlow.Platform.Application.Roles.Handlers;
///
/// Update角色Command处理器。执行业务校验后持久化。
///
-public class UpdateRoleCommandHandler(RagDbContext db) : IRequestHandler
+public class UpdateRoleCommandHandler(PlatformDbContext db) : IRequestHandler
{
public async Task Handle(UpdateRoleCommand request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Roles/Queries/GetRoleByIdQuery.cs b/src/modules/platform/Application/Roles/Queries/GetRoleByIdQuery.cs
similarity index 62%
rename from src/modules/rag/Application/Roles/Queries/GetRoleByIdQuery.cs
rename to src/modules/platform/Application/Roles/Queries/GetRoleByIdQuery.cs
index 1e34ac0..ff439b6 100644
--- a/src/modules/rag/Application/Roles/Queries/GetRoleByIdQuery.cs
+++ b/src/modules/platform/Application/Roles/Queries/GetRoleByIdQuery.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Roles.DTOs;
+using BuildFlow.Platform.Application.Roles.DTOs;
-namespace BuildFlow.Application.Roles.Queries;
+namespace BuildFlow.Platform.Application.Roles.Queries;
///
diff --git a/src/modules/rag/Application/Roles/Queries/GetRoleListQuery.cs b/src/modules/platform/Application/Roles/Queries/GetRoleListQuery.cs
similarity index 61%
rename from src/modules/rag/Application/Roles/Queries/GetRoleListQuery.cs
rename to src/modules/platform/Application/Roles/Queries/GetRoleListQuery.cs
index 0031bba..e43a2d8 100644
--- a/src/modules/rag/Application/Roles/Queries/GetRoleListQuery.cs
+++ b/src/modules/platform/Application/Roles/Queries/GetRoleListQuery.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Roles.DTOs;
+using BuildFlow.Platform.Application.Roles.DTOs;
-namespace BuildFlow.Application.Roles.Queries;
+namespace BuildFlow.Platform.Application.Roles.Queries;
///
diff --git a/src/modules/rag/Application/Roles/Validators/AssignPermissionsCommandValidator.cs b/src/modules/platform/Application/Roles/Validators/AssignPermissionsCommandValidator.cs
similarity index 80%
rename from src/modules/rag/Application/Roles/Validators/AssignPermissionsCommandValidator.cs
rename to src/modules/platform/Application/Roles/Validators/AssignPermissionsCommandValidator.cs
index 24e15b3..20b0d26 100644
--- a/src/modules/rag/Application/Roles/Validators/AssignPermissionsCommandValidator.cs
+++ b/src/modules/platform/Application/Roles/Validators/AssignPermissionsCommandValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Roles.Commands;
+using BuildFlow.Platform.Application.Roles.Commands;
-namespace BuildFlow.Application.Roles.Validators;
+namespace BuildFlow.Platform.Application.Roles.Validators;
///
/// Assign权限sCommand的请求校验器(FluentValidation)。
diff --git a/src/modules/rag/Application/Roles/Validators/CreateRoleCommandValidator.cs b/src/modules/platform/Application/Roles/Validators/CreateRoleCommandValidator.cs
similarity index 78%
rename from src/modules/rag/Application/Roles/Validators/CreateRoleCommandValidator.cs
rename to src/modules/platform/Application/Roles/Validators/CreateRoleCommandValidator.cs
index 2afb062..902a72e 100644
--- a/src/modules/rag/Application/Roles/Validators/CreateRoleCommandValidator.cs
+++ b/src/modules/platform/Application/Roles/Validators/CreateRoleCommandValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Roles.Commands;
+using BuildFlow.Platform.Application.Roles.Commands;
-namespace BuildFlow.Application.Roles.Validators;
+namespace BuildFlow.Platform.Application.Roles.Validators;
///
/// Create角色Command的请求校验器(FluentValidation)。
diff --git a/src/modules/rag/Application/Roles/Validators/DeleteRoleCommandValidator.cs b/src/modules/platform/Application/Roles/Validators/DeleteRoleCommandValidator.cs
similarity index 74%
rename from src/modules/rag/Application/Roles/Validators/DeleteRoleCommandValidator.cs
rename to src/modules/platform/Application/Roles/Validators/DeleteRoleCommandValidator.cs
index 1dae5e6..cea9e1e 100644
--- a/src/modules/rag/Application/Roles/Validators/DeleteRoleCommandValidator.cs
+++ b/src/modules/platform/Application/Roles/Validators/DeleteRoleCommandValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Roles.Commands;
+using BuildFlow.Platform.Application.Roles.Commands;
-namespace BuildFlow.Application.Roles.Validators;
+namespace BuildFlow.Platform.Application.Roles.Validators;
///
/// Delete角色Command的请求校验器(FluentValidation)。
diff --git a/src/modules/rag/Application/Roles/Validators/GetRoleByIdQueryValidator.cs b/src/modules/platform/Application/Roles/Validators/GetRoleByIdQueryValidator.cs
similarity index 74%
rename from src/modules/rag/Application/Roles/Validators/GetRoleByIdQueryValidator.cs
rename to src/modules/platform/Application/Roles/Validators/GetRoleByIdQueryValidator.cs
index 62a4ff1..754f912 100644
--- a/src/modules/rag/Application/Roles/Validators/GetRoleByIdQueryValidator.cs
+++ b/src/modules/platform/Application/Roles/Validators/GetRoleByIdQueryValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Roles.Queries;
+using BuildFlow.Platform.Application.Roles.Queries;
-namespace BuildFlow.Application.Roles.Validators;
+namespace BuildFlow.Platform.Application.Roles.Validators;
///
/// Get角色ById查询的请求校验器(FluentValidation)。
diff --git a/src/modules/rag/Application/Roles/Validators/UpdateRoleCommandValidator.cs b/src/modules/platform/Application/Roles/Validators/UpdateRoleCommandValidator.cs
similarity index 81%
rename from src/modules/rag/Application/Roles/Validators/UpdateRoleCommandValidator.cs
rename to src/modules/platform/Application/Roles/Validators/UpdateRoleCommandValidator.cs
index 50e642c..260fc05 100644
--- a/src/modules/rag/Application/Roles/Validators/UpdateRoleCommandValidator.cs
+++ b/src/modules/platform/Application/Roles/Validators/UpdateRoleCommandValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Roles.Commands;
+using BuildFlow.Platform.Application.Roles.Commands;
-namespace BuildFlow.Application.Roles.Validators;
+namespace BuildFlow.Platform.Application.Roles.Validators;
///
/// Update角色Command的请求校验器(FluentValidation)。
diff --git a/src/modules/rag/Application/Users/Commands/AssignRolesCommand.cs b/src/modules/platform/Application/Users/Commands/AssignRolesCommand.cs
similarity index 64%
rename from src/modules/rag/Application/Users/Commands/AssignRolesCommand.cs
rename to src/modules/platform/Application/Users/Commands/AssignRolesCommand.cs
index 5bde18a..28e9d41 100644
--- a/src/modules/rag/Application/Users/Commands/AssignRolesCommand.cs
+++ b/src/modules/platform/Application/Users/Commands/AssignRolesCommand.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Users.DTOs;
+using BuildFlow.Platform.Application.Users.DTOs;
-namespace BuildFlow.Application.Users.Commands;
+namespace BuildFlow.Platform.Application.Users.Commands;
///
diff --git a/src/modules/rag/Application/Users/Commands/CreateUserCommand.cs b/src/modules/platform/Application/Users/Commands/CreateUserCommand.cs
similarity index 66%
rename from src/modules/rag/Application/Users/Commands/CreateUserCommand.cs
rename to src/modules/platform/Application/Users/Commands/CreateUserCommand.cs
index 9884893..84c889e 100644
--- a/src/modules/rag/Application/Users/Commands/CreateUserCommand.cs
+++ b/src/modules/platform/Application/Users/Commands/CreateUserCommand.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Users.DTOs;
+using BuildFlow.Platform.Application.Users.DTOs;
-namespace BuildFlow.Application.Users.Commands;
+namespace BuildFlow.Platform.Application.Users.Commands;
///
diff --git a/src/modules/rag/Application/Users/Commands/DeleteUserCommand.cs b/src/modules/platform/Application/Users/Commands/DeleteUserCommand.cs
similarity index 74%
rename from src/modules/rag/Application/Users/Commands/DeleteUserCommand.cs
rename to src/modules/platform/Application/Users/Commands/DeleteUserCommand.cs
index f7af44d..0d23ab7 100644
--- a/src/modules/rag/Application/Users/Commands/DeleteUserCommand.cs
+++ b/src/modules/platform/Application/Users/Commands/DeleteUserCommand.cs
@@ -1,6 +1,6 @@
using MediatR;
-namespace BuildFlow.Application.Users.Commands;
+namespace BuildFlow.Platform.Application.Users.Commands;
///
diff --git a/src/modules/rag/Application/Users/Commands/UpdateUserCommand.cs b/src/modules/platform/Application/Users/Commands/UpdateUserCommand.cs
similarity index 67%
rename from src/modules/rag/Application/Users/Commands/UpdateUserCommand.cs
rename to src/modules/platform/Application/Users/Commands/UpdateUserCommand.cs
index 7adc361..7fd68f8 100644
--- a/src/modules/rag/Application/Users/Commands/UpdateUserCommand.cs
+++ b/src/modules/platform/Application/Users/Commands/UpdateUserCommand.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Users.DTOs;
+using BuildFlow.Platform.Application.Users.DTOs;
-namespace BuildFlow.Application.Users.Commands;
+namespace BuildFlow.Platform.Application.Users.Commands;
///
diff --git a/src/modules/rag/Application/Users/DTOs/AssignRolesRequest.cs b/src/modules/platform/Application/Users/DTOs/AssignRolesRequest.cs
similarity index 68%
rename from src/modules/rag/Application/Users/DTOs/AssignRolesRequest.cs
rename to src/modules/platform/Application/Users/DTOs/AssignRolesRequest.cs
index eb702ea..4b43bc6 100644
--- a/src/modules/rag/Application/Users/DTOs/AssignRolesRequest.cs
+++ b/src/modules/platform/Application/Users/DTOs/AssignRolesRequest.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Users.DTOs;
+namespace BuildFlow.Platform.Application.Users.DTOs;
///
/// Assign角色s请求体。
diff --git a/src/modules/rag/Application/Users/DTOs/CreateUserRequest.cs b/src/modules/platform/Application/Users/DTOs/CreateUserRequest.cs
similarity index 72%
rename from src/modules/rag/Application/Users/DTOs/CreateUserRequest.cs
rename to src/modules/platform/Application/Users/DTOs/CreateUserRequest.cs
index 8efbb1c..899b07e 100644
--- a/src/modules/rag/Application/Users/DTOs/CreateUserRequest.cs
+++ b/src/modules/platform/Application/Users/DTOs/CreateUserRequest.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Users.DTOs;
+namespace BuildFlow.Platform.Application.Users.DTOs;
///
/// Create用户请求体。
diff --git a/src/modules/rag/Application/Users/DTOs/UpdateUserRequest.cs b/src/modules/platform/Application/Users/DTOs/UpdateUserRequest.cs
similarity index 72%
rename from src/modules/rag/Application/Users/DTOs/UpdateUserRequest.cs
rename to src/modules/platform/Application/Users/DTOs/UpdateUserRequest.cs
index 882f062..ec5e9fb 100644
--- a/src/modules/rag/Application/Users/DTOs/UpdateUserRequest.cs
+++ b/src/modules/platform/Application/Users/DTOs/UpdateUserRequest.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Users.DTOs;
+namespace BuildFlow.Platform.Application.Users.DTOs;
///
/// Update用户请求体。
diff --git a/src/modules/rag/Application/Users/DTOs/UserDtos.cs b/src/modules/platform/Application/Users/DTOs/UserDtos.cs
similarity index 76%
rename from src/modules/rag/Application/Users/DTOs/UserDtos.cs
rename to src/modules/platform/Application/Users/DTOs/UserDtos.cs
index 111e059..bf1fd72 100644
--- a/src/modules/rag/Application/Users/DTOs/UserDtos.cs
+++ b/src/modules/platform/Application/Users/DTOs/UserDtos.cs
@@ -1,6 +1,6 @@
-namespace BuildFlow.Application.Users.DTOs;
+namespace BuildFlow.Platform.Application.Users.DTOs;
///
diff --git a/src/modules/rag/Application/Users/Handlers/AssignRolesCommandHandler.cs b/src/modules/platform/Application/Users/Handlers/AssignRolesCommandHandler.cs
similarity index 74%
rename from src/modules/rag/Application/Users/Handlers/AssignRolesCommandHandler.cs
rename to src/modules/platform/Application/Users/Handlers/AssignRolesCommandHandler.cs
index c292dc3..ad80538 100644
--- a/src/modules/rag/Application/Users/Handlers/AssignRolesCommandHandler.cs
+++ b/src/modules/platform/Application/Users/Handlers/AssignRolesCommandHandler.cs
@@ -1,16 +1,16 @@
using BuildFlow.Shared.Domain.Exceptions;
using MediatR;
-using BuildFlow.Application.Users.DTOs;
-using BuildFlow.Domain.Entities;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Users.Commands;
+using BuildFlow.Platform.Application.Users.DTOs;
+using BuildFlow.Platform.Domain.Entities;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Users.Commands;
-namespace BuildFlow.Application.Users.Handlers;
+namespace BuildFlow.Platform.Application.Users.Handlers;
///
/// Assign角色sCommand处理器。执行业务校验后持久化。
///
-public class AssignRolesCommandHandler(RagDbContext db) : IRequestHandler
+public class AssignRolesCommandHandler(PlatformDbContext db) : IRequestHandler
{
public async Task Handle(AssignRolesCommand request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Users/Handlers/CreateUserCommandHandler.cs b/src/modules/platform/Application/Users/Handlers/CreateUserCommandHandler.cs
similarity index 75%
rename from src/modules/rag/Application/Users/Handlers/CreateUserCommandHandler.cs
rename to src/modules/platform/Application/Users/Handlers/CreateUserCommandHandler.cs
index b6134b3..7f437d8 100644
--- a/src/modules/rag/Application/Users/Handlers/CreateUserCommandHandler.cs
+++ b/src/modules/platform/Application/Users/Handlers/CreateUserCommandHandler.cs
@@ -1,16 +1,16 @@
using BuildFlow.Shared.Domain.Exceptions;
using MediatR;
-using BuildFlow.Application.Users.DTOs;
-using BuildFlow.Domain.Entities;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Users.Commands;
+using BuildFlow.Platform.Application.Users.DTOs;
+using BuildFlow.Platform.Domain.Entities;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Users.Commands;
-namespace BuildFlow.Application.Users.Handlers;
+namespace BuildFlow.Platform.Application.Users.Handlers;
///
/// Create用户Command处理器。执行业务校验后持久化。
///
-public class CreateUserCommandHandler(RagDbContext db) : IRequestHandler
+public class CreateUserCommandHandler(PlatformDbContext db) : IRequestHandler
{
public async Task Handle(CreateUserCommand request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Users/Handlers/DeleteUserCommandHandler.cs b/src/modules/platform/Application/Users/Handlers/DeleteUserCommandHandler.cs
similarity index 69%
rename from src/modules/rag/Application/Users/Handlers/DeleteUserCommandHandler.cs
rename to src/modules/platform/Application/Users/Handlers/DeleteUserCommandHandler.cs
index d6fbdef..1de41ab 100644
--- a/src/modules/rag/Application/Users/Handlers/DeleteUserCommandHandler.cs
+++ b/src/modules/platform/Application/Users/Handlers/DeleteUserCommandHandler.cs
@@ -1,14 +1,14 @@
using BuildFlow.Shared.Domain.Exceptions;
using MediatR;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Users.Commands;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Users.Commands;
-namespace BuildFlow.Application.Users.Handlers;
+namespace BuildFlow.Platform.Application.Users.Handlers;
///
/// Delete用户Command处理器。执行业务校验后持久化。
///
-public class DeleteUserCommandHandler(RagDbContext db) : IRequestHandler
+public class DeleteUserCommandHandler(PlatformDbContext db) : IRequestHandler
{
public async Task Handle(DeleteUserCommand request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Users/Handlers/GetUserByIdQueryHandler.cs b/src/modules/platform/Application/Users/Handlers/GetUserByIdQueryHandler.cs
similarity index 67%
rename from src/modules/rag/Application/Users/Handlers/GetUserByIdQueryHandler.cs
rename to src/modules/platform/Application/Users/Handlers/GetUserByIdQueryHandler.cs
index a70f0da..044ed09 100644
--- a/src/modules/rag/Application/Users/Handlers/GetUserByIdQueryHandler.cs
+++ b/src/modules/platform/Application/Users/Handlers/GetUserByIdQueryHandler.cs
@@ -1,15 +1,15 @@
using BuildFlow.Shared.Domain.Exceptions;
using MediatR;
-using BuildFlow.Application.Users.DTOs;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Users.Queries;
+using BuildFlow.Platform.Application.Users.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Users.Queries;
-namespace BuildFlow.Application.Users.Handlers;
+namespace BuildFlow.Platform.Application.Users.Handlers;
///
/// Get用户ById查询处理器。执行业务校验后持久化。
///
-public class GetUserByIdQueryHandler(RagDbContext db) : IRequestHandler
+public class GetUserByIdQueryHandler(PlatformDbContext db) : IRequestHandler
{
public async Task Handle(GetUserByIdQuery request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Users/Handlers/GetUserListQueryHandler.cs b/src/modules/platform/Application/Users/Handlers/GetUserListQueryHandler.cs
similarity index 72%
rename from src/modules/rag/Application/Users/Handlers/GetUserListQueryHandler.cs
rename to src/modules/platform/Application/Users/Handlers/GetUserListQueryHandler.cs
index e3005ab..b661599 100644
--- a/src/modules/rag/Application/Users/Handlers/GetUserListQueryHandler.cs
+++ b/src/modules/platform/Application/Users/Handlers/GetUserListQueryHandler.cs
@@ -1,14 +1,14 @@
using MediatR;
-using BuildFlow.Application.Users.DTOs;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Users.Queries;
+using BuildFlow.Platform.Application.Users.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Users.Queries;
-namespace BuildFlow.Application.Users.Handlers;
+namespace BuildFlow.Platform.Application.Users.Handlers;
///
/// Get用户List查询处理器。执行业务校验后持久化。
///
-public class GetUserListQueryHandler(RagDbContext db) : IRequestHandler>
+public class GetUserListQueryHandler(PlatformDbContext db) : IRequestHandler>
{
public async Task> Handle(GetUserListQuery request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Users/Handlers/GetUserNamesQueryHandler.cs b/src/modules/platform/Application/Users/Handlers/GetUserNamesQueryHandler.cs
similarity index 71%
rename from src/modules/rag/Application/Users/Handlers/GetUserNamesQueryHandler.cs
rename to src/modules/platform/Application/Users/Handlers/GetUserNamesQueryHandler.cs
index 7aab433..b76fe41 100644
--- a/src/modules/rag/Application/Users/Handlers/GetUserNamesQueryHandler.cs
+++ b/src/modules/platform/Application/Users/Handlers/GetUserNamesQueryHandler.cs
@@ -1,13 +1,13 @@
using MediatR;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Users.Queries;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Users.Queries;
-namespace BuildFlow.Application.Users.Handlers;
+namespace BuildFlow.Platform.Application.Users.Handlers;
///
/// Get用户Names查询处理器。执行业务校验后持久化。
///
-public class GetUserNamesQueryHandler(RagDbContext db)
+public class GetUserNamesQueryHandler(PlatformDbContext db)
: IRequestHandler>
{
public async Task> Handle(GetUserNamesQuery request, CancellationToken ct)
diff --git a/src/modules/rag/Application/Users/Handlers/UpdateUserCommandHandler.cs b/src/modules/platform/Application/Users/Handlers/UpdateUserCommandHandler.cs
similarity index 74%
rename from src/modules/rag/Application/Users/Handlers/UpdateUserCommandHandler.cs
rename to src/modules/platform/Application/Users/Handlers/UpdateUserCommandHandler.cs
index c0e89aa..ee44bbd 100644
--- a/src/modules/rag/Application/Users/Handlers/UpdateUserCommandHandler.cs
+++ b/src/modules/platform/Application/Users/Handlers/UpdateUserCommandHandler.cs
@@ -1,15 +1,15 @@
using BuildFlow.Shared.Domain.Exceptions;
using MediatR;
-using BuildFlow.Application.Users.DTOs;
-using BuildFlow.Infrastructure.Persistence;
-using BuildFlow.Application.Users.Commands;
+using BuildFlow.Platform.Application.Users.DTOs;
+using BuildFlow.Platform.Infrastructure.Persistence;
+using BuildFlow.Platform.Application.Users.Commands;
-namespace BuildFlow.Application.Users.Handlers;
+namespace BuildFlow.Platform.Application.Users.Handlers;
///
/// Update用户Command处理器。执行业务校验后持久化。
///
-public class UpdateUserCommandHandler(RagDbContext db) : IRequestHandler
+public class UpdateUserCommandHandler(PlatformDbContext db) : IRequestHandler
{
public async Task Handle(UpdateUserCommand request, CancellationToken ct)
{
diff --git a/src/modules/rag/Application/Users/Queries/GetUserByIdQuery.cs b/src/modules/platform/Application/Users/Queries/GetUserByIdQuery.cs
similarity index 62%
rename from src/modules/rag/Application/Users/Queries/GetUserByIdQuery.cs
rename to src/modules/platform/Application/Users/Queries/GetUserByIdQuery.cs
index 519b6df..caa2fc8 100644
--- a/src/modules/rag/Application/Users/Queries/GetUserByIdQuery.cs
+++ b/src/modules/platform/Application/Users/Queries/GetUserByIdQuery.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Users.DTOs;
+using BuildFlow.Platform.Application.Users.DTOs;
-namespace BuildFlow.Application.Users.Queries;
+namespace BuildFlow.Platform.Application.Users.Queries;
///
diff --git a/src/modules/rag/Application/Users/Queries/GetUserListQuery.cs b/src/modules/platform/Application/Users/Queries/GetUserListQuery.cs
similarity index 64%
rename from src/modules/rag/Application/Users/Queries/GetUserListQuery.cs
rename to src/modules/platform/Application/Users/Queries/GetUserListQuery.cs
index be25e13..9ce1314 100644
--- a/src/modules/rag/Application/Users/Queries/GetUserListQuery.cs
+++ b/src/modules/platform/Application/Users/Queries/GetUserListQuery.cs
@@ -1,7 +1,7 @@
using MediatR;
-using BuildFlow.Application.Users.DTOs;
+using BuildFlow.Platform.Application.Users.DTOs;
-namespace BuildFlow.Application.Users.Queries;
+namespace BuildFlow.Platform.Application.Users.Queries;
///
diff --git a/src/modules/rag/Application/Users/Queries/GetUserNamesQuery.cs b/src/modules/platform/Application/Users/Queries/GetUserNamesQuery.cs
similarity index 80%
rename from src/modules/rag/Application/Users/Queries/GetUserNamesQuery.cs
rename to src/modules/platform/Application/Users/Queries/GetUserNamesQuery.cs
index cb87a37..ff88df7 100644
--- a/src/modules/rag/Application/Users/Queries/GetUserNamesQuery.cs
+++ b/src/modules/platform/Application/Users/Queries/GetUserNamesQuery.cs
@@ -1,6 +1,6 @@
using MediatR;
-namespace BuildFlow.Application.Users.Queries;
+namespace BuildFlow.Platform.Application.Users.Queries;
///
diff --git a/src/modules/rag/Application/Users/Validators/AssignRolesCommandValidator.cs b/src/modules/platform/Application/Users/Validators/AssignRolesCommandValidator.cs
similarity index 79%
rename from src/modules/rag/Application/Users/Validators/AssignRolesCommandValidator.cs
rename to src/modules/platform/Application/Users/Validators/AssignRolesCommandValidator.cs
index 8c89ade..a3ce90b 100644
--- a/src/modules/rag/Application/Users/Validators/AssignRolesCommandValidator.cs
+++ b/src/modules/platform/Application/Users/Validators/AssignRolesCommandValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Users.Commands;
+using BuildFlow.Platform.Application.Users.Commands;
-namespace BuildFlow.Application.Users.Validators;
+namespace BuildFlow.Platform.Application.Users.Validators;
///
/// Assign角色sCommand的请求校验器(FluentValidation)。
diff --git a/src/modules/rag/Application/Users/Validators/CreateUserCommandValidator.cs b/src/modules/platform/Application/Users/Validators/CreateUserCommandValidator.cs
similarity index 86%
rename from src/modules/rag/Application/Users/Validators/CreateUserCommandValidator.cs
rename to src/modules/platform/Application/Users/Validators/CreateUserCommandValidator.cs
index 0130068..07b0e94 100644
--- a/src/modules/rag/Application/Users/Validators/CreateUserCommandValidator.cs
+++ b/src/modules/platform/Application/Users/Validators/CreateUserCommandValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Users.Commands;
+using BuildFlow.Platform.Application.Users.Commands;
-namespace BuildFlow.Application.Users.Validators;
+namespace BuildFlow.Platform.Application.Users.Validators;
///
/// Create用户Command的请求校验器(FluentValidation)。
diff --git a/src/modules/rag/Application/Users/Validators/DeleteUserCommandValidator.cs b/src/modules/platform/Application/Users/Validators/DeleteUserCommandValidator.cs
similarity index 74%
rename from src/modules/rag/Application/Users/Validators/DeleteUserCommandValidator.cs
rename to src/modules/platform/Application/Users/Validators/DeleteUserCommandValidator.cs
index a1f5864..b8dfd18 100644
--- a/src/modules/rag/Application/Users/Validators/DeleteUserCommandValidator.cs
+++ b/src/modules/platform/Application/Users/Validators/DeleteUserCommandValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Users.Commands;
+using BuildFlow.Platform.Application.Users.Commands;
-namespace BuildFlow.Application.Users.Validators;
+namespace BuildFlow.Platform.Application.Users.Validators;
///
/// Delete用户Command的请求校验器(FluentValidation)。
diff --git a/src/modules/rag/Application/Users/Validators/GetUserByIdQueryValidator.cs b/src/modules/platform/Application/Users/Validators/GetUserByIdQueryValidator.cs
similarity index 74%
rename from src/modules/rag/Application/Users/Validators/GetUserByIdQueryValidator.cs
rename to src/modules/platform/Application/Users/Validators/GetUserByIdQueryValidator.cs
index eea65ac..f0cdc01 100644
--- a/src/modules/rag/Application/Users/Validators/GetUserByIdQueryValidator.cs
+++ b/src/modules/platform/Application/Users/Validators/GetUserByIdQueryValidator.cs
@@ -1,7 +1,7 @@
using FluentValidation;
-using BuildFlow.Application.Users.Queries;
+using BuildFlow.Platform.Application.Users.Queries;
-namespace BuildFlow.Application.Users.Validators;
+namespace BuildFlow.Platform.Application.Users.Validators;
///