From 2548c3ed9135979ee01451fe6918d1615913546b Mon Sep 17 00:00:00 2001 From: xiangning Date: Fri, 3 Jul 2026 17:12:48 +0800 Subject: [PATCH] =?UTF-8?q?refactor(endpoints):=20=E7=BB=9F=E4=B8=80?= =?UTF-8?q?=E5=91=BD=E5=90=8D=E7=A9=BA=E9=97=B4=E5=A4=A7=E5=B0=8F=E5=86=99?= =?UTF-8?q?=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将 file 相关端点命名空间从小写改为首字母大写 - 将 im 相关端点命名空间从小写改为首字母大写 - 将 workflow 相关端点命名空间从小写改为首字母大写 - 将 rag 相关端点命名空间从小写改为首字母大写 - 将 platform 相关端点命名空间从小写改为首字母大写 - 保持代码功能不变,仅调整命名空间命名风格一致性 --- .../File/Buckets/CreateBucketEndpoint.cs | 24 + .../File/Buckets/CreateBucketRequest.cs | 7 + .../File/Buckets/DeleteBucketEndpoint.cs | 24 + .../File/Buckets/DeleteBucketRequest.cs | 7 + .../File/Buckets/ListBucketsEndpoint.cs | 23 + .../Endpoints/File/Files/CheckFileEndpoint.cs | 24 + .../Endpoints/File/Files/CheckFileRequest.cs | 10 + .../File/Files/DeleteFileEndpoint.cs | 24 + .../Endpoints/File/Files/DeleteFileRequest.cs | 7 + .../File/Files/DownloadFileEndpoint.cs | 41 + .../File/Files/DownloadFileRequest.cs | 7 + .../File/Files/GetFileContentEndpoint.cs | 25 + .../File/Files/GetFileContentRequest.cs | 7 + .../File/Files/GetFilePreviewEndpoint.cs | 42 + .../File/Files/GetFilePreviewRequest.cs | 19 + .../File/Files/GetOfficePreviewEndpoint.cs | 27 + .../File/Files/GetOfficePreviewRequest.cs | 7 + .../Endpoints/File/Files/ListFilesEndpoint.cs | 25 + .../Endpoints/File/Files/ListFilesRequest.cs | 9 + .../File/Files/UploadFileEndpoint.cs | 28 + .../Endpoints/File/Files/UploadFileRequest.cs | 10 + .../File/Folders/CreateFolderEndpoint.cs | 26 + .../File/Folders/CreateFolderRequest.cs | 8 + .../File/Folders/DeleteFolderEndpoint.cs | 24 + .../File/Folders/DeleteFolderRequest.cs | 7 + .../File/Folders/GetFolderEndpoint.cs | 24 + .../File/Folders/GetFolderRequest.cs | 7 + .../File/Folders/GetFolderTreeEndpoint.cs | 24 + .../File/Folders/GetRootFilesEndpoint.cs | 25 + .../File/Folders/MoveFileEndpoint.cs | 25 + .../Endpoints/File/Folders/MoveFileRequest.cs | 8 + .../File/Folders/RenameFolderEndpoint.cs | 25 + .../File/Folders/RenameFolderRequest.cs | 8 + .../File/Folders/UploadToFolderEndpoint.cs | 28 + .../File/Folders/UploadToFolderRequest.cs | 11 + .../File/Multipart/AbortMultipartEndpoint.cs | 24 + .../File/Multipart/AbortMultipartRequest.cs | 8 + .../Multipart/CompleteMultipartEndpoint.cs | 26 + .../Multipart/CompleteMultipartRequest.cs | 13 + .../File/Multipart/InitMultipartEndpoint.cs | 25 + .../File/Multipart/InitMultipartRequest.cs | 14 + .../File/Multipart/ListPartsEndpoint.cs | 27 + .../File/Multipart/ListPartsRequest.cs | 8 + .../Endpoints/File/Multipart/PartRequest.cs | 8 + .../File/Multipart/UploadPartEndpoint.cs | 28 + .../File/Multipart/UploadPartRequest.cs | 10 + .../File/Settings/GetFileSettingEndpoint.cs | 18 + .../Settings/UpdateDefaultBucketEndpoint.cs | 18 + .../Settings/UpdateDefaultBucketRequest.cs | 7 + .../File/Shares/CreateShareEndpoint.cs | 29 + .../File/Shares/CreateShareRequest.cs | 11 + .../File/Shares/DeleteShareEndpoint.cs | 24 + .../File/Shares/DeleteShareRequest.cs | 7 + .../File/Shares/DownloadShareEndpoint.cs | 22 + .../File/Shares/DownloadShareRequest.cs | 8 + .../File/Shares/GetShareInfoEndpoint.cs | 21 + .../File/Shares/GetShareInfoRequest.cs | 7 + .../IM/Chat/AddGroupMemberEndpoint.cs | 25 + .../IM/Chat/AddGroupMemberEndpointRequest.cs | 6 + .../Endpoints/IM/Chat/CreateGroupEndpoint.cs | 25 + .../Chat/CreatePrivateConversationEndpoint.cs | 28 + .../Endpoints/IM/Chat/DeleteGroupEndpoint.cs | 25 + .../IM/Chat/DeleteGroupEndpointRequest.cs | 6 + .../IM/Chat/GetConversationsEndpoint.cs | 25 + .../Endpoints/IM/Chat/GetGroupEndpoint.cs | 25 + .../IM/Chat/GetGroupEndpointRequest.cs | 4 + .../IM/Chat/GetGroupMembersEndpoint.cs | 26 + .../IM/Chat/GetGroupMembersEndpointRequest.cs | 6 + .../IM/Chat/GetMessageHistoryEndpoint.cs | 27 + .../IM/Chat/GetMessageHistoryRequest.cs | 6 + .../IM/Chat/GetUnreadCountEndpoint.cs | 25 + .../IM/Chat/MarkConversationUnreadEndpoint.cs | 25 + .../IM/Chat/RecallMessageEndpoint.cs | 25 + .../IM/Chat/RecallMessageEndpointRequest.cs | 4 + .../IM/Chat/RemoveGroupMemberEndpoint.cs | 25 + .../Chat/RemoveGroupMemberEndpointRequest.cs | 6 + .../IM/Chat/SetConversationMutedEndpoint.cs | 25 + .../IM/Chat/SetConversationPinnedEndpoint.cs | 25 + .../IM/Chat/SetConversationRemarkEndpoint.cs | 25 + .../SetConversationRemarkEndpointRequest.cs | 6 + .../IM/Chat/SetConversationStateRequest.cs | 6 + .../Endpoints/IM/Chat/UpdateGroupEndpoint.cs | 26 + .../IM/Chat/UpdateGroupEndpointRequest.cs | 6 + .../Platform/Auth/ChangePasswordEndpoint.cs | 44 + .../Platform/Auth/ChangePasswordRequest.cs | 11 + .../Platform/Auth/GetAccessCodesEndpoint.cs | 24 + .../Platform/Auth/GetCurrentUserEndpoint.cs | 24 + .../Endpoints/Platform/Auth/LoginEndpoint.cs | 37 + .../Platform/Auth/LoginRequestValidator.cs | 21 + .../Endpoints/Platform/Auth/LogoutEndpoint.cs | 33 + .../Platform/Auth/RefreshTokenEndpoint.cs | 41 + .../Platform/Auth/RegisterEndpoint.cs | 26 + .../Platform/Auth/RegisterRequestValidator.cs | 24 + .../Platform/Auth/RevokeTokenEndpoint.cs | 25 + .../Auth/RevokeTokenRequestValidator.cs | 15 + .../Platform/Auth/UpdateProfileEndpoint.cs | 31 + .../Platform/Auth/UpdateProfileRequest.cs | 14 + .../Platform/Menus/CreateMenuEndpoint.cs | 42 + .../Menus/CreateMenuRequestValidator.cs | 27 + .../Platform/Menus/DeleteMenuEndpoint.cs | 22 + .../Menus/DeleteMenuEndpointRequest.cs | 6 + .../DeleteMenuEndpointRequestValidator.cs | 12 + .../Platform/Menus/GetAllMenusEndpoint.cs | 24 + .../Platform/Menus/GetMenuByIdEndpoint.cs | 23 + .../Platform/Menus/GetMenuByIdRequest.cs | 6 + .../Menus/GetMenuByIdRequestValidator.cs | 12 + .../Platform/Menus/GetMenuTreeEndpoint.cs | 23 + .../Platform/Menus/SortMenusEndpoint.cs | 27 + .../Menus/SortMenusEndpointRequest.cs | 14 + .../SortMenusEndpointRequestValidator.cs | 16 + .../Platform/Menus/UpdateMenuEndpoint.cs | 43 + .../Menus/UpdateMenuEndpointRequest.cs | 24 + .../UpdateMenuEndpointRequestValidator.cs | 20 + .../Notifications/GetNotificationsEndpoint.cs | 24 + .../Notifications/GetNotificationsRequest.cs | 13 + .../GetNotificationsRequestValidator.cs | 16 + .../GetUnreadNotificationCountEndpoint.cs | 22 + .../MarkAllNotificationsReadEndpoint.cs | 22 + .../MarkNotificationReadEndpoint.cs | 25 + .../NotificationEndpointsExtensions.cs | 15 + .../PublishNotificationEndpoint.cs | 23 + .../PublishNotificationRequest.cs | 24 + .../PublishNotificationRequestValidator.cs | 24 + .../Permissions/CreatePermissionEndpoint.cs | 24 + .../CreatePermissionRequestValidator.cs | 28 + .../Permissions/DeletePermissionEndpoint.cs | 22 + .../DeletePermissionEndpointRequest.cs | 6 + ...eletePermissionEndpointRequestValidator.cs | 12 + .../Permissions/GetPermissionByIdEndpoint.cs | 23 + .../Permissions/GetPermissionByIdRequest.cs | 6 + .../GetPermissionByIdRequestValidator.cs | 12 + .../Permissions/GetPermissionListEndpoint.cs | 24 + .../Permissions/GetPermissionTreeEndpoint.cs | 25 + .../Permissions/UpdatePermissionEndpoint.cs | 24 + .../UpdatePermissionEndpointRequest.cs | 6 + ...pdatePermissionEndpointRequestValidator.cs | 24 + .../Roles/AssignPermissionsEndpoint.cs | 24 + .../Roles/AssignPermissionsEndpointRequest.cs | 8 + ...signPermissionsEndpointRequestValidator.cs | 14 + .../Platform/Roles/CreateRoleEndpoint.cs | 26 + .../Roles/CreateRoleRequestValidator.cs | 22 + .../Platform/Roles/DeleteRoleEndpoint.cs | 23 + .../Roles/DeleteRoleEndpointRequest.cs | 8 + .../DeleteRoleEndpointRequestValidator.cs | 12 + .../Platform/Roles/GetRoleByIdEndpoint.cs | 24 + .../Platform/Roles/GetRoleByIdRequest.cs | 8 + .../Roles/GetRoleByIdRequestValidator.cs | 12 + .../Platform/Roles/GetRoleListEndpoint.cs | 23 + .../Platform/Roles/UpdateRoleEndpoint.cs | 24 + .../Roles/UpdateRoleEndpointRequest.cs | 8 + .../UpdateRoleEndpointRequestValidator.cs | 24 + .../Platform/Users/AssignRolesEndpoint.cs | 24 + .../Users/AssignRolesEndpointRequest.cs | 8 + .../AssignRolesEndpointRequestValidator.cs | 14 + .../Platform/Users/CreateUserEndpoint.cs | 26 + .../Users/CreateUserRequestValidator.cs | 24 + .../Platform/Users/DeleteUserEndpoint.cs | 23 + .../Users/DeleteUserEndpointRequest.cs | 8 + .../DeleteUserEndpointRequestValidator.cs | 12 + .../Platform/Users/GetUserByIdEndpoint.cs | 24 + .../Platform/Users/GetUserByIdRequest.cs | 8 + .../Users/GetUserByIdRequestValidator.cs | 12 + .../Platform/Users/GetUserListEndpoint.cs | 24 + .../Platform/Users/GetUserListRequest.cs | 9 + .../Platform/Users/UpdateUserEndpoint.cs | 24 + .../Users/UpdateUserEndpointRequest.cs | 8 + .../UpdateUserEndpointRequestValidator.cs | 24 + .../Endpoints/Rag/AiModel/AiModelEndpoints.cs | 96 +++ .../Rag/Chat/CreateConversationEndpoint.cs | 36 + .../Rag/Chat/CreateConversationRequest.cs | 9 + .../CreateConversationRequestValidator.cs | 14 + .../Rag/Chat/DeleteConversationEndpoint.cs | 26 + .../Chat/DeleteConversationEndpointRequest.cs | 8 + ...eteConversationEndpointRequestValidator.cs | 12 + .../Rag/Chat/GetConversationDetailEndpoint.cs | 24 + .../Rag/Chat/GetConversationDetailRequest.cs | 8 + .../GetConversationDetailRequestValidator.cs | 12 + .../Rag/Chat/GetConversationsEndpoint.cs | 23 + .../Endpoints/Rag/Chat/SendMessageEndpoint.cs | 25 + .../Endpoints/Rag/Chat/SendMessageRequest.cs | 8 + .../Rag/Chat/SendMessageRequestValidator.cs | 14 + .../Rag/Chat/StreamMessageEndpoint.cs | 83 ++ .../Rag/Chat/StreamMessageRequest.cs | 8 + .../Rag/Chat/StreamMessageRequestValidator.cs | 14 + .../Rag/Document/ChunkUploadSession.cs | 22 + .../Rag/Document/ChunkUploadStore.cs | 13 + .../Document/CompleteChunkUploadEndpoint.cs | 64 ++ .../Document/CompleteChunkUploadRequest.cs | 11 + .../CompleteChunkUploadRequestValidator.cs | 16 + .../Rag/Document/GetDocumentChunksEndpoint.cs | 24 + .../Document/ImportFromFileManagerEndpoint.cs | 59 ++ .../Document/ImportFromFileManagerRequest.cs | 23 + .../Rag/Document/InitChunkUploadEndpoint.cs | 26 + .../Rag/Document/InitChunkUploadRequest.cs | 13 + .../InitChunkUploadRequestValidator.cs | 20 + .../Rag/Document/ListDocumentsEndpoint.cs | 24 + .../Rag/Document/ProcessDocumentEndpoint.cs | 25 + .../Document/ProcessKnowledgeBaseEndpoint.cs | 27 + .../Rag/Document/UploadChunkEndpoint.cs | 43 + .../Rag/Document/UploadDocumentEndpoint.cs | 43 + .../Rag/Document/UploadDocumentRequest.cs | 8 + .../UploadDocumentRequestValidator.cs | 20 + .../Rag/Embedding/EmbedBatchEndpoint.cs | 24 + .../Rag/Embedding/EmbedBatchRequest.cs | 8 + .../Embedding/EmbedBatchRequestValidator.cs | 14 + .../Rag/Embedding/EmbedTextEndpoint.cs | 24 + .../Rag/Embedding/EmbedTextRequest.cs | 8 + .../Embedding/EmbedTextRequestValidator.cs | 14 + .../Rag/KnowledgeBase/CreateKBEndpoint.cs | 34 + .../CreateKnowledgeBaseRequestValidator.cs | 58 ++ .../Rag/KnowledgeBase/DeleteKBEndpoint.cs | 23 + .../KnowledgeBase/DeleteKBEndpointRequest.cs | 8 + .../DeleteKBEndpointRequestValidator.cs | 12 + .../Rag/KnowledgeBase/GetKBsEndpoint.cs | 23 + .../Rag/KnowledgeBase/UpdateKBEndpoint.cs | 33 + .../UpdateKnowledgeBaseRequestValidator.cs | 61 ++ .../Obsidian/ObsidianSyncRequestValidator.cs | 20 + .../Rag/Obsidian/SyncObsidianVaultEndpoint.cs | 36 + .../Endpoints/Rag/RAG/RAGQueryEndpoint.cs | 28 + .../Rag/RAG/RAGQueryRequestValidator.cs | 18 + .../Endpoints/Rag/RAG/RAGStreamEndpoint.cs | 85 ++ .../CreateBuildFlowApplicationEndpoint.cs | 24 + .../CreateBuildFlowApplicationRequest.cs | 4 + .../GetBuildFlowApplicationListEndpoint.cs | 25 + .../GetBuildFlowApplicationListRequest.cs | 12 + ...CreateBuildFlowButtonDefinitionEndpoint.cs | 38 + .../CreateBuildFlowButtonDefinitionRequest.cs | 20 + .../Buttons/ExecuteBuildFlowButtonEndpoint.cs | 22 + .../Buttons/ExecuteBuildFlowButtonRequest.cs | 4 + ...etBuildFlowButtonDefinitionListEndpoint.cs | 33 + ...GetBuildFlowButtonDefinitionListRequest.cs | 16 + .../CreateCustomFunctionEndpoint.cs | 31 + .../CreateCustomFunctionRequest.cs | 11 + .../DisableCustomFunctionEndpoint.cs | 22 + .../DisableCustomFunctionRequest.cs | 4 + .../GetCustomFunctionListEndpoint.cs | 25 + .../GetCustomFunctionListRequest.cs | 12 + .../PublishCustomFunctionEndpoint.cs | 22 + .../PublishCustomFunctionRequest.cs | 4 + .../TestCustomFunctionEndpoint.cs | 22 + .../TestCustomFunctionRequest.cs | 4 + .../CreateBuildFlowPageDefinitionEndpoint.cs | 29 + .../CreateBuildFlowPageDefinitionRequest.cs | 11 + .../GetBuildFlowPageDefinitionListEndpoint.cs | 30 + .../GetBuildFlowPageDefinitionListRequest.cs | 13 + .../Form/CompareFormVersionsEndpoint.cs | 33 + .../Form/CompareFormVersionsRequest.cs | 11 + .../Form/CreateFormComponentEndpoint.cs | 35 + .../Form/CreateFormComponentRequest.cs | 14 + .../Form/CreateFormDefinitionEndpoint.cs | 29 + .../Form/CreateFormDefinitionRequest.cs | 15 + .../Form/DeleteFormComponentEndpoint.cs | 34 + .../Form/DeleteFormComponentRequest.cs | 9 + .../Form/DeleteFormDefinitionEndpoint.cs | 34 + .../Form/DeleteFormDefinitionRequest.cs | 9 + .../Form/DisableFormDefinitionEndpoint.cs | 30 + .../Form/DisableFormDefinitionRequest.cs | 9 + .../Form/GetFormComponentByIdEndpoint.cs | 32 + .../Form/GetFormComponentByIdRequest.cs | 9 + .../Form/GetFormComponentsEndpoint.cs | 33 + .../Form/GetFormDataByInstanceEndpoint.cs | 33 + .../Form/GetFormDataByInstanceRequest.cs | 9 + .../Form/GetFormDefinitionByIdEndpoint.cs | 33 + .../Form/GetFormDefinitionByIdRequest.cs | 9 + .../Form/GetFormDefinitionListEndpoint.cs | 33 + .../Form/GetFormDefinitionListRequest.cs | 13 + .../Workflow/Form/GetFormVersionsEndpoint.cs | 32 + .../Form/PublishFormDefinitionEndpoint.cs | 29 + .../Workflow/Form/SubmitFormDataEndpoint.cs | 32 + .../Workflow/Form/SubmitFormDataRequest.cs | 11 + .../Form/UpdateFormComponentEndpoint.cs | 35 + .../Form/UpdateFormComponentRequest.cs | 15 + .../Form/UpdateFormDefinitionEndpoint.cs | 36 + .../Form/UpdateFormDefinitionRequest.cs | 15 + .../Notification/GetNotificationsEndpoint.cs | 27 + .../Notification/GetNotificationsRequest.cs | 11 + .../GetUnreadNotificationCountEndpoint.cs | 24 + .../MarkAllNotificationsReadEndpoint.cs | 26 + .../MarkNotificationReadEndpoint.cs | 26 + .../NotificationClaimsExtensions.cs | 17 + .../WorkflowDefinition/CreateEdgeEndpoint.cs | 35 + .../WorkflowDefinition/CreateEdgeRequest.cs | 15 + .../WorkflowDefinition/CreateNodeEndpoint.cs | 42 + .../WorkflowDefinition/CreateNodeRequest.cs | 15 + .../CreateWorkflowDefinitionEndpoint.cs | 33 + .../CreateWorkflowDefinitionRequest.cs | 12 + .../WorkflowDefinition/DeleteEdgeEndpoint.cs | 35 + .../WorkflowDefinition/DeleteEdgeRequest.cs | 10 + .../WorkflowDefinition/DeleteNodeEndpoint.cs | 35 + .../WorkflowDefinition/DeleteNodeRequest.cs | 10 + .../DeleteWorkflowDefinitionEndpoint.cs | 34 + .../DeleteWorkflowDefinitionRequest.cs | 9 + .../DisableWorkflowDefinitionEndpoint.cs | 29 + .../GetWorkflowDefinitionByIdEndpoint.cs | 33 + .../GetWorkflowDefinitionByIdRequest.cs | 9 + .../GetWorkflowDefinitionListEndpoint.cs | 34 + .../GetWorkflowDefinitionListRequest.cs | 13 + .../PublishWorkflowDefinitionEndpoint.cs | 29 + .../WorkflowDefinition/UpdateEdgeEndpoint.cs | 35 + .../WorkflowDefinition/UpdateEdgeRequest.cs | 14 + .../WorkflowDefinition/UpdateNodeEndpoint.cs | 40 + .../WorkflowDefinition/UpdateNodeRequest.cs | 15 + .../UpdateWorkflowDefinitionEndpoint.cs | 33 + .../UpdateWorkflowDefinitionRequest.cs | 13 + .../GetWorkflowInstanceByIdEndpoint.cs | 33 + .../GetWorkflowInstanceByIdRequest.cs | 9 + .../GetWorkflowInstanceListEndpoint.cs | 34 + .../GetWorkflowInstanceListRequest.cs | 14 + .../MonitorWorkflowInstancesEndpoint.cs | 32 + .../ResumeWorkflowInstanceEndpoint.cs | 29 + .../StartWorkflowInstanceEndpoint.cs | 32 + .../StartWorkflowInstanceRequest.cs | 12 + .../SuspendWorkflowInstanceEndpoint.cs | 29 + .../WithdrawWorkflowInstanceEndpoint.cs | 32 + .../WorkflowTask/AddSignerEndpoint.cs | 24 + .../Workflow/WorkflowTask/AddSignerRequest.cs | 14 + .../WorkflowTask/ApproveTaskEndpoint.cs | 34 + .../WorkflowTask/ApproveTaskRequest.cs | 12 + .../WorkflowTask/DelegateTaskEndpoint.cs | 34 + .../WorkflowTask/DelegateTaskRequest.cs | 11 + .../WorkflowTask/GetCcTasksEndpoint.cs | 34 + .../WorkflowTask/GetCcTasksRequest.cs | 11 + .../WorkflowTask/GetHistoryTasksEndpoint.cs | 34 + .../WorkflowTask/GetHistoryTasksRequest.cs | 11 + .../WorkflowTask/GetOverdueTasksEndpoint.cs | 34 + .../WorkflowTask/GetOverdueTasksRequest.cs | 11 + .../WorkflowTask/GetPendingTasksEndpoint.cs | 34 + .../WorkflowTask/GetPendingTasksRequest.cs | 11 + .../WorkflowTask/GetTaskByIdEndpoint.cs | 33 + .../WorkflowTask/GetTaskByIdRequest.cs | 9 + .../WorkflowTask/MarkCcTaskReadEndpoint.cs | 34 + .../WorkflowTask/MarkCcTaskReadRequest.cs | 10 + .../WorkflowTask/RejectTaskEndpoint.cs | 34 + .../WorkflowTask/RejectTaskRequest.cs | 11 + .../WorkflowTask/ReturnTaskEndpoint.cs | 24 + .../WorkflowTask/ReturnTaskRequest.cs | 8 + .../WorkflowTask/TransferTaskEndpoint.cs | 34 + .../WorkflowTask/TransferTaskRequest.cs | 11 + .../Workflow/WorkflowTask/UrgeTaskEndpoint.cs | 34 + .../Workflow/WorkflowTask/UrgeTaskRequest.cs | 10 + .../file/Buckets/CreateBucketEndpoint.cs | 2 +- .../file/Buckets/CreateBucketRequest.cs | 2 +- .../file/Buckets/DeleteBucketRequest.cs | 2 +- .../file/Buckets/ListBucketsEndpoint.cs | 2 +- .../Endpoints/file/Files/CheckFileEndpoint.cs | 2 +- .../Endpoints/file/Files/CheckFileRequest.cs | 2 +- .../file/Files/DeleteFileEndpoint.cs | 2 +- .../Endpoints/file/Files/DeleteFileRequest.cs | 2 +- .../file/Files/GetFileContentRequest.cs | 2 +- .../file/Files/GetOfficePreviewEndpoint.cs | 2 +- .../Endpoints/file/Files/ListFilesEndpoint.cs | 2 +- .../Endpoints/file/Files/ListFilesRequest.cs | 2 +- .../file/Files/UploadFileEndpoint.cs | 2 +- .../Endpoints/file/Files/UploadFileRequest.cs | 2 +- .../file/Folders/CreateFolderEndpoint.cs | 2 +- .../file/Folders/CreateFolderRequest.cs | 2 +- .../file/Folders/DeleteFolderEndpoint.cs | 2 +- .../file/Folders/GetFolderRequest.cs | 2 +- .../file/Folders/MoveFileEndpoint.cs | 2 +- .../file/Folders/RenameFolderRequest.cs | 2 +- .../file/Multipart/AbortMultipartEndpoint.cs | 2 +- .../Multipart/CompleteMultipartEndpoint.cs | 2 +- .../Multipart/CompleteMultipartRequest.cs | 2 +- .../file/Multipart/InitMultipartEndpoint.cs | 2 +- .../file/Multipart/ListPartsEndpoint.cs | 2 +- .../file/Multipart/ListPartsRequest.cs | 2 +- .../Endpoints/file/Multipart/PartRequest.cs | 2 +- .../file/Multipart/UploadPartEndpoint.cs | 2 +- .../file/Settings/GetFileSettingEndpoint.cs | 2 +- .../file/Shares/CreateShareRequest.cs | 2 +- .../file/Shares/DeleteShareEndpoint.cs | 2 +- .../file/Shares/DeleteShareRequest.cs | 2 +- .../file/Shares/DownloadShareEndpoint.cs | 2 +- .../file/Shares/GetShareInfoRequest.cs | 2 +- .../im/Chat/AddGroupMemberEndpoint.cs | 2 +- .../Endpoints/im/Chat/CreateGroupEndpoint.cs | 2 +- .../Chat/CreatePrivateConversationEndpoint.cs | 2 +- .../Endpoints/im/Chat/DeleteGroupEndpoint.cs | 2 +- .../Endpoints/im/Chat/GetGroupEndpoint.cs | 2 +- .../im/Chat/GetGroupEndpointRequest.cs | 2 +- .../im/Chat/GetMessageHistoryEndpoint.cs | 2 +- .../im/Chat/GetUnreadCountEndpoint.cs | 2 +- .../im/Chat/RemoveGroupMemberEndpoint.cs | 2 +- .../Chat/RemoveGroupMemberEndpointRequest.cs | 2 +- .../im/Chat/SetConversationPinnedEndpoint.cs | 2 +- .../im/Chat/SetConversationRemarkEndpoint.cs | 2 +- .../SetConversationRemarkEndpointRequest.cs | 2 +- .../Endpoints/im/Chat/UpdateGroupEndpoint.cs | 2 +- .../platform/Auth/ChangePasswordEndpoint.cs | 2 +- .../platform/Auth/ChangePasswordRequest.cs | 2 +- .../platform/Auth/GetAccessCodesEndpoint.cs | 2 +- .../Endpoints/platform/Auth/LoginEndpoint.cs | 2 +- .../Endpoints/platform/Auth/LogoutEndpoint.cs | 2 +- .../platform/Auth/RefreshTokenEndpoint.cs | 8 +- .../platform/Auth/RegisterEndpoint.cs | 2 +- .../platform/Auth/RegisterRequestValidator.cs | 2 +- .../platform/Auth/RevokeTokenEndpoint.cs | 2 +- .../Auth/RevokeTokenRequestValidator.cs | 2 +- .../platform/Auth/UpdateProfileEndpoint.cs | 2 +- .../platform/Menus/CreateMenuEndpoint.cs | 3 +- .../Menus/CreateMenuRequestValidator.cs | 2 +- .../Menus/DeleteMenuEndpointRequest.cs | 2 +- .../DeleteMenuEndpointRequestValidator.cs | 2 +- .../Menus/GetMenuByIdRequestValidator.cs | 2 +- .../platform/Menus/SortMenusEndpoint.cs | 2 +- .../Menus/SortMenusEndpointRequest.cs | 2 +- .../platform/Menus/UpdateMenuEndpoint.cs | 3 +- .../Menus/UpdateMenuEndpointRequest.cs | 3 +- .../Notifications/GetNotificationsEndpoint.cs | 2 +- .../GetUnreadNotificationCountEndpoint.cs | 2 +- .../MarkNotificationReadEndpoint.cs | 2 +- .../NotificationEndpointsExtensions.cs | 2 +- .../PublishNotificationRequest.cs | 2 +- .../CreatePermissionRequestValidator.cs | 2 +- ...pdatePermissionEndpointRequestValidator.cs | 2 +- .../Roles/AssignPermissionsEndpoint.cs | 2 +- ...signPermissionsEndpointRequestValidator.cs | 2 +- .../platform/Roles/DeleteRoleEndpoint.cs | 2 +- .../platform/Roles/GetRoleListEndpoint.cs | 2 +- .../platform/Roles/UpdateRoleEndpoint.cs | 2 +- .../Roles/UpdateRoleEndpointRequest.cs | 2 +- .../AssignRolesEndpointRequestValidator.cs | 2 +- .../Users/DeleteUserEndpointRequest.cs | 2 +- .../Users/GetUserByIdRequestValidator.cs | 2 +- .../platform/Users/GetUserListEndpoint.cs | 2 +- .../platform/Users/GetUserListRequest.cs | 2 +- .../platform/Users/UpdateUserEndpoint.cs | 2 +- .../Users/UpdateUserEndpointRequest.cs | 2 +- .../CreateConversationRequestValidator.cs | 2 +- .../rag/Chat/GetConversationsEndpoint.cs | 2 +- .../rag/Chat/StreamMessageRequestValidator.cs | 2 +- .../rag/Document/GetDocumentChunksEndpoint.cs | 2 +- .../Document/ImportFromFileManagerEndpoint.cs | 2 +- .../Document/ImportFromFileManagerRequest.cs | 2 +- .../rag/Document/InitChunkUploadRequest.cs | 2 +- .../Document/ProcessKnowledgeBaseEndpoint.cs | 2 +- .../rag/Document/UploadChunkEndpoint.cs | 2 +- .../rag/Document/UploadDocumentEndpoint.cs | 2 +- .../rag/Document/UploadDocumentRequest.cs | 2 +- .../UploadDocumentRequestValidator.cs | 2 +- .../rag/Embedding/EmbedBatchEndpoint.cs | 2 +- .../rag/Embedding/EmbedBatchRequest.cs | 2 +- .../Embedding/EmbedBatchRequestValidator.cs | 2 +- .../rag/Embedding/EmbedTextEndpoint.cs | 2 +- .../Embedding/EmbedTextRequestValidator.cs | 2 +- .../rag/KnowledgeBase/CreateKBEndpoint.cs | 2 +- .../CreateKnowledgeBaseRequestValidator.cs | 2 +- .../rag/KnowledgeBase/DeleteKBEndpoint.cs | 2 +- .../rag/KnowledgeBase/GetKBsEndpoint.cs | 2 +- .../rag/KnowledgeBase/UpdateKBEndpoint.cs | 2 +- .../UpdateKnowledgeBaseRequestValidator.cs | 2 +- .../rag/Obsidian/SyncObsidianVaultEndpoint.cs | 2 +- .../Endpoints/rag/RAG/RAGQueryEndpoint.cs | 2 +- .../rag/RAG/RAGQueryRequestValidator.cs | 2 +- .../CreateBuildFlowApplicationEndpoint.cs | 2 +- ...CreateBuildFlowButtonDefinitionEndpoint.cs | 2 +- .../CreateBuildFlowButtonDefinitionRequest.cs | 2 +- .../Buttons/ExecuteBuildFlowButtonEndpoint.cs | 2 +- ...etBuildFlowButtonDefinitionListEndpoint.cs | 2 +- .../CreateCustomFunctionEndpoint.cs | 2 +- .../CreateCustomFunctionRequest.cs | 2 +- .../GetCustomFunctionListEndpoint.cs | 2 +- .../GetCustomFunctionListRequest.cs | 2 +- .../GetBuildFlowPageDefinitionListEndpoint.cs | 2 +- .../GetBuildFlowPageDefinitionListRequest.cs | 2 +- .../Form/CompareFormVersionsRequest.cs | 2 +- .../Form/CreateFormComponentEndpoint.cs | 2 +- .../Form/CreateFormComponentRequest.cs | 2 +- .../Form/CreateFormDefinitionEndpoint.cs | 2 +- .../Form/CreateFormDefinitionRequest.cs | 2 +- .../Form/DeleteFormComponentRequest.cs | 2 +- .../Form/DeleteFormDefinitionEndpoint.cs | 2 +- .../Form/DeleteFormDefinitionRequest.cs | 2 +- .../Form/GetFormComponentByIdEndpoint.cs | 2 +- .../Form/GetFormDefinitionByIdRequest.cs | 2 +- .../Form/GetFormDefinitionListRequest.cs | 2 +- .../workflow/Form/SubmitFormDataEndpoint.cs | 2 +- .../Form/UpdateFormComponentEndpoint.cs | 2 +- .../Form/UpdateFormDefinitionEndpoint.cs | 2 +- .../MarkAllNotificationsReadEndpoint.cs | 2 +- .../MarkNotificationReadEndpoint.cs | 2 +- .../NotificationClaimsExtensions.cs | 2 +- .../WorkflowDefinition/CreateEdgeRequest.cs | 2 +- .../WorkflowDefinition/CreateNodeEndpoint.cs | 2 +- .../WorkflowDefinition/CreateNodeRequest.cs | 2 +- .../CreateWorkflowDefinitionRequest.cs | 2 +- .../WorkflowDefinition/DeleteEdgeRequest.cs | 2 +- .../WorkflowDefinition/DeleteNodeRequest.cs | 2 +- .../DeleteWorkflowDefinitionEndpoint.cs | 2 +- .../GetWorkflowDefinitionListEndpoint.cs | 2 +- .../WorkflowDefinition/UpdateEdgeEndpoint.cs | 2 +- .../WorkflowDefinition/UpdateEdgeRequest.cs | 2 +- .../UpdateWorkflowDefinitionEndpoint.cs | 2 +- .../GetWorkflowInstanceByIdEndpoint.cs | 2 +- .../StartWorkflowInstanceEndpoint.cs | 2 +- .../StartWorkflowInstanceRequest.cs | 2 +- .../WorkflowTask/AddSignerEndpoint.cs | 2 +- .../workflow/WorkflowTask/AddSignerRequest.cs | 2 +- .../WorkflowTask/DelegateTaskRequest.cs | 2 +- .../WorkflowTask/GetCcTasksEndpoint.cs | 2 +- .../WorkflowTask/GetCcTasksRequest.cs | 2 +- .../WorkflowTask/GetOverdueTasksRequest.cs | 2 +- .../WorkflowTask/GetPendingTasksEndpoint.cs | 2 +- .../WorkflowTask/GetTaskByIdEndpoint.cs | 2 +- .../WorkflowTask/GetTaskByIdRequest.cs | 2 +- .../WorkflowTask/MarkCcTaskReadEndpoint.cs | 2 +- .../WorkflowTask/MarkCcTaskReadRequest.cs | 2 +- .../WorkflowTask/RejectTaskEndpoint.cs | 2 +- .../WorkflowTask/ReturnTaskRequest.cs | 2 +- .../WorkflowTask/TransferTaskRequest.cs | 2 +- .../workflow/WorkflowTask/UrgeTaskEndpoint.cs | 2 +- .../workflow/WorkflowTask/UrgeTaskRequest.cs | 2 +- .../Menus/Commands/CreateMenuCommand.cs | 1 + .../Menus/Commands/UpdateMenuCommand.cs | 1 + .../Menus/DTOs/CreateMenuRequest.cs | 1 + .../Application/Menus/DTOs/MenuDto.cs | 1 + .../Handlers/CreateMenuCommandHandler.cs | 5 + .../Menus/Handlers/MenuHandlerMapping.cs | 1 + .../Handlers/UpdateMenuCommandHandler.cs | 8 + src/modules/platform/Domain/Entities/Menu.cs | 7 + .../20260703084733_AddMenuCode.Designer.cs | 792 ++++++++++++++++++ .../Migrations/20260703084733_AddMenuCode.cs | 41 + .../PlatformDbContextModelSnapshot.cs | 11 + .../Configurations/MenuConfiguration.cs | 2 + .../Infrastructure/Persistence/SeedData.cs | 96 +++ .../Infrastructure/Persistence/SeedMenu.cs | 23 + .../Domain/Entities/WorkflowDefinition.cs | 6 +- .../Api/ServiceCollectionExtensions.cs | 17 +- 528 files changed, 8417 insertions(+), 180 deletions(-) create mode 100644 src/BuildFlow.Host/Endpoints/File/Buckets/CreateBucketEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Buckets/CreateBucketRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Buckets/DeleteBucketEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Buckets/DeleteBucketRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Buckets/ListBucketsEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/CheckFileEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/CheckFileRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/DeleteFileEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/DeleteFileRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/DownloadFileEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/DownloadFileRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/GetFileContentEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/GetFileContentRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/GetFilePreviewEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/GetFilePreviewRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/GetOfficePreviewEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/GetOfficePreviewRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/ListFilesEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/ListFilesRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/UploadFileEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Files/UploadFileRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Folders/CreateFolderEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Folders/CreateFolderRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Folders/DeleteFolderEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Folders/DeleteFolderRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Folders/GetFolderEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Folders/GetFolderRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Folders/GetFolderTreeEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Folders/GetRootFilesEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Folders/MoveFileEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Folders/MoveFileRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Folders/RenameFolderEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Folders/RenameFolderRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Folders/UploadToFolderEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Folders/UploadToFolderRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Multipart/AbortMultipartEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Multipart/AbortMultipartRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Multipart/CompleteMultipartEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Multipart/CompleteMultipartRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Multipart/InitMultipartEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Multipart/InitMultipartRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Multipart/ListPartsEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Multipart/ListPartsRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Multipart/PartRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Multipart/UploadPartEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Multipart/UploadPartRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Settings/GetFileSettingEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Settings/UpdateDefaultBucketEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Settings/UpdateDefaultBucketRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Shares/CreateShareEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Shares/CreateShareRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Shares/DeleteShareEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Shares/DeleteShareRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Shares/DownloadShareEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Shares/DownloadShareRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Shares/GetShareInfoEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/File/Shares/GetShareInfoRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/AddGroupMemberEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/AddGroupMemberEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/CreateGroupEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/CreatePrivateConversationEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/DeleteGroupEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/DeleteGroupEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/GetConversationsEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupMembersEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupMembersEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/GetMessageHistoryEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/GetMessageHistoryRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/GetUnreadCountEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/MarkConversationUnreadEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/RecallMessageEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/RecallMessageEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/RemoveGroupMemberEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/RemoveGroupMemberEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationMutedEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationPinnedEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationRemarkEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationRemarkEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationStateRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/UpdateGroupEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/IM/Chat/UpdateGroupEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Auth/ChangePasswordEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Auth/ChangePasswordRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Auth/GetAccessCodesEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Auth/GetCurrentUserEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Auth/LoginEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Auth/LoginRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Auth/LogoutEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Auth/RefreshTokenEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Auth/RegisterEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Auth/RegisterRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Auth/RevokeTokenEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Auth/RevokeTokenRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Auth/UpdateProfileEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Auth/UpdateProfileRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/CreateMenuEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/CreateMenuRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/DeleteMenuEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/DeleteMenuEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/DeleteMenuEndpointRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/GetAllMenusEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/GetMenuByIdEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/GetMenuByIdRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/GetMenuByIdRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/GetMenuTreeEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/SortMenusEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/SortMenusEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/SortMenusEndpointRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/UpdateMenuEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/UpdateMenuEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Menus/UpdateMenuEndpointRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Notifications/GetNotificationsEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Notifications/GetNotificationsRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Notifications/GetNotificationsRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Notifications/GetUnreadNotificationCountEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Notifications/MarkAllNotificationsReadEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Notifications/MarkNotificationReadEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Notifications/NotificationEndpointsExtensions.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Notifications/PublishNotificationEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Notifications/PublishNotificationRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Notifications/PublishNotificationRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Permissions/CreatePermissionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Permissions/CreatePermissionRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Permissions/DeletePermissionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Permissions/DeletePermissionEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Permissions/DeletePermissionEndpointRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Permissions/GetPermissionByIdEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Permissions/GetPermissionByIdRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Permissions/GetPermissionByIdRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Permissions/GetPermissionListEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Permissions/GetPermissionTreeEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Permissions/UpdatePermissionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Permissions/UpdatePermissionEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Permissions/UpdatePermissionEndpointRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/AssignPermissionsEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/AssignPermissionsEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/AssignPermissionsEndpointRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/CreateRoleEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/CreateRoleRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/DeleteRoleEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/DeleteRoleEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/DeleteRoleEndpointRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleByIdEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleByIdRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleByIdRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleListEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/UpdateRoleEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/UpdateRoleEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Roles/UpdateRoleEndpointRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/AssignRolesEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/AssignRolesEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/AssignRolesEndpointRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/CreateUserEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/CreateUserRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/DeleteUserEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/DeleteUserEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/DeleteUserEndpointRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/GetUserByIdEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/GetUserByIdRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/GetUserByIdRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/GetUserListEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/GetUserListRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/UpdateUserEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/UpdateUserEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Platform/Users/UpdateUserEndpointRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/AiModel/AiModelEndpoints.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/CreateConversationEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/CreateConversationRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/CreateConversationRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/DeleteConversationEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/DeleteConversationEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/DeleteConversationEndpointRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationDetailEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationDetailRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationDetailRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationsEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/SendMessageEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/SendMessageRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/SendMessageRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/StreamMessageEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/StreamMessageRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Chat/StreamMessageRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/ChunkUploadSession.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/ChunkUploadStore.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/CompleteChunkUploadEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/CompleteChunkUploadRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/CompleteChunkUploadRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/GetDocumentChunksEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/ImportFromFileManagerEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/ImportFromFileManagerRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/InitChunkUploadEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/InitChunkUploadRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/InitChunkUploadRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/ListDocumentsEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/ProcessDocumentEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/ProcessKnowledgeBaseEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/UploadChunkEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/UploadDocumentEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/UploadDocumentRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Document/UploadDocumentRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedBatchEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedBatchRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedBatchRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedTextEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedTextRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedTextRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/CreateKBEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/CreateKnowledgeBaseRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/DeleteKBEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/DeleteKBEndpointRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/DeleteKBEndpointRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/GetKBsEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/UpdateKBEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/UpdateKnowledgeBaseRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Obsidian/ObsidianSyncRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/Obsidian/SyncObsidianVaultEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/RAG/RAGQueryEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/RAG/RAGQueryRequestValidator.cs create mode 100644 src/BuildFlow.Host/Endpoints/Rag/RAG/RAGStreamEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/CreateBuildFlowApplicationEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/CreateBuildFlowApplicationRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/GetBuildFlowApplicationListEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/GetBuildFlowApplicationListRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/ExecuteBuildFlowButtonEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/ExecuteBuildFlowButtonRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/GetBuildFlowButtonDefinitionListEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/GetBuildFlowButtonDefinitionListRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/CreateCustomFunctionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/CreateCustomFunctionRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/DisableCustomFunctionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/DisableCustomFunctionRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/GetCustomFunctionListEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/GetCustomFunctionListRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/PublishCustomFunctionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/PublishCustomFunctionRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/TestCustomFunctionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/TestCustomFunctionRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/CreateBuildFlowPageDefinitionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/CreateBuildFlowPageDefinitionRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/CompareFormVersionsEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/CompareFormVersionsRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormComponentEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormComponentRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormDefinitionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormDefinitionRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormComponentEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormComponentRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormDefinitionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormDefinitionRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/DisableFormDefinitionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/DisableFormDefinitionRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormComponentByIdEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormComponentByIdRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormComponentsEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDataByInstanceEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDataByInstanceRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionByIdEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionByIdRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionListEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionListRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormVersionsEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/PublishFormDefinitionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/SubmitFormDataEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/SubmitFormDataRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormComponentEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormComponentRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormDefinitionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormDefinitionRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Notification/GetNotificationsEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Notification/GetNotificationsRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Notification/GetUnreadNotificationCountEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Notification/MarkAllNotificationsReadEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Notification/MarkNotificationReadEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/Notification/NotificationClaimsExtensions.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateEdgeEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateEdgeRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateNodeEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateNodeRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateWorkflowDefinitionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateWorkflowDefinitionRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteEdgeEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteEdgeRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteNodeEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteNodeRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteWorkflowDefinitionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteWorkflowDefinitionRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DisableWorkflowDefinitionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionByIdEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionByIdRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionListEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionListRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/PublishWorkflowDefinitionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateEdgeEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateEdgeRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateNodeEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateNodeRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateWorkflowDefinitionEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateWorkflowDefinitionRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceByIdEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceByIdRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceListEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceListRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/MonitorWorkflowInstancesEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/ResumeWorkflowInstanceEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/StartWorkflowInstanceEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/StartWorkflowInstanceRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/SuspendWorkflowInstanceEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/WithdrawWorkflowInstanceEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/AddSignerEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/AddSignerRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ApproveTaskEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ApproveTaskRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/DelegateTaskEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/DelegateTaskRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetCcTasksEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetCcTasksRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetHistoryTasksEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetHistoryTasksRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetOverdueTasksEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetOverdueTasksRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetPendingTasksEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetPendingTasksRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetTaskByIdEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetTaskByIdRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/MarkCcTaskReadEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/MarkCcTaskReadRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/RejectTaskEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/RejectTaskRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ReturnTaskEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ReturnTaskRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/TransferTaskEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/TransferTaskRequest.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/UrgeTaskEndpoint.cs create mode 100644 src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/UrgeTaskRequest.cs create mode 100644 src/modules/platform/Infrastructure/Migrations/20260703084733_AddMenuCode.Designer.cs create mode 100644 src/modules/platform/Infrastructure/Migrations/20260703084733_AddMenuCode.cs create mode 100644 src/modules/platform/Infrastructure/Persistence/SeedMenu.cs diff --git a/src/BuildFlow.Host/Endpoints/File/Buckets/CreateBucketEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Buckets/CreateBucketEndpoint.cs new file mode 100644 index 0000000..c46222d --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Buckets/CreateBucketEndpoint.cs @@ -0,0 +1,24 @@ +using File.Application.Features.Buckets.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Buckets; + + +/// 创建存储桶端点。POST /api/buckets,按名称创建存储桶。 +[Authorize] +/// +/// undefined +/// +public class CreateBucketEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/buckets"); + } + + public override async Task HandleAsync(CreateBucketRequest req, CancellationToken ct) + { + var message = await mediator.Send(new CreateBucketCommand(req.Name), ct); + await Send.OkAsync(new { message }, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Buckets/CreateBucketRequest.cs b/src/BuildFlow.Host/Endpoints/File/Buckets/CreateBucketRequest.cs new file mode 100644 index 0000000..b5843ca --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Buckets/CreateBucketRequest.cs @@ -0,0 +1,7 @@ +namespace BuildFlow.Host.Endpoints.File.Buckets; + +/// 创建存储桶请求。携带待创建存储桶的名称。 +public class CreateBucketRequest +{ + public string Name { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Buckets/DeleteBucketEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Buckets/DeleteBucketEndpoint.cs new file mode 100644 index 0000000..131539b --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Buckets/DeleteBucketEndpoint.cs @@ -0,0 +1,24 @@ +using File.Application.Features.Buckets.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Buckets; + + +/// 删除存储桶端点。DELETE /api/buckets,按名称删除存储桶。 +[Authorize] +/// +/// undefined +/// +public class DeleteBucketEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Delete("/buckets"); + } + + public override async Task HandleAsync(DeleteBucketRequest req, CancellationToken ct) + { + var message = await mediator.Send(new DeleteBucketCommand(req.Name), ct); + await Send.OkAsync(new { message }, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Buckets/DeleteBucketRequest.cs b/src/BuildFlow.Host/Endpoints/File/Buckets/DeleteBucketRequest.cs new file mode 100644 index 0000000..4300b64 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Buckets/DeleteBucketRequest.cs @@ -0,0 +1,7 @@ +namespace BuildFlow.Host.Endpoints.File.Buckets; + +/// 删除存储桶请求。以查询参数传入存储桶名称。 +public class DeleteBucketRequest +{ + [QueryParam] public string Name { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Buckets/ListBucketsEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Buckets/ListBucketsEndpoint.cs new file mode 100644 index 0000000..8a0e864 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Buckets/ListBucketsEndpoint.cs @@ -0,0 +1,23 @@ +using File.Application.Features.Buckets.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Buckets; + +/// 列出存储桶端点。GET /api/buckets,返回全部存储桶名称。 +[Authorize] +/// +/// undefined +/// +public class ListBucketsEndpoint(IMediator mediator) : Endpoint> +{ + public override void Configure() + { + Get("/buckets"); + } + + public override async Task HandleAsync(EmptyRequest req, CancellationToken ct) + { + var result = await mediator.Send(new ListBucketsQuery(), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Files/CheckFileEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Files/CheckFileEndpoint.cs new file mode 100644 index 0000000..b52b3e9 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/CheckFileEndpoint.cs @@ -0,0 +1,24 @@ +using File.Application.Features.Files.DTOs; +using File.Application.Features.Files.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Files; + +/// 秒传预检端点。POST /api/files/check,按哈希查同用户已存在文件。 +[Authorize] +/// +/// undefined +/// +public class CheckFileEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/files/check"); + } + + public override async Task HandleAsync(CheckFileRequest req, CancellationToken ct) + { + var result = await mediator.Send(new CheckFileQuery(req.ContentHash, req.Size), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Files/CheckFileRequest.cs b/src/BuildFlow.Host/Endpoints/File/Files/CheckFileRequest.cs new file mode 100644 index 0000000..34ad267 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/CheckFileRequest.cs @@ -0,0 +1,10 @@ +namespace BuildFlow.Host.Endpoints.File.Files; + +/// 秒传预检请求。前端上传前带 content_hash 与 size 查重。 +public class CheckFileRequest +{ + /// 文件内容 SHA-256 哈希(前端计算)。 + public string ContentHash { get; init; } = default!; + /// 文件大小(字节),防哈希碰撞。 + public long Size { get; init; } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Files/DeleteFileEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Files/DeleteFileEndpoint.cs new file mode 100644 index 0000000..f8cbeaa --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/DeleteFileEndpoint.cs @@ -0,0 +1,24 @@ +using File.Application.Features.Files.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Files; + + +/// 删除文件端点。DELETE /api/files/delete,按对象键删除文件。 +[Authorize] +/// +/// undefined +/// +public class DeleteFileEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Delete("/files/delete"); + } + + public override async Task HandleAsync(DeleteFileRequest req, CancellationToken ct) + { + await mediator.Send(new DeleteFileCommand(req.ObjectKey), ct); + await Send.OkAsync(new { message = "deleted" }, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Files/DeleteFileRequest.cs b/src/BuildFlow.Host/Endpoints/File/Files/DeleteFileRequest.cs new file mode 100644 index 0000000..1134c41 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/DeleteFileRequest.cs @@ -0,0 +1,7 @@ +namespace BuildFlow.Host.Endpoints.File.Files; + +/// 删除文件请求。以查询参数指定对象键。 +public class DeleteFileRequest +{ + [QueryParam] public string ObjectKey { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Files/DownloadFileEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Files/DownloadFileEndpoint.cs new file mode 100644 index 0000000..b02bbe6 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/DownloadFileEndpoint.cs @@ -0,0 +1,41 @@ +using System.Net.Mime; +using File.Application.Features.Files.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Files; + +/// +/// 下载文件端点。GET /api/files/download,按对象键流式返回文件内容。 +/// 直接把 S3 响应流透传到 HTTP 响应体,整文件不进内存;Content-Disposition 触发浏览器下载。 +/// 该路径已在 ApiResponseMiddlewareOptions.PassthroughPrefixes 注册,绕过响应包裹中间件的缓冲。 +/// +[Authorize] +/// +/// undefined +/// +public class DownloadFileEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() => Get("/files/download"); + + public override async Task HandleAsync(DownloadFileRequest req, CancellationToken ct) + { + var result = await mediator.Send(new DownloadFileQuery(req.ObjectKey), ct); + + // 设置响应头:真实 ContentType + 触发下载的文件名 + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = result.ContentType; + var disposition = new ContentDisposition { FileName = result.FileName, Inline = false }; + HttpContext.Response.Headers.ContentDisposition = disposition.ToString(); + + // 流式透传:S3 流 → HTTP 响应体,零内存拷贝 + try + { + await result.Stream.CopyToAsync(HttpContext.Response.Body, ct); + await HttpContext.Response.Body.FlushAsync(ct); + } + finally + { + await result.Stream.DisposeAsync(); + } + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Files/DownloadFileRequest.cs b/src/BuildFlow.Host/Endpoints/File/Files/DownloadFileRequest.cs new file mode 100644 index 0000000..ff1e7bd --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/DownloadFileRequest.cs @@ -0,0 +1,7 @@ +namespace BuildFlow.Host.Endpoints.File.Files; + +/// 下载文件请求。以查询参数指定对象键。 +public class DownloadFileRequest +{ + [QueryParam] public string ObjectKey { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Files/GetFileContentEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Files/GetFileContentEndpoint.cs new file mode 100644 index 0000000..3358adc --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/GetFileContentEndpoint.cs @@ -0,0 +1,25 @@ +using File.Application.Features.Files.DTOs; +using File.Application.Features.Files.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Files; + + +/// 文件内容端点。GET /api/files/content,返回文件文本内容。 +[Authorize] +/// +/// undefined +/// +public class GetFileContentEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Get("/files/content"); + } + + public override async Task HandleAsync(GetFileContentRequest req, CancellationToken ct) + { + var result = await mediator.Send(new GetFileContentQuery(req.ObjectKey), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Files/GetFileContentRequest.cs b/src/BuildFlow.Host/Endpoints/File/Files/GetFileContentRequest.cs new file mode 100644 index 0000000..c62cc6d --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/GetFileContentRequest.cs @@ -0,0 +1,7 @@ +namespace BuildFlow.Host.Endpoints.File.Files; + +/// 文件内容请求。以查询参数指定对象键(bucket 由系统设置统一管理)。 +public class GetFileContentRequest +{ + [QueryParam] public string ObjectKey { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Files/GetFilePreviewEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Files/GetFilePreviewEndpoint.cs new file mode 100644 index 0000000..4635f2a --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/GetFilePreviewEndpoint.cs @@ -0,0 +1,42 @@ +using System.Net.Mime; +using File.Application.Features.Files.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Files; + +/// +/// 文件预览端点。GET /api/files/preview,流式返回文件内容供内联展示(非下载)。 +/// 后端从 S3 拉流透传,前端永远不接触 S3 URL 和凭据。 +/// 鉴权:[Authorize] + JWT 中间件从 token query 参数读 JWT(img src / window.open 无法带 header)。 +/// 该路径在 ApiResponseMiddlewareOptions.PassthroughPrefixes 注册,绕过响应包裹中间件的缓冲。 +/// +[Authorize] +public class GetFilePreviewEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Get("/files/preview"); + } + + public override async Task HandleAsync(GetFilePreviewRequest req, CancellationToken ct) + { + // 复用下载查询(返回 Stream + ContentType + FileName) + var result = await mediator.Send(new DownloadFileQuery(req.ObjectKey), ct); + + // inline = 浏览器内联展示(图片/PDF 直接渲染),而非触发下载 + HttpContext.Response.ContentType = result.ContentType; + var disposition = new ContentDisposition { FileName = result.FileName, Inline = true }; + HttpContext.Response.Headers.ContentDisposition = disposition.ToString(); + + // 流式透传:S3 流 → HTTP 响应体 + try + { + await result.Stream.CopyToAsync(HttpContext.Response.Body, ct); + await HttpContext.Response.Body.FlushAsync(ct); + } + finally + { + await result.Stream.DisposeAsync(); + } + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Files/GetFilePreviewRequest.cs b/src/BuildFlow.Host/Endpoints/File/Files/GetFilePreviewRequest.cs new file mode 100644 index 0000000..860500b --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/GetFilePreviewRequest.cs @@ -0,0 +1,19 @@ +namespace BuildFlow.Host.Endpoints.File.Files; + +/// +/// 文件预览请求。以查询参数指定对象键。 +/// 鉴权三选一:Authorization header / Token 查询参数(JWT) / InternalToken+Expires(KKFileView 内部回拉)。 +/// +public class GetFilePreviewRequest +{ + [QueryParam] public string ObjectKey { get; init; } = default!; + + /// JWT token(用于 img src / window.open 等无法带 Authorization header 的场景)。 + [QueryParam] public string? Token { get; init; } + + /// KKFileView 内部回拉签名(HMAC),配合 Expires 使用。 + [QueryParam] public string? InternalToken { get; init; } + + /// 内部签名过期时间戳(Unix 秒)。 + [QueryParam] public long? Expires { get; init; } +} 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..8d39236 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/GetOfficePreviewEndpoint.cs @@ -0,0 +1,27 @@ +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] +/// +/// undefined +/// +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.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..7e0341c --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/GetOfficePreviewRequest.cs @@ -0,0 +1,7 @@ +namespace BuildFlow.Host.Endpoints.File.Files; + +/// Office/PDF 文档预览请求。以查询参数指定对象键。 +public class GetOfficePreviewRequest +{ + [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 new file mode 100644 index 0000000..47d6010 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/ListFilesEndpoint.cs @@ -0,0 +1,25 @@ +using File.Application.Features.Files.DTOs; +using File.Application.Features.Files.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Files; + + +/// 列举文件端点。GET /api/files/list,支持前缀与分页查询。 +[Authorize] +/// +/// undefined +/// +public class ListFilesEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Get("/files/list"); + } + + public override async Task HandleAsync(ListFilesRequest req, CancellationToken ct) + { + var result = await mediator.Send(new ListFilesQuery(req.Prefix, req.MaxKeys, req.ContinuationToken), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Files/ListFilesRequest.cs b/src/BuildFlow.Host/Endpoints/File/Files/ListFilesRequest.cs new file mode 100644 index 0000000..2ef89f7 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/ListFilesRequest.cs @@ -0,0 +1,9 @@ +namespace BuildFlow.Host.Endpoints.File.Files; + +/// 列举文件请求。包含前缀、最大键数与续传令牌。 +public class ListFilesRequest +{ + [QueryParam] public string? Prefix { get; init; } + [QueryParam] public int? MaxKeys { get; init; } + [QueryParam] public string? ContinuationToken { get; init; } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Files/UploadFileEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Files/UploadFileEndpoint.cs new file mode 100644 index 0000000..76a1f89 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/UploadFileEndpoint.cs @@ -0,0 +1,28 @@ +using File.Application.Features.Files.Commands; +using File.Application.Features.Files.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Files; + + +/// 上传文件端点。POST /api/files/upload,支持 multipart 文件上传。 +[Authorize] +/// +/// undefined +/// +public class UploadFileEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/files/upload"); + AllowFileUploads(); + } + + public override async Task HandleAsync(UploadFileRequest req, CancellationToken ct) + { + await using var stream = req.File.OpenReadStream(); + var result = await mediator.Send(new UploadFileCommand(req.ObjectKey, + stream, req.File.ContentType, req.File.Length, req.ContentHash), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Files/UploadFileRequest.cs b/src/BuildFlow.Host/Endpoints/File/Files/UploadFileRequest.cs new file mode 100644 index 0000000..f00c7b8 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Files/UploadFileRequest.cs @@ -0,0 +1,10 @@ +namespace BuildFlow.Host.Endpoints.File.Files; + +/// 上传文件请求。包含 object_key 与文件数据。 +public class UploadFileRequest +{ + public string ObjectKey { get; init; } = default!; + public IFormFile File { get; init; } = default!; + /// 文件内容哈希(可选),秒传查重用。 + public string? ContentHash { get; init; } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Folders/CreateFolderEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Folders/CreateFolderEndpoint.cs new file mode 100644 index 0000000..c289114 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Folders/CreateFolderEndpoint.cs @@ -0,0 +1,26 @@ +using File.Application.Features.Folders.Commands; +using File.Application.Features.Folders.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Folders; + + +/// 创建文件夹端点。POST /api/folders。 +[Authorize] +/// +/// undefined +/// +public class CreateFolderEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/folders"); + } + + public override async Task HandleAsync(CreateFolderRequest req, CancellationToken ct) + { + var parentId = string.IsNullOrEmpty(req.ParentId) ? (Guid?)null : Guid.Parse(req.ParentId); + var result = await mediator.Send(new CreateFolderCommand(parentId, req.Name), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Folders/CreateFolderRequest.cs b/src/BuildFlow.Host/Endpoints/File/Folders/CreateFolderRequest.cs new file mode 100644 index 0000000..9300bb3 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Folders/CreateFolderRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.File.Folders; + +/// 创建文件夹请求体(父目录 Id 与名称)。 +public class CreateFolderRequest +{ + public string? ParentId { get; init; } + public string Name { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Folders/DeleteFolderEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Folders/DeleteFolderEndpoint.cs new file mode 100644 index 0000000..5efa8ad --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Folders/DeleteFolderEndpoint.cs @@ -0,0 +1,24 @@ +using File.Application.Features.Folders.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Folders; + + +/// 删除文件夹端点。DELETE /api/folders/{Id}。 +[Authorize] +/// +/// undefined +/// +public class DeleteFolderEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Delete("/folders/{Id}"); + } + + public override async Task HandleAsync(DeleteFolderRequest req, CancellationToken ct) + { + await mediator.Send(new DeleteFolderCommand(Guid.Parse(req.Id)), ct); + await Send.OkAsync(new { message = "deleted" }, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Folders/DeleteFolderRequest.cs b/src/BuildFlow.Host/Endpoints/File/Folders/DeleteFolderRequest.cs new file mode 100644 index 0000000..fb71d2c --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Folders/DeleteFolderRequest.cs @@ -0,0 +1,7 @@ +namespace BuildFlow.Host.Endpoints.File.Folders; + +/// 删除文件夹请求(路由取 Id)。 +public class DeleteFolderRequest +{ + [RouteParam] public string Id { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Folders/GetFolderEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Folders/GetFolderEndpoint.cs new file mode 100644 index 0000000..373ef7c --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Folders/GetFolderEndpoint.cs @@ -0,0 +1,24 @@ +using File.Application.Features.Folders.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Folders; + + +/// 获取文件夹详情端点。GET /api/folders/{Id}。 +[Authorize] +/// +/// undefined +/// +public class GetFolderEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Get("/folders/{Id}"); + } + + public override async Task HandleAsync(GetFolderRequest req, CancellationToken ct) + { + var result = await mediator.Send(new GetFolderQuery(Guid.Parse(req.Id)), ct); + await Send.OkAsync(result!, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Folders/GetFolderRequest.cs b/src/BuildFlow.Host/Endpoints/File/Folders/GetFolderRequest.cs new file mode 100644 index 0000000..3b9efe7 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Folders/GetFolderRequest.cs @@ -0,0 +1,7 @@ +namespace BuildFlow.Host.Endpoints.File.Folders; + +/// 获取文件夹请求(路由取 Id)。 +public class GetFolderRequest +{ + [RouteParam] public string Id { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Folders/GetFolderTreeEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Folders/GetFolderTreeEndpoint.cs new file mode 100644 index 0000000..6965032 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Folders/GetFolderTreeEndpoint.cs @@ -0,0 +1,24 @@ +using File.Application.Features.Folders.DTOs; +using File.Application.Features.Folders.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Folders; + +/// 获取整棵文件夹树端点。GET /api/folders/tree。 +[Authorize] +/// +/// undefined +/// +public class GetFolderTreeEndpoint(IMediator mediator) : Endpoint> +{ + public override void Configure() + { + Get("/folders/tree"); + } + + public override async Task HandleAsync(EmptyRequest req, CancellationToken ct) + { + var result = await mediator.Send(new GetFolderTreeQuery(), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Folders/GetRootFilesEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Folders/GetRootFilesEndpoint.cs new file mode 100644 index 0000000..4ca7fbf --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Folders/GetRootFilesEndpoint.cs @@ -0,0 +1,25 @@ +using File.Application.Features.Folders.DTOs; +using File.Application.Features.Folders.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Folders; + +/// +/// 查询根级文件端点。GET /api/files/root, +/// 返回当前用户 FolderId=null 的所有 FileMeta,使根目录与子文件夹共享同一数据源(DB)。 +/// 注意:路径用 /files/root 而非 /folders/root/files,避免与 POST /folders/{FolderId}/files 模板冲突。 +/// +[Authorize] +public class GetRootFilesEndpoint(IMediator mediator) : Endpoint> +{ + public override void Configure() + { + Get("/files/root"); + } + + public override async Task HandleAsync(EmptyRequest req, CancellationToken ct) + { + var result = await mediator.Send(new GetRootFilesQuery(), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Folders/MoveFileEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Folders/MoveFileEndpoint.cs new file mode 100644 index 0000000..b98f973 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Folders/MoveFileEndpoint.cs @@ -0,0 +1,25 @@ +using File.Application.Features.Folders.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Folders; + + +/// 移动文件到目标文件夹端点。POST /api/files/{Id}/move。 +[Authorize] +/// +/// undefined +/// +public class MoveFileEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/files/{Id}/move"); + } + + public override async Task HandleAsync(MoveFileRequest req, CancellationToken ct) + { + var targetId = string.IsNullOrEmpty(req.TargetFolderId) ? (Guid?)null : Guid.Parse(req.TargetFolderId); + await mediator.Send(new MoveFileCommand(Guid.Parse(req.Id), targetId), ct); + await Send.OkAsync(new { message = "moved" }, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Folders/MoveFileRequest.cs b/src/BuildFlow.Host/Endpoints/File/Folders/MoveFileRequest.cs new file mode 100644 index 0000000..a46c75d --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Folders/MoveFileRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.File.Folders; + +/// 移动文件请求(文件 Id 与目标目录)。 +public class MoveFileRequest +{ + [RouteParam] public string Id { get; init; } = default!; + public string? TargetFolderId { get; init; } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Folders/RenameFolderEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Folders/RenameFolderEndpoint.cs new file mode 100644 index 0000000..5f217d4 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Folders/RenameFolderEndpoint.cs @@ -0,0 +1,25 @@ +using File.Application.Features.Folders.Commands; +using File.Application.Features.Folders.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Folders; + + +/// 重命名文件夹端点。PUT /api/folders/{Id}。 +[Authorize] +/// +/// undefined +/// +public class RenameFolderEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Put("/folders/{Id}"); + } + + public override async Task HandleAsync(RenameFolderRequest req, CancellationToken ct) + { + var result = await mediator.Send(new RenameFolderCommand(Guid.Parse(req.Id), req.Name), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Folders/RenameFolderRequest.cs b/src/BuildFlow.Host/Endpoints/File/Folders/RenameFolderRequest.cs new file mode 100644 index 0000000..3e389a5 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Folders/RenameFolderRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.File.Folders; + +/// 重命名文件夹请求(路由 Id 与新名称)。 +public class RenameFolderRequest +{ + [RouteParam] public string Id { get; init; } = default!; + public string Name { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Folders/UploadToFolderEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Folders/UploadToFolderEndpoint.cs new file mode 100644 index 0000000..d72b114 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Folders/UploadToFolderEndpoint.cs @@ -0,0 +1,28 @@ +using File.Application.Features.Folders.Commands; +using File.Application.Features.Folders.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Folders; + + +/// 上传文件到指定文件夹端点。POST /api/folders/{FolderId}/files。 +[Authorize] +/// +/// undefined +/// +public class UploadToFolderEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/folders/{FolderId}/files"); + AllowFileUploads(); + } + + public override async Task HandleAsync(UploadToFolderRequest req, CancellationToken ct) + { + await using var stream = req.File.OpenReadStream(); + var result = await mediator.Send(new UploadToFolderCommand(Guid.Parse(req.FolderId), + req.FileName, stream, req.File.ContentType, req.File.Length, req.ContentHash), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Folders/UploadToFolderRequest.cs b/src/BuildFlow.Host/Endpoints/File/Folders/UploadToFolderRequest.cs new file mode 100644 index 0000000..9ef1f43 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Folders/UploadToFolderRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.File.Folders; + +/// 上传文件到文件夹请求(含 multipart 文件流)。 +public class UploadToFolderRequest +{ + [RouteParam] public string FolderId { get; init; } = default!; + public string FileName { get; init; } = default!; + public IFormFile File { get; init; } = default!; + /// 文件内容哈希(可选),秒传查重用。 + public string? ContentHash { get; init; } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Multipart/AbortMultipartEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Multipart/AbortMultipartEndpoint.cs new file mode 100644 index 0000000..b5573bc --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Multipart/AbortMultipartEndpoint.cs @@ -0,0 +1,24 @@ +using File.Application.Features.Multipart.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Multipart; + + +/// 中止分片上传端点。POST /api/files/multipart/abort。 +[Authorize] +/// +/// undefined +/// +public class AbortMultipartEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/files/multipart/abort"); + } + + public override async Task HandleAsync(AbortMultipartRequest req, CancellationToken ct) + { + await mediator.Send(new AbortMultipartCommand(req.ObjectKey, req.UploadId), ct); + await Send.OkAsync(new { message = "aborted" }, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Multipart/AbortMultipartRequest.cs b/src/BuildFlow.Host/Endpoints/File/Multipart/AbortMultipartRequest.cs new file mode 100644 index 0000000..d7300e9 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Multipart/AbortMultipartRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.File.Multipart; + +/// 中止分片上传请求(对象 key、UploadId)。 +public class AbortMultipartRequest +{ + public string ObjectKey { get; init; } = default!; + public string UploadId { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Multipart/CompleteMultipartEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Multipart/CompleteMultipartEndpoint.cs new file mode 100644 index 0000000..164600e --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Multipart/CompleteMultipartEndpoint.cs @@ -0,0 +1,26 @@ +using File.Application.Features.Multipart.Commands; +using File.Application.Features.Multipart.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Multipart; + + +/// 完成分片上传端点。POST /api/files/multipart/complete。 +[Authorize] +/// +/// undefined +/// +public class CompleteMultipartEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/files/multipart/complete"); + } + + public override async Task HandleAsync(CompleteMultipartRequest req, CancellationToken ct) + { + var parts = req.Parts.Select(p => new CompletedPartDto(p.PartNumber, p.ETag)).ToList(); + var result = await mediator.Send(new CompleteMultipartCommand(req.ObjectKey, req.UploadId, parts, req.FileName, req.Size), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Multipart/CompleteMultipartRequest.cs b/src/BuildFlow.Host/Endpoints/File/Multipart/CompleteMultipartRequest.cs new file mode 100644 index 0000000..18d93f8 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Multipart/CompleteMultipartRequest.cs @@ -0,0 +1,13 @@ +namespace BuildFlow.Host.Endpoints.File.Multipart; + +/// 完成分片上传请求(含各分片信息列表)。 +public class CompleteMultipartRequest +{ + public string ObjectKey { get; init; } = default!; + public string UploadId { get; init; } = default!; + public List Parts { get; init; } = new(); + /// 文件名(可选),完成后落 FileMeta 用,供秒传查重。 + public string? FileName { get; init; } + /// 文件总大小(可选),落 FileMeta 用。 + public long Size { get; init; } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Multipart/InitMultipartEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Multipart/InitMultipartEndpoint.cs new file mode 100644 index 0000000..0173a9c --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Multipart/InitMultipartEndpoint.cs @@ -0,0 +1,25 @@ +using File.Application.Features.Multipart.Commands; +using File.Application.Features.Multipart.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Multipart; + + +/// 初始化分片上传端点。POST /api/files/multipart/init。 +[Authorize] +/// +/// undefined +/// +public class InitMultipartEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/files/multipart/init"); + } + + public override async Task HandleAsync(InitMultipartRequest req, CancellationToken ct) + { + var result = await mediator.Send(new InitMultipartCommand(req.ObjectKey, req.ContentHash, req.TotalParts, req.Size), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Multipart/InitMultipartRequest.cs b/src/BuildFlow.Host/Endpoints/File/Multipart/InitMultipartRequest.cs new file mode 100644 index 0000000..e4a792a --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Multipart/InitMultipartRequest.cs @@ -0,0 +1,14 @@ +namespace BuildFlow.Host.Endpoints.File.Multipart; + +/// 初始化分片上传请求。ContentHash/TotalParts 可选,断点续传时由前端附带。 +public class InitMultipartRequest +{ + /// S3 对象 key(断点续传建议用内容哈希派生稳定值)。 + public string ObjectKey { get; init; } = default!; + /// 文件内容哈希(可选),仅落库记录用。 + public string? ContentHash { get; init; } + /// 预计分片总数(可选),进度参考。 + public int? TotalParts { get; init; } + /// 文件大小(可选),秒传判定用(防哈希碰撞)。 + public long? Size { get; init; } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Multipart/ListPartsEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Multipart/ListPartsEndpoint.cs new file mode 100644 index 0000000..ad33099 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Multipart/ListPartsEndpoint.cs @@ -0,0 +1,27 @@ +using File.Application.Features.Multipart.DTOs; +using File.Application.Features.Multipart.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Multipart; + +/// +/// 查询分片上传已传分片清单端点。GET /api/files/multipart/parts?upload_id=xxx。 +/// 断点续传恢复点:前端续传前调用,据此跳过已传 partNumber。 +/// +[Authorize] +/// +/// undefined +/// +public class ListPartsEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Get("/files/multipart/parts"); + } + + public override async Task HandleAsync(ListPartsRequest req, CancellationToken ct) + { + var result = await mediator.Send(new ListPartsQuery(req.UploadId), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Multipart/ListPartsRequest.cs b/src/BuildFlow.Host/Endpoints/File/Multipart/ListPartsRequest.cs new file mode 100644 index 0000000..e7f0eba --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Multipart/ListPartsRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.File.Multipart; + +/// 查询已传分片清单请求。upload_id 经 query string 传入。 +public class ListPartsRequest +{ + /// 分片上传会话的 S3 UploadId。 + [QueryParam] public string UploadId { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Multipart/PartRequest.cs b/src/BuildFlow.Host/Endpoints/File/Multipart/PartRequest.cs new file mode 100644 index 0000000..eff74e1 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Multipart/PartRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.File.Multipart; + +/// 分片上传的单片信息(CompleteMultipart 时用)。 +public class PartRequest +{ + public int PartNumber { get; init; } + public string ETag { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Multipart/UploadPartEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Multipart/UploadPartEndpoint.cs new file mode 100644 index 0000000..b68ddd8 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Multipart/UploadPartEndpoint.cs @@ -0,0 +1,28 @@ +using File.Application.Features.Multipart.Commands; +using File.Application.Features.Multipart.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Multipart; + + +/// 上传单个分片端点。PUT /api/files/multipart/part。 +[Authorize] +/// +/// undefined +/// +public class UploadPartEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Put("/files/multipart/part"); + AllowFileUploads(); + } + + public override async Task HandleAsync(UploadPartRequest req, CancellationToken ct) + { + await using var stream = req.File.OpenReadStream(); + var result = await mediator.Send(new UploadPartCommand(req.ObjectKey, + req.UploadId, req.PartNumber, stream), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Multipart/UploadPartRequest.cs b/src/BuildFlow.Host/Endpoints/File/Multipart/UploadPartRequest.cs new file mode 100644 index 0000000..a485a12 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Multipart/UploadPartRequest.cs @@ -0,0 +1,10 @@ +namespace BuildFlow.Host.Endpoints.File.Multipart; + +/// 上传单个分片请求(含 multipart 文件流)。 +public class UploadPartRequest +{ + public string ObjectKey { get; init; } = default!; + public string UploadId { get; init; } = default!; + public int PartNumber { get; init; } + public IFormFile File { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Settings/GetFileSettingEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Settings/GetFileSettingEndpoint.cs new file mode 100644 index 0000000..0047109 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Settings/GetFileSettingEndpoint.cs @@ -0,0 +1,18 @@ +using File.Application.Features.Settings.DTOs; +using File.Application.Features.Settings.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Settings; + +/// 查询文件系统设置端点。GET /api/file-settings,返回当前默认存储桶。 +[Authorize] +public class GetFileSettingEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() => Get("/file-settings"); + + public override async Task HandleAsync(EmptyRequest req, CancellationToken ct) + { + var result = await mediator.Send(new GetFileSettingQuery(), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Settings/UpdateDefaultBucketEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Settings/UpdateDefaultBucketEndpoint.cs new file mode 100644 index 0000000..494541a --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Settings/UpdateDefaultBucketEndpoint.cs @@ -0,0 +1,18 @@ +using File.Application.Features.Settings.Commands; +using File.Application.Features.Settings.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Settings; + +/// 更新默认存储桶端点。PUT /api/file-settings/default-bucket。 +[Authorize] +public class UpdateDefaultBucketEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() => Put("/file-settings/default-bucket"); + + public override async Task HandleAsync(UpdateDefaultBucketRequest req, CancellationToken ct) + { + var result = await mediator.Send(new UpdateDefaultBucketCommand(req.DefaultBucket), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Settings/UpdateDefaultBucketRequest.cs b/src/BuildFlow.Host/Endpoints/File/Settings/UpdateDefaultBucketRequest.cs new file mode 100644 index 0000000..5159726 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Settings/UpdateDefaultBucketRequest.cs @@ -0,0 +1,7 @@ +namespace BuildFlow.Host.Endpoints.File.Settings; + +/// 更新默认存储桶请求。 +public class UpdateDefaultBucketRequest +{ + public string DefaultBucket { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Shares/CreateShareEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Shares/CreateShareEndpoint.cs new file mode 100644 index 0000000..7eee996 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Shares/CreateShareEndpoint.cs @@ -0,0 +1,29 @@ +using File.Application.Features.Shares.Commands; +using File.Application.Features.Shares.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Shares; + + +/// 创建分享链接端点。POST /api/share。 +[Authorize] +/// +/// undefined +/// +public class CreateShareEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/share"); + } + + public override async Task HandleAsync(CreateShareRequest req, CancellationToken ct) + { + var expiresAt = string.IsNullOrEmpty(req.ExpiresAt) + ? (DateTime?)null + : DateTime.Parse(req.ExpiresAt, null, System.Globalization.DateTimeStyles.RoundtripKind); + var result = await mediator.Send(new CreateShareCommand(req.ResourceType, + Guid.Parse(req.ResourceId), req.Password, expiresAt, req.MaxDownloads), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Shares/CreateShareRequest.cs b/src/BuildFlow.Host/Endpoints/File/Shares/CreateShareRequest.cs new file mode 100644 index 0000000..11a221b --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Shares/CreateShareRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.File.Shares; + +/// 创建分享请求(资源、密码、过期、下载上限)。 +public class CreateShareRequest +{ + public string ResourceType { get; init; } = default!; + public string ResourceId { get; init; } = default!; + public string? Password { get; init; } + public string? ExpiresAt { get; init; } // ISO 8601 字符串 + public int? MaxDownloads { get; init; } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Shares/DeleteShareEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Shares/DeleteShareEndpoint.cs new file mode 100644 index 0000000..f07deec --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Shares/DeleteShareEndpoint.cs @@ -0,0 +1,24 @@ +using File.Application.Features.Shares.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Shares; + + +/// 删除分享端点。DELETE /api/share/{Id}。 +[Authorize] +/// +/// undefined +/// +public class DeleteShareEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Delete("/share/{Id}"); + } + + public override async Task HandleAsync(DeleteShareRequest req, CancellationToken ct) + { + await mediator.Send(new DeleteShareCommand(Guid.Parse(req.Id)), ct); + await Send.OkAsync(new { message = "deleted" }, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Shares/DeleteShareRequest.cs b/src/BuildFlow.Host/Endpoints/File/Shares/DeleteShareRequest.cs new file mode 100644 index 0000000..88df3d3 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Shares/DeleteShareRequest.cs @@ -0,0 +1,7 @@ +namespace BuildFlow.Host.Endpoints.File.Shares; + +/// 删除分享请求(路由取 Id)。 +public class DeleteShareRequest +{ + [RouteParam] public string Id { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/File/Shares/DownloadShareEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Shares/DownloadShareEndpoint.cs new file mode 100644 index 0000000..3582eda --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Shares/DownloadShareEndpoint.cs @@ -0,0 +1,22 @@ +using File.Application.Features.Shares.DTOs; +using File.Application.Features.Shares.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Shares; + + +/// 下载分享端点(匿名访问)。POST /api/share/{Token}/download。 +public class DownloadShareEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/share/{Token}/download"); + AllowAnonymous(); + } + + public override async Task HandleAsync(DownloadShareRequest req, CancellationToken ct) + { + var result = await mediator.Send(new DownloadShareQuery(req.Token, req.Password), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Shares/DownloadShareRequest.cs b/src/BuildFlow.Host/Endpoints/File/Shares/DownloadShareRequest.cs new file mode 100644 index 0000000..a3d7baf --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Shares/DownloadShareRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.File.Shares; + +/// 下载分享请求(Token 与可选密码)。 +public class DownloadShareRequest +{ + [RouteParam] public string Token { get; init; } = default!; + public string? Password { get; init; } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Shares/GetShareInfoEndpoint.cs b/src/BuildFlow.Host/Endpoints/File/Shares/GetShareInfoEndpoint.cs new file mode 100644 index 0000000..9a89c48 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Shares/GetShareInfoEndpoint.cs @@ -0,0 +1,21 @@ +using File.Application.Features.Shares.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.File.Shares; + + +/// 查询分享信息端点(匿名访问)。GET /api/share/{Token}。 +public class GetShareInfoEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Get("/share/{Token}"); + AllowAnonymous(); + } + + public override async Task HandleAsync(GetShareInfoRequest req, CancellationToken ct) + { + var result = await mediator.Send(new GetShareInfoQuery(req.Token), ct); + await Send.OkAsync(result!, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/File/Shares/GetShareInfoRequest.cs b/src/BuildFlow.Host/Endpoints/File/Shares/GetShareInfoRequest.cs new file mode 100644 index 0000000..d0f9f08 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/File/Shares/GetShareInfoRequest.cs @@ -0,0 +1,7 @@ +namespace BuildFlow.Host.Endpoints.File.Shares; + +/// 查询分享信息请求(路由取 Token)。 +public class GetShareInfoRequest +{ + [RouteParam] public string Token { get; init; } = default!; +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/AddGroupMemberEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/AddGroupMemberEndpoint.cs new file mode 100644 index 0000000..82a43f3 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/AddGroupMemberEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + + +/// +/// 批量添加群成员端点。POST /groups/{GroupId}/members。 +/// +public class AddGroupMemberEndpoint(IMediator mediator, ICurrentUserContext userContext) : Endpoint +{ + public override void Configure() + { + Post("/groups/{GroupId}/members"); + Permissions("im:group:manage"); + } + + public override async Task HandleAsync(AddGroupMemberEndpointRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + await mediator.Send(new AddGroupMemberCommand(req.GroupId, userId, req.UserIds), ct); + HttpContext.Response.StatusCode = 204; + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/AddGroupMemberEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/AddGroupMemberEndpointRequest.cs new file mode 100644 index 0000000..6c7ead5 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/AddGroupMemberEndpointRequest.cs @@ -0,0 +1,6 @@ +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 批量添加群成员请求体。 +/// +public record AddGroupMemberEndpointRequest(Guid GroupId, List UserIds); diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/CreateGroupEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/CreateGroupEndpoint.cs new file mode 100644 index 0000000..f3b8c7b --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/CreateGroupEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.Commands; +using IM.Application.Chat.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 创建群组端点。POST /groups。 +/// +public class CreateGroupEndpoint(IMediator mediator, ICurrentUserContext userContext) : Endpoint +{ + public override void Configure() + { + Post("/groups"); + Permissions("im:group:create"); + } + + public override async Task HandleAsync(CreateGroupRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + var result = await mediator.Send(new CreateGroupCommand(req.Name, req.Avatar, req.Description, userId, req.MemberUserIds), ct); + await Send.ResponseAsync(result, 201, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/CreatePrivateConversationEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/CreatePrivateConversationEndpoint.cs new file mode 100644 index 0000000..8377fd9 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/CreatePrivateConversationEndpoint.cs @@ -0,0 +1,28 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.Commands; +using IM.Application.Chat.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 创建或复用私聊会话。若当前用户与目标用户间已存在私聊会话则直接返回,保证幂等。 +/// +public class CreatePrivateConversationEndpoint( + IMediator mediator, + ICurrentUserContext userContext) : Endpoint +{ + public override void Configure() + { + Post("/conversations/private"); + Permissions("im:chat"); + } + + public override async Task HandleAsync(CreatePrivateConversationRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + var result = await mediator.Send( + new CreatePrivateConversationCommand(userId, req.TargetUserId), ct); + await Send.ResponseAsync(result, 200, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/DeleteGroupEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/DeleteGroupEndpoint.cs new file mode 100644 index 0000000..e1d8e43 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/DeleteGroupEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + + +/// +/// 解散群组端点。DELETE /groups/{GroupId}。 +/// +public class DeleteGroupEndpoint(IMediator mediator, ICurrentUserContext userContext) : Endpoint +{ + public override void Configure() + { + Delete("/groups/{GroupId}"); + Permissions("im:group:manage"); + } + + public override async Task HandleAsync(DeleteGroupEndpointRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + await mediator.Send(new DeleteGroupCommand(req.GroupId, userId), ct); + HttpContext.Response.StatusCode = 204; + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/DeleteGroupEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/DeleteGroupEndpointRequest.cs new file mode 100644 index 0000000..26fba49 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/DeleteGroupEndpointRequest.cs @@ -0,0 +1,6 @@ +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 解散群组请求体(路由参数绑定)。 +/// +public record DeleteGroupEndpointRequest(Guid GroupId); diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/GetConversationsEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/GetConversationsEndpoint.cs new file mode 100644 index 0000000..a914eb6 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/GetConversationsEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.DTOs; +using IM.Application.Chat.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 查询用户会话列表端点。GET /conversations。 +/// +public class GetConversationsEndpoint(IMediator mediator, ICurrentUserContext userContext) : EndpointWithoutRequest> +{ + public override void Configure() + { + Get("/conversations"); + Permissions("im:read"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + var result = await mediator.Send(new GetConversationsQuery(userId), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupEndpoint.cs new file mode 100644 index 0000000..e464c56 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.DTOs; +using IM.Application.Chat.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 查询单个群详情(含公告/成员数)。 +/// +public class GetGroupEndpoint(IMediator mediator, ICurrentUserContext userContext) : Endpoint +{ + public override void Configure() + { + Get("/groups/{GroupId}"); + Permissions("im:read"); + } + + public override async Task HandleAsync(GetGroupEndpointRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + var result = await mediator.Send(new GetGroupQuery(req.GroupId, userId), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupEndpointRequest.cs new file mode 100644 index 0000000..94501a9 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupEndpointRequest.cs @@ -0,0 +1,4 @@ +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// 查询群详情请求。GroupId 由路由参数绑定。 +public record GetGroupEndpointRequest(Guid GroupId); diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupMembersEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupMembersEndpoint.cs new file mode 100644 index 0000000..d8fcc6c --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupMembersEndpoint.cs @@ -0,0 +1,26 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.DTOs; +using IM.Application.Chat.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + + +/// +/// 查询群成员列表端点。GET /groups/{GroupId}/members。 +/// +public class GetGroupMembersEndpoint(IMediator mediator, ICurrentUserContext userContext) : Endpoint> +{ + public override void Configure() + { + Get("/groups/{GroupId}/members"); + Permissions("im:read"); + } + + public override async Task HandleAsync(GetGroupMembersEndpointRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + var result = await mediator.Send(new GetGroupMembersQuery(userId, req.GroupId), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupMembersEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupMembersEndpointRequest.cs new file mode 100644 index 0000000..92556b3 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/GetGroupMembersEndpointRequest.cs @@ -0,0 +1,6 @@ +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 群成员列表查询请求体(路由参数绑定)。 +/// +public record GetGroupMembersEndpointRequest(Guid GroupId); diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/GetMessageHistoryEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/GetMessageHistoryEndpoint.cs new file mode 100644 index 0000000..47c07e5 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/GetMessageHistoryEndpoint.cs @@ -0,0 +1,27 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.DTOs; +using IM.Application.Chat.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + + +/// +/// 查询历史消息端点。GET /conversations/{ConversationId}/messages。 +/// +public class GetMessageHistoryEndpoint(IMediator mediator, ICurrentUserContext userContext) : Endpoint +{ + public override void Configure() + { + Get("/conversations/{ConversationId}/messages"); + Permissions("im:read"); + } + + public override async Task HandleAsync(GetMessageHistoryRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + var result = await mediator.Send( + new GetMessageHistoryQuery(userId, req.ConversationId, req.BeforeId, req.Limit), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/GetMessageHistoryRequest.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/GetMessageHistoryRequest.cs new file mode 100644 index 0000000..a4fad1d --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/GetMessageHistoryRequest.cs @@ -0,0 +1,6 @@ +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 历史消息查询请求体。含游标与分页大小。 +/// +public record GetMessageHistoryRequest(Guid ConversationId, string? BeforeId, int Limit = 50); diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/GetUnreadCountEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/GetUnreadCountEndpoint.cs new file mode 100644 index 0000000..231954e --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/GetUnreadCountEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.DTOs; +using IM.Application.Chat.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 查询未读消息数端点。GET /conversations/unread。 +/// +public class GetUnreadCountEndpoint(IMediator mediator, ICurrentUserContext userContext) : EndpointWithoutRequest +{ + public override void Configure() + { + Get("/unread"); + Permissions("im:read"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + var result = await mediator.Send(new GetUnreadCountQuery(userId), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/MarkConversationUnreadEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/MarkConversationUnreadEndpoint.cs new file mode 100644 index 0000000..07a630a --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/MarkConversationUnreadEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 标记会话未读端点。POST /conversations/{ConversationId}/unread。 +/// +public class MarkConversationUnreadEndpoint(IMediator mediator, ICurrentUserContext userContext) : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/conversations/{ConversationId}/unread"); + Permissions("im:conversation:manage"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + var conversationId = Route("ConversationId"); + await mediator.Send(new MarkConversationUnreadCommand(conversationId, userId), ct); + await Send.OkAsync(ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/RecallMessageEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/RecallMessageEndpoint.cs new file mode 100644 index 0000000..3d9b69b --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/RecallMessageEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 撤回消息 REST 端点(SignalR 的非实时兜底通道)。 +/// 权限与时间窗校验在 RecallMessageCommandHandler 内统一执行。 +/// +public class RecallMessageEndpoint(IMediator mediator, ICurrentUserContext userContext) : Endpoint +{ + public override void Configure() + { + Post("/conversations/{ConversationId}/messages/{MessageId}/recall"); + Permissions("im:chat"); + } + + public override async Task HandleAsync(RecallMessageEndpointRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + await mediator.Send(new RecallMessageCommand(req.ConversationId, req.MessageId, userId), ct); + await Send.OkAsync(ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/RecallMessageEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/RecallMessageEndpointRequest.cs new file mode 100644 index 0000000..b3b0731 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/RecallMessageEndpointRequest.cs @@ -0,0 +1,4 @@ +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// 撤回消息请求。ConversationId 与 MessageId 由路由参数绑定。 +public record RecallMessageEndpointRequest(Guid ConversationId, string MessageId); diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/RemoveGroupMemberEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/RemoveGroupMemberEndpoint.cs new file mode 100644 index 0000000..55be69f --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/RemoveGroupMemberEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + + +/// +/// 移除群成员端点。DELETE /groups/{GroupId}/members/{UserId}。 +/// +public class RemoveGroupMemberEndpoint(IMediator mediator, ICurrentUserContext userContext) : Endpoint +{ + public override void Configure() + { + Delete("/groups/{GroupId}/members/{TargetUserId}"); + Permissions("im:group:manage"); + } + + public override async Task HandleAsync(RemoveGroupMemberEndpointRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + await mediator.Send(new RemoveGroupMemberCommand(req.GroupId, userId, req.TargetUserId), ct); + HttpContext.Response.StatusCode = 204; + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/RemoveGroupMemberEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/RemoveGroupMemberEndpointRequest.cs new file mode 100644 index 0000000..925e5c2 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/RemoveGroupMemberEndpointRequest.cs @@ -0,0 +1,6 @@ +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 移除群成员请求体(路由参数绑定)。 +/// +public record RemoveGroupMemberEndpointRequest(Guid GroupId, Guid TargetUserId); diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationMutedEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationMutedEndpoint.cs new file mode 100644 index 0000000..a6471de --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationMutedEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 设置会话免打扰端点。PUT /conversations/{ConversationId}/muted。 +/// +public class SetConversationMutedEndpoint(IMediator mediator, ICurrentUserContext userContext) : Endpoint +{ + public override void Configure() + { + Put("/conversations/{ConversationId}/muted"); + Permissions("im:conversation:manage"); + } + + public override async Task HandleAsync(SetConversationStateRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + var conversationId = Route("ConversationId"); + await mediator.Send(new SetConversationMutedCommand(conversationId, userId, req.Value), ct); + await Send.OkAsync(ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationPinnedEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationPinnedEndpoint.cs new file mode 100644 index 0000000..b402831 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationPinnedEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 设置会话置顶端点。PUT /conversations/{ConversationId}/pinned。 +/// +public class SetConversationPinnedEndpoint(IMediator mediator, ICurrentUserContext userContext) : Endpoint +{ + public override void Configure() + { + Put("/conversations/{ConversationId}/pinned"); + Permissions("im:conversation:manage"); + } + + public override async Task HandleAsync(SetConversationStateRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + var conversationId = Route("ConversationId"); + await mediator.Send(new SetConversationPinnedCommand(conversationId, userId, req.Value), ct); + await Send.OkAsync(ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationRemarkEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationRemarkEndpoint.cs new file mode 100644 index 0000000..6c50672 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationRemarkEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 设置会话备注名端点。PUT /conversations/{ConversationId}/remark。 +/// +public class SetConversationRemarkEndpoint(IMediator mediator, ICurrentUserContext userContext) : Endpoint +{ + public override void Configure() + { + Put("/conversations/{ConversationId}/remark"); + Permissions("im:conversation:manage"); + } + + public override async Task HandleAsync(SetConversationRemarkEndpointRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + var conversationId = Route("ConversationId"); + await mediator.Send(new SetConversationRemarkCommand(conversationId, userId, req.Remark), ct); + await Send.OkAsync(ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationRemarkEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationRemarkEndpointRequest.cs new file mode 100644 index 0000000..3cfaa61 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationRemarkEndpointRequest.cs @@ -0,0 +1,6 @@ +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 设置会话备注名请求体。Remark 为空或 null 表示清除备注。 +/// +public record SetConversationRemarkEndpointRequest(string? Remark); diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationStateRequest.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationStateRequest.cs new file mode 100644 index 0000000..6a5ea5e --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/SetConversationStateRequest.cs @@ -0,0 +1,6 @@ +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 设置会话置顶/免打扰状态的请求体。isPinned 与 isMuted 不同时使用,视端点语义而定。 +/// +public record SetConversationStateRequest(bool Value); diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/UpdateGroupEndpoint.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/UpdateGroupEndpoint.cs new file mode 100644 index 0000000..c3512f3 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/UpdateGroupEndpoint.cs @@ -0,0 +1,26 @@ +using BuildFlow.Shared.Domain.Common; +using IM.Application.Chat.Commands; +using IM.Application.Chat.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.IM.Chat; + + +/// +/// 更新群信息端点。PUT /groups/{GroupId}。 +/// +public class UpdateGroupEndpoint(IMediator mediator, ICurrentUserContext userContext) : Endpoint +{ + public override void Configure() + { + Put("/groups/{GroupId}"); + Permissions("im:group:manage"); + } + + public override async Task HandleAsync(UpdateGroupEndpointRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserGuid(); + var result = await mediator.Send(new UpdateGroupCommand(req.GroupId, userId, req.Name, req.Avatar, req.Description, req.Announcement), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/IM/Chat/UpdateGroupEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/IM/Chat/UpdateGroupEndpointRequest.cs new file mode 100644 index 0000000..79e6d65 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/IM/Chat/UpdateGroupEndpointRequest.cs @@ -0,0 +1,6 @@ +namespace BuildFlow.Host.Endpoints.IM.Chat; + +/// +/// 更新群信息请求体。 +/// +public record UpdateGroupEndpointRequest(Guid GroupId, string? Name, string? Avatar, string? Description, string? Announcement = null); diff --git a/src/BuildFlow.Host/Endpoints/Platform/Auth/ChangePasswordEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Auth/ChangePasswordEndpoint.cs new file mode 100644 index 0000000..19b45b8 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Auth/ChangePasswordEndpoint.cs @@ -0,0 +1,44 @@ +using BuildFlow.Platform.Infrastructure.Persistence; +using BuildFlow.Shared.Domain.Common; + +namespace BuildFlow.Host.Endpoints.Platform.Auth; + +/// +/// 修改当前用户密码。验证旧密码后更新为新密码。 +/// POST /api/user/change-password +/// +public class ChangePasswordEndpoint(PlatformDbContext db, ICurrentUserContext userContext) + : Endpoint +{ + public override void Configure() + { + Post("/user/change-password"); + } + + public override async Task HandleAsync(ChangePasswordRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserId(); + + var user = await db.Users + .FirstOrDefaultAsync(u => u.Id.ToString() == userId, ct) + ?? throw new UnauthorizedException("用户不存在"); + + // 验证旧密码 + if (!BCrypt.Net.BCrypt.Verify(req.OldPassword, user.PasswordHash)) + { + throw new BusinessException("旧密码不正确"); + } + + // 新密码不能与旧密码相同 + if (req.OldPassword == req.NewPassword) + { + throw new BusinessException("新密码不能与旧密码相同"); + } + + // 更新密码 + user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(req.NewPassword); + await db.SaveChangesAsync(ct); + + await Send.OkAsync(ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Auth/ChangePasswordRequest.cs b/src/BuildFlow.Host/Endpoints/Platform/Auth/ChangePasswordRequest.cs new file mode 100644 index 0000000..d8fa9e0 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Auth/ChangePasswordRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.Platform.Auth; + +/// 修改密码请求。包含旧密码(用于二次校验)与新密码。 +public class ChangePasswordRequest +{ + /// 旧密码(登录态下二次校验,防止会话被劫持后改密)。 + public string OldPassword { get; set; } = string.Empty; + + /// 新密码(明文传入,服务端 BCrypt 哈希后存储)。 + public string NewPassword { get; set; } = string.Empty; +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Auth/GetAccessCodesEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Auth/GetAccessCodesEndpoint.cs new file mode 100644 index 0000000..41a0b20 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Auth/GetAccessCodesEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Platform.Application.Auth.Queries; +using BuildFlow.Shared.Domain.Common; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Auth; + +/// +/// 获取当前用户的权限码列表。前端据此渲染按钮/菜单的可见性(细粒度前端权限控制)。 +/// 鉴权通过 GetRequiredUserId 强制——未登录直接抛 401。 +/// +public class GetAccessCodesEndpoint(IMediator mediator, ICurrentUserContext userContext) : EndpointWithoutRequest> +{ + public override void Configure() + { + Get("/auth/codes"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var userId = userContext.GetRequiredUserId(); + var codes = await mediator.Send(new GetAccessCodesQuery(userId), ct); + await Send.OkAsync(codes, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Auth/GetCurrentUserEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Auth/GetCurrentUserEndpoint.cs new file mode 100644 index 0000000..3f6828b --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Auth/GetCurrentUserEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Platform.Application.Auth.Queries; +using BuildFlow.Shared.Domain.Common; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Auth; + +/// +/// 获取当前登录用户信息端点。前端登录后调用以填充用户菜单、权限、头像。 +/// GetRequiredUserId 在未登录时抛 UnauthorizedException,等同强制鉴权(无需显式 Permissions)。 +/// +public class GetCurrentUserEndpoint(IMediator mediator, ICurrentUserContext userContext) : EndpointWithoutRequest +{ + public override void Configure() + { + Get("/user/info"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var userId = userContext.GetRequiredUserId(); + var result = await mediator.Send(new GetCurrentUserQuery(userId), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Auth/LoginEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Auth/LoginEndpoint.cs new file mode 100644 index 0000000..96dc332 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Auth/LoginEndpoint.cs @@ -0,0 +1,37 @@ +using BuildFlow.Platform.Application.Auth.Commands; +using BuildFlow.Platform.Application.Auth.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Auth; + + +/// +/// 登录端点。 +/// +public class LoginEndpoint(IMediator mediator, IConfiguration config) : Endpoint +{ + public override void Configure() + { + Post("/auth/login"); + AllowAnonymous(); + } + + public override async Task HandleAsync(LoginRequest req, CancellationToken ct) + { + var result = await mediator.Send(new LoginCommand(req.Username, req.Password), ct); + + // refresh_token 写入 HttpOnly Cookie:浏览器自动随请求带上,前端 JS 不可读,防 XSS + HttpContext.Response.Cookies.Append("jwt", result.RefreshToken, new CookieOptions + { + HttpOnly = true, + Secure = config.GetValue("Cookie:Secure"), + SameSite = SameSiteMode.Lax, + Expires = DateTimeOffset.UtcNow.AddDays(7), + Path = "/" + }); + + await Send.OkAsync(result, ct); + } +} + +/// 登录请求校验。规则与 LoginCommandValidator 一致,HTTP 入口层提前拦截非法输入。 diff --git a/src/BuildFlow.Host/Endpoints/Platform/Auth/LoginRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Auth/LoginRequestValidator.cs new file mode 100644 index 0000000..45d0c22 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Auth/LoginRequestValidator.cs @@ -0,0 +1,21 @@ +using BuildFlow.Platform.Application.Auth.DTOs; + +namespace BuildFlow.Host.Endpoints.Platform.Auth; + +/// +/// 登录Request的请求校验器(FluentValidation)。 +/// +public class LoginRequestValidator : Validator +{ + public LoginRequestValidator() + { + RuleFor(x => x.Username) + .NotEmpty().WithMessage("用户名不能为空") + .MaximumLength(50).WithMessage("用户名长度不能超过 50 个字符") + .Must(u => u == u.Trim()).WithMessage("用户名前后不能有空格"); + + RuleFor(x => x.Password) + .NotEmpty().WithMessage("密码不能为空") + .MaximumLength(100).WithMessage("密码长度不能超过 100 个字符"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Auth/LogoutEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Auth/LogoutEndpoint.cs new file mode 100644 index 0000000..6a91578 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Auth/LogoutEndpoint.cs @@ -0,0 +1,33 @@ +using BuildFlow.Platform.Application.Auth.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Auth; + +/// +/// 登出接口:撤销 refresh token 并清除 jwt Cookie。 +/// 前端通过 baseRequestClient 调用(withCredentials: true 发送 Cookie)。 +/// +public class LogoutEndpoint(IMediator mediator) : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/auth/logout"); + AllowAnonymous(); + } + + public override async Task HandleAsync(CancellationToken ct) + { + // 从 Cookie 中读取 refresh token + var refreshToken = HttpContext.Request.Cookies["jwt"]; + + if (!string.IsNullOrEmpty(refreshToken)) + { + await mediator.Send(new LogoutCommand(refreshToken), ct); + } + + // 清除 Cookie + HttpContext.Response.Cookies.Delete("jwt"); + + await Send.OkAsync(string.Empty, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Auth/RefreshTokenEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Auth/RefreshTokenEndpoint.cs new file mode 100644 index 0000000..f420b50 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Auth/RefreshTokenEndpoint.cs @@ -0,0 +1,41 @@ +using BuildFlow.Platform.Application.Auth.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Auth; + +/// +/// 刷新令牌端点。从 HttpOnly Cookie 读 refresh_token(前端无法读取,只能由浏览器自动随请求带上), +/// 换取新 access_token 以纯文本响应(被 ApiResponseMiddleware 列入 ExcludedPaths 不包裹)。 +/// ExcludeFromDescription 避免 Swagger 暴露此内部接口。 +/// +public class RefreshTokenEndpoint(IMediator mediator, IConfiguration config) : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/auth/refresh"); + AllowAnonymous(); + Options(b => b.ExcludeFromDescription()); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var refreshToken = HttpContext.Request.Cookies["jwt"] + ?? throw new UnauthorizedException("缺少刷新令牌"); + + var result = await mediator.Send(new RefreshTokenCommand(refreshToken), ct); + + // 新 refresh_token 写回 Cookie(Rotation:旧 token 已在 Handler 中作废) + HttpContext.Response.Cookies.Append("jwt", result.RefreshToken, new CookieOptions + { + HttpOnly = true, + Secure = config.GetValue("Cookie:Secure"), + SameSite = SameSiteMode.Lax, + Expires = DateTimeOffset.UtcNow.AddDays(7), + Path = "/" + }); + + // 用 FastEndpoints 的 Send.StringAsync 返回纯文本 access token。 + // 之前用 HttpContext.Response.WriteAsync 被 FastEndpoints 管线覆盖成 204 空响应。 + await Send.StringAsync(result.AccessToken, 200, "text/plain; charset=utf-8", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Auth/RegisterEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Auth/RegisterEndpoint.cs new file mode 100644 index 0000000..c19e6bc --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Auth/RegisterEndpoint.cs @@ -0,0 +1,26 @@ +using BuildFlow.Platform.Application.Auth.Commands; +using BuildFlow.Platform.Application.Auth.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Auth; + + +/// +/// 注册端点。 +/// +public class RegisterEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/auth/register"); + AllowAnonymous(); + } + + public override async Task HandleAsync(RegisterRequest req, CancellationToken ct) + { + await mediator.Send(new RegisterCommand(req.Username, req.Email, req.Password), ct); + await Send.OkAsync(true, ct); + } +} + +/// 自助注册请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/Platform/Auth/RegisterRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Auth/RegisterRequestValidator.cs new file mode 100644 index 0000000..124cfd2 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Auth/RegisterRequestValidator.cs @@ -0,0 +1,24 @@ +using BuildFlow.Platform.Application.Auth.DTOs; + +namespace BuildFlow.Host.Endpoints.Platform.Auth; + +/// +/// 注册Request的请求校验器(FluentValidation)。 +/// +public class RegisterRequestValidator : Validator +{ + public RegisterRequestValidator() + { + RuleFor(x => x.Username) + .NotEmpty().WithMessage("用户名不能为空") + .Length(3, 50).WithMessage("用户名长度 3-50 个字符"); + + RuleFor(x => x.Email) + .NotEmpty().WithMessage("邮箱不能为空") + .EmailAddress().WithMessage("邮箱格式不正确"); + + RuleFor(x => x.Password) + .NotEmpty().WithMessage("密码不能为空") + .Length(6, 100).WithMessage("密码长度 6-100 个字符"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Auth/RevokeTokenEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Auth/RevokeTokenEndpoint.cs new file mode 100644 index 0000000..b3970cd --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Auth/RevokeTokenEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Platform.Application.Auth.Commands; +using BuildFlow.Platform.Application.Auth.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Auth; + + +/// +/// 吊销令牌端点。 +/// +public class RevokeTokenEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/auth/revoke"); + } + + public override async Task HandleAsync(RevokeTokenRequest req, CancellationToken ct) + { + await mediator.Send(new RevokeTokenCommand(req.RefreshToken), ct); + await Send.OkAsync(true, ct); + } +} + +/// 吊销刷新令牌请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/Platform/Auth/RevokeTokenRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Auth/RevokeTokenRequestValidator.cs new file mode 100644 index 0000000..5af69a8 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Auth/RevokeTokenRequestValidator.cs @@ -0,0 +1,15 @@ +using BuildFlow.Platform.Application.Auth.DTOs; + +namespace BuildFlow.Host.Endpoints.Platform.Auth; + +/// +/// 吊销令牌Request的请求校验器(FluentValidation)。 +/// +public class RevokeTokenRequestValidator : Validator +{ + public RevokeTokenRequestValidator() + { + RuleFor(x => x.RefreshToken) + .NotEmpty().WithMessage("RefreshToken 不能为空"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Auth/UpdateProfileEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Auth/UpdateProfileEndpoint.cs new file mode 100644 index 0000000..d9b50f4 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Auth/UpdateProfileEndpoint.cs @@ -0,0 +1,31 @@ +using BuildFlow.Platform.Application.Auth.Commands; +using BuildFlow.Platform.Application.Auth.Queries; +using BuildFlow.Shared.Domain.Common; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Auth; + +/// +/// 更新当前用户个人资料(姓名、头像、简介)。 +/// PUT /api/user/profile +/// +public class UpdateProfileEndpoint(IMediator mediator, ICurrentUserContext userContext) + : Endpoint +{ + public override void Configure() + { + Put("/user/profile"); + } + + public override async Task HandleAsync(UpdateProfileRequest req, CancellationToken ct) + { + var userId = userContext.GetRequiredUserId(); + var result = await mediator.Send(new UpdateProfileCommand( + UserId: userId, + RealName: req.RealName, + Avatar: req.Avatar, + Description: req.Description), ct); + + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Auth/UpdateProfileRequest.cs b/src/BuildFlow.Host/Endpoints/Platform/Auth/UpdateProfileRequest.cs new file mode 100644 index 0000000..0e3526d --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Auth/UpdateProfileRequest.cs @@ -0,0 +1,14 @@ +namespace BuildFlow.Host.Endpoints.Platform.Auth; + +/// 更新个人资料请求。三个字段均可选,仅更新非 null 的字段。 +public class UpdateProfileRequest +{ + /// 真实姓名(可选)。 + public string? RealName { get; set; } + + /// 头像 URL(可选)。 + public string? Avatar { get; set; } + + /// 个人简介(可选)。 + public string? Description { get; set; } +} 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..45500d4 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Menus/CreateMenuEndpoint.cs @@ -0,0 +1,42 @@ +using BuildFlow.Platform.Application.Menus.Commands; +using BuildFlow.Platform.Application.Menus.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.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, + Code = req.Code, + 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..c50a0e5 --- /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.Platform.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..3c9dc56 --- /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.Platform.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..758c710 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Menus/DeleteMenuEndpointRequest.cs @@ -0,0 +1,6 @@ +namespace BuildFlow.Host.Endpoints.Platform.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..296a62d --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Menus/DeleteMenuEndpointRequestValidator.cs @@ -0,0 +1,12 @@ +namespace BuildFlow.Host.Endpoints.Platform.Menus; + +/// +/// 删除菜单请求校验。 +/// +public class DeleteMenuEndpointRequestValidator : Validator +{ + public DeleteMenuEndpointRequestValidator() + { + RuleFor(x => x.Id).NotEmpty().WithMessage("菜单 ID 不能为空"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Menus/GetAllMenusEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Menus/GetAllMenusEndpoint.cs new file mode 100644 index 0000000..7cba30b --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Menus/GetAllMenusEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Platform.Application.Menus.DTOs; +using BuildFlow.Platform.Application.Menus.Queries; +using BuildFlow.Shared.Domain.Common; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Menus; + +/// +/// GetAll菜单s端点。 +/// +public class GetAllMenusEndpoint(IMediator mediator, ICurrentUserContext userContext) : EndpointWithoutRequest> +{ + public override void Configure() + { + Get("/menu/all"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var userId = userContext.GetRequiredUserId(); + var menus = await mediator.Send(new GetAllMenusQuery(userId), ct); + await Send.OkAsync(menus, ct); + } +} 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..90a03de --- /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.Platform.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..0bb4039 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Menus/GetMenuByIdRequest.cs @@ -0,0 +1,6 @@ +namespace BuildFlow.Host.Endpoints.Platform.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..dc8dfaf --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Menus/GetMenuByIdRequestValidator.cs @@ -0,0 +1,12 @@ +namespace BuildFlow.Host.Endpoints.Platform.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..b708816 --- /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.Platform.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/SortMenusEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Menus/SortMenusEndpoint.cs new file mode 100644 index 0000000..ffcb3b0 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Menus/SortMenusEndpoint.cs @@ -0,0 +1,27 @@ +using BuildFlow.Platform.Application.Menus.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Menus; + +/// +/// 批量排序菜单端点。供菜单管理页拖拽排序(同级调整 + 跨层级移动)落库使用。 +/// 路由 PUT /menus/sort,需 menu:update 权限,事务内原子更新多个菜单的 ParentId 与 Order。 +/// +public class SortMenusEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Put("/menus/sort"); + Permissions("menu:update"); + } + + public override async Task HandleAsync(SortMenusEndpointRequest req, CancellationToken ct) + { + var items = req.Items + .Select(i => new MenuSortItem(i.Id, i.ParentId, i.Order)) + .ToList(); + + var affected = await mediator.Send(new SortMenusCommand(items), ct); + await Send.OkAsync(affected, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Menus/SortMenusEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/Platform/Menus/SortMenusEndpointRequest.cs new file mode 100644 index 0000000..0fe475d --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Menus/SortMenusEndpointRequest.cs @@ -0,0 +1,14 @@ +namespace BuildFlow.Host.Endpoints.Platform.Menus; + +/// +/// 批量排序菜单请求体。 +/// +public record SortMenusEndpointRequest(List Items); + +/// +/// 排序单项 DTO。与后端 MenuSortItem 对应。 +/// +/// 被排序菜单主键。 +/// 目标父菜单 Id,null 表示顶级菜单。 +/// 同级内序号(从 0 开始)。 +public record MenuSortItemDto(Guid Id, Guid? ParentId, int Order); diff --git a/src/BuildFlow.Host/Endpoints/Platform/Menus/SortMenusEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Menus/SortMenusEndpointRequestValidator.cs new file mode 100644 index 0000000..0a9ad96 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Menus/SortMenusEndpointRequestValidator.cs @@ -0,0 +1,16 @@ +namespace BuildFlow.Host.Endpoints.Platform.Menus; + +/// +/// 批量排序菜单请求校验。 +/// +public class SortMenusEndpointRequestValidator : Validator +{ + public SortMenusEndpointRequestValidator() + { + RuleFor(x => x.Items).NotEmpty().WithMessage("排序项不能为空"); + RuleForEach(x => x.Items).ChildRules(item => + { + item.RuleFor(i => i.Id).NotEmpty().WithMessage("菜单 ID 不能为空"); + }); + } +} 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..c6702da --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Menus/UpdateMenuEndpoint.cs @@ -0,0 +1,43 @@ +using BuildFlow.Platform.Application.Menus.Commands; +using BuildFlow.Platform.Application.Menus.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.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, + Code = req.Code, + 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..d53bbf4 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Menus/UpdateMenuEndpointRequest.cs @@ -0,0 +1,24 @@ +namespace BuildFlow.Host.Endpoints.Platform.Menus; + +/// +/// 更新菜单请求体。携带路由 Id。 +/// +public record UpdateMenuEndpointRequest( + Guid Id, + Guid? ParentId, + string? Name, + string? Path, + string? Component, + string? Redirect, + string? Title, + string? Code, + 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..ed6a750 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Menus/UpdateMenuEndpointRequestValidator.cs @@ -0,0 +1,20 @@ +namespace BuildFlow.Host.Endpoints.Platform.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/Platform/Notifications/GetNotificationsEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Notifications/GetNotificationsEndpoint.cs new file mode 100644 index 0000000..3e94b49 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Notifications/GetNotificationsEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Platform.Application.Notifications.DTOs; +using BuildFlow.Platform.Application.Notifications.Queries; +using BuildFlow.Shared.Domain.Common; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Notifications; + +/// 获取当前用户的通知列表(分页,可只看未读)。 +public class GetNotificationsEndpoint(IMediator mediator, ICurrentUserContext userContext) + : Endpoint> +{ + public override void Configure() + { + Get("/notifications"); + } + + public override async Task HandleAsync(GetNotificationsRequest req, CancellationToken ct) + { + var userId = userContext.GetRecipientId(); + var result = await mediator.Send( + new GetNotificationsQuery(userId, req.UnreadOnly, req.PageIndex, req.PageSize), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Notifications/GetNotificationsRequest.cs b/src/BuildFlow.Host/Endpoints/Platform/Notifications/GetNotificationsRequest.cs new file mode 100644 index 0000000..cf5bf58 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Notifications/GetNotificationsRequest.cs @@ -0,0 +1,13 @@ +namespace BuildFlow.Host.Endpoints.Platform.Notifications; + +/// +/// Get通知s请求体。 +/// +public record GetNotificationsRequest +{ + public bool UnreadOnly { get; init; } + public int PageIndex { get; init; } = 1; + public int PageSize { get; init; } = 20; +} + +/// 查询通知列表请求校验(分页参数取值范围)。 diff --git a/src/BuildFlow.Host/Endpoints/Platform/Notifications/GetNotificationsRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Notifications/GetNotificationsRequestValidator.cs new file mode 100644 index 0000000..f5c590a --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Notifications/GetNotificationsRequestValidator.cs @@ -0,0 +1,16 @@ +namespace BuildFlow.Host.Endpoints.Platform.Notifications; + +/// +/// Get通知sRequest的请求校验器(FluentValidation)。 +/// +public class GetNotificationsRequestValidator : Validator +{ + public GetNotificationsRequestValidator() + { + RuleFor(x => x.PageIndex) + .InclusiveBetween(1, 1000).WithMessage("页码 PageIndex 取值范围 1-1000"); + + RuleFor(x => x.PageSize) + .InclusiveBetween(1, 100).WithMessage("每页数量 PageSize 取值范围 1-100"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Notifications/GetUnreadNotificationCountEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Notifications/GetUnreadNotificationCountEndpoint.cs new file mode 100644 index 0000000..c212c91 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Notifications/GetUnreadNotificationCountEndpoint.cs @@ -0,0 +1,22 @@ +using BuildFlow.Platform.Application.Notifications.Queries; +using BuildFlow.Shared.Domain.Common; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Notifications; + +/// 获取当前用户未读通知数(前端铃铛角标)。 +public class GetUnreadNotificationCountEndpoint(IMediator mediator, ICurrentUserContext userContext) + : EndpointWithoutRequest +{ + public override void Configure() + { + Get("/notifications/unread-count"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var userId = userContext.GetRecipientId(); + var count = await mediator.Send(new GetUnreadNotificationCountQuery(userId), ct); + await Send.OkAsync(count, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Notifications/MarkAllNotificationsReadEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Notifications/MarkAllNotificationsReadEndpoint.cs new file mode 100644 index 0000000..2f028e6 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Notifications/MarkAllNotificationsReadEndpoint.cs @@ -0,0 +1,22 @@ +using BuildFlow.Platform.Application.Notifications.Commands; +using BuildFlow.Shared.Domain.Common; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Notifications; + +/// 标记当前用户所有通知为已读。 +public class MarkAllNotificationsReadEndpoint(IMediator mediator, ICurrentUserContext userContext) + : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/notifications/read-all"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var userId = userContext.GetRecipientId(); + var count = await mediator.Send(new MarkAllNotificationsReadCommand(userId), ct); + await Send.OkAsync(count, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Notifications/MarkNotificationReadEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Notifications/MarkNotificationReadEndpoint.cs new file mode 100644 index 0000000..197bc9e --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Notifications/MarkNotificationReadEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Platform.Application.Notifications.Commands; +using BuildFlow.Shared.Domain.Common; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Notifications; + +/// 标记单条通知为已读。 +public class MarkNotificationReadEndpoint(IMediator mediator, ICurrentUserContext userContext) + : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/notifications/{Id}/read"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var id = Route("Id"); + var userId = userContext.GetRecipientId(); + var ok = await mediator.Send(new MarkNotificationReadCommand(id, userId), ct); + if (!ok) + throw new NotFoundException("通知不存在"); + await Send.OkAsync(ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Notifications/NotificationEndpointsExtensions.cs b/src/BuildFlow.Host/Endpoints/Platform/Notifications/NotificationEndpointsExtensions.cs new file mode 100644 index 0000000..68e13e7 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Notifications/NotificationEndpointsExtensions.cs @@ -0,0 +1,15 @@ +using BuildFlow.Shared.Domain.Common; + +namespace BuildFlow.Host.Endpoints.Platform.Notifications; + +/// +/// 通知EndpointsExtensions扩展方法。 +/// +internal static class NotificationEndpointsExtensions +{ + public static Guid GetRecipientId(this ICurrentUserContext ctx) + { + var id = ctx.GetRequiredUserId(); + return Guid.Parse(id); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Notifications/PublishNotificationEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Notifications/PublishNotificationEndpoint.cs new file mode 100644 index 0000000..108d65f --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Notifications/PublishNotificationEndpoint.cs @@ -0,0 +1,23 @@ +using BuildFlow.Platform.Application.Notifications.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Notifications; + +/// 发布通知(Fanout 扇出,业务系统只需推一条消息)。 +public class PublishNotificationEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/notifications/publish"); + Permissions("notification:publish"); + } + + public override async Task HandleAsync(PublishNotificationRequest req, CancellationToken ct) + { + var count = await mediator.Send(new PublishNotificationCommand( + req.Type, req.Title, req.Content, req.Source, + req.RelatedId, req.RelatedType, + req.RecipientUserIds, req.RecipientRoles), ct); + await Send.OkAsync(count, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Notifications/PublishNotificationRequest.cs b/src/BuildFlow.Host/Endpoints/Platform/Notifications/PublishNotificationRequest.cs new file mode 100644 index 0000000..c822687 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Notifications/PublishNotificationRequest.cs @@ -0,0 +1,24 @@ +namespace BuildFlow.Host.Endpoints.Platform.Notifications; + +/// +/// Publish通知请求体。 +/// +public record PublishNotificationRequest +{ + public string Type { get; init; } = "system"; + public string Title { get; init; } = default!; + public string Content { get; init; } = default!; + public string Source { get; init; } = "system"; + public string? RelatedId { get; init; } + public string? RelatedType { get; init; } + /// 精确接收人用户 ID 列表(与 RecipientRoles 二选一或并存)。 + public List? RecipientUserIds { get; init; } + /// 接收角色名列表(中心按角色展开为用户)。 + public List? RecipientRoles { get; init; } +} + +/// +/// 发布通知请求校验。 +/// 接收人范围(RecipientUserIds / RecipientRoles)可同时为空——表示全量广播, +/// 具体扇出语义由 PublishNotificationCommand 决定,此处仅校验必填字段与长度。 +/// diff --git a/src/BuildFlow.Host/Endpoints/Platform/Notifications/PublishNotificationRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Notifications/PublishNotificationRequestValidator.cs new file mode 100644 index 0000000..35a4cba --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Notifications/PublishNotificationRequestValidator.cs @@ -0,0 +1,24 @@ +namespace BuildFlow.Host.Endpoints.Platform.Notifications; + +/// +/// Publish通知Request的请求校验器(FluentValidation)。 +/// +public class PublishNotificationRequestValidator : Validator +{ + public PublishNotificationRequestValidator() + { + RuleFor(x => x.Title) + .NotEmpty().WithMessage("通知标题不能为空") + .MaximumLength(200).WithMessage("通知标题不能超过 200 个字符"); + + RuleFor(x => x.Content) + .NotEmpty().WithMessage("通知内容不能为空") + .MaximumLength(5000).WithMessage("通知内容不能超过 5000 个字符"); + + RuleFor(x => x.Type) + .MaximumLength(50).WithMessage("通知类型 Type 长度不能超过 50 个字符"); + + RuleFor(x => x.Source) + .MaximumLength(50).WithMessage("通知来源 Source 长度不能超过 50 个字符"); + } +} 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..7c97835 --- /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.Platform.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..8375cfe --- /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.Platform.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..86344e5 --- /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.Platform.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..241131e --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Permissions/DeletePermissionEndpointRequest.cs @@ -0,0 +1,6 @@ +namespace BuildFlow.Host.Endpoints.Platform.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..98b00c7 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Permissions/DeletePermissionEndpointRequestValidator.cs @@ -0,0 +1,12 @@ +namespace BuildFlow.Host.Endpoints.Platform.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..3c37bf7 --- /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.Platform.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..ca645e7 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Permissions/GetPermissionByIdRequest.cs @@ -0,0 +1,6 @@ +namespace BuildFlow.Host.Endpoints.Platform.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..35f8ac2 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Permissions/GetPermissionByIdRequestValidator.cs @@ -0,0 +1,12 @@ +namespace BuildFlow.Host.Endpoints.Platform.Permissions; + +/// +/// 按主键查询权限请求校验。 +/// +public class GetPermissionByIdRequestValidator : Validator +{ + public GetPermissionByIdRequestValidator() + { + RuleFor(x => x.Id).NotEmpty().WithMessage("权限 ID 不能为空"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Permissions/GetPermissionListEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Permissions/GetPermissionListEndpoint.cs new file mode 100644 index 0000000..559198c --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Permissions/GetPermissionListEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Platform.Application.Permissions.DTOs; +using BuildFlow.Platform.Application.Permissions.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Permissions; + +/// +/// 获取全部权限列表(供角色分配权限页选择)。 +/// 需 permission:read 权限——权限码本身是敏感信息,仅授权用户可见。 +/// +public class GetPermissionListEndpoint(IMediator mediator) : EndpointWithoutRequest> +{ + public override void Configure() + { + Get("/permissions"); + Permissions("permission:read"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var result = await mediator.Send(new GetPermissionListQuery(), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Permissions/GetPermissionTreeEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Permissions/GetPermissionTreeEndpoint.cs new file mode 100644 index 0000000..26aab35 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Permissions/GetPermissionTreeEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Platform.Application.Permissions.DTOs; +using BuildFlow.Platform.Application.Permissions.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Permissions; + +/// +/// 获取权限分组树。按 Group 聚合,供管理端树形表格展示。 +/// 需 permission:read 权限——权限码本身是敏感信息,仅授权用户可见。 +/// +public class GetPermissionTreeEndpoint(IMediator mediator) + : EndpointWithoutRequest> +{ + public override void Configure() + { + Get("/permission/tree"); + Permissions("permission:read"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var tree = await mediator.Send(new GetPermissionTreeQuery(), ct); + await Send.OkAsync(tree, ct); + } +} 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..fd209e6 --- /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.Platform.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..df8d0b2 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Permissions/UpdatePermissionEndpointRequest.cs @@ -0,0 +1,6 @@ +namespace BuildFlow.Host.Endpoints.Platform.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..9c64255 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Permissions/UpdatePermissionEndpointRequestValidator.cs @@ -0,0 +1,24 @@ +namespace BuildFlow.Host.Endpoints.Platform.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/Platform/Roles/AssignPermissionsEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/AssignPermissionsEndpoint.cs new file mode 100644 index 0000000..71437b8 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/AssignPermissionsEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Platform.Application.Roles.Commands; +using BuildFlow.Platform.Application.Roles.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Roles; + + +/// +/// Assign权限s端点。 +/// +public class AssignPermissionsEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/roles/{RoleId}/permissions"); + Permissions("role:assign-permission"); + } + + public override async Task HandleAsync(AssignPermissionsEndpointRequest req, CancellationToken ct) + { + var result = await mediator.Send(new AssignPermissionsCommand(req.RoleId, req.PermissionIds), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Roles/AssignPermissionsEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/AssignPermissionsEndpointRequest.cs new file mode 100644 index 0000000..8d6fb10 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/AssignPermissionsEndpointRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Platform.Roles; + +/// +/// Assign权限sEndpoint请求体。 +/// +public record AssignPermissionsEndpointRequest(Guid RoleId, List PermissionIds); + +/// 给角色分配权限请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/Platform/Roles/AssignPermissionsEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/AssignPermissionsEndpointRequestValidator.cs new file mode 100644 index 0000000..d0364e4 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/AssignPermissionsEndpointRequestValidator.cs @@ -0,0 +1,14 @@ +namespace BuildFlow.Host.Endpoints.Platform.Roles; + +/// +/// Assign权限sEndpointRequest的请求校验器(FluentValidation)。 +/// +public class AssignPermissionsEndpointRequestValidator : Validator +{ + public AssignPermissionsEndpointRequestValidator() + { + RuleFor(x => x.RoleId).NotEmpty().WithMessage("角色 ID 不能为空"); + RuleFor(x => x.PermissionIds) + .NotEmpty().WithMessage("权限列表不能为空"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Roles/CreateRoleEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/CreateRoleEndpoint.cs new file mode 100644 index 0000000..0ded8a9 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/CreateRoleEndpoint.cs @@ -0,0 +1,26 @@ +using BuildFlow.Platform.Application.Roles.Commands; +using BuildFlow.Platform.Application.Roles.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Roles; + + +/// +/// Create角色端点。 +/// +public class CreateRoleEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/roles"); + Permissions("role:create"); + } + + public override async Task HandleAsync(CreateRoleRequest req, CancellationToken ct) + { + var result = await mediator.Send(new CreateRoleCommand(req.Name, req.Description), ct); + await Send.ResponseAsync(result, 201, ct); + } +} + +/// 创建角色请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/Platform/Roles/CreateRoleRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/CreateRoleRequestValidator.cs new file mode 100644 index 0000000..0b266a0 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/CreateRoleRequestValidator.cs @@ -0,0 +1,22 @@ +using BuildFlow.Platform.Application.Roles.DTOs; + +namespace BuildFlow.Host.Endpoints.Platform.Roles; + +/// +/// Create角色Request的请求校验器(FluentValidation)。 +/// +public class CreateRoleRequestValidator : Validator +{ + public CreateRoleRequestValidator() + { + RuleFor(x => x.Name) + .NotEmpty().WithMessage("角色名称不能为空") + .Length(2, 50).WithMessage("角色名称长度 2-50 个字符"); + + When(x => x.Description is not null, () => + { + RuleFor(x => x.Description!) + .MaximumLength(500).WithMessage("角色描述长度不能超过 500 个字符"); + }); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Roles/DeleteRoleEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/DeleteRoleEndpoint.cs new file mode 100644 index 0000000..b2f4fb9 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/DeleteRoleEndpoint.cs @@ -0,0 +1,23 @@ +using BuildFlow.Platform.Application.Roles.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Roles; + + +/// +/// Delete角色端点。 +/// +public class DeleteRoleEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Delete("/roles/{Id}"); + Permissions("role:delete"); + } + + public override async Task HandleAsync(DeleteRoleEndpointRequest req, CancellationToken ct) + { + await mediator.Send(new DeleteRoleCommand(req.Id), ct); + await Send.OkAsync(true, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Roles/DeleteRoleEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/DeleteRoleEndpointRequest.cs new file mode 100644 index 0000000..446f8ec --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/DeleteRoleEndpointRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Platform.Roles; + +/// +/// Delete角色Endpoint请求体。 +/// +public record DeleteRoleEndpointRequest(Guid Id); + +/// 删除角色请求校验(Id 由路由提供)。 diff --git a/src/BuildFlow.Host/Endpoints/Platform/Roles/DeleteRoleEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/DeleteRoleEndpointRequestValidator.cs new file mode 100644 index 0000000..81a30d2 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/DeleteRoleEndpointRequestValidator.cs @@ -0,0 +1,12 @@ +namespace BuildFlow.Host.Endpoints.Platform.Roles; + +/// +/// Delete角色EndpointRequest的请求校验器(FluentValidation)。 +/// +public class DeleteRoleEndpointRequestValidator : Validator +{ + public DeleteRoleEndpointRequestValidator() + { + RuleFor(x => x.Id).NotEmpty().WithMessage("角色 ID 不能为空"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleByIdEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleByIdEndpoint.cs new file mode 100644 index 0000000..a310074 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleByIdEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Platform.Application.Roles.DTOs; +using BuildFlow.Platform.Application.Roles.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Roles; + + +/// +/// Get角色ById端点。 +/// +public class GetRoleByIdEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Get("/roles/{Id}"); + Permissions("role:read"); + } + + public override async Task HandleAsync(GetRoleByIdRequest req, CancellationToken ct) + { + var result = await mediator.Send(new GetRoleByIdQuery(req.Id), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleByIdRequest.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleByIdRequest.cs new file mode 100644 index 0000000..8bdbd17 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleByIdRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Platform.Roles; + +/// +/// Get角色ById请求体。 +/// +public record GetRoleByIdRequest(Guid Id); + +/// 根据角色 ID 查询请求校验(Id 由路由提供)。 diff --git a/src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleByIdRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleByIdRequestValidator.cs new file mode 100644 index 0000000..86ecace --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleByIdRequestValidator.cs @@ -0,0 +1,12 @@ +namespace BuildFlow.Host.Endpoints.Platform.Roles; + +/// +/// Get角色ByIdRequest的请求校验器(FluentValidation)。 +/// +public class GetRoleByIdRequestValidator : Validator +{ + public GetRoleByIdRequestValidator() + { + RuleFor(x => x.Id).NotEmpty().WithMessage("角色 ID 不能为空"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleListEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleListEndpoint.cs new file mode 100644 index 0000000..a495061 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/GetRoleListEndpoint.cs @@ -0,0 +1,23 @@ +using BuildFlow.Platform.Application.Roles.DTOs; +using BuildFlow.Platform.Application.Roles.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Roles; + +/// +/// Get角色List端点。 +/// +public class GetRoleListEndpoint(IMediator mediator) : EndpointWithoutRequest> +{ + public override void Configure() + { + Get("/roles"); + Permissions("role:read"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var result = await mediator.Send(new GetRoleListQuery(), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Roles/UpdateRoleEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/UpdateRoleEndpoint.cs new file mode 100644 index 0000000..05dfac7 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/UpdateRoleEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Platform.Application.Roles.Commands; +using BuildFlow.Platform.Application.Roles.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Roles; + + +/// +/// Update角色端点。 +/// +public class UpdateRoleEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Put("/roles/{Id}"); + Permissions("role:update"); + } + + public override async Task HandleAsync(UpdateRoleEndpointRequest req, CancellationToken ct) + { + var result = await mediator.Send(new UpdateRoleCommand(req.Id, req.Name, req.Description), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Roles/UpdateRoleEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/UpdateRoleEndpointRequest.cs new file mode 100644 index 0000000..947a922 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/UpdateRoleEndpointRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Platform.Roles; + +/// +/// Update角色Endpoint请求体。 +/// +public record UpdateRoleEndpointRequest(Guid Id, string? Name, string? Description); + +/// 更新角色请求校验。Name 为可选更新字段,仅当提供时校验长度。 diff --git a/src/BuildFlow.Host/Endpoints/Platform/Roles/UpdateRoleEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Roles/UpdateRoleEndpointRequestValidator.cs new file mode 100644 index 0000000..a413276 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Roles/UpdateRoleEndpointRequestValidator.cs @@ -0,0 +1,24 @@ +namespace BuildFlow.Host.Endpoints.Platform.Roles; + +/// +/// Update角色EndpointRequest的请求校验器(FluentValidation)。 +/// +public class UpdateRoleEndpointRequestValidator : Validator +{ + public UpdateRoleEndpointRequestValidator() + { + 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 个字符"); + }); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/AssignRolesEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/AssignRolesEndpoint.cs new file mode 100644 index 0000000..0f7c407 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/AssignRolesEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Platform.Application.Users.Commands; +using BuildFlow.Platform.Application.Users.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Users; + + +/// +/// Assign角色s端点。 +/// +public class AssignRolesEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/users/{UserId}/roles"); + Permissions("user:assign-role"); + } + + public override async Task HandleAsync(AssignRolesEndpointRequest req, CancellationToken ct) + { + var result = await mediator.Send(new AssignRolesCommand(req.UserId, req.RoleIds), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/AssignRolesEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/AssignRolesEndpointRequest.cs new file mode 100644 index 0000000..decb6b1 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/AssignRolesEndpointRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Platform.Users; + +/// +/// Assign角色sEndpoint请求体。 +/// +public record AssignRolesEndpointRequest(Guid UserId, List RoleIds); + +/// 给用户分配角色请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/AssignRolesEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/AssignRolesEndpointRequestValidator.cs new file mode 100644 index 0000000..bf1f367 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/AssignRolesEndpointRequestValidator.cs @@ -0,0 +1,14 @@ +namespace BuildFlow.Host.Endpoints.Platform.Users; + +/// +/// Assign角色sEndpointRequest的请求校验器(FluentValidation)。 +/// +public class AssignRolesEndpointRequestValidator : Validator +{ + public AssignRolesEndpointRequestValidator() + { + RuleFor(x => x.UserId).NotEmpty().WithMessage("用户 ID 不能为空"); + RuleFor(x => x.RoleIds) + .NotEmpty().WithMessage("角色列表不能为空"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/CreateUserEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/CreateUserEndpoint.cs new file mode 100644 index 0000000..02ea7cd --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/CreateUserEndpoint.cs @@ -0,0 +1,26 @@ +using BuildFlow.Platform.Application.Users.Commands; +using BuildFlow.Platform.Application.Users.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Users; + + +/// +/// Create用户端点。 +/// +public class CreateUserEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/users"); + Permissions("user:create"); + } + + public override async Task HandleAsync(CreateUserRequest req, CancellationToken ct) + { + var result = await mediator.Send(new CreateUserCommand(req.Username, req.Email, req.Password), ct); + await Send.ResponseAsync(result, 201, ct); + } +} + +/// 管理员创建用户请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/CreateUserRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/CreateUserRequestValidator.cs new file mode 100644 index 0000000..826b1b0 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/CreateUserRequestValidator.cs @@ -0,0 +1,24 @@ +using BuildFlow.Platform.Application.Users.DTOs; + +namespace BuildFlow.Host.Endpoints.Platform.Users; + +/// +/// Create用户Request的请求校验器(FluentValidation)。 +/// +public class CreateUserRequestValidator : Validator +{ + public CreateUserRequestValidator() + { + RuleFor(x => x.Username) + .NotEmpty().WithMessage("用户名不能为空") + .Length(3, 50).WithMessage("用户名长度 3-50 个字符"); + + RuleFor(x => x.Email) + .NotEmpty().WithMessage("邮箱不能为空") + .EmailAddress().WithMessage("邮箱格式不正确"); + + RuleFor(x => x.Password) + .NotEmpty().WithMessage("密码不能为空") + .Length(6, 100).WithMessage("密码长度 6-100 个字符"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/DeleteUserEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/DeleteUserEndpoint.cs new file mode 100644 index 0000000..83daebd --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/DeleteUserEndpoint.cs @@ -0,0 +1,23 @@ +using BuildFlow.Platform.Application.Users.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Users; + + +/// +/// Delete用户端点。 +/// +public class DeleteUserEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Delete("/users/{Id}"); + Permissions("user:delete"); + } + + public override async Task HandleAsync(DeleteUserEndpointRequest req, CancellationToken ct) + { + await mediator.Send(new DeleteUserCommand(req.Id), ct); + await Send.OkAsync(true, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/DeleteUserEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/DeleteUserEndpointRequest.cs new file mode 100644 index 0000000..85c8c4e --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/DeleteUserEndpointRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Platform.Users; + +/// +/// Delete用户Endpoint请求体。 +/// +public record DeleteUserEndpointRequest(Guid Id); + +/// 删除用户请求校验(Id 由路由提供)。 diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/DeleteUserEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/DeleteUserEndpointRequestValidator.cs new file mode 100644 index 0000000..76c53fb --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/DeleteUserEndpointRequestValidator.cs @@ -0,0 +1,12 @@ +namespace BuildFlow.Host.Endpoints.Platform.Users; + +/// +/// Delete用户EndpointRequest的请求校验器(FluentValidation)。 +/// +public class DeleteUserEndpointRequestValidator : Validator +{ + public DeleteUserEndpointRequestValidator() + { + RuleFor(x => x.Id).NotEmpty().WithMessage("用户 ID 不能为空"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserByIdEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserByIdEndpoint.cs new file mode 100644 index 0000000..25c2192 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserByIdEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Platform.Application.Users.DTOs; +using BuildFlow.Platform.Application.Users.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Users; + + +/// +/// Get用户ById端点。 +/// +public class GetUserByIdEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Get("/users/{Id}"); + Permissions("user:read"); + } + + public override async Task HandleAsync(GetUserByIdRequest req, CancellationToken ct) + { + var result = await mediator.Send(new GetUserByIdQuery(req.Id), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserByIdRequest.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserByIdRequest.cs new file mode 100644 index 0000000..82c8ec6 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserByIdRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Platform.Users; + +/// +/// Get用户ById请求体。 +/// +public record GetUserByIdRequest(Guid Id); + +/// 根据用户 ID 查询请求校验(Id 由路由提供)。 diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserByIdRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserByIdRequestValidator.cs new file mode 100644 index 0000000..63fa4d1 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserByIdRequestValidator.cs @@ -0,0 +1,12 @@ +namespace BuildFlow.Host.Endpoints.Platform.Users; + +/// +/// Get用户ByIdRequest的请求校验器(FluentValidation)。 +/// +public class GetUserByIdRequestValidator : Validator +{ + public GetUserByIdRequestValidator() + { + RuleFor(x => x.Id).NotEmpty().WithMessage("用户 ID 不能为空"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserListEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserListEndpoint.cs new file mode 100644 index 0000000..709db40 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserListEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Platform.Application.Users.DTOs; +using BuildFlow.Platform.Application.Users.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Users; + + +/// +/// Get用户List端点。 +/// +public class GetUserListEndpoint(IMediator mediator) : Endpoint> +{ + public override void Configure() + { + Get("/users"); + Permissions("user:read"); + } + + public override async Task HandleAsync(GetUserListRequest req, CancellationToken ct) + { + var result = await mediator.Send(new GetUserListQuery(req.Search), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserListRequest.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserListRequest.cs new file mode 100644 index 0000000..c79fdf9 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/GetUserListRequest.cs @@ -0,0 +1,9 @@ +namespace BuildFlow.Host.Endpoints.Platform.Users; + +/// +/// Get用户List请求体。 +/// +public record GetUserListRequest +{ + public string? Search { get; init; } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/UpdateUserEndpoint.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/UpdateUserEndpoint.cs new file mode 100644 index 0000000..019b205 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/UpdateUserEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Platform.Application.Users.Commands; +using BuildFlow.Platform.Application.Users.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Platform.Users; + + +/// +/// Update用户端点。 +/// +public class UpdateUserEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Put("/users/{Id}"); + Permissions("user:update"); + } + + public override async Task HandleAsync(UpdateUserEndpointRequest req, CancellationToken ct) + { + var result = await mediator.Send(new UpdateUserCommand(req.Id, req.Email, req.Password, req.IsActive), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/UpdateUserEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/UpdateUserEndpointRequest.cs new file mode 100644 index 0000000..203ec94 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/UpdateUserEndpointRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Platform.Users; + +/// +/// Update用户Endpoint请求体。 +/// +public record UpdateUserEndpointRequest(Guid Id, string? Email, string? Password, bool? IsActive); + +/// 更新用户请求校验。Id 由路由提供;Email/Password 为可选更新字段,仅当提供时校验格式。 diff --git a/src/BuildFlow.Host/Endpoints/Platform/Users/UpdateUserEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Platform/Users/UpdateUserEndpointRequestValidator.cs new file mode 100644 index 0000000..56d0be1 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Platform/Users/UpdateUserEndpointRequestValidator.cs @@ -0,0 +1,24 @@ +namespace BuildFlow.Host.Endpoints.Platform.Users; + +/// +/// Update用户EndpointRequest的请求校验器(FluentValidation)。 +/// +public class UpdateUserEndpointRequestValidator : Validator +{ + public UpdateUserEndpointRequestValidator() + { + RuleFor(x => x.Id).NotEmpty().WithMessage("用户 ID 不能为空"); + + When(x => x.Email is not null, () => + { + RuleFor(x => x.Email!) + .EmailAddress().WithMessage("邮箱格式不正确"); + }); + + When(x => x.Password is not null, () => + { + RuleFor(x => x.Password!) + .Length(6, 100).WithMessage("密码长度 6-100 个字符"); + }); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/AiModel/AiModelEndpoints.cs b/src/BuildFlow.Host/Endpoints/Rag/AiModel/AiModelEndpoints.cs new file mode 100644 index 0000000..8a06845 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/AiModel/AiModelEndpoints.cs @@ -0,0 +1,96 @@ +using FastEndpoints; +using MediatR; +using BuildFlow.Application.AiModel.Commands; +using BuildFlow.Application.AiModel.DTOs; +using BuildFlow.Application.AiModel.Queries; + +namespace BuildFlow.Host.Endpoints.Rag.AiModel; + +/// 查询模型列表。可选 modelType 筛选(0=Chat, 1=Embedding)。 +public class GetAiModelsEndpoint(IMediator mediator) : EndpointWithoutRequest> +{ + public override void Configure() + { + Get("/ai/models"); + AllowAnonymous(); + } + + public override async Task HandleAsync(CancellationToken ct) + { + // Query 第三参数 isRequired=false,让 modelType 成为可选参数 + var modelType = Query("modelType", false); + var result = await mediator.Send(new GetAiModelsQuery(modelType), ct); + await Send.OkAsync(result, ct); + } +} + +/// 新建模型。 +public class CreateAiModelEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/ai/models"); + AllowAnonymous(); + } + + public override async Task HandleAsync(CreateAiModelRequest req, CancellationToken ct) + { + var result = await mediator.Send(new CreateAiModelCommand( + req.Name, req.Provider, req.ModelId, req.BaseUrl, req.ApiKey, + req.ModelType, req.IsDefault, req.Temperature, req.MaxTokens, req.DefaultInstructions), ct); + await Send.ResponseAsync(result, 201, ct); + } +} + +/// 更新模型。 +public class UpdateAiModelEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Put("/ai/models/{Id}"); + AllowAnonymous(); + } + + public override async Task HandleAsync(UpdateAiModelRequest req, CancellationToken ct) + { + var id = Route("Id"); + var result = await mediator.Send(new UpdateAiModelCommand( + id, req.Name, req.Provider, req.ModelId, req.BaseUrl, req.ApiKey, + req.ModelType, req.IsActive, req.Temperature, req.MaxTokens, req.DefaultInstructions), ct); + await Send.OkAsync(result, ct); + } +} + +/// 删除模型。 +public class DeleteAiModelEndpoint(IMediator mediator) : EndpointWithoutRequest +{ + public override void Configure() + { + Delete("/ai/models/{Id}"); + AllowAnonymous(); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var id = Route("Id"); + await mediator.Send(new DeleteAiModelCommand(id), ct); + await Send.OkAsync(true, ct); + } +} + +/// 设为默认模型。 +public class SetDefaultAiModelEndpoint(IMediator mediator) : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/ai/models/{Id}/default"); + AllowAnonymous(); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var id = Route("Id"); + var result = await mediator.Send(new SetDefaultAiModelCommand(id), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/CreateConversationEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/CreateConversationEndpoint.cs new file mode 100644 index 0000000..486820b --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/CreateConversationEndpoint.cs @@ -0,0 +1,36 @@ +using BuildFlow.Application.Chat.Commands; +using BuildFlow.Application.Chat.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.Chat; + +public class CreateConversationEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/chat/conversations"); + AllowAnonymous(); + } + + public override async Task HandleAsync(CreateConversationRequest req, CancellationToken ct) + { + var result = await mediator.Send(new CreateConversationCommand(req.Title, req.KnowledgeBaseId), ct); + await Send.ResponseAsync(result, 201, ct); + } +} + +public class UpdateConversationEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Put("/chat/conversations/{Id}"); + AllowAnonymous(); + } + + public override async Task HandleAsync(UpdateConversationRequest req, CancellationToken ct) + { + var id = Route("Id"); + var result = await mediator.Send(new UpdateConversationCommand(id, req.Title, req.KnowledgeBaseId), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/CreateConversationRequest.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/CreateConversationRequest.cs new file mode 100644 index 0000000..628aab5 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/CreateConversationRequest.cs @@ -0,0 +1,9 @@ +namespace BuildFlow.Host.Endpoints.Rag.Chat; + +/// +/// Create会话请求体。KnowledgeBaseId 可选,关联后对话走 RAG 检索增强。 +/// +public record CreateConversationRequest(string Title, Guid? KnowledgeBaseId = null); + +/// 更新会话请求体(重命名 / 切换知识库)。 +public record UpdateConversationRequest(string? Title, Guid? KnowledgeBaseId = null); diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/CreateConversationRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/CreateConversationRequestValidator.cs new file mode 100644 index 0000000..7d0f719 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/CreateConversationRequestValidator.cs @@ -0,0 +1,14 @@ +namespace BuildFlow.Host.Endpoints.Rag.Chat; + +/// +/// Create会话Request的请求校验器(FluentValidation)。 +/// +public class CreateConversationRequestValidator : Validator +{ + public CreateConversationRequestValidator() + { + RuleFor(x => x.Title) + .NotEmpty().WithMessage("会话标题不能为空") + .MaximumLength(200).WithMessage("会话标题不能超过 200 个字符"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/DeleteConversationEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/DeleteConversationEndpoint.cs new file mode 100644 index 0000000..0b77c57 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/DeleteConversationEndpoint.cs @@ -0,0 +1,26 @@ +using BuildFlow.Application.Chat.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.Chat; + + +/// +/// Delete会话端点。 +/// +public class DeleteConversationEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Delete("/chat/conversations/{Id}"); + AllowAnonymous(); + } + + public override async Task HandleAsync(DeleteConversationEndpointRequest req, CancellationToken ct) + { + await mediator.Send(new DeleteConversationCommand(req.Id), ct); + // 返回 200 + 非空 JSON(true),让 ApiResponseMiddleware 包裹为标准 + // { code:0, data:true, message:"ok" }。不能用 204/空 body——前端 + // responseReturn:'data' 拦截器会把空响应当错误抛出,导致"删除失败"。 + await Send.OkAsync(true, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/DeleteConversationEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/DeleteConversationEndpointRequest.cs new file mode 100644 index 0000000..464db70 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/DeleteConversationEndpointRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Rag.Chat; + +/// +/// Delete会话Endpoint请求体。 +/// +public record DeleteConversationEndpointRequest(Guid Id); + +/// 删除会话请求校验(Id 由路由提供)。 diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/DeleteConversationEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/DeleteConversationEndpointRequestValidator.cs new file mode 100644 index 0000000..5903b99 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/DeleteConversationEndpointRequestValidator.cs @@ -0,0 +1,12 @@ +namespace BuildFlow.Host.Endpoints.Rag.Chat; + +/// +/// Delete会话EndpointRequest的请求校验器(FluentValidation)。 +/// +public class DeleteConversationEndpointRequestValidator : Validator +{ + public DeleteConversationEndpointRequestValidator() + { + RuleFor(x => x.Id).NotEmpty().WithMessage("会话 ID 不能为空"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationDetailEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationDetailEndpoint.cs new file mode 100644 index 0000000..b83086f --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationDetailEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Application.Chat.DTOs; +using BuildFlow.Application.Chat.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.Chat; + + +/// +/// Get会话Detail端点。 +/// +public class GetConversationDetailEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Get("/chat/conversations/{Id}"); + AllowAnonymous(); + } + + public override async Task HandleAsync(GetConversationDetailRequest req, CancellationToken ct) + { + var result = await mediator.Send(new GetConversationDetailQuery(req.Id), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationDetailRequest.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationDetailRequest.cs new file mode 100644 index 0000000..74237c1 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationDetailRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Rag.Chat; + +/// +/// Get会话Detail请求体。 +/// +public record GetConversationDetailRequest(Guid Id); + +/// 查询会话详情请求校验(Id 由路由提供)。 diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationDetailRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationDetailRequestValidator.cs new file mode 100644 index 0000000..d5bcb00 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationDetailRequestValidator.cs @@ -0,0 +1,12 @@ +namespace BuildFlow.Host.Endpoints.Rag.Chat; + +/// +/// Get会话DetailRequest的请求校验器(FluentValidation)。 +/// +public class GetConversationDetailRequestValidator : Validator +{ + public GetConversationDetailRequestValidator() + { + RuleFor(x => x.Id).NotEmpty().WithMessage("会话 ID 不能为空"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationsEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationsEndpoint.cs new file mode 100644 index 0000000..8db4814 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/GetConversationsEndpoint.cs @@ -0,0 +1,23 @@ +using BuildFlow.Application.Chat.DTOs; +using BuildFlow.Application.Chat.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.Chat; + +/// +/// Get会话s端点。 +/// +public class GetConversationsEndpoint(IMediator mediator) : EndpointWithoutRequest> +{ + public override void Configure() + { + Get("/chat/conversations"); + AllowAnonymous(); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var result = await mediator.Send(new GetConversationsQuery(), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/SendMessageEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/SendMessageEndpoint.cs new file mode 100644 index 0000000..bae9953 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/SendMessageEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Application.Chat.Commands; +using BuildFlow.Application.Chat.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.Chat; + + +/// +/// Send消息端点。 +/// +public class SendMessageEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/chat/conversations/{ConversationId}/messages"); + AllowAnonymous(); + } + + public override async Task HandleAsync(SendMessageRequest req, CancellationToken ct) + { + var conversationId = Route("ConversationId"); + var result = await mediator.Send(new SendMessageCommand(conversationId, req.Content), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/SendMessageRequest.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/SendMessageRequest.cs new file mode 100644 index 0000000..c64869f --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/SendMessageRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Rag.Chat; + +/// +/// Send消息请求体。 +/// +public record SendMessageRequest(string Content); + +/// 发送消息请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/SendMessageRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/SendMessageRequestValidator.cs new file mode 100644 index 0000000..da92dec --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/SendMessageRequestValidator.cs @@ -0,0 +1,14 @@ +namespace BuildFlow.Host.Endpoints.Rag.Chat; + +/// +/// Send消息Request的请求校验器(FluentValidation)。 +/// +public class SendMessageRequestValidator : Validator +{ + public SendMessageRequestValidator() + { + RuleFor(x => x.Content) + .NotEmpty().WithMessage("消息内容不能为空") + .MaximumLength(10000).WithMessage("消息内容不能超过 10000 个字符"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/StreamMessageEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/StreamMessageEndpoint.cs new file mode 100644 index 0000000..2024844 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/StreamMessageEndpoint.cs @@ -0,0 +1,83 @@ +using System.Text; +using System.Text.Json; +using BuildFlow.Domain.Entities; +using BuildFlow.Domain.Enums; +using BuildFlow.Domain.Interfaces; +using BuildFlow.Infrastructure.Persistence; +using AiChatMessage = Microsoft.Extensions.AI.ChatMessage; +using AiChatRole = Microsoft.Extensions.AI.ChatRole; + +namespace BuildFlow.Host.Endpoints.Rag.Chat; + +public class StreamMessageEndpoint(RagDbContext db, IAIChatAgent chatAgent, IChatMessageCache cache) + : Endpoint +{ + public override void Configure() + { + Post("/chat/conversations/{ConversationId}/stream"); + AllowAnonymous(); + } + + public override async Task HandleAsync(StreamMessageRequest req, CancellationToken ct) + { + var conversationId = Route("ConversationId"); + + var conversation = await db.Conversations.FindAsync([conversationId], ct); + if (conversation is null) + { + HttpContext.Response.StatusCode = 404; + return; + } + + var userMessage = new ChatMessage + { + ConversationId = conversationId, + Role = ChatRole.User, + Content = req.Content + }; + await db.ChatMessages.AddAsync(userMessage, ct); + await db.SaveChangesAsync(ct); + await cache.AppendMessageAsync(conversationId, + new CachedChatMessage(userMessage.Id, ChatRole.User.ToString(), userMessage.Content, null, userMessage.CreatedAt), ct); + + var dbMessages = await db.ChatMessages + .Where(m => m.ConversationId == conversationId) + .OrderBy(m => m.CreatedAt) + .ToListAsync(ct); + + var chatMessages = dbMessages.Select(m => new AiChatMessage( + m.Role == ChatRole.User ? AiChatRole.User : AiChatRole.Assistant, + m.Content)).ToList(); + + HttpContext.Response.ContentType = "text/event-stream"; + HttpContext.Response.Headers.CacheControl = "no-cache"; + HttpContext.Response.Headers.Connection = "keep-alive"; + + var fullReply = new StringBuilder(); + + await foreach (var chunk in chatAgent.RunStreamingAsync(chatMessages, ct)) + { + fullReply.Append(chunk); + var sseData = JsonSerializer.Serialize(new { content = chunk }); + await HttpContext.Response.WriteAsync($"data: {sseData}\n\n", ct); + await HttpContext.Response.Body.FlushAsync(ct); + } + + var replyText = fullReply.ToString(); + + var assistantMessage = new ChatMessage + { + ConversationId = conversationId, + Role = ChatRole.Assistant, + Content = replyText + }; + await db.ChatMessages.AddAsync(assistantMessage, ct); + await db.SaveChangesAsync(ct); + await cache.AppendMessageAsync(conversationId, + new CachedChatMessage(assistantMessage.Id, ChatRole.Assistant.ToString(), assistantMessage.Content, null, assistantMessage.CreatedAt), ct); + + var doneData = JsonSerializer.Serialize(new { messageId = assistantMessage.Id }); + await HttpContext.Response.WriteAsync($"event: done\ndata: {doneData}\n\n", ct); + await HttpContext.Response.Body.FlushAsync(ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/StreamMessageRequest.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/StreamMessageRequest.cs new file mode 100644 index 0000000..a8738fe --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/StreamMessageRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Rag.Chat; + +/// +/// Stream消息请求体。 +/// +public record StreamMessageRequest(string Content); + +/// 流式发送消息请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/Rag/Chat/StreamMessageRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/Chat/StreamMessageRequestValidator.cs new file mode 100644 index 0000000..10d21fd --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Chat/StreamMessageRequestValidator.cs @@ -0,0 +1,14 @@ +namespace BuildFlow.Host.Endpoints.Rag.Chat; + +/// +/// Stream消息Request的请求校验器(FluentValidation)。 +/// +public class StreamMessageRequestValidator : Validator +{ + public StreamMessageRequestValidator() + { + RuleFor(x => x.Content) + .NotEmpty().WithMessage("消息内容不能为空") + .MaximumLength(10000).WithMessage("消息内容不能超过 10000 个字符"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/ChunkUploadSession.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/ChunkUploadSession.cs new file mode 100644 index 0000000..e7b1b75 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/ChunkUploadSession.cs @@ -0,0 +1,22 @@ +using System.Collections.Concurrent; + +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// 分块上传Session类型。 +/// +public class ChunkUploadSession(string sessionId, Guid knowledgeBaseId, string fileName, long fileSize, int chunkCount, string tempDir) +{ + public string SessionId { get; } = sessionId; + public Guid KnowledgeBaseId { get; } = knowledgeBaseId; + public string FileName { get; } = fileName; + public long FileSize { get; } = fileSize; + public int ChunkCount { get; } = chunkCount; + public string TempDir { get; } = tempDir; + public ConcurrentDictionary UploadedChunks { get; } = []; +} + +/// +/// 分片上传会话的进程内存储。单机内存方案(ConcurrentDictionary),不适用于多实例部署—— +/// 横向扩展时需替换为 Redis 等共享存储。会话无 TTL 清理,依赖客户端调用 complete 触发清理。 +/// diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/ChunkUploadStore.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/ChunkUploadStore.cs new file mode 100644 index 0000000..52bc422 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/ChunkUploadStore.cs @@ -0,0 +1,13 @@ +using System.Collections.Concurrent; + +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// 分块上传Store类型。 +/// +public static class ChunkUploadStore +{ + public static readonly ConcurrentDictionary Sessions = []; +} + +// ===== 初始化 ===== diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/CompleteChunkUploadEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/CompleteChunkUploadEndpoint.cs new file mode 100644 index 0000000..d053818 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/CompleteChunkUploadEndpoint.cs @@ -0,0 +1,64 @@ +using BuildFlow.Application.Document.Commands; +using BuildFlow.Application.Document.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// 合并完成。客户端所有分片上传完毕后调用:按分片索引顺序合并为完整文件,再走入库流程。 +/// +public class CompleteChunkUploadEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/documents/chunk-upload/{SessionId}/complete"); + AllowAnonymous(); + } + + public override async Task HandleAsync(CompleteChunkUploadRequest req, CancellationToken ct) + { + var sessionId = Route("SessionId"); + + if (!ChunkUploadStore.Sessions.TryGetValue(sessionId!, out var session)) + { + HttpContext.Response.StatusCode = 404; + return; + } + + // 完整性校验:分片数必须与声明一致,否则拒绝合并避免产出残缺文件 + if (session.UploadedChunks.Count != session.ChunkCount) + { + ThrowError($"分片不完整:已上传 {session.UploadedChunks.Count}/{session.ChunkCount}"); + return; + } + + var ext = Path.GetExtension(session.FileName); + var mergedPath = Path.Combine(Path.GetTempPath(), $"rag_{Guid.NewGuid()}{ext}"); + // 按索引顺序拼接分片:分片上传到达顺序不确定,必须按 ChunkIndex 重建原文件 + await using (var mergedStream = System.IO.File.Create(mergedPath)) + { + for (var i = 0; i < session.ChunkCount; i++) + { + if (!session.UploadedChunks.TryGetValue(i, out var chunkPath)) continue; + await using var chunkStream = System.IO.File.OpenRead(chunkPath); + await chunkStream.CopyToAsync(mergedStream, ct); + } + } + + // Command 需要 Stream(对接 file-system),打开合并后的文件传入。 + var fileStream = System.IO.File.OpenRead(mergedPath); + var result = await mediator.Send(new UploadDocumentCommand( + session.KnowledgeBaseId, + req.Title ?? session.FileName, + session.FileName, + fileStream, + session.FileSize, + "application/octet-stream" + ), ct); + + try { Directory.Delete(session.TempDir, true); } catch { /* ignore */ } + ChunkUploadStore.Sessions.TryRemove(sessionId!, out _); + + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/CompleteChunkUploadRequest.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/CompleteChunkUploadRequest.cs new file mode 100644 index 0000000..c1f1172 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/CompleteChunkUploadRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// Complete分块上传请求体。 +/// +public class CompleteChunkUploadRequest +{ + public string? Title { get; set; } +} + +/// 分片上传合并完成请求校验。Title 可选(不传则用原文件名)。 diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/CompleteChunkUploadRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/CompleteChunkUploadRequestValidator.cs new file mode 100644 index 0000000..de29816 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/CompleteChunkUploadRequestValidator.cs @@ -0,0 +1,16 @@ +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// Complete分块上传Request的请求校验器(FluentValidation)。 +/// +public class CompleteChunkUploadRequestValidator : Validator +{ + public CompleteChunkUploadRequestValidator() + { + When(x => x.Title is not null, () => + { + RuleFor(x => x.Title!) + .MaximumLength(500).WithMessage("文档标题不能超过 500 个字符"); + }); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/GetDocumentChunksEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/GetDocumentChunksEndpoint.cs new file mode 100644 index 0000000..db6ec83 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/GetDocumentChunksEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Application.Document.DTOs; +using BuildFlow.Application.Document.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// Get文档分块端点。 +/// +public class GetDocumentChunksEndpoint(IMediator mediator) : EndpointWithoutRequest> +{ + public override void Configure() + { + Get("/documents/{DocumentId}/chunks"); + AllowAnonymous(); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var docId = Route("DocumentId"); + var result = await mediator.Send(new GetDocumentChunksQuery(docId), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/ImportFromFileManagerEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/ImportFromFileManagerEndpoint.cs new file mode 100644 index 0000000..a539fc6 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/ImportFromFileManagerEndpoint.cs @@ -0,0 +1,59 @@ +using BuildFlow.Application.Document.Commands; +using BuildFlow.Application.Document.DTOs; +using BuildFlow.Domain.Enums; +using File.Infrastructure.Storage; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// 从文件管理(S3)入库文档到知识库。 +/// 串联:文件管理上传的文件 → 直接成为 RAG 知识库的语料(分片+向量化)。 +/// 这打通了"文件 → 知识库 → AI对话"的核心 RAG 闭环。 +/// +public class ImportFromFileManagerEndpoint( + IMediator mediator, + IS3StorageService s3) : Endpoint +{ + public override void Configure() + { + Post("/knowledge-bases/{KnowledgeBaseId}/import-file"); + AllowAnonymous(); + } + + public override async Task HandleAsync(ImportFromFileManagerRequest req, CancellationToken ct) + { + var kbId = Route("KnowledgeBaseId"); + + // 1. 从 S3 下载文件(文件管理存储的文件) + var (stream, contentType) = await s3.DownloadFileAsync(req.BucketName, req.ObjectKey, ct); + using var fileStream = stream; + + // 2. 获取文件大小(从请求传入,或从 stream 推断) + var fileSize = req.FileSize > 0 ? req.FileSize : fileStream.Length; + var fileName = string.IsNullOrEmpty(req.FileName) ? req.ObjectKey : req.FileName; + var title = string.IsNullOrEmpty(req.Title) ? fileName : req.Title; + + // 3. 调 RAG 上传文档(写入 RAG 的 Document 表 + 存储文件引用) + ChunkingMode? overrideMode = req.ChunkingMode switch + { + >= 0 and <= 5 => (ChunkingMode)req.ChunkingMode.Value, + _ => null, + }; + + var doc = await mediator.Send(new UploadDocumentCommand( + KnowledgeBaseId: kbId, + Title: title, + FileName: fileName, + FileStream: fileStream, + FileSize: fileSize, + ContentType: contentType, + ChunkingModeOverride: overrideMode + ), ct); + + // 4. 自动触发文档处理(分片 + 向量化)—— 异步不阻塞响应 + _ = mediator.Send(new ProcessDocumentCommand(doc.Id), ct); + + await Send.ResponseAsync(doc, 201, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/ImportFromFileManagerRequest.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/ImportFromFileManagerRequest.cs new file mode 100644 index 0000000..ad571b6 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/ImportFromFileManagerRequest.cs @@ -0,0 +1,23 @@ +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// 从文件管理入库的请求。指定 S3 桶与对象,服务端下载后写入 RAG 知识库。 +public class ImportFromFileManagerRequest +{ + /// S3 桶名(文件管理的 bucket)。 + public string BucketName { get; set; } = string.Empty; + + /// S3 对象 key(文件管理存储的 UUID key)。 + public string ObjectKey { get; set; } = string.Empty; + + /// 文件名(可选,默认用 ObjectKey)。 + public string? FileName { get; set; } + + /// 文档标题(可选,默认用文件名)。 + public string? Title { get; set; } + + /// 文件大小(可选)。 + public long FileSize { get; set; } + + /// 分块策略覆盖(-1=跟随知识库默认, 0-5=指定策略)。 + public int? ChunkingMode { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/InitChunkUploadEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/InitChunkUploadEndpoint.cs new file mode 100644 index 0000000..5308cc5 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/InitChunkUploadEndpoint.cs @@ -0,0 +1,26 @@ +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// Init分块上传端点。 +/// +public class InitChunkUploadEndpoint : Endpoint +{ + public override void Configure() + { + Post("/knowledge-bases/{KnowledgeBaseId}/documents/chunk-upload/init"); + AllowAnonymous(); + } + + public override async Task HandleAsync(InitChunkUploadRequest req, CancellationToken ct) + { + var kbId = Route("KnowledgeBaseId"); + var sessionId = Guid.NewGuid().ToString("N"); + var tempDir = Path.Combine(Path.GetTempPath(), "rag_chunks", sessionId); + Directory.CreateDirectory(tempDir); + + var session = new ChunkUploadSession(sessionId, kbId, req.FileName, req.FileSize, req.ChunkCount, tempDir); + ChunkUploadStore.Sessions[sessionId] = session; + + await Send.OkAsync(session, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/InitChunkUploadRequest.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/InitChunkUploadRequest.cs new file mode 100644 index 0000000..5110731 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/InitChunkUploadRequest.cs @@ -0,0 +1,13 @@ +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// Init分块上传请求体。 +/// +public class InitChunkUploadRequest +{ + public string FileName { get; set; } = default!; + public long FileSize { get; set; } + public int ChunkCount { get; set; } +} + +/// 分片上传初始化请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/InitChunkUploadRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/InitChunkUploadRequestValidator.cs new file mode 100644 index 0000000..930c1ee --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/InitChunkUploadRequestValidator.cs @@ -0,0 +1,20 @@ +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// Init分块上传Request的请求校验器(FluentValidation)。 +/// +public class InitChunkUploadRequestValidator : Validator +{ + public InitChunkUploadRequestValidator() + { + RuleFor(x => x.FileName) + .NotEmpty().WithMessage("文件名不能为空") + .MaximumLength(500).WithMessage("文件名不能超过 500 个字符"); + + RuleFor(x => x.FileSize) + .GreaterThan(0).WithMessage("文件大小必须大于 0"); + + RuleFor(x => x.ChunkCount) + .InclusiveBetween(1, 10000).WithMessage("分片数量 ChunkCount 取值范围 1-10000"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/ListDocumentsEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/ListDocumentsEndpoint.cs new file mode 100644 index 0000000..4cc6d69 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/ListDocumentsEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Application.Document.DTOs; +using BuildFlow.Application.Document.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// List文档s端点。 +/// +public class ListDocumentsEndpoint(IMediator mediator) : EndpointWithoutRequest> +{ + public override void Configure() + { + Get("/knowledge-bases/{KnowledgeBaseId}/documents"); + AllowAnonymous(); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var kbId = Route("KnowledgeBaseId"); + var result = await mediator.Send(new GetDocumentsQuery(kbId), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/ProcessDocumentEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/ProcessDocumentEndpoint.cs new file mode 100644 index 0000000..a9ee93a --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/ProcessDocumentEndpoint.cs @@ -0,0 +1,25 @@ +using BuildFlow.Application.Document.Commands; +using BuildFlow.Application.Document.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// 触发单文档处理流水线(提取→分块→向量化→入库)。 +/// 上传后须调用此端点才能让文档进入可检索状态;失败文档也可重复调用重试。 +/// +public class ProcessDocumentEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/documents/{DocumentId}/process"); + AllowAnonymous(); + } + + public override async Task HandleAsync(EmptyRequest req, CancellationToken ct) + { + var docId = Route("DocumentId"); + var result = await mediator.Send(new ProcessDocumentCommand(docId), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/ProcessKnowledgeBaseEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/ProcessKnowledgeBaseEndpoint.cs new file mode 100644 index 0000000..5d7c302 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/ProcessKnowledgeBaseEndpoint.cs @@ -0,0 +1,27 @@ +using BuildFlow.Application.Document.Commands; +using BuildFlow.Application.Document.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// 批量处理知识库内所有待处理/失败的文档。 +/// POST /api/knowledge-bases/{KnowledgeBaseId}/process-all +/// 返回处理统计(成功/失败/错误明细)。Obsidian 同步后可调用此接口一键入库。 +/// +public class ProcessKnowledgeBaseEndpoint(IMediator mediator) + : Endpoint +{ + public override void Configure() + { + Post("/knowledge-bases/{KnowledgeBaseId}/process-all"); + AllowAnonymous(); + } + + public override async Task HandleAsync(EmptyRequest req, CancellationToken ct) + { + var kbId = Route("KnowledgeBaseId"); + var result = await mediator.Send(new ProcessKnowledgeBaseCommand(kbId), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/UploadChunkEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/UploadChunkEndpoint.cs new file mode 100644 index 0000000..f0dae26 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/UploadChunkEndpoint.cs @@ -0,0 +1,43 @@ +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// 上传单个分片。客户端按分片索引逐个上传,服务端写入临时目录。 +/// +public class UploadChunkEndpoint : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/documents/chunk-upload/{SessionId}/chunks/{ChunkIndex}"); + AllowAnonymous(); + AllowFileUploads(); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var sessionId = Route("SessionId"); + var chunkIndex = Route("ChunkIndex"); + + if (!ChunkUploadStore.Sessions.TryGetValue(sessionId!, out var session)) + { + HttpContext.Response.StatusCode = 404; + return; + } + + var file = Files.FirstOrDefault(); + if (file is null) + { + ThrowError("请上传分片文件"); + return; + } + + var chunkPath = Path.Combine(session.TempDir, $"chunk_{chunkIndex}"); + await using (var stream = System.IO.File.Create(chunkPath)) + { + await file.CopyToAsync(stream, ct); + } + + session.UploadedChunks.TryAdd(chunkIndex, chunkPath); + HttpContext.Response.StatusCode = 200; + await HttpContext.Response.WriteAsJsonAsync(new { uploaded = session.UploadedChunks.Count, total = session.ChunkCount }, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/UploadDocumentEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/UploadDocumentEndpoint.cs new file mode 100644 index 0000000..eed5ddc --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/UploadDocumentEndpoint.cs @@ -0,0 +1,43 @@ +using BuildFlow.Application.Document.Commands; +using BuildFlow.Application.Document.DTOs; +using BuildFlow.Domain.Enums; +using MediatR; +using DomainExceptions = BuildFlow.Shared.Domain.Exceptions; + +namespace BuildFlow.Host.Endpoints.Rag.Document; + + +/// +/// 上传文档端点。 +/// +public class UploadDocumentEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/knowledge-bases/{KnowledgeBaseId}/documents"); + AllowAnonymous(); + AllowFileUploads(); + } + + public override async Task HandleAsync(UploadDocumentRequest req, CancellationToken ct) + { + var kbId = Route("KnowledgeBaseId"); + var file = Files.FirstOrDefault(); + if (file is null) + throw new DomainExceptions.BusinessException("请上传文件"); + + // 分块策略覆盖:0=General,1=Heading,2=ParentChild;null=用知识库默认 + ChunkingMode? overrideMode = req.ChunkingMode switch + { + >= 0 and <= 2 => (ChunkingMode)req.ChunkingMode.Value, + _ => null + }; + + // 直接把文件流传给 command,由 command 上传到文件服务 S3(不再存临时目录) + await using var stream = file.OpenReadStream(); + var result = await mediator.Send(new UploadDocumentCommand(kbId, req.Title ?? file.FileName, + file.FileName, stream, file.Length, file.ContentType, overrideMode), ct); + + await Send.ResponseAsync(result, 201, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/UploadDocumentRequest.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/UploadDocumentRequest.cs new file mode 100644 index 0000000..cd26a55 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/UploadDocumentRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// 上传文档请求体。 +/// +public record UploadDocumentRequest(string? Title, int? ChunkingMode = null); + +/// 单文件上传请求校验。Title 可选(不传则用文件名),ChunkingMode 仅当提供时校验取值。 diff --git a/src/BuildFlow.Host/Endpoints/Rag/Document/UploadDocumentRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/Document/UploadDocumentRequestValidator.cs new file mode 100644 index 0000000..5acf5b9 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Document/UploadDocumentRequestValidator.cs @@ -0,0 +1,20 @@ +namespace BuildFlow.Host.Endpoints.Rag.Document; + +/// +/// 上传文档Request的请求校验器(FluentValidation)。 +/// +public class UploadDocumentRequestValidator : Validator +{ + public UploadDocumentRequestValidator() + { + When(x => x.Title is not null, () => + { + RuleFor(x => x.Title!) + .MaximumLength(500).WithMessage("文档标题不能超过 500 个字符"); + }); + + RuleFor(x => x.ChunkingMode) + .InclusiveBetween(0, 2).When(x => x.ChunkingMode.HasValue) + .WithMessage("分块模式 ChunkingMode 取值 0=General,1=Heading,2=ParentChild"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedBatchEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedBatchEndpoint.cs new file mode 100644 index 0000000..bb3efee --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedBatchEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Application.Embedding.Commands; +using BuildFlow.Application.Embedding.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.Embedding; + + +/// +/// 批量向量化端点。 +/// +public class EmbedBatchEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/embeddings/batch"); + AllowAnonymous(); + } + + public override async Task HandleAsync(EmbedBatchRequest req, CancellationToken ct) + { + var result = await mediator.Send(new EmbedBatchCommand(req.Texts), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedBatchRequest.cs b/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedBatchRequest.cs new file mode 100644 index 0000000..2d90a3e --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedBatchRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Rag.Embedding; + +/// +/// 批量向量化请求体。 +/// +public record EmbedBatchRequest(List Texts); + +/// 批量文本向量化请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedBatchRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedBatchRequestValidator.cs new file mode 100644 index 0000000..5f907e3 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedBatchRequestValidator.cs @@ -0,0 +1,14 @@ +namespace BuildFlow.Host.Endpoints.Rag.Embedding; + +/// +/// 批量向量化Request的请求校验器(FluentValidation)。 +/// +public class EmbedBatchRequestValidator : Validator +{ + public EmbedBatchRequestValidator() + { + RuleFor(x => x.Texts) + .NotEmpty().WithMessage("文本列表不能为空") + .Must(t => t.Count <= 100).WithMessage("批量文本不能超过 100 条"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedTextEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedTextEndpoint.cs new file mode 100644 index 0000000..2e6fb7f --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedTextEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Application.Embedding.Commands; +using BuildFlow.Application.Embedding.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.Embedding; + + +/// +/// 文本向量化端点。 +/// +public class EmbedTextEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/embeddings"); + AllowAnonymous(); + } + + public override async Task HandleAsync(EmbedTextRequest req, CancellationToken ct) + { + var result = await mediator.Send(new EmbedTextCommand(req.Text), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedTextRequest.cs b/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedTextRequest.cs new file mode 100644 index 0000000..c6d724e --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedTextRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Rag.Embedding; + +/// +/// 文本向量化请求体。 +/// +public record EmbedTextRequest(string Text); + +/// 单条文本向量化请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedTextRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedTextRequestValidator.cs new file mode 100644 index 0000000..2590ca3 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Embedding/EmbedTextRequestValidator.cs @@ -0,0 +1,14 @@ +namespace BuildFlow.Host.Endpoints.Rag.Embedding; + +/// +/// 文本向量化Request的请求校验器(FluentValidation)。 +/// +public class EmbedTextRequestValidator : Validator +{ + public EmbedTextRequestValidator() + { + RuleFor(x => x.Text) + .NotEmpty().WithMessage("文本内容不能为空") + .MaximumLength(10000).WithMessage("单条文本不能超过 10000 个字符"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/CreateKBEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/CreateKBEndpoint.cs new file mode 100644 index 0000000..093f1ff --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/CreateKBEndpoint.cs @@ -0,0 +1,34 @@ +using BuildFlow.Application.KnowledgeBase.Commands; +using BuildFlow.Application.KnowledgeBase.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.KnowledgeBase; + + +/// +/// Create知识库端点。 +/// +public class CreateKBEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/knowledge-bases"); + AllowAnonymous(); + } + + public override async Task HandleAsync(CreateKnowledgeBaseRequest req, CancellationToken ct) + { + var result = await mediator.Send( + new CreateKnowledgeBaseCommand( + req.Name, req.Description, req.EmbeddingModel, req.ChunkSize, req.ChunkOverlap, + req.ChunkingMode, req.Separator, req.RetrievalMode, req.RerankStrategy, + req.RetrievalTopK, req.ContextTopK, req.SimilarityThreshold, req.VectorWeight), + ct); + await Send.ResponseAsync(result, 201, ct); + } +} + +/// +/// 创建知识库请求校验。 +/// 名称必填;数值参数(分块/检索配置)限定合理取值范围,避免传入非法值导致下游处理异常。 +/// diff --git a/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/CreateKnowledgeBaseRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/CreateKnowledgeBaseRequestValidator.cs new file mode 100644 index 0000000..0f6830b --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/CreateKnowledgeBaseRequestValidator.cs @@ -0,0 +1,58 @@ +using BuildFlow.Application.KnowledgeBase.DTOs; + +namespace BuildFlow.Host.Endpoints.Rag.KnowledgeBase; + +/// +/// Create知识库Request的请求校验器(FluentValidation)。 +/// +public class CreateKnowledgeBaseRequestValidator : Validator +{ + public CreateKnowledgeBaseRequestValidator() + { + RuleFor(x => x.Name) + .NotEmpty().WithMessage("知识库名称不能为空") + .MaximumLength(200).WithMessage("名称不能超过 200 个字符"); + + When(x => x.Description is not null, () => + { + RuleFor(x => x.Description!) + .MaximumLength(1000).WithMessage("描述不能超过 1000 个字符"); + }); + + RuleFor(x => x.ChunkSize) + .InclusiveBetween(100, 8000).When(x => x.ChunkSize.HasValue) + .WithMessage("分块大小 ChunkSize 取值范围 100-8000"); + + RuleFor(x => x.ChunkOverlap) + .InclusiveBetween(0, 1000).When(x => x.ChunkOverlap.HasValue) + .WithMessage("分块重叠 ChunkOverlap 取值范围 0-1000"); + + RuleFor(x => x.ChunkingMode) + .InclusiveBetween(0, 2).When(x => x.ChunkingMode.HasValue) + .WithMessage("分块模式 ChunkingMode 取值 0=General,1=Heading,2=ParentChild"); + + RuleFor(x => x.RetrievalMode) + .InclusiveBetween(0, 2).When(x => x.RetrievalMode.HasValue) + .WithMessage("检索模式 RetrievalMode 取值范围 0-2"); + + RuleFor(x => x.RerankStrategy) + .InclusiveBetween(0, 2).When(x => x.RerankStrategy.HasValue) + .WithMessage("重排策略 RerankStrategy 取值范围 0-2"); + + RuleFor(x => x.RetrievalTopK) + .InclusiveBetween(1, 50).When(x => x.RetrievalTopK.HasValue) + .WithMessage("检索数量 RetrievalTopK 取值范围 1-50"); + + RuleFor(x => x.ContextTopK) + .InclusiveBetween(1, 50).When(x => x.ContextTopK.HasValue) + .WithMessage("上下文数量 ContextTopK 取值范围 1-50"); + + RuleFor(x => x.SimilarityThreshold) + .InclusiveBetween(0, 1).When(x => x.SimilarityThreshold.HasValue) + .WithMessage("相似度阈值 SimilarityThreshold 取值范围 0-1"); + + RuleFor(x => x.VectorWeight) + .InclusiveBetween(0, 1).When(x => x.VectorWeight.HasValue) + .WithMessage("向量权重 VectorWeight 取值范围 0-1"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/DeleteKBEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/DeleteKBEndpoint.cs new file mode 100644 index 0000000..8f9d558 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/DeleteKBEndpoint.cs @@ -0,0 +1,23 @@ +using BuildFlow.Application.KnowledgeBase.Commands; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.KnowledgeBase; + + +/// +/// Delete知识库端点。 +/// +public class DeleteKBEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Delete("/knowledge-bases/{Id}"); + AllowAnonymous(); + } + + public override async Task HandleAsync(DeleteKBEndpointRequest req, CancellationToken ct) + { + await mediator.Send(new DeleteKnowledgeBaseCommand(req.Id), ct); + await Send.OkAsync(true, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/DeleteKBEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/DeleteKBEndpointRequest.cs new file mode 100644 index 0000000..cac2bf0 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/DeleteKBEndpointRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Rag.KnowledgeBase; + +/// +/// Delete知识库Endpoint请求体。 +/// +public record DeleteKBEndpointRequest(Guid Id); + +/// 删除知识库请求校验(Id 由路由提供)。 diff --git a/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/DeleteKBEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/DeleteKBEndpointRequestValidator.cs new file mode 100644 index 0000000..ec17392 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/DeleteKBEndpointRequestValidator.cs @@ -0,0 +1,12 @@ +namespace BuildFlow.Host.Endpoints.Rag.KnowledgeBase; + +/// +/// Delete知识库EndpointRequest的请求校验器(FluentValidation)。 +/// +public class DeleteKBEndpointRequestValidator : Validator +{ + public DeleteKBEndpointRequestValidator() + { + RuleFor(x => x.Id).NotEmpty().WithMessage("知识库 ID 不能为空"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/GetKBsEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/GetKBsEndpoint.cs new file mode 100644 index 0000000..8330ca5 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/GetKBsEndpoint.cs @@ -0,0 +1,23 @@ +using BuildFlow.Application.KnowledgeBase.DTOs; +using BuildFlow.Application.KnowledgeBase.Queries; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.KnowledgeBase; + +/// +/// Get知识库s端点。 +/// +public class GetKBsEndpoint(IMediator mediator) : EndpointWithoutRequest> +{ + public override void Configure() + { + Get("/knowledge-bases"); + AllowAnonymous(); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var result = await mediator.Send(new GetKnowledgeBasesQuery(), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/UpdateKBEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/UpdateKBEndpoint.cs new file mode 100644 index 0000000..84f592f --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/UpdateKBEndpoint.cs @@ -0,0 +1,33 @@ +using BuildFlow.Application.KnowledgeBase.Commands; +using BuildFlow.Application.KnowledgeBase.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.KnowledgeBase; + + +/// +/// Update知识库端点。 +/// +public class UpdateKBEndpoint(IMediator mediator) + : Endpoint +{ + public override void Configure() + { + Put("/knowledge-bases/{KnowledgeBaseId}"); + AllowAnonymous(); + } + + public override async Task HandleAsync(UpdateKnowledgeBaseRequest req, CancellationToken ct) + { + var kbId = Route("KnowledgeBaseId"); + var result = await mediator.Send( + new UpdateKnowledgeBaseCommand( + kbId, req.Name, req.Description, req.ChunkSize, req.ChunkOverlap, + req.ChunkingMode, req.Separator, req.RetrievalMode, req.RerankStrategy, + req.RetrievalTopK, req.ContextTopK, req.SimilarityThreshold, req.VectorWeight), + ct); + await Send.OkAsync(result, ct); + } +} + +/// 更新知识库请求校验。仅校验请求体中提供的字段(非 null 时才校验)。 diff --git a/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/UpdateKnowledgeBaseRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/UpdateKnowledgeBaseRequestValidator.cs new file mode 100644 index 0000000..57573c4 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/KnowledgeBase/UpdateKnowledgeBaseRequestValidator.cs @@ -0,0 +1,61 @@ +using BuildFlow.Application.KnowledgeBase.DTOs; + +namespace BuildFlow.Host.Endpoints.Rag.KnowledgeBase; + +/// +/// Update知识库Request的请求校验器(FluentValidation)。 +/// +public class UpdateKnowledgeBaseRequestValidator : Validator +{ + public UpdateKnowledgeBaseRequestValidator() + { + When(x => x.Name is not null, () => + { + RuleFor(x => x.Name!) + .NotEmpty().WithMessage("知识库名称不能为空") + .MaximumLength(200).WithMessage("名称不能超过 200 个字符"); + }); + + When(x => x.Description is not null, () => + { + RuleFor(x => x.Description!) + .MaximumLength(1000).WithMessage("描述不能超过 1000 个字符"); + }); + + RuleFor(x => x.ChunkSize) + .InclusiveBetween(100, 8000).When(x => x.ChunkSize.HasValue) + .WithMessage("分块大小 ChunkSize 取值范围 100-8000"); + + RuleFor(x => x.ChunkOverlap) + .InclusiveBetween(0, 1000).When(x => x.ChunkOverlap.HasValue) + .WithMessage("分块重叠 ChunkOverlap 取值范围 0-1000"); + + RuleFor(x => x.ChunkingMode) + .InclusiveBetween(0, 2).When(x => x.ChunkingMode.HasValue) + .WithMessage("分块模式 ChunkingMode 取值 0=General,1=Heading,2=ParentChild"); + + RuleFor(x => x.RetrievalMode) + .InclusiveBetween(0, 2).When(x => x.RetrievalMode.HasValue) + .WithMessage("检索模式 RetrievalMode 取值范围 0-2"); + + RuleFor(x => x.RerankStrategy) + .InclusiveBetween(0, 2).When(x => x.RerankStrategy.HasValue) + .WithMessage("重排策略 RerankStrategy 取值范围 0-2"); + + RuleFor(x => x.RetrievalTopK) + .InclusiveBetween(1, 50).When(x => x.RetrievalTopK.HasValue) + .WithMessage("检索数量 RetrievalTopK 取值范围 1-50"); + + RuleFor(x => x.ContextTopK) + .InclusiveBetween(1, 50).When(x => x.ContextTopK.HasValue) + .WithMessage("上下文数量 ContextTopK 取值范围 1-50"); + + RuleFor(x => x.SimilarityThreshold) + .InclusiveBetween(0, 1).When(x => x.SimilarityThreshold.HasValue) + .WithMessage("相似度阈值 SimilarityThreshold 取值范围 0-1"); + + RuleFor(x => x.VectorWeight) + .InclusiveBetween(0, 1).When(x => x.VectorWeight.HasValue) + .WithMessage("向量权重 VectorWeight 取值范围 0-1"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Obsidian/ObsidianSyncRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/Obsidian/ObsidianSyncRequestValidator.cs new file mode 100644 index 0000000..011eb60 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Obsidian/ObsidianSyncRequestValidator.cs @@ -0,0 +1,20 @@ +using BuildFlow.Application.Obsidian.DTOs; + +namespace BuildFlow.Host.Endpoints.Rag.Obsidian; + +/// +/// Obsidian同步SyncRequest的请求校验器(FluentValidation)。 +/// +public class ObsidianSyncRequestValidator : Validator +{ + public ObsidianSyncRequestValidator() + { + RuleFor(x => x.VaultDirectory) + .NotEmpty().WithMessage("Vault 目录不能为空") + .MaximumLength(1000).WithMessage("Vault 目录路径不能超过 1000 个字符"); + + RuleFor(x => x.ChunkingMode) + .InclusiveBetween(0, 2).When(x => x.ChunkingMode.HasValue) + .WithMessage("分块模式 ChunkingMode 取值 0=General,1=Heading,2=ParentChild"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/Obsidian/SyncObsidianVaultEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/Obsidian/SyncObsidianVaultEndpoint.cs new file mode 100644 index 0000000..eef3cb7 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/Obsidian/SyncObsidianVaultEndpoint.cs @@ -0,0 +1,36 @@ +using BuildFlow.Application.Obsidian.Commands; +using BuildFlow.Application.Obsidian.DTOs; +using BuildFlow.Domain.Enums; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.Obsidian; + + +/// +/// SyncObsidian同步仓库端点。 +/// +public class SyncObsidianVaultEndpoint(IMediator mediator) + : Endpoint +{ + public override void Configure() + { + Post("/knowledge-bases/{KnowledgeBaseId}/obsidian/sync"); + AllowAnonymous(); + } + + public override async Task HandleAsync(ObsidianSyncRequest req, CancellationToken ct) + { + var kbId = Route("KnowledgeBaseId"); + ChunkingMode? overrideMode = req.ChunkingMode is >= 0 and <= 2 + ? (ChunkingMode)req.ChunkingMode.Value + : null; + var result = await mediator.Send(new SyncObsidianVaultCommand(kbId, req.VaultDirectory, overrideMode), ct); + await Send.OkAsync(result, ct); + } +} + +/// +/// Obsidian vault 同步请求校验。 +/// 注意:目录存在性属于 IO 层校验,留给 handler 处理(避免 validator 内做磁盘 IO); +/// 此处仅校验非空、长度与枚举取值。 +/// diff --git a/src/BuildFlow.Host/Endpoints/Rag/RAG/RAGQueryEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/RAG/RAGQueryEndpoint.cs new file mode 100644 index 0000000..7ce426c --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/RAG/RAGQueryEndpoint.cs @@ -0,0 +1,28 @@ +using BuildFlow.Application.RagQA.Commands; +using BuildFlow.Application.RagQA.DTOs; +using MediatR; + +namespace BuildFlow.Host.Endpoints.Rag.RAG; + + +/// +/// RAG检索问答查询端点。 +/// +public class RAGQueryEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/rag/query"); + AllowAnonymous(); + } + + public override async Task HandleAsync(RAGQueryRequest req, CancellationToken ct) + { + var result = await mediator.Send(new RAGQueryCommand(req.KnowledgeBaseId, req.Question), ct); + await Send.OkAsync(result, ct); + } +} + +/// +/// RAG 问答请求校验。/rag/query 与 /rag/stream 共用同一请求 DTO,故此校验对两个端点同时生效。 +/// diff --git a/src/BuildFlow.Host/Endpoints/Rag/RAG/RAGQueryRequestValidator.cs b/src/BuildFlow.Host/Endpoints/Rag/RAG/RAGQueryRequestValidator.cs new file mode 100644 index 0000000..9c7b2a4 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/RAG/RAGQueryRequestValidator.cs @@ -0,0 +1,18 @@ +using BuildFlow.Application.RagQA.DTOs; + +namespace BuildFlow.Host.Endpoints.Rag.RAG; + +/// +/// RAG检索问答查询Request的请求校验器(FluentValidation)。 +/// +public class RAGQueryRequestValidator : Validator +{ + public RAGQueryRequestValidator() + { + RuleFor(x => x.KnowledgeBaseId).NotEmpty().WithMessage("知识库 ID 不能为空"); + + RuleFor(x => x.Question) + .NotEmpty().WithMessage("问题不能为空") + .MaximumLength(1000).WithMessage("问题不能超过 1000 个字符"); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Rag/RAG/RAGStreamEndpoint.cs b/src/BuildFlow.Host/Endpoints/Rag/RAG/RAGStreamEndpoint.cs new file mode 100644 index 0000000..e610162 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Rag/RAG/RAGStreamEndpoint.cs @@ -0,0 +1,85 @@ +using System.Text; +using System.Text.Json; +using Microsoft.Extensions.AI; +using BuildFlow.Application.RagQA.DTOs; +using BuildFlow.Domain.Interfaces; +using BuildFlow.Infrastructure.Persistence; +// 别名消歧义 +using AiChatMessage = Microsoft.Extensions.AI.ChatMessage; +using AiChatRole = Microsoft.Extensions.AI.ChatRole; + +namespace BuildFlow.Host.Endpoints.Rag.RAG; + +/// +/// RAG 流式问答端点,以 Server-Sent Events 推送。 +/// 协议分三段:1) event:sources 推送命中的来源片段(前端即时展示引用);2) data: 流式推送 LLM 生成内容; +/// 3) data:[DONE] 标记结束。被 ApiResponseMiddleware 通过 IsStreamEndpoint 排除包裹,直接透传字节流。 +/// +public class RAGStreamEndpoint( + RagDbContext db, + IRagRetrievalService retrievalService, + IAIChatAgent chatAgent) + : Endpoint +{ + public override void Configure() + { + Post("/rag/stream"); + AllowAnonymous(); + } + + public override async Task HandleAsync(RAGQueryRequest req, CancellationToken ct) + { + var kb = await db.KnowledgeBases.FindAsync([req.KnowledgeBaseId], ct) + ?? throw new NotFoundException("知识库不存在"); + + // 检索流水线(策略由知识库配置决定) + var hits = await retrievalService.RetrieveAsync(kb, req.Question, ct); + + // SSE:声明流式响应头,必须先于任何 body 写入 + HttpContext.Response.ContentType = "text/event-stream"; + HttpContext.Response.Headers.CacheControl = "no-cache"; + HttpContext.Response.Headers.Connection = "keep-alive"; + + if (hits.Count == 0) + { + var noData = JsonSerializer.Serialize(new { content = "未在知识库中找到相关内容。" }); + await HttpContext.Response.WriteAsync($"data: {noData}\n\n", ct); + await HttpContext.Response.WriteAsync("data: [DONE]\n\n", ct); + await HttpContext.Response.Body.FlushAsync(ct); + return; + } + + // 先推送命中的来源片段 + var sources = hits.Select(h => new SourceChunk( + h.DocumentId, + h.DocumentTitle, + h.ContextContent.Length > 200 ? h.ContextContent[..200] + "..." : h.ContextContent, + Math.Round(h.Score, 4) + )).ToList(); + var sourcesData = JsonSerializer.Serialize(new { sources }); + await HttpContext.Response.WriteAsync($"event: sources\ndata: {sourcesData}\n\n", ct); + await HttpContext.Response.Body.FlushAsync(ct); + + // 构建 MAF ChatMessage(RAG 上下文 + 用户问题) + var contextBuilder = new StringBuilder(); + contextBuilder.AppendLine("以下是检索到的相关上下文:"); + for (var i = 0; i < hits.Count; i++) + contextBuilder.AppendLine($"\n--- 上下文 {i + 1} ---\n{hits[i].ContextContent}"); + + var ragMessages = new List + { + new(AiChatRole.System, "基于提供的上下文回答问题。如果上下文中没有相关信息,请如实说明。"), + new(AiChatRole.User, $"{contextBuilder}\n\n问题:{req.Question}"), + }; + + await foreach (var chunk in chatAgent.RunStreamingAsync(ragMessages, ct)) + { + var sseData = JsonSerializer.Serialize(new { content = chunk }); + await HttpContext.Response.WriteAsync($"data: {sseData}\n\n", ct); + await HttpContext.Response.Body.FlushAsync(ct); + } + + await HttpContext.Response.WriteAsync("data: [DONE]\n\n", ct); + await HttpContext.Response.Body.FlushAsync(ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/CreateBuildFlowApplicationEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/CreateBuildFlowApplicationEndpoint.cs new file mode 100644 index 0000000..8bf457d --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/CreateBuildFlowApplicationEndpoint.cs @@ -0,0 +1,24 @@ +using MediatR; +using Workflow.Application.BuildFlow.Applications.Commands; +using Workflow.Application.BuildFlow.Applications.DTOs; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Applications; + +/// 创建 BuildFlow 应用端点。POST /buildflow/applications。 +public class CreateBuildFlowApplicationEndpoint(IMediator mediator) + : Endpoint +{ + public override void Configure() + { + Post("/buildflow/applications"); + Permissions("buildflow:application:create"); + } + + public override async Task HandleAsync(CreateBuildFlowApplicationRequest req, CancellationToken ct) + { + var result = await mediator.Send( + new CreateBuildFlowApplicationCommand(req.Code, req.Name, req.Description), + ct); + await Send.ResponseAsync(result, 201, ct); + } +} \ No newline at end of file diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/CreateBuildFlowApplicationRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/CreateBuildFlowApplicationRequest.cs new file mode 100644 index 0000000..be9804a --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/CreateBuildFlowApplicationRequest.cs @@ -0,0 +1,4 @@ +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Applications; + +/// 创建 BuildFlow 应用请求。 +public sealed record CreateBuildFlowApplicationRequest(string Code, string Name, string? Description); diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/GetBuildFlowApplicationListEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/GetBuildFlowApplicationListEndpoint.cs new file mode 100644 index 0000000..2575d8a --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/GetBuildFlowApplicationListEndpoint.cs @@ -0,0 +1,25 @@ +using MediatR; +using Workflow.Application.BuildFlow.Applications.DTOs; +using Workflow.Application.BuildFlow.Applications.Queries; +using Workflow.Application.Common; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Applications; + +/// BuildFlow 应用分页查询端点。GET /buildflow/applications。 +public class GetBuildFlowApplicationListEndpoint(IMediator mediator) + : Endpoint> +{ + public override void Configure() + { + Get("/buildflow/applications"); + Permissions("buildflow:application:read"); + } + + public override async Task HandleAsync(GetBuildFlowApplicationListRequest req, CancellationToken ct) + { + var result = await mediator.Send( + new GetBuildFlowApplicationListQuery(req.PageIndex, req.PageSize, req.Status, req.Keyword), + ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/GetBuildFlowApplicationListRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/GetBuildFlowApplicationListRequest.cs new file mode 100644 index 0000000..4bd3880 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Applications/GetBuildFlowApplicationListRequest.cs @@ -0,0 +1,12 @@ +using Workflow.Domain.Enums; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Applications; + +/// BuildFlow 应用分页查询请求。 +public class GetBuildFlowApplicationListRequest +{ + public int PageIndex { get; set; } = 1; + public int PageSize { get; set; } = 20; + public BuildFlowMetadataStatus? Status { get; set; } + public string? Keyword { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionEndpoint.cs new file mode 100644 index 0000000..57ed8f4 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionEndpoint.cs @@ -0,0 +1,38 @@ +using MediatR; +using Workflow.Application.BuildFlow.Buttons.Commands; +using Workflow.Application.BuildFlow.Buttons.DTOs; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Buttons; + +/// 创建 BuildFlow 按钮定义端点。POST /buildflow/buttons。 +public class CreateBuildFlowButtonDefinitionEndpoint(IMediator mediator) + : Endpoint +{ + public override void Configure() + { + Post("/buildflow/buttons"); + Permissions("buildflow:button:create"); + } + + public override async Task HandleAsync(CreateBuildFlowButtonDefinitionRequest req, CancellationToken ct) + { + var result = await mediator.Send( + new CreateBuildFlowButtonDefinitionCommand( + req.ApplicationId, + req.PageDefinitionId, + req.FormDefinitionId, + req.WorkflowDefinitionId, + req.Code, + req.Label, + req.Icon, + req.Placement, + req.PermissionCode, + req.VisibleWhenJson, + req.DisabledWhenJson, + req.ConfirmJson, + req.ActionsJson, + req.SortOrder), + ct); + await Send.ResponseAsync(result, 201, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionRequest.cs new file mode 100644 index 0000000..c101674 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionRequest.cs @@ -0,0 +1,20 @@ +using Workflow.Domain.Enums; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Buttons; + +/// 创建 BuildFlow 按钮定义请求。 +public sealed record CreateBuildFlowButtonDefinitionRequest( + Guid? ApplicationId, + Guid? PageDefinitionId, + Guid? FormDefinitionId, + Guid? WorkflowDefinitionId, + string Code, + string Label, + string? Icon, + BuildFlowButtonPlacement Placement, + string? PermissionCode, + string? VisibleWhenJson, + string? DisabledWhenJson, + string? ConfirmJson, + string ActionsJson, + int SortOrder); diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/ExecuteBuildFlowButtonEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/ExecuteBuildFlowButtonEndpoint.cs new file mode 100644 index 0000000..913b946 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/ExecuteBuildFlowButtonEndpoint.cs @@ -0,0 +1,22 @@ +using MediatR; +using Workflow.Application.BuildFlow.Buttons.Commands; +using Workflow.Application.BuildFlow.Buttons.DTOs; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Buttons; + +/// 执行 BuildFlow 按钮动作链端点。POST /buildflow/buttons/{id}/execute。 +public class ExecuteBuildFlowButtonEndpoint(IMediator mediator) + : Endpoint +{ + public override void Configure() + { + Post("/buildflow/buttons/{id}/execute"); + Permissions("buildflow:button:execute"); + } + + public override async Task HandleAsync(ExecuteBuildFlowButtonRequest req, CancellationToken ct) + { + var result = await mediator.Send(new ExecuteBuildFlowButtonCommand(req.Id, req.InputJson), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/ExecuteBuildFlowButtonRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/ExecuteBuildFlowButtonRequest.cs new file mode 100644 index 0000000..b075509 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/ExecuteBuildFlowButtonRequest.cs @@ -0,0 +1,4 @@ +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Buttons; + +/// 执行 BuildFlow 按钮动作链请求。 +public sealed record ExecuteBuildFlowButtonRequest(Guid Id, string InputJson); diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/GetBuildFlowButtonDefinitionListEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/GetBuildFlowButtonDefinitionListEndpoint.cs new file mode 100644 index 0000000..cdfc731 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/GetBuildFlowButtonDefinitionListEndpoint.cs @@ -0,0 +1,33 @@ +using MediatR; +using Workflow.Application.BuildFlow.Buttons.DTOs; +using Workflow.Application.BuildFlow.Buttons.Queries; +using Workflow.Application.Common; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Buttons; + +/// BuildFlow 按钮定义分页查询端点。GET /buildflow/buttons。 +public class GetBuildFlowButtonDefinitionListEndpoint(IMediator mediator) + : Endpoint> +{ + public override void Configure() + { + Get("/buildflow/buttons"); + Permissions("buildflow:button:read"); + } + + public override async Task HandleAsync(GetBuildFlowButtonDefinitionListRequest req, CancellationToken ct) + { + var result = await mediator.Send( + new GetBuildFlowButtonDefinitionListQuery( + req.PageIndex, + req.PageSize, + req.ApplicationId, + req.PageDefinitionId, + req.FormDefinitionId, + req.WorkflowDefinitionId, + req.Placement, + req.Status), + ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/GetBuildFlowButtonDefinitionListRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/GetBuildFlowButtonDefinitionListRequest.cs new file mode 100644 index 0000000..2683fe3 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Buttons/GetBuildFlowButtonDefinitionListRequest.cs @@ -0,0 +1,16 @@ +using Workflow.Domain.Enums; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Buttons; + +/// BuildFlow 按钮定义分页查询请求。 +public class GetBuildFlowButtonDefinitionListRequest +{ + public int PageIndex { get; set; } = 1; + public int PageSize { get; set; } = 20; + public Guid? ApplicationId { get; set; } + public Guid? PageDefinitionId { get; set; } + public Guid? FormDefinitionId { get; set; } + public Guid? WorkflowDefinitionId { get; set; } + public BuildFlowButtonPlacement? Placement { get; set; } + public BuildFlowMetadataStatus? Status { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/CreateCustomFunctionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/CreateCustomFunctionEndpoint.cs new file mode 100644 index 0000000..8396162 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/CreateCustomFunctionEndpoint.cs @@ -0,0 +1,31 @@ +using MediatR; +using Workflow.Application.BuildFlow.CustomFunctions.Commands; +using Workflow.Application.BuildFlow.CustomFunctions.DTOs; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.CustomFunctions; + +/// 创建自定义函数端点。POST /buildflow/custom-functions。 +public class CreateCustomFunctionEndpoint(IMediator mediator) + : Endpoint +{ + public override void Configure() + { + Post("/buildflow/custom-functions"); + Permissions("buildflow:function:create"); + } + + public override async Task HandleAsync(CreateCustomFunctionRequest req, CancellationToken ct) + { + var result = await mediator.Send( + new CreateCustomFunctionCommand( + req.Name, + req.DisplayName, + req.Description, + req.Code, + req.InputSchema, + req.OutputSchema, + req.TimeoutMs), + ct); + await Send.ResponseAsync(result, 201, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/CreateCustomFunctionRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/CreateCustomFunctionRequest.cs new file mode 100644 index 0000000..78bfa05 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/CreateCustomFunctionRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.CustomFunctions; + +/// 创建自定义函数请求。 +public sealed record CreateCustomFunctionRequest( + string Name, + string DisplayName, + string? Description, + string Code, + string? InputSchema, + string? OutputSchema, + int TimeoutMs); diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/DisableCustomFunctionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/DisableCustomFunctionEndpoint.cs new file mode 100644 index 0000000..67370a6 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/DisableCustomFunctionEndpoint.cs @@ -0,0 +1,22 @@ +using MediatR; +using Workflow.Application.BuildFlow.CustomFunctions.Commands; +using Workflow.Application.BuildFlow.CustomFunctions.DTOs; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.CustomFunctions; + +/// 禁用自定义函数端点。POST /buildflow/custom-functions/{id}/disable。 +public class DisableCustomFunctionEndpoint(IMediator mediator) + : Endpoint +{ + public override void Configure() + { + Post("/buildflow/custom-functions/{id}/disable"); + Permissions("buildflow:function:disable"); + } + + public override async Task HandleAsync(DisableCustomFunctionRequest req, CancellationToken ct) + { + var result = await mediator.Send(new DisableCustomFunctionCommand(req.Id), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/DisableCustomFunctionRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/DisableCustomFunctionRequest.cs new file mode 100644 index 0000000..5e00623 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/DisableCustomFunctionRequest.cs @@ -0,0 +1,4 @@ +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.CustomFunctions; + +/// 禁用自定义函数请求。 +public sealed record DisableCustomFunctionRequest(Guid Id); diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/GetCustomFunctionListEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/GetCustomFunctionListEndpoint.cs new file mode 100644 index 0000000..79d330b --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/GetCustomFunctionListEndpoint.cs @@ -0,0 +1,25 @@ +using MediatR; +using Workflow.Application.BuildFlow.CustomFunctions.DTOs; +using Workflow.Application.BuildFlow.CustomFunctions.Queries; +using Workflow.Application.Common; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.CustomFunctions; + +/// 自定义函数分页查询端点。GET /buildflow/custom-functions。 +public class GetCustomFunctionListEndpoint(IMediator mediator) + : Endpoint> +{ + public override void Configure() + { + Get("/buildflow/custom-functions"); + Permissions("buildflow:function:read"); + } + + public override async Task HandleAsync(GetCustomFunctionListRequest req, CancellationToken ct) + { + var result = await mediator.Send( + new GetCustomFunctionListQuery(req.PageIndex, req.PageSize, req.Status, req.Keyword), + ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/GetCustomFunctionListRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/GetCustomFunctionListRequest.cs new file mode 100644 index 0000000..2c61275 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/GetCustomFunctionListRequest.cs @@ -0,0 +1,12 @@ +using Workflow.Domain.Enums; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.CustomFunctions; + +/// 自定义函数分页查询请求。 +public class GetCustomFunctionListRequest +{ + public int PageIndex { get; set; } = 1; + public int PageSize { get; set; } = 20; + public BuildFlowMetadataStatus? Status { get; set; } + public string? Keyword { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/PublishCustomFunctionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/PublishCustomFunctionEndpoint.cs new file mode 100644 index 0000000..17693ee --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/PublishCustomFunctionEndpoint.cs @@ -0,0 +1,22 @@ +using MediatR; +using Workflow.Application.BuildFlow.CustomFunctions.Commands; +using Workflow.Application.BuildFlow.CustomFunctions.DTOs; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.CustomFunctions; + +/// 发布自定义函数端点。POST /buildflow/custom-functions/{id}/publish。 +public class PublishCustomFunctionEndpoint(IMediator mediator) + : Endpoint +{ + public override void Configure() + { + Post("/buildflow/custom-functions/{id}/publish"); + Permissions("buildflow:function:publish"); + } + + public override async Task HandleAsync(PublishCustomFunctionRequest req, CancellationToken ct) + { + var result = await mediator.Send(new PublishCustomFunctionCommand(req.Id), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/PublishCustomFunctionRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/PublishCustomFunctionRequest.cs new file mode 100644 index 0000000..48d0ce9 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/PublishCustomFunctionRequest.cs @@ -0,0 +1,4 @@ +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.CustomFunctions; + +/// 发布自定义函数请求。 +public sealed record PublishCustomFunctionRequest(Guid Id); diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/TestCustomFunctionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/TestCustomFunctionEndpoint.cs new file mode 100644 index 0000000..4f3a21b --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/TestCustomFunctionEndpoint.cs @@ -0,0 +1,22 @@ +using MediatR; +using Workflow.Application.BuildFlow.CustomFunctions.Commands; +using Workflow.Application.BuildFlow.CustomFunctions.DTOs; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.CustomFunctions; + +/// 测试执行自定义函数端点。POST /buildflow/custom-functions/{id}/test。 +public class TestCustomFunctionEndpoint(IMediator mediator) + : Endpoint +{ + public override void Configure() + { + Post("/buildflow/custom-functions/{id}/test"); + Permissions("buildflow:function:test"); + } + + public override async Task HandleAsync(TestCustomFunctionRequest req, CancellationToken ct) + { + var result = await mediator.Send(new TestCustomFunctionCommand(req.Id, req.InputJson), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/TestCustomFunctionRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/TestCustomFunctionRequest.cs new file mode 100644 index 0000000..2c2270a --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/CustomFunctions/TestCustomFunctionRequest.cs @@ -0,0 +1,4 @@ +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.CustomFunctions; + +/// 测试执行自定义函数请求。 +public sealed record TestCustomFunctionRequest(Guid Id, string InputJson); diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/CreateBuildFlowPageDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/CreateBuildFlowPageDefinitionEndpoint.cs new file mode 100644 index 0000000..a1aa723 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/CreateBuildFlowPageDefinitionEndpoint.cs @@ -0,0 +1,29 @@ +using MediatR; +using Workflow.Application.BuildFlow.Pages.Commands; +using Workflow.Application.BuildFlow.Pages.DTOs; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Pages; + +/// 创建 BuildFlow 页面定义端点。POST /buildflow/pages。 +public class CreateBuildFlowPageDefinitionEndpoint(IMediator mediator) + : Endpoint +{ + public override void Configure() + { + Post("/buildflow/pages"); + Permissions("buildflow:page:create"); + } + + public override async Task HandleAsync(CreateBuildFlowPageDefinitionRequest req, CancellationToken ct) + { + var result = await mediator.Send( + new CreateBuildFlowPageDefinitionCommand( + req.ApplicationId, + req.Code, + req.Name, + req.PageType, + req.SchemaJson), + ct); + await Send.ResponseAsync(result, 201, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/CreateBuildFlowPageDefinitionRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/CreateBuildFlowPageDefinitionRequest.cs new file mode 100644 index 0000000..c5a8452 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/CreateBuildFlowPageDefinitionRequest.cs @@ -0,0 +1,11 @@ +using Workflow.Domain.Enums; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Pages; + +/// 创建 BuildFlow 页面定义请求。 +public sealed record CreateBuildFlowPageDefinitionRequest( + Guid ApplicationId, + string Code, + string Name, + BuildFlowPageType PageType, + string SchemaJson); diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListEndpoint.cs new file mode 100644 index 0000000..a020916 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListEndpoint.cs @@ -0,0 +1,30 @@ +using MediatR; +using Workflow.Application.BuildFlow.Pages.DTOs; +using Workflow.Application.BuildFlow.Pages.Queries; +using Workflow.Application.Common; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Pages; + +/// BuildFlow 页面定义分页查询端点。GET /buildflow/pages。 +public class GetBuildFlowPageDefinitionListEndpoint(IMediator mediator) + : Endpoint> +{ + public override void Configure() + { + Get("/buildflow/pages"); + Permissions("buildflow:page:read"); + } + + public override async Task HandleAsync(GetBuildFlowPageDefinitionListRequest req, CancellationToken ct) + { + var result = await mediator.Send( + new GetBuildFlowPageDefinitionListQuery( + req.PageIndex, + req.PageSize, + req.ApplicationId, + req.PageType, + req.Status), + ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListRequest.cs new file mode 100644 index 0000000..3bf80d1 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListRequest.cs @@ -0,0 +1,13 @@ +using Workflow.Domain.Enums; + +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Pages; + +/// BuildFlow 页面定义分页查询请求。 +public class GetBuildFlowPageDefinitionListRequest +{ + public int PageIndex { get; set; } = 1; + public int PageSize { get; set; } = 20; + public Guid? ApplicationId { get; set; } + public BuildFlowPageType? PageType { get; set; } + public BuildFlowMetadataStatus? Status { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/CompareFormVersionsEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/CompareFormVersionsEndpoint.cs new file mode 100644 index 0000000..3fb85e9 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/CompareFormVersionsEndpoint.cs @@ -0,0 +1,33 @@ +using MediatR; +using Workflow.Application.Form.DTOs; +using Workflow.Application.Form.FormDefinition.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + + +/// +/// 对比两个表单版本差异端点。 +/// +public class CompareFormVersionsEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public CompareFormVersionsEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/forms/{Id}/versions/compare"); + Permissions("form:read"); + Summary(s => + { + s.Summary = "对比表单的两个版本"; + }); + } + + public override async Task HandleAsync(CompareFormVersionsRequest req, CancellationToken ct) + { + var query = new CompareFormVersionsQuery(req.Id, req.OldVersionId, req.NewVersionId); + var result = await _mediator.Send(query, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/CompareFormVersionsRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/CompareFormVersionsRequest.cs new file mode 100644 index 0000000..3f1bb78 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/CompareFormVersionsRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 版本对比请求体。含两个版本 ID。 +/// +public class CompareFormVersionsRequest +{ + public Guid Id { get; set; } + public Guid? OldVersionId { get; set; } + public Guid? NewVersionId { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormComponentEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormComponentEndpoint.cs new file mode 100644 index 0000000..239130e --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormComponentEndpoint.cs @@ -0,0 +1,35 @@ +using MediatR; +using Workflow.Application.Form.ComponentRegistry.Commands; +using Workflow.Application.Form.ComponentRegistry.DTOs; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + + +/// +/// 创建表单组件端点(可复用组件库)。 +/// +public class CreateFormComponentEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public CreateFormComponentEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Post("/form-components"); + Permissions("form:write"); + Summary(s => + { + s.Summary = "创建组件注册"; + }); + } + + public override async Task HandleAsync(CreateFormComponentRequest req, CancellationToken ct) + { + var command = new CreateFormComponentCommand( + req.Name, req.DisplayName, req.Category, req.Icon, + req.DefaultSchema, req.SupportedProps); + var result = await _mediator.Send(command, ct); + await Send.ResponseAsync(result, 201, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormComponentRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormComponentRequest.cs new file mode 100644 index 0000000..274b548 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormComponentRequest.cs @@ -0,0 +1,14 @@ +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 创建表单组件请求体。 +/// +public class CreateFormComponentRequest +{ + public string Name { get; set; } = string.Empty; + public string DisplayName { get; set; } = string.Empty; + public string Category { get; set; } = string.Empty; + public string Icon { get; set; } = string.Empty; + public string DefaultSchema { get; set; } = string.Empty; + public string SupportedProps { get; set; } = "{}"; +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormDefinitionEndpoint.cs new file mode 100644 index 0000000..74537e6 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormDefinitionEndpoint.cs @@ -0,0 +1,29 @@ +using MediatR; +using Workflow.Application.Form.DTOs; +using Workflow.Application.Form.FormDefinition.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + + +/// +/// 创建表单定义端点。POST /forms,含字段 schema。 +/// +public class CreateFormDefinitionEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/forms"); + Permissions("form:write"); + Summary(s => + { + s.Summary = "创建表单定义(传入 Formily JSON Schema)"; + }); + } + + public override async Task HandleAsync(CreateFormDefinitionRequest req, CancellationToken ct) + { + var command = new CreateFormDefinitionCommand(req.Name, req.Code, req.Description, req.SchemaJson); + var result = await mediator.Send(command, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormDefinitionRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormDefinitionRequest.cs new file mode 100644 index 0000000..728ee53 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/CreateFormDefinitionRequest.cs @@ -0,0 +1,15 @@ +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 创建表单定义请求体。含表单名与字段 schema。 +/// +public class CreateFormDefinitionRequest +{ + public string Name { get; set; } = string.Empty; + public string Code { get; set; } = string.Empty; + public string? Description { get; set; } + /// + /// Formily JSON Schema 字符串。 + /// + public string SchemaJson { get; set; } = string.Empty; +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormComponentEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormComponentEndpoint.cs new file mode 100644 index 0000000..c54fb75 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormComponentEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Form.ComponentRegistry.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + + +/// +/// 删除表单组件端点。 +/// +public class DeleteFormComponentEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public DeleteFormComponentEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Delete("/form-components/{Id}"); + Permissions("form:write"); + Summary(s => + { + s.Summary = "删除组件注册(软删除)"; + }); + } + + public override async Task HandleAsync(DeleteFormComponentRequest req, CancellationToken ct) + { + var command = new DeleteFormComponentCommand(req.Id); + await _mediator.Send(command, ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormComponentRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormComponentRequest.cs new file mode 100644 index 0000000..7213cc2 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormComponentRequest.cs @@ -0,0 +1,9 @@ +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 删除表单组件请求体(路由参数绑定)。 +/// +public class DeleteFormComponentRequest +{ + public Guid Id { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormDefinitionEndpoint.cs new file mode 100644 index 0000000..0e9a1bf --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormDefinitionEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Form.FormDefinition.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + + +/// +/// 删除表单定义端点。DELETE /forms/{Id}(校验无流程引用)。 +/// +public class DeleteFormDefinitionEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public DeleteFormDefinitionEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Delete("/forms/{Id}"); + Permissions("form:write"); + Summary(s => + { + s.Summary = "Delete a form definition (soft delete)"; + }); + } + + public override async Task HandleAsync(DeleteFormDefinitionRequest req, CancellationToken ct) + { + var command = new DeleteFormDefinitionCommand(req.Id); + await _mediator.Send(command, ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormDefinitionRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormDefinitionRequest.cs new file mode 100644 index 0000000..39f0bf9 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/DeleteFormDefinitionRequest.cs @@ -0,0 +1,9 @@ +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 删除表单定义请求体(路由参数绑定)。 +/// +public class DeleteFormDefinitionRequest +{ + public Guid Id { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/DisableFormDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/DisableFormDefinitionEndpoint.cs new file mode 100644 index 0000000..772cddb --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/DisableFormDefinitionEndpoint.cs @@ -0,0 +1,30 @@ +using MediatR; +using Workflow.Application.Form.FormDefinition.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + + +/// +/// 停用表单定义端点。阻断新流程引用。 +/// +public class DisableFormDefinitionEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/forms/{Id}/disable"); + Permissions("form:write"); + Summary(s => + { + s.Summary = "禁用表单定义"; + }); + } + + public override async Task HandleAsync(DisableFormDefinitionRequest req, CancellationToken ct) + { + var command = new DisableFormDefinitionCommand(req.Id); + await mediator.Send(command, ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/DisableFormDefinitionRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/DisableFormDefinitionRequest.cs new file mode 100644 index 0000000..1855f62 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/DisableFormDefinitionRequest.cs @@ -0,0 +1,9 @@ +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 停用表单定义请求体(路由参数绑定)。 +/// +public class DisableFormDefinitionRequest +{ + public Guid Id { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormComponentByIdEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormComponentByIdEndpoint.cs new file mode 100644 index 0000000..eb5c02f --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormComponentByIdEndpoint.cs @@ -0,0 +1,32 @@ +using MediatR; +using Workflow.Application.Form.ComponentRegistry.DTOs; +using Workflow.Application.Form.ComponentRegistry.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + + +/// +/// 查询单个表单组件端点。 +/// +public class GetFormComponentByIdEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public GetFormComponentByIdEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/form-components/{Id}"); + Permissions("form:read"); + Summary(s => + { + s.Summary = "根据ID获取组件注册详情"; + }); + } + + public override async Task HandleAsync(GetFormComponentByIdRequest req, CancellationToken ct) + { + var result = await _mediator.Send(new GetFormComponentByIdQuery(req.Id), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormComponentByIdRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormComponentByIdRequest.cs new file mode 100644 index 0000000..ccd2492 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormComponentByIdRequest.cs @@ -0,0 +1,9 @@ +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 表单组件查询请求体(路由参数绑定)。 +/// +public class GetFormComponentByIdRequest +{ + public Guid Id { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormComponentsEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormComponentsEndpoint.cs new file mode 100644 index 0000000..80b46e9 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormComponentsEndpoint.cs @@ -0,0 +1,33 @@ +using MediatR; +using Workflow.Application.Form.ComponentRegistry.DTOs; +using Workflow.Application.Form.ComponentRegistry.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 查询表单组件库列表端点。 +/// +public class GetFormComponentsEndpoint : EndpointWithoutRequest> +{ + private readonly IMediator _mediator; + + public GetFormComponentsEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/form-components"); + Permissions("form:read"); + Summary(s => + { + s.Summary = "获取组件注册列表"; + }); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var category = Query("category", isRequired: false); + var isActive = Query("isActive", isRequired: false); + var result = await _mediator.Send(new GetFormComponentsQuery(category, isActive), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDataByInstanceEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDataByInstanceEndpoint.cs new file mode 100644 index 0000000..757f43f --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDataByInstanceEndpoint.cs @@ -0,0 +1,33 @@ +using MediatR; +using Workflow.Application.Form.DTOs; +using Workflow.Application.Form.FormData.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + + +/// +/// 按流程实例查询表单数据端点。 +/// +public class GetFormDataByInstanceEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public GetFormDataByInstanceEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/forms/data/{InstanceId}"); + Permissions("form:read"); + Summary(s => + { + s.Summary = "Get form data by workflow instance id"; + }); + } + + public override async Task HandleAsync(GetFormDataByInstanceRequest req, CancellationToken ct) + { + var query = new GetFormDataByInstanceQuery(req.InstanceId); + var result = await _mediator.Send(query, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDataByInstanceRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDataByInstanceRequest.cs new file mode 100644 index 0000000..52fea89 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDataByInstanceRequest.cs @@ -0,0 +1,9 @@ +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 实例表单数据查询请求体。 +/// +public class GetFormDataByInstanceRequest +{ + public Guid InstanceId { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionByIdEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionByIdEndpoint.cs new file mode 100644 index 0000000..467395b --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionByIdEndpoint.cs @@ -0,0 +1,33 @@ +using MediatR; +using Workflow.Application.Form.DTOs; +using Workflow.Application.Form.FormDefinition.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + + +/// +/// 查询表单定义详情端点。GET /forms/{Id}。 +/// +public class GetFormDefinitionByIdEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public GetFormDefinitionByIdEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/forms/{Id}"); + Permissions("form:read"); + Summary(s => + { + s.Summary = "Get form definition detail by id (includes fields)"; + }); + } + + public override async Task HandleAsync(GetFormDefinitionByIdRequest req, CancellationToken ct) + { + var query = new GetFormDefinitionByIdQuery(req.Id); + var result = await _mediator.Send(query, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionByIdRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionByIdRequest.cs new file mode 100644 index 0000000..d09c45c --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionByIdRequest.cs @@ -0,0 +1,9 @@ +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 表单定义详情查询请求体(路由参数绑定)。 +/// +public class GetFormDefinitionByIdRequest +{ + public Guid Id { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionListEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionListEndpoint.cs new file mode 100644 index 0000000..d1a1db5 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionListEndpoint.cs @@ -0,0 +1,33 @@ +using MediatR; +using Workflow.Application.Form.DTOs; +using Workflow.Application.Form.FormDefinition.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + + +/// +/// 查询表单定义列表端点。GET /forms。 +/// +public class GetFormDefinitionListEndpoint : Endpoint> +{ + private readonly IMediator _mediator; + + public GetFormDefinitionListEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/forms"); + Permissions("form:read"); + Summary(s => + { + s.Summary = "Get paginated list of form definitions"; + }); + } + + public override async Task HandleAsync(GetFormDefinitionListRequest req, CancellationToken ct) + { + var query = new GetFormDefinitionListQuery(req.PageIndex, req.PageSize, req.Status); + var result = await _mediator.Send(query, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionListRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionListRequest.cs new file mode 100644 index 0000000..803692a --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormDefinitionListRequest.cs @@ -0,0 +1,13 @@ +using Workflow.Domain.Enums; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 表单定义列表查询请求体。含分页与状态过滤。 +/// +public class GetFormDefinitionListRequest +{ + public int PageIndex { get; set; } = 1; + public int PageSize { get; set; } = 20; + public FormStatus? Status { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormVersionsEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormVersionsEndpoint.cs new file mode 100644 index 0000000..6c9ed7e --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/GetFormVersionsEndpoint.cs @@ -0,0 +1,32 @@ +using MediatR; +using Workflow.Application.Form.DTOs; +using Workflow.Application.Form.FormDefinition.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 查询表单版本历史端点。GET /forms/{Id}/versions。 +/// +public class GetFormVersionsEndpoint : EndpointWithoutRequest> +{ + private readonly IMediator _mediator; + + public GetFormVersionsEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/forms/{Id}/versions"); + Permissions("form:read"); + Summary(s => + { + s.Summary = "获取表单的历史版本列表"; + }); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var id = Route("Id"); + var result = await _mediator.Send(new GetFormVersionsQuery(id), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/PublishFormDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/PublishFormDefinitionEndpoint.cs new file mode 100644 index 0000000..4dbba4c --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/PublishFormDefinitionEndpoint.cs @@ -0,0 +1,29 @@ +using MediatR; +using Workflow.Application.Form.FormDefinition.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 发布表单定义端点。锁定 schema,可供流程引用。 +/// +public class PublishFormDefinitionEndpoint(IMediator mediator) : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/forms/{Id}/publish"); + Permissions("form:write"); + Summary(s => + { + s.Summary = "Publish a form definition"; + }); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var id = Route("Id"); + await mediator.Send(new PublishFormDefinitionCommand(id), ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/SubmitFormDataEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/SubmitFormDataEndpoint.cs new file mode 100644 index 0000000..e2c3a43 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/SubmitFormDataEndpoint.cs @@ -0,0 +1,32 @@ +using MediatR; +using Workflow.Application.Form.FormData.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + + +/// +/// 提交表单数据端点。关联流程实例写入 formData。 +/// +public class SubmitFormDataEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public SubmitFormDataEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Post("/forms/data"); + Permissions("form:submit"); + Summary(s => + { + s.Summary = "Submit form data for a workflow instance"; + }); + } + + public override async Task HandleAsync(SubmitFormDataRequest req, CancellationToken ct) + { + var command = new SubmitFormDataCommand(req.FormDefinitionId, req.InstanceId, req.DataJson); + var result = await _mediator.Send(command, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/SubmitFormDataRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/SubmitFormDataRequest.cs new file mode 100644 index 0000000..93d896d --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/SubmitFormDataRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 提交表单数据请求体。含表单定义 ID 与数据 JSON。 +/// +public class SubmitFormDataRequest +{ + public Guid FormDefinitionId { get; set; } + public Guid InstanceId { get; set; } + public string DataJson { get; set; } = string.Empty; +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormComponentEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormComponentEndpoint.cs new file mode 100644 index 0000000..6034fc2 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormComponentEndpoint.cs @@ -0,0 +1,35 @@ +using MediatR; +using Workflow.Application.Form.ComponentRegistry.Commands; +using Workflow.Application.Form.ComponentRegistry.DTOs; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + + +/// +/// 更新表单组件端点。 +/// +public class UpdateFormComponentEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public UpdateFormComponentEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Put("/form-components/{Id}"); + Permissions("form:write"); + Summary(s => + { + s.Summary = "更新组件注册"; + }); + } + + public override async Task HandleAsync(UpdateFormComponentRequest req, CancellationToken ct) + { + var command = new UpdateFormComponentCommand( + req.Id, req.DisplayName, req.Category, req.Icon, + req.DefaultSchema, req.SupportedProps, req.IsActive); + var result = await _mediator.Send(command, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormComponentRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormComponentRequest.cs new file mode 100644 index 0000000..84022c8 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormComponentRequest.cs @@ -0,0 +1,15 @@ +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 更新表单组件请求体。 +/// +public class UpdateFormComponentRequest +{ + public Guid Id { get; set; } + public string DisplayName { get; set; } = string.Empty; + public string Category { get; set; } = string.Empty; + public string Icon { get; set; } = string.Empty; + public string DefaultSchema { get; set; } = string.Empty; + public string SupportedProps { get; set; } = "{}"; + public bool IsActive { get; set; } = true; +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormDefinitionEndpoint.cs new file mode 100644 index 0000000..649cc43 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormDefinitionEndpoint.cs @@ -0,0 +1,36 @@ +using MediatR; +using Workflow.Application.Form.DTOs; +using Workflow.Application.Form.FormDefinition.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.Form; + + +/// +/// 更新表单定义端点。PUT /forms/{Id}(仅 Draft 态可改)。 +/// +public class UpdateFormDefinitionEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public UpdateFormDefinitionEndpoint(IMediator mediator) + { + _mediator = mediator; + } + + public override void Configure() + { + Put("/forms/{Id}"); + Permissions("form:write"); + Summary(s => + { + s.Summary = "更新表单定义(传入新的 Formily JSON Schema)"; + }); + } + + public override async Task HandleAsync(UpdateFormDefinitionRequest req, CancellationToken ct) + { + var command = new UpdateFormDefinitionCommand(req.Id, req.Name, req.Description, req.SchemaJson); + var result = await _mediator.Send(command, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormDefinitionRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormDefinitionRequest.cs new file mode 100644 index 0000000..d901d1f --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Form/UpdateFormDefinitionRequest.cs @@ -0,0 +1,15 @@ +namespace BuildFlow.Host.Endpoints.Workflow.Form; + +/// +/// 更新表单定义请求体。 +/// +public class UpdateFormDefinitionRequest +{ + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + /// + /// Formily JSON Schema 字符串。 + /// + public string SchemaJson { get; set; } = string.Empty; +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Notification/GetNotificationsEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Notification/GetNotificationsEndpoint.cs new file mode 100644 index 0000000..85c4e65 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Notification/GetNotificationsEndpoint.cs @@ -0,0 +1,27 @@ +using BuildFlow.Host.Services.Users; +using BuildFlow.Shared.Domain.Common; +using MediatR; +using Workflow.Application.Common; +using Workflow.Application.Features.Notifications; + +namespace BuildFlow.Host.Endpoints.Workflow.Notification; + +/// 获取当前用户的通知列表(含按角色匹配的通知)。 +public class GetNotificationsEndpoint(IMediator mediator, ICurrentUserContext userContext) + : Endpoint> +{ + public override void Configure() + { + Get("/wf/notifications"); + Permissions("wf-notification:read"); + } + + public override async Task HandleAsync(GetNotificationsRequest req, CancellationToken ct) + { + var userId = userContext.GetUserIdGuid(); + var roles = User.GetUserRoles(); + var result = await mediator.Send( + new GetNotificationsQuery(userId, roles, req.UnreadOnly, req.PageIndex, req.PageSize), ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Notification/GetNotificationsRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/Notification/GetNotificationsRequest.cs new file mode 100644 index 0000000..3446af5 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Notification/GetNotificationsRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.Workflow.Notification; + +/// +/// 通知列表查询请求体。含分页与已读过滤。 +/// +public class GetNotificationsRequest +{ + public bool UnreadOnly { get; set; } + public int PageIndex { get; set; } = 1; + public int PageSize { get; set; } = 20; +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Notification/GetUnreadNotificationCountEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Notification/GetUnreadNotificationCountEndpoint.cs new file mode 100644 index 0000000..b8bf4ec --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Notification/GetUnreadNotificationCountEndpoint.cs @@ -0,0 +1,24 @@ +using BuildFlow.Host.Services.Users; +using BuildFlow.Shared.Domain.Common; +using MediatR; +using Workflow.Application.Features.Notifications; + +namespace BuildFlow.Host.Endpoints.Workflow.Notification; + +/// 获取当前用户的未读通知数(前端角标用)。 +public class GetUnreadNotificationCountEndpoint(IMediator mediator, ICurrentUserContext userContext) : EndpointWithoutRequest +{ + public override void Configure() + { + Get("/wf/notifications/unread-count"); + Permissions("wf-notification:read"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var userId = userContext.GetUserIdGuid(); + var roles = User.GetUserRoles(); + var count = await mediator.Send(new GetUnreadNotificationCountQuery(userId, roles), ct); + await Send.OkAsync(count, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Notification/MarkAllNotificationsReadEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Notification/MarkAllNotificationsReadEndpoint.cs new file mode 100644 index 0000000..30ffa1a --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Notification/MarkAllNotificationsReadEndpoint.cs @@ -0,0 +1,26 @@ +using BuildFlow.Host.Services.Users; +using BuildFlow.Shared.Domain.Common; +using MediatR; +using Workflow.Application.Features.Notifications; + +namespace BuildFlow.Host.Endpoints.Workflow.Notification; + +/// 标记当前用户所有通知为已读。 +public class MarkAllNotificationsReadEndpoint(IMediator mediator, ICurrentUserContext userContext) : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/wf/notifications/read-all"); + Permissions("wf-notification:write"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var userId = userContext.GetUserIdGuid(); + var roles = User.GetUserRoles(); + await mediator.Send(new MarkAllNotificationsReadCommand(userId, roles), ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Notification/MarkNotificationReadEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/Notification/MarkNotificationReadEndpoint.cs new file mode 100644 index 0000000..c1875e4 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Notification/MarkNotificationReadEndpoint.cs @@ -0,0 +1,26 @@ +using BuildFlow.Host.Services.Users; +using BuildFlow.Shared.Domain.Common; +using MediatR; +using Workflow.Application.Features.Notifications; + +namespace BuildFlow.Host.Endpoints.Workflow.Notification; + +/// 标记单条通知为已读。 +public class MarkNotificationReadEndpoint(IMediator mediator, ICurrentUserContext userContext) : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/wf/notifications/{Id}/read"); + Permissions("wf-notification:write"); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var id = Route("Id"); + var userId = userContext.GetUserIdGuid(); + await mediator.Send(new MarkNotificationReadCommand(id, userId), ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/Notification/NotificationClaimsExtensions.cs b/src/BuildFlow.Host/Endpoints/Workflow/Notification/NotificationClaimsExtensions.cs new file mode 100644 index 0000000..c4a8355 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/Notification/NotificationClaimsExtensions.cs @@ -0,0 +1,17 @@ +using System.Security.Claims; + +namespace BuildFlow.Host.Endpoints.Workflow.Notification; + +/// ClaimsPrincipal 扩展。从 JWT claims 提取用户角色列表(兼容短名 role 与长名 ClaimTypes.Role)。 +internal static class NotificationClaimsExtensions +{ + public static IReadOnlyList GetUserRoles(this ClaimsPrincipal user) + { + return user.FindAll("role") + .Concat(user.FindAll(ClaimTypes.Role)) + .Select(c => c.Value) + .Where(v => !string.IsNullOrWhiteSpace(v)) + .Distinct() + .ToList(); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateEdgeEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateEdgeEndpoint.cs new file mode 100644 index 0000000..1131308 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateEdgeEndpoint.cs @@ -0,0 +1,35 @@ +using MediatR; +using Workflow.Application.Features.WorkflowDefinitions.Commands; +using Workflow.Application.Features.WorkflowDefinitions.DTOs; +using Workflow.Domain.Enums; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + + +/// +/// 创建流程边端点。 +/// +[Obsolete("已废弃,改用整图 PUT 保存(过渡期保留)")] +public class CreateEdgeEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public CreateEdgeEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Post("/workflow-definitions/{DefinitionId}/edges"); + Permissions("workflow-definition:write"); + Summary(s => + { + s.Summary = "Create a new edge in a workflow definition"; + }); + } + + public override async Task HandleAsync(CreateEdgeRequest req, CancellationToken ct) + { + var command = new CreateEdgeCommand(req.DefinitionId, req.SourceNodeId, req.TargetNodeId, (EdgeType)req.EdgeType, req.Label, req.Condition, req.Order); + var result = await _mediator.Send(command, ct); + await Send.ResponseAsync(result, 201, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateEdgeRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateEdgeRequest.cs new file mode 100644 index 0000000..eaeca1e --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateEdgeRequest.cs @@ -0,0 +1,15 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + +/// +/// 创建边请求体。含源/目标节点与条件。 +/// +public class CreateEdgeRequest +{ + public Guid DefinitionId { get; set; } + public Guid SourceNodeId { get; set; } + public Guid TargetNodeId { get; set; } + public int EdgeType { get; set; } + public string? Label { get; set; } + public string? Condition { get; set; } + public int Order { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateNodeEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateNodeEndpoint.cs new file mode 100644 index 0000000..ebd6ee0 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateNodeEndpoint.cs @@ -0,0 +1,42 @@ +using MediatR; +using Workflow.Application.Features.WorkflowDefinitions.Commands; +using Workflow.Application.Features.WorkflowDefinitions.DTOs; +using Workflow.Domain.Enums; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + + +/// +/// 创建流程节点端点。 +/// +[Obsolete("已废弃,改用整图 PUT 保存(过渡期保留)")] +public class CreateNodeEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public CreateNodeEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Post("/workflow-definitions/{DefinitionId}/nodes"); + Permissions("workflow-definition:write"); + Summary(s => + { + s.Summary = "Create a new node in a workflow definition"; + }); + } + + public override async Task HandleAsync(CreateNodeRequest req, CancellationToken ct) + { + var command = new CreateNodeCommand( + req.DefinitionId, + (NodeType)req.NodeType, + req.Name, + req.Config, + req.PositionX, + req.PositionY, + req.FormDefinitionId); + var result = await _mediator.Send(command, ct); + await Send.ResponseAsync(result, 201, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateNodeRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateNodeRequest.cs new file mode 100644 index 0000000..8906a40 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateNodeRequest.cs @@ -0,0 +1,15 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + +/// +/// 创建节点请求体。含节点类型与配置。 +/// +public class CreateNodeRequest +{ + public Guid DefinitionId { get; set; } + public int NodeType { get; set; } + public string Name { get; set; } = string.Empty; + public string? Config { get; set; } + public int PositionX { get; set; } + public int PositionY { get; set; } + public Guid? FormDefinitionId { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateWorkflowDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateWorkflowDefinitionEndpoint.cs new file mode 100644 index 0000000..909384a --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateWorkflowDefinitionEndpoint.cs @@ -0,0 +1,33 @@ +using MediatR; +using Workflow.Application.Features.WorkflowDefinitions.Commands; +using Workflow.Application.Features.WorkflowDefinitions.DTOs; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + + +/// +/// 创建流程定义端点。POST /definitions(Draft 态)。 +/// +public class CreateWorkflowDefinitionEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public CreateWorkflowDefinitionEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Post("/workflow-definitions"); + Permissions("workflow-definition:write"); + Summary(s => + { + s.Summary = "Create a new workflow definition"; + }); + } + + public override async Task HandleAsync(CreateWorkflowDefinitionRequest req, CancellationToken ct) + { + var command = new CreateWorkflowDefinitionCommand(req.Name, req.Code, req.Description, req.FormDefinitionId); + var result = await _mediator.Send(command, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateWorkflowDefinitionRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateWorkflowDefinitionRequest.cs new file mode 100644 index 0000000..06fa64e --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/CreateWorkflowDefinitionRequest.cs @@ -0,0 +1,12 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + +/// +/// 创建流程定义请求体。含名称与节点/边。 +/// +public class CreateWorkflowDefinitionRequest +{ + public string Name { get; set; } = string.Empty; + public string Code { get; set; } = string.Empty; + public string? Description { get; set; } + public Guid? FormDefinitionId { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteEdgeEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteEdgeEndpoint.cs new file mode 100644 index 0000000..7636a62 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteEdgeEndpoint.cs @@ -0,0 +1,35 @@ +using MediatR; +using Workflow.Application.Features.WorkflowDefinitions.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + + +/// +/// 删除流程边端点。 +/// +[Obsolete("已废弃,改用整图 PUT 保存(过渡期保留)")] +public class DeleteEdgeEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public DeleteEdgeEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Delete("/workflow-definitions/{DefinitionId}/edges/{EdgeId}"); + Permissions("workflow-definition:write"); + Summary(s => + { + s.Summary = "Delete an edge from a workflow definition"; + }); + } + + public override async Task HandleAsync(DeleteEdgeRequest req, CancellationToken ct) + { + var command = new DeleteEdgeCommand(req.EdgeId); + await _mediator.Send(command, ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteEdgeRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteEdgeRequest.cs new file mode 100644 index 0000000..b04fc0f --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteEdgeRequest.cs @@ -0,0 +1,10 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + +/// +/// 删除边请求体(路由参数绑定)。 +/// +public class DeleteEdgeRequest +{ + public Guid DefinitionId { get; set; } + public Guid EdgeId { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteNodeEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteNodeEndpoint.cs new file mode 100644 index 0000000..5efebd3 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteNodeEndpoint.cs @@ -0,0 +1,35 @@ +using MediatR; +using Workflow.Application.Features.WorkflowDefinitions.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + + +/// +/// 删除流程节点端点。 +/// +[Obsolete("已废弃,改用整图 PUT 保存(过渡期保留)")] +public class DeleteNodeEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public DeleteNodeEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Delete("/workflow-definitions/{DefinitionId}/nodes/{NodeId}"); + Permissions("workflow-definition:write"); + Summary(s => + { + s.Summary = "Delete a node from a workflow definition"; + }); + } + + public override async Task HandleAsync(DeleteNodeRequest req, CancellationToken ct) + { + var command = new DeleteNodeCommand(req.NodeId); + await _mediator.Send(command, ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteNodeRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteNodeRequest.cs new file mode 100644 index 0000000..41c430f --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteNodeRequest.cs @@ -0,0 +1,10 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + +/// +/// 删除节点请求体(路由参数绑定)。 +/// +public class DeleteNodeRequest +{ + public Guid DefinitionId { get; set; } + public Guid NodeId { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteWorkflowDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteWorkflowDefinitionEndpoint.cs new file mode 100644 index 0000000..3955e53 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteWorkflowDefinitionEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Features.WorkflowDefinitions.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + + +/// +/// 删除流程定义端点(校验无运行中实例)。 +/// +public class DeleteWorkflowDefinitionEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public DeleteWorkflowDefinitionEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Delete("/workflow-definitions/{Id}"); + Permissions("workflow-definition:write"); + Summary(s => + { + s.Summary = "Delete a workflow definition (soft delete)"; + }); + } + + public override async Task HandleAsync(DeleteWorkflowDefinitionRequest req, CancellationToken ct) + { + var command = new DeleteWorkflowDefinitionCommand(req.Id); + await _mediator.Send(command, ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteWorkflowDefinitionRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteWorkflowDefinitionRequest.cs new file mode 100644 index 0000000..73ce477 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DeleteWorkflowDefinitionRequest.cs @@ -0,0 +1,9 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + +/// +/// 删除流程定义请求体(路由参数绑定)。 +/// +public class DeleteWorkflowDefinitionRequest +{ + public Guid Id { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DisableWorkflowDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DisableWorkflowDefinitionEndpoint.cs new file mode 100644 index 0000000..ba08d7c --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/DisableWorkflowDefinitionEndpoint.cs @@ -0,0 +1,29 @@ +using MediatR; +using Workflow.Application.Features.WorkflowDefinitions.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + +/// +/// 停用流程定义端点。阻断新实例发起。 +/// +public class DisableWorkflowDefinitionEndpoint(IMediator mediator) : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/workflow-definitions/{Id}/disable"); + Permissions("workflow-definition:write"); + Summary(s => + { + s.Summary = "Disable a workflow definition"; + }); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var id = Route("Id"); + await mediator.Send(new DisableWorkflowDefinitionCommand(id), ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionByIdEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionByIdEndpoint.cs new file mode 100644 index 0000000..5af15f2 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionByIdEndpoint.cs @@ -0,0 +1,33 @@ +using MediatR; +using Workflow.Application.Features.WorkflowDefinitions.DTOs; +using Workflow.Application.Features.WorkflowDefinitions.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + + +/// +/// 查询流程定义详情端点。GET /definitions/{Id}。 +/// +public class GetWorkflowDefinitionByIdEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public GetWorkflowDefinitionByIdEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/workflow-definitions/{Id}"); + Permissions("workflow-definition:read"); + Summary(s => + { + s.Summary = "Get workflow definition detail by id (includes nodes and edges)"; + }); + } + + public override async Task HandleAsync(GetWorkflowDefinitionByIdRequest req, CancellationToken ct) + { + var query = new GetWorkflowDefinitionByIdQuery(req.Id); + var result = await _mediator.Send(query, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionByIdRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionByIdRequest.cs new file mode 100644 index 0000000..59ed456 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionByIdRequest.cs @@ -0,0 +1,9 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + +/// +/// 流程定义详情查询请求体(路由参数绑定)。 +/// +public class GetWorkflowDefinitionByIdRequest +{ + public Guid Id { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionListEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionListEndpoint.cs new file mode 100644 index 0000000..99688b6 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionListEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Common; +using Workflow.Application.Features.WorkflowDefinitions.DTOs; +using Workflow.Application.Features.WorkflowDefinitions.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + + +/// +/// 查询流程定义列表端点。GET /definitions。 +/// +public class GetWorkflowDefinitionListEndpoint : Endpoint> +{ + private readonly IMediator _mediator; + + public GetWorkflowDefinitionListEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/workflow-definitions"); + Permissions("workflow-definition:read"); + Summary(s => + { + s.Summary = "Get paginated list of workflow definitions"; + }); + } + + public override async Task HandleAsync(GetWorkflowDefinitionListRequest req, CancellationToken ct) + { + var query = new GetWorkflowDefinitionListQuery(req.PageIndex, req.PageSize, req.Status); + var result = await _mediator.Send(query, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionListRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionListRequest.cs new file mode 100644 index 0000000..e560d0a --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/GetWorkflowDefinitionListRequest.cs @@ -0,0 +1,13 @@ +using Workflow.Domain.Enums; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + +/// +/// 流程定义列表查询请求体。含分页与状态过滤。 +/// +public class GetWorkflowDefinitionListRequest +{ + public int PageIndex { get; set; } = 1; + public int PageSize { get; set; } = 20; + public DefinitionStatus? Status { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/PublishWorkflowDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/PublishWorkflowDefinitionEndpoint.cs new file mode 100644 index 0000000..1fcc632 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/PublishWorkflowDefinitionEndpoint.cs @@ -0,0 +1,29 @@ +using MediatR; +using Workflow.Application.Features.WorkflowDefinitions.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + +/// +/// 发布流程定义端点。锁定不可改,可发起实例。 +/// +public class PublishWorkflowDefinitionEndpoint(IMediator mediator) : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/workflow-definitions/{Id}/publish"); + Permissions("workflow-definition:write"); + Summary(s => + { + s.Summary = "Publish a workflow definition"; + }); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var id = Route("Id"); + await mediator.Send(new PublishWorkflowDefinitionCommand(id), ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateEdgeEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateEdgeEndpoint.cs new file mode 100644 index 0000000..7512154 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateEdgeEndpoint.cs @@ -0,0 +1,35 @@ +using MediatR; +using Workflow.Application.Features.WorkflowDefinitions.Commands; +using Workflow.Application.Features.WorkflowDefinitions.DTOs; +using Workflow.Domain.Enums; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + + +/// +/// 更新流程边端点。 +/// +[Obsolete("已废弃,改用整图 PUT 保存(过渡期保留)")] +public class UpdateEdgeEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public UpdateEdgeEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Put("/workflow-definitions/{DefinitionId}/edges/{EdgeId}"); + Permissions("workflow-definition:write"); + Summary(s => + { + s.Summary = "Update an edge in a workflow definition"; + }); + } + + public override async Task HandleAsync(UpdateEdgeRequest req, CancellationToken ct) + { + var command = new UpdateEdgeCommand(req.EdgeId, (EdgeType)req.EdgeType, req.Label, req.Condition, req.Order); + var result = await _mediator.Send(command, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateEdgeRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateEdgeRequest.cs new file mode 100644 index 0000000..80b6d7f --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateEdgeRequest.cs @@ -0,0 +1,14 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + +/// +/// 更新边请求体。 +/// +public class UpdateEdgeRequest +{ + public Guid DefinitionId { get; set; } + public Guid EdgeId { get; set; } + public int EdgeType { get; set; } + public string? Label { get; set; } + public string? Condition { get; set; } + public int Order { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateNodeEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateNodeEndpoint.cs new file mode 100644 index 0000000..29af4c7 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateNodeEndpoint.cs @@ -0,0 +1,40 @@ +using MediatR; +using Workflow.Application.Features.WorkflowDefinitions.Commands; +using Workflow.Application.Features.WorkflowDefinitions.DTOs; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + + +/// +/// 更新流程节点端点。 +/// +[Obsolete("已废弃,改用整图 PUT 保存(过渡期保留)")] +public class UpdateNodeEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public UpdateNodeEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Put("/workflow-definitions/{DefinitionId}/nodes/{NodeId}"); + Permissions("workflow-definition:write"); + Summary(s => + { + s.Summary = "Update a node in a workflow definition"; + }); + } + + public override async Task HandleAsync(UpdateNodeRequest req, CancellationToken ct) + { + var command = new UpdateNodeCommand( + req.NodeId, + req.Name, + req.Config, + req.PositionX, + req.PositionY, + req.FormDefinitionId); + var result = await _mediator.Send(command, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateNodeRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateNodeRequest.cs new file mode 100644 index 0000000..02f6dcd --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateNodeRequest.cs @@ -0,0 +1,15 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + +/// +/// 更新节点请求体。 +/// +public class UpdateNodeRequest +{ + public Guid DefinitionId { get; set; } + public Guid NodeId { get; set; } + public string Name { get; set; } = string.Empty; + public string? Config { get; set; } + public int PositionX { get; set; } + public int PositionY { get; set; } + public Guid? FormDefinitionId { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateWorkflowDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateWorkflowDefinitionEndpoint.cs new file mode 100644 index 0000000..a83a7ab --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateWorkflowDefinitionEndpoint.cs @@ -0,0 +1,33 @@ +using MediatR; +using Workflow.Application.Features.WorkflowDefinitions.Commands; +using Workflow.Application.Features.WorkflowDefinitions.DTOs; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + + +/// +/// 更新流程定义端点(仅 Draft 态可改)。 +/// +public class UpdateWorkflowDefinitionEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public UpdateWorkflowDefinitionEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Put("/workflow-definitions/{Id}"); + Permissions("workflow-definition:write"); + Summary(s => + { + s.Summary = "Update a workflow definition"; + }); + } + + public override async Task HandleAsync(UpdateWorkflowDefinitionRequest req, CancellationToken ct) + { + var command = new UpdateWorkflowDefinitionCommand(req.Id, req.Name, req.Description, req.DefinitionJson, req.FormDefinitionId); + var result = await _mediator.Send(command, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateWorkflowDefinitionRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateWorkflowDefinitionRequest.cs new file mode 100644 index 0000000..1a3d5ac --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowDefinition/UpdateWorkflowDefinitionRequest.cs @@ -0,0 +1,13 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; + +/// +/// 更新流程定义请求体。 +/// +public class UpdateWorkflowDefinitionRequest +{ + public Guid Id { get; set; } + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + public string? DefinitionJson { get; set; } + public Guid? FormDefinitionId { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceByIdEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceByIdEndpoint.cs new file mode 100644 index 0000000..223a21b --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceByIdEndpoint.cs @@ -0,0 +1,33 @@ +using MediatR; +using Workflow.Application.Features.WorkflowInstances.DTOs; +using Workflow.Application.Features.WorkflowInstances.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowInstance; + + +/// +/// 查询流程实例详情端点。GET /instances/{Id}。 +/// +public class GetWorkflowInstanceByIdEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public GetWorkflowInstanceByIdEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/workflow-instances/{Id}"); + Permissions("workflow-instance:read"); + Summary(s => + { + s.Summary = "Get workflow instance detail by id (includes tokens and tasks)"; + }); + } + + public override async Task HandleAsync(GetWorkflowInstanceByIdRequest req, CancellationToken ct) + { + var query = new GetWorkflowInstanceByIdQuery(req.Id); + var result = await _mediator.Send(query, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceByIdRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceByIdRequest.cs new file mode 100644 index 0000000..54e2642 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceByIdRequest.cs @@ -0,0 +1,9 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowInstance; + +/// +/// 实例详情查询请求体(路由参数绑定)。 +/// +public class GetWorkflowInstanceByIdRequest +{ + public Guid Id { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceListEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceListEndpoint.cs new file mode 100644 index 0000000..4804ec1 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceListEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Common; +using Workflow.Application.Features.WorkflowInstances.DTOs; +using Workflow.Application.Features.WorkflowInstances.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowInstance; + + +/// +/// 查询流程实例列表端点。GET /instances。 +/// +public class GetWorkflowInstanceListEndpoint : Endpoint> +{ + private readonly IMediator _mediator; + + public GetWorkflowInstanceListEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/workflow-instances"); + Permissions("workflow-instance:read"); + Summary(s => + { + s.Summary = "Get paginated list of workflow instances"; + }); + } + + public override async Task HandleAsync(GetWorkflowInstanceListRequest req, CancellationToken ct) + { + var query = new GetWorkflowInstanceListQuery(req.PageIndex, req.PageSize, req.Status, req.InitiatorId); + var result = await _mediator.Send(query, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceListRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceListRequest.cs new file mode 100644 index 0000000..a23f306 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/GetWorkflowInstanceListRequest.cs @@ -0,0 +1,14 @@ +using Workflow.Domain.Enums; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowInstance; + +/// +/// 实例列表查询请求体。含分页与状态过滤。 +/// +public class GetWorkflowInstanceListRequest +{ + public int PageIndex { get; set; } = 1; + public int PageSize { get; set; } = 20; + public InstanceStatus? Status { get; set; } + public Guid? InitiatorId { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/MonitorWorkflowInstancesEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/MonitorWorkflowInstancesEndpoint.cs new file mode 100644 index 0000000..1fcc931 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/MonitorWorkflowInstancesEndpoint.cs @@ -0,0 +1,32 @@ +using MediatR; +using Workflow.Application.Features.WorkflowInstances.DTOs; +using Workflow.Application.Features.WorkflowInstances.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowInstance; + +/// +/// 流程实例监控端点。聚合运行中/逾期实例统计。 +/// +public class MonitorWorkflowInstancesEndpoint : EndpointWithoutRequest +{ + private readonly IMediator _mediator; + + public MonitorWorkflowInstancesEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/workflow-instances/monitor"); + Permissions("workflow-instance:read"); + Summary(s => + { + s.Summary = "Get workflow monitoring statistics"; + }); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var query = new MonitorWorkflowInstancesQuery(); + var result = await _mediator.Send(query, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/ResumeWorkflowInstanceEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/ResumeWorkflowInstanceEndpoint.cs new file mode 100644 index 0000000..c146bf2 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/ResumeWorkflowInstanceEndpoint.cs @@ -0,0 +1,29 @@ +using MediatR; +using Workflow.Application.Features.WorkflowInstances.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowInstance; + +/// +/// 恢复挂起的流程实例端点。 +/// +public class ResumeWorkflowInstanceEndpoint(IMediator mediator) : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/workflow-instances/{Id}/resume"); + Permissions("workflow-instance:manage"); + Summary(s => + { + s.Summary = "Resume a suspended workflow instance"; + }); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var id = Route("Id"); + await mediator.Send(new ResumeWorkflowInstanceCommand(id), ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/StartWorkflowInstanceEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/StartWorkflowInstanceEndpoint.cs new file mode 100644 index 0000000..208d7d0 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/StartWorkflowInstanceEndpoint.cs @@ -0,0 +1,32 @@ +using MediatR; +using Workflow.Application.Features.WorkflowInstances.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowInstance; + + +/// +/// 发起流程实例端点。POST /instances,按定义创建实例并产生首个 token。 +/// +public class StartWorkflowInstanceEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public StartWorkflowInstanceEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Post("/workflow-instances"); + Permissions("workflow-instance:start"); + Summary(s => + { + s.Summary = "Start a new workflow instance"; + }); + } + + public override async Task HandleAsync(StartWorkflowInstanceRequest req, CancellationToken ct) + { + var command = new StartWorkflowInstanceCommand(req.DefinitionCode, req.Title, req.Variables, req.FormDataJson); + var result = await _mediator.Send(command, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/StartWorkflowInstanceRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/StartWorkflowInstanceRequest.cs new file mode 100644 index 0000000..87e5336 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/StartWorkflowInstanceRequest.cs @@ -0,0 +1,12 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowInstance; + +/// +/// 发起实例请求体。含流程定义 ID 与表单数据。 +/// +public class StartWorkflowInstanceRequest +{ + public string DefinitionCode { get; set; } = string.Empty; + public string Title { get; set; } = string.Empty; + public string? Variables { get; set; } + public string? FormDataJson { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/SuspendWorkflowInstanceEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/SuspendWorkflowInstanceEndpoint.cs new file mode 100644 index 0000000..3bcd658 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/SuspendWorkflowInstanceEndpoint.cs @@ -0,0 +1,29 @@ +using MediatR; +using Workflow.Application.Features.WorkflowInstances.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowInstance; + +/// +/// 挂起流程实例端点。暂停 token 流转。 +/// +public class SuspendWorkflowInstanceEndpoint(IMediator mediator) : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/workflow-instances/{Id}/suspend"); + Permissions("workflow-instance:manage"); + Summary(s => + { + s.Summary = "Suspend a running workflow instance"; + }); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var id = Route("Id"); + await mediator.Send(new SuspendWorkflowInstanceCommand(id), ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/WithdrawWorkflowInstanceEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/WithdrawWorkflowInstanceEndpoint.cs new file mode 100644 index 0000000..269b9ee --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowInstance/WithdrawWorkflowInstanceEndpoint.cs @@ -0,0 +1,32 @@ +using BuildFlow.Host.Services.Users; +using BuildFlow.Shared.Domain.Common; +using MediatR; +using Workflow.Application.Features.WorkflowInstances.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowInstance; + +/// +/// 撤回流程实例端点(发起人专用,尚未处理任何节点时)。 +/// +public class WithdrawWorkflowInstanceEndpoint(IMediator mediator, ICurrentUserContext userContext) : EndpointWithoutRequest +{ + public override void Configure() + { + Post("/workflow-instances/{Id}/withdraw"); + Permissions("workflow-instance:manage"); + Summary(s => + { + s.Summary = "Withdraw a workflow instance (initiator only)"; + }); + } + + public override async Task HandleAsync(CancellationToken ct) + { + var id = Route("Id"); + var userId = userContext.GetUserIdGuid(); + await mediator.Send(new WithdrawWorkflowInstanceCommand(id, userId), ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/AddSignerEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/AddSignerEndpoint.cs new file mode 100644 index 0000000..b94b93c --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/AddSignerEndpoint.cs @@ -0,0 +1,24 @@ +using MediatR; +using Workflow.Application.Features.WorkflowTasks.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// +/// 加签端点。审批人在审批前临时增加审批人(前加签/后加签)。 +/// POST /workflow-tasks/{Id}/add-signer +/// +public class AddSignerEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/workflow-tasks/{Id}/add-signer"); + Permissions("workflow-task:manage"); + } + + public override async Task HandleAsync(AddSignerRequest req, CancellationToken ct) + { + var id = Route("Id"); + await mediator.Send(new AddSignerCommand(id, req.CurrentUserId, req.SignerUserId, req.Position, req.Comment), ct); + await Send.OkAsync(ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/AddSignerRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/AddSignerRequest.cs new file mode 100644 index 0000000..cb5f4e9 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/AddSignerRequest.cs @@ -0,0 +1,14 @@ +using Workflow.Domain.Enums; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// 加签请求 DTO。 +/// 操作人用户 ID。 +/// 被加签人用户 ID。 +/// 加签位置(Before / After)。 +/// 加签备注(可选)。 +public record AddSignerRequest( + Guid CurrentUserId, + Guid SignerUserId, + SignPosition Position, + string? Comment); diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ApproveTaskEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ApproveTaskEndpoint.cs new file mode 100644 index 0000000..82822cb --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ApproveTaskEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Features.WorkflowTasks.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + + +/// +/// 审批通过任务端点。驱动 TaskStateMachine 转 Approved,按 Approved 边推进流程。 +/// +public class ApproveTaskEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public ApproveTaskEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Post("/workflow-tasks/{Id}/approve"); + Permissions("workflow-task:approve"); + Summary(s => + { + s.Summary = "Approve a pending task"; + }); + } + + public override async Task HandleAsync(ApproveTaskRequest req, CancellationToken ct) + { + var command = new ApproveTaskCommand(req.Id, req.UserId, req.Comment, req.FormDataJson); + await _mediator.Send(command, ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ApproveTaskRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ApproveTaskRequest.cs new file mode 100644 index 0000000..bddccac --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ApproveTaskRequest.cs @@ -0,0 +1,12 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// +/// 审批通过请求体。含任务 ID 与可选审批意见。 +/// +public class ApproveTaskRequest +{ + public Guid Id { get; set; } + public Guid UserId { get; set; } + public string? Comment { get; set; } + public string? FormDataJson { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/DelegateTaskEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/DelegateTaskEndpoint.cs new file mode 100644 index 0000000..9c4a409 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/DelegateTaskEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Features.WorkflowTasks.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + + +/// +/// 委派任务端点。任务暂转 Delegated,被委派人处理后回 Pending。 +/// +public class DelegateTaskEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public DelegateTaskEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Post("/workflow-tasks/{Id}/delegate"); + Permissions("workflow-task:delegate"); + Summary(s => + { + s.Summary = "Delegate a task to another user"; + }); + } + + public override async Task HandleAsync(DelegateTaskRequest req, CancellationToken ct) + { + var command = new DelegateTaskCommand(req.Id, req.FromUserId, req.ToUserId); + await _mediator.Send(command, ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/DelegateTaskRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/DelegateTaskRequest.cs new file mode 100644 index 0000000..b0c8700 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/DelegateTaskRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// +/// 委派请求体。含任务 ID 与被委派人 ID。 +/// +public class DelegateTaskRequest +{ + public Guid Id { get; set; } + public Guid FromUserId { get; set; } + public Guid ToUserId { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetCcTasksEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetCcTasksEndpoint.cs new file mode 100644 index 0000000..3776beb --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetCcTasksEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Common; +using Workflow.Application.Features.WorkflowTasks.DTOs; +using Workflow.Application.Features.WorkflowTasks.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + + +/// +/// 查询抄送任务端点。GET /tasks/cc。 +/// +public class GetCcTasksEndpoint : Endpoint> +{ + private readonly IMediator _mediator; + + public GetCcTasksEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/workflow-tasks/cc"); + Permissions("workflow-task:read"); + Summary(s => + { + s.Summary = "Get CC (carbon copy) tasks for a user"; + }); + } + + public override async Task HandleAsync(GetCcTasksRequest req, CancellationToken ct) + { + var query = new GetCcTasksQuery(req.UserId, req.PageIndex, req.PageSize); + var result = await _mediator.Send(query, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetCcTasksRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetCcTasksRequest.cs new file mode 100644 index 0000000..00cc954 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetCcTasksRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// +/// 抄送任务查询请求体。含分页参数。 +/// +public class GetCcTasksRequest +{ + public Guid UserId { get; set; } + public int PageIndex { get; set; } = 1; + public int PageSize { get; set; } = 20; +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetHistoryTasksEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetHistoryTasksEndpoint.cs new file mode 100644 index 0000000..65f256c --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetHistoryTasksEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Common; +using Workflow.Application.Features.WorkflowTasks.DTOs; +using Workflow.Application.Features.WorkflowTasks.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + + +/// +/// 查询历史任务(已处理)端点。GET /tasks/history。 +/// +public class GetHistoryTasksEndpoint : Endpoint> +{ + private readonly IMediator _mediator; + + public GetHistoryTasksEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/workflow-tasks/history"); + Permissions("workflow-task:read"); + Summary(s => + { + s.Summary = "Get completed (approved/rejected) tasks for a user"; + }); + } + + public override async Task HandleAsync(GetHistoryTasksRequest req, CancellationToken ct) + { + var query = new GetHistoryTasksQuery(req.UserId, req.PageIndex, req.PageSize); + var result = await _mediator.Send(query, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetHistoryTasksRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetHistoryTasksRequest.cs new file mode 100644 index 0000000..3f9dacc --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetHistoryTasksRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// +/// 历史任务查询请求体。含分页与状态过滤。 +/// +public class GetHistoryTasksRequest +{ + public Guid UserId { get; set; } + public int PageIndex { get; set; } = 1; + public int PageSize { get; set; } = 20; +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetOverdueTasksEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetOverdueTasksEndpoint.cs new file mode 100644 index 0000000..3866bcc --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetOverdueTasksEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Common; +using Workflow.Application.Features.WorkflowTasks.DTOs; +using Workflow.Application.Features.WorkflowTasks.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + + +/// +/// 查询逾期任务端点。GET /tasks/overdue。 +/// +public class GetOverdueTasksEndpoint : Endpoint> +{ + private readonly IMediator _mediator; + + public GetOverdueTasksEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/workflow-tasks/overdue"); + Permissions("workflow-task:read"); + Summary(s => + { + s.Summary = "Get overdue tasks (past due date, still pending)"; + }); + } + + public override async Task HandleAsync(GetOverdueTasksRequest req, CancellationToken ct) + { + var query = new GetOverdueTasksQuery(req.UserId, req.PageIndex, req.PageSize); + var result = await _mediator.Send(query, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetOverdueTasksRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetOverdueTasksRequest.cs new file mode 100644 index 0000000..233e9a2 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetOverdueTasksRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// +/// 逾期任务查询请求体。 +/// +public class GetOverdueTasksRequest +{ + public Guid? UserId { get; set; } + public int PageIndex { get; set; } = 1; + public int PageSize { get; set; } = 20; +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetPendingTasksEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetPendingTasksEndpoint.cs new file mode 100644 index 0000000..4d7e755 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetPendingTasksEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Common; +using Workflow.Application.Features.WorkflowTasks.DTOs; +using Workflow.Application.Features.WorkflowTasks.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + + +/// +/// 查询待办任务列表端点。GET /tasks/pending。 +/// +public class GetPendingTasksEndpoint : Endpoint> +{ + private readonly IMediator _mediator; + + public GetPendingTasksEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/workflow-tasks/pending"); + Permissions("workflow-task:read"); + Summary(s => + { + s.Summary = "Get pending tasks for a user"; + }); + } + + public override async Task HandleAsync(GetPendingTasksRequest req, CancellationToken ct) + { + var query = new GetPendingTasksQuery(req.UserId, req.PageIndex, req.PageSize); + var result = await _mediator.Send(query, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetPendingTasksRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetPendingTasksRequest.cs new file mode 100644 index 0000000..c6a2c2f --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetPendingTasksRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// +/// 待办任务查询请求体。含分页参数。 +/// +public class GetPendingTasksRequest +{ + public Guid UserId { get; set; } + public int PageIndex { get; set; } = 1; + public int PageSize { get; set; } = 20; +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetTaskByIdEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetTaskByIdEndpoint.cs new file mode 100644 index 0000000..194987a --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetTaskByIdEndpoint.cs @@ -0,0 +1,33 @@ +using MediatR; +using Workflow.Application.Features.WorkflowTasks.DTOs; +using Workflow.Application.Features.WorkflowTasks.Queries; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + + +/// +/// 查询任务详情端点。GET /tasks/{Id}。 +/// +public class GetTaskByIdEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public GetTaskByIdEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Get("/workflow-tasks/{Id}"); + Permissions("workflow-task:read"); + Summary(s => + { + s.Summary = "Get task detail by id"; + }); + } + + public override async Task HandleAsync(GetTaskByIdRequest req, CancellationToken ct) + { + var query = new GetTaskByIdQuery(req.Id); + var result = await _mediator.Send(query, ct); + await Send.OkAsync(result, ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetTaskByIdRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetTaskByIdRequest.cs new file mode 100644 index 0000000..a5f746e --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/GetTaskByIdRequest.cs @@ -0,0 +1,9 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// +/// 任务详情查询请求体(路由参数绑定)。 +/// +public class GetTaskByIdRequest +{ + public Guid Id { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/MarkCcTaskReadEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/MarkCcTaskReadEndpoint.cs new file mode 100644 index 0000000..7f785bc --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/MarkCcTaskReadEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Features.WorkflowTasks.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + + +/// +/// 标记抄送任务已读端点。Cc 任务转 Read,不影响主流程。 +/// +public class MarkCcTaskReadEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public MarkCcTaskReadEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Post("/workflow-tasks/{Id}/mark-read"); + Permissions("workflow-task:manage"); + Summary(s => + { + s.Summary = "Mark a CC task as read"; + }); + } + + public override async Task HandleAsync(MarkCcTaskReadRequest req, CancellationToken ct) + { + var command = new MarkCcTaskReadCommand(req.Id, req.UserId); + await _mediator.Send(command, ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/MarkCcTaskReadRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/MarkCcTaskReadRequest.cs new file mode 100644 index 0000000..d2b582d --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/MarkCcTaskReadRequest.cs @@ -0,0 +1,10 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// +/// 标记已读请求体。含任务 ID。 +/// +public class MarkCcTaskReadRequest +{ + public Guid Id { get; set; } + public Guid UserId { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/RejectTaskEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/RejectTaskEndpoint.cs new file mode 100644 index 0000000..e6d1cea --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/RejectTaskEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Features.WorkflowTasks.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + + +/// +/// 驳回任务端点。转 Rejected 终态,按 Rejected 边流转(若无则结束实例)。 +/// +public class RejectTaskEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public RejectTaskEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Post("/workflow-tasks/{Id}/reject"); + Permissions("workflow-task:reject"); + Summary(s => + { + s.Summary = "Reject a pending task"; + }); + } + + public override async Task HandleAsync(RejectTaskRequest req, CancellationToken ct) + { + var command = new RejectTaskCommand(req.Id, req.UserId, req.Comment); + await _mediator.Send(command, ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/RejectTaskRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/RejectTaskRequest.cs new file mode 100644 index 0000000..d058a62 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/RejectTaskRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// +/// 驳回请求体。含任务 ID 与驳回理由(必填)。 +/// +public class RejectTaskRequest +{ + public Guid Id { get; set; } + public Guid UserId { get; set; } + public string? Comment { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ReturnTaskEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ReturnTaskEndpoint.cs new file mode 100644 index 0000000..273c52b --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ReturnTaskEndpoint.cs @@ -0,0 +1,24 @@ +using MediatR; +using Workflow.Application.Features.WorkflowTasks.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// +/// 退回端点。将当前审批任务退回到上一个审批节点重新审批(实例继续运行)。 +/// POST /workflow-tasks/{Id}/return +/// +public class ReturnTaskEndpoint(IMediator mediator) : Endpoint +{ + public override void Configure() + { + Post("/workflow-tasks/{Id}/return"); + Permissions("workflow-task:delegate"); + } + + public override async Task HandleAsync(ReturnTaskRequest req, CancellationToken ct) + { + var id = Route("Id"); + await mediator.Send(new ReturnTaskCommand(id, req.CurrentUserId, req.Comment), ct); + await Send.OkAsync(ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ReturnTaskRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ReturnTaskRequest.cs new file mode 100644 index 0000000..2298c87 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/ReturnTaskRequest.cs @@ -0,0 +1,8 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// 退回请求 DTO。 +/// 操作人用户 ID。 +/// 退回备注(可选)。 +public record ReturnTaskRequest( + Guid CurrentUserId, + string? Comment); diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/TransferTaskEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/TransferTaskEndpoint.cs new file mode 100644 index 0000000..871a843 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/TransferTaskEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Features.WorkflowTasks.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + + +/// +/// 转交任务端点。任务转给目标用户,原任务转 Transferred 终态。 +/// +public class TransferTaskEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public TransferTaskEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Post("/workflow-tasks/{Id}/transfer"); + Permissions("workflow-task:delegate"); + Summary(s => + { + s.Summary = "Transfer a task to another user"; + }); + } + + public override async Task HandleAsync(TransferTaskRequest req, CancellationToken ct) + { + var command = new TransferTaskCommand(req.Id, req.FromUserId, req.ToUserId); + await _mediator.Send(command, ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/TransferTaskRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/TransferTaskRequest.cs new file mode 100644 index 0000000..7a4c8ba --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/TransferTaskRequest.cs @@ -0,0 +1,11 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// +/// 转交请求体。含任务 ID 与目标用户 ID。 +/// +public class TransferTaskRequest +{ + public Guid Id { get; set; } + public Guid FromUserId { get; set; } + public Guid ToUserId { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/UrgeTaskEndpoint.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/UrgeTaskEndpoint.cs new file mode 100644 index 0000000..0699983 --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/UrgeTaskEndpoint.cs @@ -0,0 +1,34 @@ +using MediatR; +using Workflow.Application.Features.WorkflowTasks.Commands; + +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + + +/// +/// 催办端点。向待办人发送催办通知。 +/// +public class UrgeTaskEndpoint : Endpoint +{ + private readonly IMediator _mediator; + + public UrgeTaskEndpoint(IMediator mediator) => _mediator = mediator; + + public override void Configure() + { + Post("/workflow-tasks/{Id}/urge"); + Permissions("workflow-task:manage"); + Summary(s => + { + s.Summary = "Urge a pending task (send notification to assignee)"; + }); + } + + public override async Task HandleAsync(UrgeTaskRequest req, CancellationToken ct) + { + var command = new UrgeTaskCommand(req.Id, req.UserId); + await _mediator.Send(command, ct); + HttpContext.Response.StatusCode = 200; + HttpContext.Response.ContentType = "application/json"; + await HttpContext.Response.WriteAsync("{}", ct); + } +} diff --git a/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/UrgeTaskRequest.cs b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/UrgeTaskRequest.cs new file mode 100644 index 0000000..f362f9c --- /dev/null +++ b/src/BuildFlow.Host/Endpoints/Workflow/WorkflowTask/UrgeTaskRequest.cs @@ -0,0 +1,10 @@ +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; + +/// +/// 催办请求体。含任务 ID。 +/// +public class UrgeTaskRequest +{ + public Guid Id { get; set; } + public Guid UserId { get; set; } +} diff --git a/src/BuildFlow.Host/Endpoints/file/Buckets/CreateBucketEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Buckets/CreateBucketEndpoint.cs index 8eff577..c46222d 100644 --- a/src/BuildFlow.Host/Endpoints/file/Buckets/CreateBucketEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Buckets/CreateBucketEndpoint.cs @@ -1,7 +1,7 @@ using File.Application.Features.Buckets.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Buckets; +namespace BuildFlow.Host.Endpoints.File.Buckets; /// 创建存储桶端点。POST /api/buckets,按名称创建存储桶。 diff --git a/src/BuildFlow.Host/Endpoints/file/Buckets/CreateBucketRequest.cs b/src/BuildFlow.Host/Endpoints/file/Buckets/CreateBucketRequest.cs index 4658363..b5843ca 100644 --- a/src/BuildFlow.Host/Endpoints/file/Buckets/CreateBucketRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Buckets/CreateBucketRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Buckets; +namespace BuildFlow.Host.Endpoints.File.Buckets; /// 创建存储桶请求。携带待创建存储桶的名称。 public class CreateBucketRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Buckets/DeleteBucketRequest.cs b/src/BuildFlow.Host/Endpoints/file/Buckets/DeleteBucketRequest.cs index afe1f24..4300b64 100644 --- a/src/BuildFlow.Host/Endpoints/file/Buckets/DeleteBucketRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Buckets/DeleteBucketRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Buckets; +namespace BuildFlow.Host.Endpoints.File.Buckets; /// 删除存储桶请求。以查询参数传入存储桶名称。 public class DeleteBucketRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Buckets/ListBucketsEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Buckets/ListBucketsEndpoint.cs index a523d10..8a0e864 100644 --- a/src/BuildFlow.Host/Endpoints/file/Buckets/ListBucketsEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Buckets/ListBucketsEndpoint.cs @@ -1,7 +1,7 @@ using File.Application.Features.Buckets.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Buckets; +namespace BuildFlow.Host.Endpoints.File.Buckets; /// 列出存储桶端点。GET /api/buckets,返回全部存储桶名称。 [Authorize] diff --git a/src/BuildFlow.Host/Endpoints/file/Files/CheckFileEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Files/CheckFileEndpoint.cs index 1d3c6da..b52b3e9 100644 --- a/src/BuildFlow.Host/Endpoints/file/Files/CheckFileEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Files/CheckFileEndpoint.cs @@ -2,7 +2,7 @@ using File.Application.Features.Files.DTOs; using File.Application.Features.Files.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Files; +namespace BuildFlow.Host.Endpoints.File.Files; /// 秒传预检端点。POST /api/files/check,按哈希查同用户已存在文件。 [Authorize] diff --git a/src/BuildFlow.Host/Endpoints/file/Files/CheckFileRequest.cs b/src/BuildFlow.Host/Endpoints/file/Files/CheckFileRequest.cs index 8a689c1..34ad267 100644 --- a/src/BuildFlow.Host/Endpoints/file/Files/CheckFileRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Files/CheckFileRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Files; +namespace BuildFlow.Host.Endpoints.File.Files; /// 秒传预检请求。前端上传前带 content_hash 与 size 查重。 public class CheckFileRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Files/DeleteFileEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Files/DeleteFileEndpoint.cs index ddc1e29..f8cbeaa 100644 --- a/src/BuildFlow.Host/Endpoints/file/Files/DeleteFileEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Files/DeleteFileEndpoint.cs @@ -1,7 +1,7 @@ using File.Application.Features.Files.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Files; +namespace BuildFlow.Host.Endpoints.File.Files; /// 删除文件端点。DELETE /api/files/delete,按对象键删除文件。 diff --git a/src/BuildFlow.Host/Endpoints/file/Files/DeleteFileRequest.cs b/src/BuildFlow.Host/Endpoints/file/Files/DeleteFileRequest.cs index 1f98a68..1134c41 100644 --- a/src/BuildFlow.Host/Endpoints/file/Files/DeleteFileRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Files/DeleteFileRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Files; +namespace BuildFlow.Host.Endpoints.File.Files; /// 删除文件请求。以查询参数指定对象键。 public class DeleteFileRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Files/GetFileContentRequest.cs b/src/BuildFlow.Host/Endpoints/file/Files/GetFileContentRequest.cs index c3ca190..c62cc6d 100644 --- a/src/BuildFlow.Host/Endpoints/file/Files/GetFileContentRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Files/GetFileContentRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Files; +namespace BuildFlow.Host.Endpoints.File.Files; /// 文件内容请求。以查询参数指定对象键(bucket 由系统设置统一管理)。 public class GetFileContentRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Files/GetOfficePreviewEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Files/GetOfficePreviewEndpoint.cs index da7d1fc..8d39236 100644 --- a/src/BuildFlow.Host/Endpoints/file/Files/GetOfficePreviewEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Files/GetOfficePreviewEndpoint.cs @@ -2,7 +2,7 @@ using File.Application.Features.Files.DTOs; using File.Application.Features.Files.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Files; +namespace BuildFlow.Host.Endpoints.File.Files; /// /// Office/PDF 文档在线预览端点。GET /api/files/office-preview, diff --git a/src/BuildFlow.Host/Endpoints/file/Files/ListFilesEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Files/ListFilesEndpoint.cs index e19a5e9..47d6010 100644 --- a/src/BuildFlow.Host/Endpoints/file/Files/ListFilesEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Files/ListFilesEndpoint.cs @@ -2,7 +2,7 @@ using File.Application.Features.Files.DTOs; using File.Application.Features.Files.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Files; +namespace BuildFlow.Host.Endpoints.File.Files; /// 列举文件端点。GET /api/files/list,支持前缀与分页查询。 diff --git a/src/BuildFlow.Host/Endpoints/file/Files/ListFilesRequest.cs b/src/BuildFlow.Host/Endpoints/file/Files/ListFilesRequest.cs index 0d42f76..2ef89f7 100644 --- a/src/BuildFlow.Host/Endpoints/file/Files/ListFilesRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Files/ListFilesRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Files; +namespace BuildFlow.Host.Endpoints.File.Files; /// 列举文件请求。包含前缀、最大键数与续传令牌。 public class ListFilesRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Files/UploadFileEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Files/UploadFileEndpoint.cs index cb9debb..76a1f89 100644 --- a/src/BuildFlow.Host/Endpoints/file/Files/UploadFileEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Files/UploadFileEndpoint.cs @@ -2,7 +2,7 @@ using File.Application.Features.Files.Commands; using File.Application.Features.Files.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Files; +namespace BuildFlow.Host.Endpoints.File.Files; /// 上传文件端点。POST /api/files/upload,支持 multipart 文件上传。 diff --git a/src/BuildFlow.Host/Endpoints/file/Files/UploadFileRequest.cs b/src/BuildFlow.Host/Endpoints/file/Files/UploadFileRequest.cs index 35495bb..f00c7b8 100644 --- a/src/BuildFlow.Host/Endpoints/file/Files/UploadFileRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Files/UploadFileRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Files; +namespace BuildFlow.Host.Endpoints.File.Files; /// 上传文件请求。包含 object_key 与文件数据。 public class UploadFileRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Folders/CreateFolderEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Folders/CreateFolderEndpoint.cs index 591f34a..c289114 100644 --- a/src/BuildFlow.Host/Endpoints/file/Folders/CreateFolderEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Folders/CreateFolderEndpoint.cs @@ -2,7 +2,7 @@ using File.Application.Features.Folders.Commands; using File.Application.Features.Folders.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Folders; +namespace BuildFlow.Host.Endpoints.File.Folders; /// 创建文件夹端点。POST /api/folders。 diff --git a/src/BuildFlow.Host/Endpoints/file/Folders/CreateFolderRequest.cs b/src/BuildFlow.Host/Endpoints/file/Folders/CreateFolderRequest.cs index 841cc56..9300bb3 100644 --- a/src/BuildFlow.Host/Endpoints/file/Folders/CreateFolderRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Folders/CreateFolderRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Folders; +namespace BuildFlow.Host.Endpoints.File.Folders; /// 创建文件夹请求体(父目录 Id 与名称)。 public class CreateFolderRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Folders/DeleteFolderEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Folders/DeleteFolderEndpoint.cs index 0e852a7..5efa8ad 100644 --- a/src/BuildFlow.Host/Endpoints/file/Folders/DeleteFolderEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Folders/DeleteFolderEndpoint.cs @@ -1,7 +1,7 @@ using File.Application.Features.Folders.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Folders; +namespace BuildFlow.Host.Endpoints.File.Folders; /// 删除文件夹端点。DELETE /api/folders/{Id}。 diff --git a/src/BuildFlow.Host/Endpoints/file/Folders/GetFolderRequest.cs b/src/BuildFlow.Host/Endpoints/file/Folders/GetFolderRequest.cs index c00f1f1..3b9efe7 100644 --- a/src/BuildFlow.Host/Endpoints/file/Folders/GetFolderRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Folders/GetFolderRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Folders; +namespace BuildFlow.Host.Endpoints.File.Folders; /// 获取文件夹请求(路由取 Id)。 public class GetFolderRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Folders/MoveFileEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Folders/MoveFileEndpoint.cs index f23e9a4..b98f973 100644 --- a/src/BuildFlow.Host/Endpoints/file/Folders/MoveFileEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Folders/MoveFileEndpoint.cs @@ -1,7 +1,7 @@ using File.Application.Features.Folders.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Folders; +namespace BuildFlow.Host.Endpoints.File.Folders; /// 移动文件到目标文件夹端点。POST /api/files/{Id}/move。 diff --git a/src/BuildFlow.Host/Endpoints/file/Folders/RenameFolderRequest.cs b/src/BuildFlow.Host/Endpoints/file/Folders/RenameFolderRequest.cs index b322371..3e389a5 100644 --- a/src/BuildFlow.Host/Endpoints/file/Folders/RenameFolderRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Folders/RenameFolderRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Folders; +namespace BuildFlow.Host.Endpoints.File.Folders; /// 重命名文件夹请求(路由 Id 与新名称)。 public class RenameFolderRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Multipart/AbortMultipartEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Multipart/AbortMultipartEndpoint.cs index 96eb928..b5573bc 100644 --- a/src/BuildFlow.Host/Endpoints/file/Multipart/AbortMultipartEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Multipart/AbortMultipartEndpoint.cs @@ -1,7 +1,7 @@ using File.Application.Features.Multipart.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Multipart; +namespace BuildFlow.Host.Endpoints.File.Multipart; /// 中止分片上传端点。POST /api/files/multipart/abort。 diff --git a/src/BuildFlow.Host/Endpoints/file/Multipart/CompleteMultipartEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Multipart/CompleteMultipartEndpoint.cs index 1784579..164600e 100644 --- a/src/BuildFlow.Host/Endpoints/file/Multipart/CompleteMultipartEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Multipart/CompleteMultipartEndpoint.cs @@ -2,7 +2,7 @@ using File.Application.Features.Multipart.Commands; using File.Application.Features.Multipart.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Multipart; +namespace BuildFlow.Host.Endpoints.File.Multipart; /// 完成分片上传端点。POST /api/files/multipart/complete。 diff --git a/src/BuildFlow.Host/Endpoints/file/Multipart/CompleteMultipartRequest.cs b/src/BuildFlow.Host/Endpoints/file/Multipart/CompleteMultipartRequest.cs index 3f42e90..18d93f8 100644 --- a/src/BuildFlow.Host/Endpoints/file/Multipart/CompleteMultipartRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Multipart/CompleteMultipartRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Multipart; +namespace BuildFlow.Host.Endpoints.File.Multipart; /// 完成分片上传请求(含各分片信息列表)。 public class CompleteMultipartRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Multipart/InitMultipartEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Multipart/InitMultipartEndpoint.cs index 5595eac..0173a9c 100644 --- a/src/BuildFlow.Host/Endpoints/file/Multipart/InitMultipartEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Multipart/InitMultipartEndpoint.cs @@ -2,7 +2,7 @@ using File.Application.Features.Multipart.Commands; using File.Application.Features.Multipart.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Multipart; +namespace BuildFlow.Host.Endpoints.File.Multipart; /// 初始化分片上传端点。POST /api/files/multipart/init。 diff --git a/src/BuildFlow.Host/Endpoints/file/Multipart/ListPartsEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Multipart/ListPartsEndpoint.cs index 2b7ffa3..ad33099 100644 --- a/src/BuildFlow.Host/Endpoints/file/Multipart/ListPartsEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Multipart/ListPartsEndpoint.cs @@ -2,7 +2,7 @@ using File.Application.Features.Multipart.DTOs; using File.Application.Features.Multipart.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Multipart; +namespace BuildFlow.Host.Endpoints.File.Multipart; /// /// 查询分片上传已传分片清单端点。GET /api/files/multipart/parts?upload_id=xxx。 diff --git a/src/BuildFlow.Host/Endpoints/file/Multipart/ListPartsRequest.cs b/src/BuildFlow.Host/Endpoints/file/Multipart/ListPartsRequest.cs index e53285c..e7f0eba 100644 --- a/src/BuildFlow.Host/Endpoints/file/Multipart/ListPartsRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Multipart/ListPartsRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Multipart; +namespace BuildFlow.Host.Endpoints.File.Multipart; /// 查询已传分片清单请求。upload_id 经 query string 传入。 public class ListPartsRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Multipart/PartRequest.cs b/src/BuildFlow.Host/Endpoints/file/Multipart/PartRequest.cs index 125db8e..eff74e1 100644 --- a/src/BuildFlow.Host/Endpoints/file/Multipart/PartRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Multipart/PartRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Multipart; +namespace BuildFlow.Host.Endpoints.File.Multipart; /// 分片上传的单片信息(CompleteMultipart 时用)。 public class PartRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Multipart/UploadPartEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Multipart/UploadPartEndpoint.cs index c9d4ef5..b68ddd8 100644 --- a/src/BuildFlow.Host/Endpoints/file/Multipart/UploadPartEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Multipart/UploadPartEndpoint.cs @@ -2,7 +2,7 @@ using File.Application.Features.Multipart.Commands; using File.Application.Features.Multipart.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Multipart; +namespace BuildFlow.Host.Endpoints.File.Multipart; /// 上传单个分片端点。PUT /api/files/multipart/part。 diff --git a/src/BuildFlow.Host/Endpoints/file/Settings/GetFileSettingEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Settings/GetFileSettingEndpoint.cs index f6da851..0047109 100644 --- a/src/BuildFlow.Host/Endpoints/file/Settings/GetFileSettingEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Settings/GetFileSettingEndpoint.cs @@ -2,7 +2,7 @@ using File.Application.Features.Settings.DTOs; using File.Application.Features.Settings.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Settings; +namespace BuildFlow.Host.Endpoints.File.Settings; /// 查询文件系统设置端点。GET /api/file-settings,返回当前默认存储桶。 [Authorize] diff --git a/src/BuildFlow.Host/Endpoints/file/Shares/CreateShareRequest.cs b/src/BuildFlow.Host/Endpoints/file/Shares/CreateShareRequest.cs index bdcda25..11a221b 100644 --- a/src/BuildFlow.Host/Endpoints/file/Shares/CreateShareRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Shares/CreateShareRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Shares; +namespace BuildFlow.Host.Endpoints.File.Shares; /// 创建分享请求(资源、密码、过期、下载上限)。 public class CreateShareRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Shares/DeleteShareEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Shares/DeleteShareEndpoint.cs index 8164394..f07deec 100644 --- a/src/BuildFlow.Host/Endpoints/file/Shares/DeleteShareEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Shares/DeleteShareEndpoint.cs @@ -1,7 +1,7 @@ using File.Application.Features.Shares.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Shares; +namespace BuildFlow.Host.Endpoints.File.Shares; /// 删除分享端点。DELETE /api/share/{Id}。 diff --git a/src/BuildFlow.Host/Endpoints/file/Shares/DeleteShareRequest.cs b/src/BuildFlow.Host/Endpoints/file/Shares/DeleteShareRequest.cs index 5f2bdad..88df3d3 100644 --- a/src/BuildFlow.Host/Endpoints/file/Shares/DeleteShareRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Shares/DeleteShareRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Shares; +namespace BuildFlow.Host.Endpoints.File.Shares; /// 删除分享请求(路由取 Id)。 public class DeleteShareRequest diff --git a/src/BuildFlow.Host/Endpoints/file/Shares/DownloadShareEndpoint.cs b/src/BuildFlow.Host/Endpoints/file/Shares/DownloadShareEndpoint.cs index 81e69f9..3582eda 100644 --- a/src/BuildFlow.Host/Endpoints/file/Shares/DownloadShareEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/file/Shares/DownloadShareEndpoint.cs @@ -2,7 +2,7 @@ using File.Application.Features.Shares.DTOs; using File.Application.Features.Shares.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.file.Shares; +namespace BuildFlow.Host.Endpoints.File.Shares; /// 下载分享端点(匿名访问)。POST /api/share/{Token}/download。 diff --git a/src/BuildFlow.Host/Endpoints/file/Shares/GetShareInfoRequest.cs b/src/BuildFlow.Host/Endpoints/file/Shares/GetShareInfoRequest.cs index 0cde4fc..d0f9f08 100644 --- a/src/BuildFlow.Host/Endpoints/file/Shares/GetShareInfoRequest.cs +++ b/src/BuildFlow.Host/Endpoints/file/Shares/GetShareInfoRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.file.Shares; +namespace BuildFlow.Host.Endpoints.File.Shares; /// 查询分享信息请求(路由取 Token)。 public class GetShareInfoRequest diff --git a/src/BuildFlow.Host/Endpoints/im/Chat/AddGroupMemberEndpoint.cs b/src/BuildFlow.Host/Endpoints/im/Chat/AddGroupMemberEndpoint.cs index c1d60d0..82a43f3 100644 --- a/src/BuildFlow.Host/Endpoints/im/Chat/AddGroupMemberEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/im/Chat/AddGroupMemberEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Shared.Domain.Common; using IM.Application.Chat.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.im.Chat; +namespace BuildFlow.Host.Endpoints.IM.Chat; /// diff --git a/src/BuildFlow.Host/Endpoints/im/Chat/CreateGroupEndpoint.cs b/src/BuildFlow.Host/Endpoints/im/Chat/CreateGroupEndpoint.cs index a98b834..f3b8c7b 100644 --- a/src/BuildFlow.Host/Endpoints/im/Chat/CreateGroupEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/im/Chat/CreateGroupEndpoint.cs @@ -3,7 +3,7 @@ using IM.Application.Chat.Commands; using IM.Application.Chat.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.im.Chat; +namespace BuildFlow.Host.Endpoints.IM.Chat; /// /// 创建群组端点。POST /groups。 diff --git a/src/BuildFlow.Host/Endpoints/im/Chat/CreatePrivateConversationEndpoint.cs b/src/BuildFlow.Host/Endpoints/im/Chat/CreatePrivateConversationEndpoint.cs index 336cf64..8377fd9 100644 --- a/src/BuildFlow.Host/Endpoints/im/Chat/CreatePrivateConversationEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/im/Chat/CreatePrivateConversationEndpoint.cs @@ -3,7 +3,7 @@ using IM.Application.Chat.Commands; using IM.Application.Chat.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.im.Chat; +namespace BuildFlow.Host.Endpoints.IM.Chat; /// /// 创建或复用私聊会话。若当前用户与目标用户间已存在私聊会话则直接返回,保证幂等。 diff --git a/src/BuildFlow.Host/Endpoints/im/Chat/DeleteGroupEndpoint.cs b/src/BuildFlow.Host/Endpoints/im/Chat/DeleteGroupEndpoint.cs index f19b622..e1d8e43 100644 --- a/src/BuildFlow.Host/Endpoints/im/Chat/DeleteGroupEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/im/Chat/DeleteGroupEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Shared.Domain.Common; using IM.Application.Chat.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.im.Chat; +namespace BuildFlow.Host.Endpoints.IM.Chat; /// diff --git a/src/BuildFlow.Host/Endpoints/im/Chat/GetGroupEndpoint.cs b/src/BuildFlow.Host/Endpoints/im/Chat/GetGroupEndpoint.cs index b1041d6..e464c56 100644 --- a/src/BuildFlow.Host/Endpoints/im/Chat/GetGroupEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/im/Chat/GetGroupEndpoint.cs @@ -3,7 +3,7 @@ using IM.Application.Chat.DTOs; using IM.Application.Chat.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.im.Chat; +namespace BuildFlow.Host.Endpoints.IM.Chat; /// /// 查询单个群详情(含公告/成员数)。 diff --git a/src/BuildFlow.Host/Endpoints/im/Chat/GetGroupEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/im/Chat/GetGroupEndpointRequest.cs index 95dc04f..94501a9 100644 --- a/src/BuildFlow.Host/Endpoints/im/Chat/GetGroupEndpointRequest.cs +++ b/src/BuildFlow.Host/Endpoints/im/Chat/GetGroupEndpointRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.im.Chat; +namespace BuildFlow.Host.Endpoints.IM.Chat; /// 查询群详情请求。GroupId 由路由参数绑定。 public record GetGroupEndpointRequest(Guid GroupId); diff --git a/src/BuildFlow.Host/Endpoints/im/Chat/GetMessageHistoryEndpoint.cs b/src/BuildFlow.Host/Endpoints/im/Chat/GetMessageHistoryEndpoint.cs index 7df8f85..47c07e5 100644 --- a/src/BuildFlow.Host/Endpoints/im/Chat/GetMessageHistoryEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/im/Chat/GetMessageHistoryEndpoint.cs @@ -3,7 +3,7 @@ using IM.Application.Chat.DTOs; using IM.Application.Chat.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.im.Chat; +namespace BuildFlow.Host.Endpoints.IM.Chat; /// diff --git a/src/BuildFlow.Host/Endpoints/im/Chat/GetUnreadCountEndpoint.cs b/src/BuildFlow.Host/Endpoints/im/Chat/GetUnreadCountEndpoint.cs index e7ee99e..231954e 100644 --- a/src/BuildFlow.Host/Endpoints/im/Chat/GetUnreadCountEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/im/Chat/GetUnreadCountEndpoint.cs @@ -3,7 +3,7 @@ using IM.Application.Chat.DTOs; using IM.Application.Chat.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.im.Chat; +namespace BuildFlow.Host.Endpoints.IM.Chat; /// /// 查询未读消息数端点。GET /conversations/unread。 diff --git a/src/BuildFlow.Host/Endpoints/im/Chat/RemoveGroupMemberEndpoint.cs b/src/BuildFlow.Host/Endpoints/im/Chat/RemoveGroupMemberEndpoint.cs index 512fbc6..55be69f 100644 --- a/src/BuildFlow.Host/Endpoints/im/Chat/RemoveGroupMemberEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/im/Chat/RemoveGroupMemberEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Shared.Domain.Common; using IM.Application.Chat.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.im.Chat; +namespace BuildFlow.Host.Endpoints.IM.Chat; /// diff --git a/src/BuildFlow.Host/Endpoints/im/Chat/RemoveGroupMemberEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/im/Chat/RemoveGroupMemberEndpointRequest.cs index 5ddbc00..925e5c2 100644 --- a/src/BuildFlow.Host/Endpoints/im/Chat/RemoveGroupMemberEndpointRequest.cs +++ b/src/BuildFlow.Host/Endpoints/im/Chat/RemoveGroupMemberEndpointRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.im.Chat; +namespace BuildFlow.Host.Endpoints.IM.Chat; /// /// 移除群成员请求体(路由参数绑定)。 diff --git a/src/BuildFlow.Host/Endpoints/im/Chat/SetConversationPinnedEndpoint.cs b/src/BuildFlow.Host/Endpoints/im/Chat/SetConversationPinnedEndpoint.cs index d48c316..b402831 100644 --- a/src/BuildFlow.Host/Endpoints/im/Chat/SetConversationPinnedEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/im/Chat/SetConversationPinnedEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Shared.Domain.Common; using IM.Application.Chat.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.im.Chat; +namespace BuildFlow.Host.Endpoints.IM.Chat; /// /// 设置会话置顶端点。PUT /conversations/{ConversationId}/pinned。 diff --git a/src/BuildFlow.Host/Endpoints/im/Chat/SetConversationRemarkEndpoint.cs b/src/BuildFlow.Host/Endpoints/im/Chat/SetConversationRemarkEndpoint.cs index 8b4a894..6c50672 100644 --- a/src/BuildFlow.Host/Endpoints/im/Chat/SetConversationRemarkEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/im/Chat/SetConversationRemarkEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Shared.Domain.Common; using IM.Application.Chat.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.im.Chat; +namespace BuildFlow.Host.Endpoints.IM.Chat; /// /// 设置会话备注名端点。PUT /conversations/{ConversationId}/remark。 diff --git a/src/BuildFlow.Host/Endpoints/im/Chat/SetConversationRemarkEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/im/Chat/SetConversationRemarkEndpointRequest.cs index 08ef173..3cfaa61 100644 --- a/src/BuildFlow.Host/Endpoints/im/Chat/SetConversationRemarkEndpointRequest.cs +++ b/src/BuildFlow.Host/Endpoints/im/Chat/SetConversationRemarkEndpointRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.im.Chat; +namespace BuildFlow.Host.Endpoints.IM.Chat; /// /// 设置会话备注名请求体。Remark 为空或 null 表示清除备注。 diff --git a/src/BuildFlow.Host/Endpoints/im/Chat/UpdateGroupEndpoint.cs b/src/BuildFlow.Host/Endpoints/im/Chat/UpdateGroupEndpoint.cs index 56b331a..c3512f3 100644 --- a/src/BuildFlow.Host/Endpoints/im/Chat/UpdateGroupEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/im/Chat/UpdateGroupEndpoint.cs @@ -3,7 +3,7 @@ using IM.Application.Chat.Commands; using IM.Application.Chat.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.im.Chat; +namespace BuildFlow.Host.Endpoints.IM.Chat; /// diff --git a/src/BuildFlow.Host/Endpoints/platform/Auth/ChangePasswordEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/ChangePasswordEndpoint.cs index 55ce463..19b45b8 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Auth/ChangePasswordEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Auth/ChangePasswordEndpoint.cs @@ -1,7 +1,7 @@ using BuildFlow.Platform.Infrastructure.Persistence; using BuildFlow.Shared.Domain.Common; -namespace BuildFlow.Host.Endpoints.rag.Auth; +namespace BuildFlow.Host.Endpoints.Platform.Auth; /// /// 修改当前用户密码。验证旧密码后更新为新密码。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Auth/ChangePasswordRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/ChangePasswordRequest.cs index d143c93..d8fa9e0 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Auth/ChangePasswordRequest.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Auth/ChangePasswordRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Auth; +namespace BuildFlow.Host.Endpoints.Platform.Auth; /// 修改密码请求。包含旧密码(用于二次校验)与新密码。 public class ChangePasswordRequest diff --git a/src/BuildFlow.Host/Endpoints/platform/Auth/GetAccessCodesEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/GetAccessCodesEndpoint.cs index a164bf6..41a0b20 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Auth/GetAccessCodesEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Auth/GetAccessCodesEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Platform.Application.Auth.Queries; using BuildFlow.Shared.Domain.Common; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Auth; +namespace BuildFlow.Host.Endpoints.Platform.Auth; /// /// 获取当前用户的权限码列表。前端据此渲染按钮/菜单的可见性(细粒度前端权限控制)。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Auth/LoginEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/LoginEndpoint.cs index 623a5a2..96dc332 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Auth/LoginEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Auth/LoginEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Platform.Application.Auth.Commands; using BuildFlow.Platform.Application.Auth.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Auth; +namespace BuildFlow.Host.Endpoints.Platform.Auth; /// diff --git a/src/BuildFlow.Host/Endpoints/platform/Auth/LogoutEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/LogoutEndpoint.cs index 323410b..6a91578 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Auth/LogoutEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Auth/LogoutEndpoint.cs @@ -1,7 +1,7 @@ using BuildFlow.Platform.Application.Auth.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Auth; +namespace BuildFlow.Host.Endpoints.Platform.Auth; /// /// 登出接口:撤销 refresh token 并清除 jwt Cookie。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Auth/RefreshTokenEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/RefreshTokenEndpoint.cs index c75a1d9..f420b50 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Auth/RefreshTokenEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Auth/RefreshTokenEndpoint.cs @@ -1,7 +1,7 @@ using BuildFlow.Platform.Application.Auth.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Auth; +namespace BuildFlow.Host.Endpoints.Platform.Auth; /// /// 刷新令牌端点。从 HttpOnly Cookie 读 refresh_token(前端无法读取,只能由浏览器自动随请求带上), @@ -34,8 +34,8 @@ public class RefreshTokenEndpoint(IMediator mediator, IConfiguration config) : E Path = "/" }); - HttpContext.Response.StatusCode = 200; - HttpContext.Response.ContentType = "text/plain; charset=utf-8"; - await HttpContext.Response.WriteAsync(result.AccessToken, ct); + // 用 FastEndpoints 的 Send.StringAsync 返回纯文本 access token。 + // 之前用 HttpContext.Response.WriteAsync 被 FastEndpoints 管线覆盖成 204 空响应。 + await Send.StringAsync(result.AccessToken, 200, "text/plain; charset=utf-8", ct); } } diff --git a/src/BuildFlow.Host/Endpoints/platform/Auth/RegisterEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/RegisterEndpoint.cs index 25cf80e..c19e6bc 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Auth/RegisterEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Auth/RegisterEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Platform.Application.Auth.Commands; using BuildFlow.Platform.Application.Auth.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Auth; +namespace BuildFlow.Host.Endpoints.Platform.Auth; /// diff --git a/src/BuildFlow.Host/Endpoints/platform/Auth/RegisterRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/RegisterRequestValidator.cs index ef20364..124cfd2 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Auth/RegisterRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Auth/RegisterRequestValidator.cs @@ -1,6 +1,6 @@ using BuildFlow.Platform.Application.Auth.DTOs; -namespace BuildFlow.Host.Endpoints.rag.Auth; +namespace BuildFlow.Host.Endpoints.Platform.Auth; /// /// 注册Request的请求校验器(FluentValidation)。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Auth/RevokeTokenEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/RevokeTokenEndpoint.cs index 459ac9d..b3970cd 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Auth/RevokeTokenEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Auth/RevokeTokenEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Platform.Application.Auth.Commands; using BuildFlow.Platform.Application.Auth.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Auth; +namespace BuildFlow.Host.Endpoints.Platform.Auth; /// diff --git a/src/BuildFlow.Host/Endpoints/platform/Auth/RevokeTokenRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/RevokeTokenRequestValidator.cs index abd2614..5af69a8 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Auth/RevokeTokenRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Auth/RevokeTokenRequestValidator.cs @@ -1,6 +1,6 @@ using BuildFlow.Platform.Application.Auth.DTOs; -namespace BuildFlow.Host.Endpoints.rag.Auth; +namespace BuildFlow.Host.Endpoints.Platform.Auth; /// /// 吊销令牌Request的请求校验器(FluentValidation)。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Auth/UpdateProfileEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Auth/UpdateProfileEndpoint.cs index f19828d..d9b50f4 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Auth/UpdateProfileEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Auth/UpdateProfileEndpoint.cs @@ -3,7 +3,7 @@ using BuildFlow.Platform.Application.Auth.Queries; using BuildFlow.Shared.Domain.Common; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Auth; +namespace BuildFlow.Host.Endpoints.Platform.Auth; /// /// 更新当前用户个人资料(姓名、头像、简介)。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/CreateMenuEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/CreateMenuEndpoint.cs index a0ee9e3..45500d4 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Menus/CreateMenuEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Menus/CreateMenuEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Platform.Application.Menus.Commands; using BuildFlow.Platform.Application.Menus.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Menus; +namespace BuildFlow.Host.Endpoints.Platform.Menus; /// /// 创建菜单端点。 @@ -25,6 +25,7 @@ public class CreateMenuEndpoint(IMediator mediator) : Endpoint /// 创建菜单请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpointRequest.cs index 398efb8..758c710 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpointRequest.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpointRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Menus; +namespace BuildFlow.Host.Endpoints.Platform.Menus; /// /// 删除菜单请求体。携带路由 Id。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpointRequestValidator.cs index 47918be..296a62d 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpointRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Menus/DeleteMenuEndpointRequestValidator.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Menus; +namespace BuildFlow.Host.Endpoints.Platform.Menus; /// /// 删除菜单请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuByIdRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuByIdRequestValidator.cs index 274c1b2..dc8dfaf 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuByIdRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Menus/GetMenuByIdRequestValidator.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Menus; +namespace BuildFlow.Host.Endpoints.Platform.Menus; /// /// 按主键查询菜单请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/SortMenusEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/SortMenusEndpoint.cs index b4d54b0..ffcb3b0 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Menus/SortMenusEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Menus/SortMenusEndpoint.cs @@ -1,7 +1,7 @@ using BuildFlow.Platform.Application.Menus.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Menus; +namespace BuildFlow.Host.Endpoints.Platform.Menus; /// /// 批量排序菜单端点。供菜单管理页拖拽排序(同级调整 + 跨层级移动)落库使用。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/SortMenusEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/SortMenusEndpointRequest.cs index 888180f..0fe475d 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Menus/SortMenusEndpointRequest.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Menus/SortMenusEndpointRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Menus; +namespace BuildFlow.Host.Endpoints.Platform.Menus; /// /// 批量排序菜单请求体。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Menus/UpdateMenuEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Menus/UpdateMenuEndpoint.cs index 9dc6da6..c6702da 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Menus/UpdateMenuEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Menus/UpdateMenuEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Platform.Application.Menus.Commands; using BuildFlow.Platform.Application.Menus.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Menus; +namespace BuildFlow.Host.Endpoints.Platform.Menus; /// /// 更新菜单端点。 @@ -26,6 +26,7 @@ public class UpdateMenuEndpoint(IMediator mediator) : Endpoint /// 更新菜单请求体。携带路由 Id。 @@ -11,6 +11,7 @@ public record UpdateMenuEndpointRequest( string? Component, string? Redirect, string? Title, + string? Code, string? Icon, string? ActiveIcon, int? Order, diff --git a/src/BuildFlow.Host/Endpoints/platform/Notifications/GetNotificationsEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/GetNotificationsEndpoint.cs index 2a4d58e..3e94b49 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Notifications/GetNotificationsEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Notifications/GetNotificationsEndpoint.cs @@ -3,7 +3,7 @@ using BuildFlow.Platform.Application.Notifications.Queries; using BuildFlow.Shared.Domain.Common; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Notifications; +namespace BuildFlow.Host.Endpoints.Platform.Notifications; /// 获取当前用户的通知列表(分页,可只看未读)。 public class GetNotificationsEndpoint(IMediator mediator, ICurrentUserContext userContext) diff --git a/src/BuildFlow.Host/Endpoints/platform/Notifications/GetUnreadNotificationCountEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/GetUnreadNotificationCountEndpoint.cs index 2197afe..c212c91 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Notifications/GetUnreadNotificationCountEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Notifications/GetUnreadNotificationCountEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Platform.Application.Notifications.Queries; using BuildFlow.Shared.Domain.Common; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Notifications; +namespace BuildFlow.Host.Endpoints.Platform.Notifications; /// 获取当前用户未读通知数(前端铃铛角标)。 public class GetUnreadNotificationCountEndpoint(IMediator mediator, ICurrentUserContext userContext) diff --git a/src/BuildFlow.Host/Endpoints/platform/Notifications/MarkNotificationReadEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/MarkNotificationReadEndpoint.cs index 6707852..197bc9e 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Notifications/MarkNotificationReadEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Notifications/MarkNotificationReadEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Platform.Application.Notifications.Commands; using BuildFlow.Shared.Domain.Common; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Notifications; +namespace BuildFlow.Host.Endpoints.Platform.Notifications; /// 标记单条通知为已读。 public class MarkNotificationReadEndpoint(IMediator mediator, ICurrentUserContext userContext) diff --git a/src/BuildFlow.Host/Endpoints/platform/Notifications/NotificationEndpointsExtensions.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/NotificationEndpointsExtensions.cs index dcd6e66..68e13e7 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Notifications/NotificationEndpointsExtensions.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Notifications/NotificationEndpointsExtensions.cs @@ -1,6 +1,6 @@ using BuildFlow.Shared.Domain.Common; -namespace BuildFlow.Host.Endpoints.rag.Notifications; +namespace BuildFlow.Host.Endpoints.Platform.Notifications; /// /// 通知EndpointsExtensions扩展方法。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Notifications/PublishNotificationRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Notifications/PublishNotificationRequest.cs index 27b0d9d..c822687 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Notifications/PublishNotificationRequest.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Notifications/PublishNotificationRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Notifications; +namespace BuildFlow.Host.Endpoints.Platform.Notifications; /// /// Publish通知请求体。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Permissions/CreatePermissionRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Permissions/CreatePermissionRequestValidator.cs index 756732d..8375cfe 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Permissions/CreatePermissionRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Permissions/CreatePermissionRequestValidator.cs @@ -1,6 +1,6 @@ using BuildFlow.Platform.Application.Permissions.DTOs; -namespace BuildFlow.Host.Endpoints.rag.Permissions; +namespace BuildFlow.Host.Endpoints.Platform.Permissions; /// /// 创建权限请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Permissions/UpdatePermissionEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Permissions/UpdatePermissionEndpointRequestValidator.cs index bd18c25..9c64255 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Permissions/UpdatePermissionEndpointRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Permissions/UpdatePermissionEndpointRequestValidator.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Permissions; +namespace BuildFlow.Host.Endpoints.Platform.Permissions; /// /// 更新权限请求校验。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpoint.cs index b93f158..71437b8 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Platform.Application.Roles.Commands; using BuildFlow.Platform.Application.Roles.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Roles; +namespace BuildFlow.Host.Endpoints.Platform.Roles; /// diff --git a/src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpointRequestValidator.cs index e53dc37..d0364e4 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpointRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Roles/AssignPermissionsEndpointRequestValidator.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Roles; +namespace BuildFlow.Host.Endpoints.Platform.Roles; /// /// Assign权限sEndpointRequest的请求校验器(FluentValidation)。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Roles/DeleteRoleEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/DeleteRoleEndpoint.cs index c052483..b2f4fb9 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Roles/DeleteRoleEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Roles/DeleteRoleEndpoint.cs @@ -1,7 +1,7 @@ using BuildFlow.Platform.Application.Roles.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Roles; +namespace BuildFlow.Host.Endpoints.Platform.Roles; /// diff --git a/src/BuildFlow.Host/Endpoints/platform/Roles/GetRoleListEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/GetRoleListEndpoint.cs index f543d6e..a495061 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Roles/GetRoleListEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Roles/GetRoleListEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Platform.Application.Roles.DTOs; using BuildFlow.Platform.Application.Roles.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Roles; +namespace BuildFlow.Host.Endpoints.Platform.Roles; /// /// Get角色List端点。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpoint.cs index b876fe3..05dfac7 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Platform.Application.Roles.Commands; using BuildFlow.Platform.Application.Roles.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Roles; +namespace BuildFlow.Host.Endpoints.Platform.Roles; /// diff --git a/src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpointRequest.cs index 3f6ba17..947a922 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpointRequest.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Roles/UpdateRoleEndpointRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Roles; +namespace BuildFlow.Host.Endpoints.Platform.Roles; /// /// Update角色Endpoint请求体。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Users/AssignRolesEndpointRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Users/AssignRolesEndpointRequestValidator.cs index d1f4dba..bf1f367 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Users/AssignRolesEndpointRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Users/AssignRolesEndpointRequestValidator.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Users; +namespace BuildFlow.Host.Endpoints.Platform.Users; /// /// Assign角色sEndpointRequest的请求校验器(FluentValidation)。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Users/DeleteUserEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Users/DeleteUserEndpointRequest.cs index 3d98581..85c8c4e 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Users/DeleteUserEndpointRequest.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Users/DeleteUserEndpointRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Users; +namespace BuildFlow.Host.Endpoints.Platform.Users; /// /// Delete用户Endpoint请求体。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Users/GetUserByIdRequestValidator.cs b/src/BuildFlow.Host/Endpoints/platform/Users/GetUserByIdRequestValidator.cs index aa973a6..63fa4d1 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Users/GetUserByIdRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Users/GetUserByIdRequestValidator.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Users; +namespace BuildFlow.Host.Endpoints.Platform.Users; /// /// Get用户ByIdRequest的请求校验器(FluentValidation)。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Users/GetUserListEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Users/GetUserListEndpoint.cs index bc1db37..709db40 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Users/GetUserListEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Users/GetUserListEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Platform.Application.Users.DTOs; using BuildFlow.Platform.Application.Users.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Users; +namespace BuildFlow.Host.Endpoints.Platform.Users; /// diff --git a/src/BuildFlow.Host/Endpoints/platform/Users/GetUserListRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Users/GetUserListRequest.cs index a8abde9..c79fdf9 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Users/GetUserListRequest.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Users/GetUserListRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Users; +namespace BuildFlow.Host.Endpoints.Platform.Users; /// /// Get用户List请求体。 diff --git a/src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpoint.cs b/src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpoint.cs index b9b8eaa..019b205 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Platform.Application.Users.Commands; using BuildFlow.Platform.Application.Users.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Users; +namespace BuildFlow.Host.Endpoints.Platform.Users; /// diff --git a/src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpointRequest.cs b/src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpointRequest.cs index 8ab3c7c..203ec94 100644 --- a/src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpointRequest.cs +++ b/src/BuildFlow.Host/Endpoints/platform/Users/UpdateUserEndpointRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Users; +namespace BuildFlow.Host.Endpoints.Platform.Users; /// /// Update用户Endpoint请求体。 diff --git a/src/BuildFlow.Host/Endpoints/rag/Chat/CreateConversationRequestValidator.cs b/src/BuildFlow.Host/Endpoints/rag/Chat/CreateConversationRequestValidator.cs index 0f2bfd7..7d0f719 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Chat/CreateConversationRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Chat/CreateConversationRequestValidator.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Chat; +namespace BuildFlow.Host.Endpoints.Rag.Chat; /// /// Create会话Request的请求校验器(FluentValidation)。 diff --git a/src/BuildFlow.Host/Endpoints/rag/Chat/GetConversationsEndpoint.cs b/src/BuildFlow.Host/Endpoints/rag/Chat/GetConversationsEndpoint.cs index d7bedc3..8db4814 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Chat/GetConversationsEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Chat/GetConversationsEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Application.Chat.DTOs; using BuildFlow.Application.Chat.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Chat; +namespace BuildFlow.Host.Endpoints.Rag.Chat; /// /// Get会话s端点。 diff --git a/src/BuildFlow.Host/Endpoints/rag/Chat/StreamMessageRequestValidator.cs b/src/BuildFlow.Host/Endpoints/rag/Chat/StreamMessageRequestValidator.cs index 9aca8a1..10d21fd 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Chat/StreamMessageRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Chat/StreamMessageRequestValidator.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Chat; +namespace BuildFlow.Host.Endpoints.Rag.Chat; /// /// Stream消息Request的请求校验器(FluentValidation)。 diff --git a/src/BuildFlow.Host/Endpoints/rag/Document/GetDocumentChunksEndpoint.cs b/src/BuildFlow.Host/Endpoints/rag/Document/GetDocumentChunksEndpoint.cs index 3fbd0be..db6ec83 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Document/GetDocumentChunksEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Document/GetDocumentChunksEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Application.Document.DTOs; using BuildFlow.Application.Document.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Document; +namespace BuildFlow.Host.Endpoints.Rag.Document; /// /// Get文档分块端点。 diff --git a/src/BuildFlow.Host/Endpoints/rag/Document/ImportFromFileManagerEndpoint.cs b/src/BuildFlow.Host/Endpoints/rag/Document/ImportFromFileManagerEndpoint.cs index 3529725..a539fc6 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Document/ImportFromFileManagerEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Document/ImportFromFileManagerEndpoint.cs @@ -4,7 +4,7 @@ using BuildFlow.Domain.Enums; using File.Infrastructure.Storage; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Document; +namespace BuildFlow.Host.Endpoints.Rag.Document; /// /// 从文件管理(S3)入库文档到知识库。 diff --git a/src/BuildFlow.Host/Endpoints/rag/Document/ImportFromFileManagerRequest.cs b/src/BuildFlow.Host/Endpoints/rag/Document/ImportFromFileManagerRequest.cs index 39c6387..ad571b6 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Document/ImportFromFileManagerRequest.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Document/ImportFromFileManagerRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Document; +namespace BuildFlow.Host.Endpoints.Rag.Document; /// 从文件管理入库的请求。指定 S3 桶与对象,服务端下载后写入 RAG 知识库。 public class ImportFromFileManagerRequest diff --git a/src/BuildFlow.Host/Endpoints/rag/Document/InitChunkUploadRequest.cs b/src/BuildFlow.Host/Endpoints/rag/Document/InitChunkUploadRequest.cs index 4ede41e..5110731 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Document/InitChunkUploadRequest.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Document/InitChunkUploadRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Document; +namespace BuildFlow.Host.Endpoints.Rag.Document; /// /// Init分块上传请求体。 diff --git a/src/BuildFlow.Host/Endpoints/rag/Document/ProcessKnowledgeBaseEndpoint.cs b/src/BuildFlow.Host/Endpoints/rag/Document/ProcessKnowledgeBaseEndpoint.cs index f1493b8..5d7c302 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Document/ProcessKnowledgeBaseEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Document/ProcessKnowledgeBaseEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Application.Document.Commands; using BuildFlow.Application.Document.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Document; +namespace BuildFlow.Host.Endpoints.Rag.Document; /// /// 批量处理知识库内所有待处理/失败的文档。 diff --git a/src/BuildFlow.Host/Endpoints/rag/Document/UploadChunkEndpoint.cs b/src/BuildFlow.Host/Endpoints/rag/Document/UploadChunkEndpoint.cs index 3ebc790..f0dae26 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Document/UploadChunkEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Document/UploadChunkEndpoint.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Document; +namespace BuildFlow.Host.Endpoints.Rag.Document; /// /// 上传单个分片。客户端按分片索引逐个上传,服务端写入临时目录。 diff --git a/src/BuildFlow.Host/Endpoints/rag/Document/UploadDocumentEndpoint.cs b/src/BuildFlow.Host/Endpoints/rag/Document/UploadDocumentEndpoint.cs index c3bc5ef..eed5ddc 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Document/UploadDocumentEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Document/UploadDocumentEndpoint.cs @@ -4,7 +4,7 @@ using BuildFlow.Domain.Enums; using MediatR; using DomainExceptions = BuildFlow.Shared.Domain.Exceptions; -namespace BuildFlow.Host.Endpoints.rag.Document; +namespace BuildFlow.Host.Endpoints.Rag.Document; /// diff --git a/src/BuildFlow.Host/Endpoints/rag/Document/UploadDocumentRequest.cs b/src/BuildFlow.Host/Endpoints/rag/Document/UploadDocumentRequest.cs index c8622c2..cd26a55 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Document/UploadDocumentRequest.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Document/UploadDocumentRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Document; +namespace BuildFlow.Host.Endpoints.Rag.Document; /// /// 上传文档请求体。 diff --git a/src/BuildFlow.Host/Endpoints/rag/Document/UploadDocumentRequestValidator.cs b/src/BuildFlow.Host/Endpoints/rag/Document/UploadDocumentRequestValidator.cs index 8a3e82a..5acf5b9 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Document/UploadDocumentRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Document/UploadDocumentRequestValidator.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Document; +namespace BuildFlow.Host.Endpoints.Rag.Document; /// /// 上传文档Request的请求校验器(FluentValidation)。 diff --git a/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedBatchEndpoint.cs b/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedBatchEndpoint.cs index 57674c2..bb3efee 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedBatchEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedBatchEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Application.Embedding.Commands; using BuildFlow.Application.Embedding.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Embedding; +namespace BuildFlow.Host.Endpoints.Rag.Embedding; /// diff --git a/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedBatchRequest.cs b/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedBatchRequest.cs index 3670032..2d90a3e 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedBatchRequest.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedBatchRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Embedding; +namespace BuildFlow.Host.Endpoints.Rag.Embedding; /// /// 批量向量化请求体。 diff --git a/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedBatchRequestValidator.cs b/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedBatchRequestValidator.cs index 6b996db..5f907e3 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedBatchRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedBatchRequestValidator.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Embedding; +namespace BuildFlow.Host.Endpoints.Rag.Embedding; /// /// 批量向量化Request的请求校验器(FluentValidation)。 diff --git a/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedTextEndpoint.cs b/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedTextEndpoint.cs index 3eeb17e..2e6fb7f 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedTextEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedTextEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Application.Embedding.Commands; using BuildFlow.Application.Embedding.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Embedding; +namespace BuildFlow.Host.Endpoints.Rag.Embedding; /// diff --git a/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedTextRequestValidator.cs b/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedTextRequestValidator.cs index d3be4c2..2590ca3 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedTextRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Embedding/EmbedTextRequestValidator.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.rag.Embedding; +namespace BuildFlow.Host.Endpoints.Rag.Embedding; /// /// 文本向量化Request的请求校验器(FluentValidation)。 diff --git a/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/CreateKBEndpoint.cs b/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/CreateKBEndpoint.cs index 650e9fe..093f1ff 100644 --- a/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/CreateKBEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/CreateKBEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Application.KnowledgeBase.Commands; using BuildFlow.Application.KnowledgeBase.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.KnowledgeBase; +namespace BuildFlow.Host.Endpoints.Rag.KnowledgeBase; /// diff --git a/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/CreateKnowledgeBaseRequestValidator.cs b/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/CreateKnowledgeBaseRequestValidator.cs index dcaeb78..0f6830b 100644 --- a/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/CreateKnowledgeBaseRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/CreateKnowledgeBaseRequestValidator.cs @@ -1,6 +1,6 @@ using BuildFlow.Application.KnowledgeBase.DTOs; -namespace BuildFlow.Host.Endpoints.rag.KnowledgeBase; +namespace BuildFlow.Host.Endpoints.Rag.KnowledgeBase; /// /// Create知识库Request的请求校验器(FluentValidation)。 diff --git a/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/DeleteKBEndpoint.cs b/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/DeleteKBEndpoint.cs index efd0764..8f9d558 100644 --- a/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/DeleteKBEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/DeleteKBEndpoint.cs @@ -1,7 +1,7 @@ using BuildFlow.Application.KnowledgeBase.Commands; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.KnowledgeBase; +namespace BuildFlow.Host.Endpoints.Rag.KnowledgeBase; /// diff --git a/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/GetKBsEndpoint.cs b/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/GetKBsEndpoint.cs index a20b6f6..8330ca5 100644 --- a/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/GetKBsEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/GetKBsEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Application.KnowledgeBase.DTOs; using BuildFlow.Application.KnowledgeBase.Queries; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.KnowledgeBase; +namespace BuildFlow.Host.Endpoints.Rag.KnowledgeBase; /// /// Get知识库s端点。 diff --git a/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/UpdateKBEndpoint.cs b/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/UpdateKBEndpoint.cs index eaec94b..84f592f 100644 --- a/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/UpdateKBEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/UpdateKBEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Application.KnowledgeBase.Commands; using BuildFlow.Application.KnowledgeBase.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.KnowledgeBase; +namespace BuildFlow.Host.Endpoints.Rag.KnowledgeBase; /// diff --git a/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/UpdateKnowledgeBaseRequestValidator.cs b/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/UpdateKnowledgeBaseRequestValidator.cs index ca55f9c..57573c4 100644 --- a/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/UpdateKnowledgeBaseRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/rag/KnowledgeBase/UpdateKnowledgeBaseRequestValidator.cs @@ -1,6 +1,6 @@ using BuildFlow.Application.KnowledgeBase.DTOs; -namespace BuildFlow.Host.Endpoints.rag.KnowledgeBase; +namespace BuildFlow.Host.Endpoints.Rag.KnowledgeBase; /// /// Update知识库Request的请求校验器(FluentValidation)。 diff --git a/src/BuildFlow.Host/Endpoints/rag/Obsidian/SyncObsidianVaultEndpoint.cs b/src/BuildFlow.Host/Endpoints/rag/Obsidian/SyncObsidianVaultEndpoint.cs index 362711a..eef3cb7 100644 --- a/src/BuildFlow.Host/Endpoints/rag/Obsidian/SyncObsidianVaultEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/rag/Obsidian/SyncObsidianVaultEndpoint.cs @@ -3,7 +3,7 @@ using BuildFlow.Application.Obsidian.DTOs; using BuildFlow.Domain.Enums; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.Obsidian; +namespace BuildFlow.Host.Endpoints.Rag.Obsidian; /// diff --git a/src/BuildFlow.Host/Endpoints/rag/RAG/RAGQueryEndpoint.cs b/src/BuildFlow.Host/Endpoints/rag/RAG/RAGQueryEndpoint.cs index e51fae0..7ce426c 100644 --- a/src/BuildFlow.Host/Endpoints/rag/RAG/RAGQueryEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/rag/RAG/RAGQueryEndpoint.cs @@ -2,7 +2,7 @@ using BuildFlow.Application.RagQA.Commands; using BuildFlow.Application.RagQA.DTOs; using MediatR; -namespace BuildFlow.Host.Endpoints.rag.RAG; +namespace BuildFlow.Host.Endpoints.Rag.RAG; /// diff --git a/src/BuildFlow.Host/Endpoints/rag/RAG/RAGQueryRequestValidator.cs b/src/BuildFlow.Host/Endpoints/rag/RAG/RAGQueryRequestValidator.cs index cb4f3b1..9c7b2a4 100644 --- a/src/BuildFlow.Host/Endpoints/rag/RAG/RAGQueryRequestValidator.cs +++ b/src/BuildFlow.Host/Endpoints/rag/RAG/RAGQueryRequestValidator.cs @@ -1,6 +1,6 @@ using BuildFlow.Application.RagQA.DTOs; -namespace BuildFlow.Host.Endpoints.rag.RAG; +namespace BuildFlow.Host.Endpoints.Rag.RAG; /// /// RAG检索问答查询Request的请求校验器(FluentValidation)。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Applications/CreateBuildFlowApplicationEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Applications/CreateBuildFlowApplicationEndpoint.cs index 1bb5589..8bf457d 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Applications/CreateBuildFlowApplicationEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Applications/CreateBuildFlowApplicationEndpoint.cs @@ -2,7 +2,7 @@ using MediatR; using Workflow.Application.BuildFlow.Applications.Commands; using Workflow.Application.BuildFlow.Applications.DTOs; -namespace BuildFlow.Host.Endpoints.workflow.BuildFlow.Applications; +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Applications; /// 创建 BuildFlow 应用端点。POST /buildflow/applications。 public class CreateBuildFlowApplicationEndpoint(IMediator mediator) diff --git a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionEndpoint.cs index 85293af..57ed8f4 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionEndpoint.cs @@ -2,7 +2,7 @@ using MediatR; using Workflow.Application.BuildFlow.Buttons.Commands; using Workflow.Application.BuildFlow.Buttons.DTOs; -namespace BuildFlow.Host.Endpoints.workflow.BuildFlow.Buttons; +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Buttons; /// 创建 BuildFlow 按钮定义端点。POST /buildflow/buttons。 public class CreateBuildFlowButtonDefinitionEndpoint(IMediator mediator) diff --git a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionRequest.cs index ae0726c..c101674 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/CreateBuildFlowButtonDefinitionRequest.cs @@ -1,6 +1,6 @@ using Workflow.Domain.Enums; -namespace BuildFlow.Host.Endpoints.workflow.BuildFlow.Buttons; +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Buttons; /// 创建 BuildFlow 按钮定义请求。 public sealed record CreateBuildFlowButtonDefinitionRequest( diff --git a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/ExecuteBuildFlowButtonEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/ExecuteBuildFlowButtonEndpoint.cs index d8e256e..913b946 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/ExecuteBuildFlowButtonEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/ExecuteBuildFlowButtonEndpoint.cs @@ -2,7 +2,7 @@ using MediatR; using Workflow.Application.BuildFlow.Buttons.Commands; using Workflow.Application.BuildFlow.Buttons.DTOs; -namespace BuildFlow.Host.Endpoints.workflow.BuildFlow.Buttons; +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Buttons; /// 执行 BuildFlow 按钮动作链端点。POST /buildflow/buttons/{id}/execute。 public class ExecuteBuildFlowButtonEndpoint(IMediator mediator) diff --git a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/GetBuildFlowButtonDefinitionListEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/GetBuildFlowButtonDefinitionListEndpoint.cs index 673dc6a..cdfc731 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/GetBuildFlowButtonDefinitionListEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Buttons/GetBuildFlowButtonDefinitionListEndpoint.cs @@ -3,7 +3,7 @@ using Workflow.Application.BuildFlow.Buttons.DTOs; using Workflow.Application.BuildFlow.Buttons.Queries; using Workflow.Application.Common; -namespace BuildFlow.Host.Endpoints.workflow.BuildFlow.Buttons; +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Buttons; /// BuildFlow 按钮定义分页查询端点。GET /buildflow/buttons。 public class GetBuildFlowButtonDefinitionListEndpoint(IMediator mediator) diff --git a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/CreateCustomFunctionEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/CreateCustomFunctionEndpoint.cs index ee6d21e..8396162 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/CreateCustomFunctionEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/CreateCustomFunctionEndpoint.cs @@ -2,7 +2,7 @@ using MediatR; using Workflow.Application.BuildFlow.CustomFunctions.Commands; using Workflow.Application.BuildFlow.CustomFunctions.DTOs; -namespace BuildFlow.Host.Endpoints.workflow.BuildFlow.CustomFunctions; +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.CustomFunctions; /// 创建自定义函数端点。POST /buildflow/custom-functions。 public class CreateCustomFunctionEndpoint(IMediator mediator) diff --git a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/CreateCustomFunctionRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/CreateCustomFunctionRequest.cs index 28094f6..78bfa05 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/CreateCustomFunctionRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/CreateCustomFunctionRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.BuildFlow.CustomFunctions; +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.CustomFunctions; /// 创建自定义函数请求。 public sealed record CreateCustomFunctionRequest( diff --git a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/GetCustomFunctionListEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/GetCustomFunctionListEndpoint.cs index eff83f1..79d330b 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/GetCustomFunctionListEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/GetCustomFunctionListEndpoint.cs @@ -3,7 +3,7 @@ using Workflow.Application.BuildFlow.CustomFunctions.DTOs; using Workflow.Application.BuildFlow.CustomFunctions.Queries; using Workflow.Application.Common; -namespace BuildFlow.Host.Endpoints.workflow.BuildFlow.CustomFunctions; +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.CustomFunctions; /// 自定义函数分页查询端点。GET /buildflow/custom-functions。 public class GetCustomFunctionListEndpoint(IMediator mediator) diff --git a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/GetCustomFunctionListRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/GetCustomFunctionListRequest.cs index 92b82c8..2c61275 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/GetCustomFunctionListRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/CustomFunctions/GetCustomFunctionListRequest.cs @@ -1,6 +1,6 @@ using Workflow.Domain.Enums; -namespace BuildFlow.Host.Endpoints.workflow.BuildFlow.CustomFunctions; +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.CustomFunctions; /// 自定义函数分页查询请求。 public class GetCustomFunctionListRequest diff --git a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListEndpoint.cs index 454bbdf..a020916 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListEndpoint.cs @@ -3,7 +3,7 @@ using Workflow.Application.BuildFlow.Pages.DTOs; using Workflow.Application.BuildFlow.Pages.Queries; using Workflow.Application.Common; -namespace BuildFlow.Host.Endpoints.workflow.BuildFlow.Pages; +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Pages; /// BuildFlow 页面定义分页查询端点。GET /buildflow/pages。 public class GetBuildFlowPageDefinitionListEndpoint(IMediator mediator) diff --git a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListRequest.cs index 6c3adb2..3bf80d1 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/BuildFlow/Pages/GetBuildFlowPageDefinitionListRequest.cs @@ -1,6 +1,6 @@ using Workflow.Domain.Enums; -namespace BuildFlow.Host.Endpoints.workflow.BuildFlow.Pages; +namespace BuildFlow.Host.Endpoints.Workflow.BuildFlow.Pages; /// BuildFlow 页面定义分页查询请求。 public class GetBuildFlowPageDefinitionListRequest diff --git a/src/BuildFlow.Host/Endpoints/workflow/Form/CompareFormVersionsRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/Form/CompareFormVersionsRequest.cs index 6587656..3f1bb78 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Form/CompareFormVersionsRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Form/CompareFormVersionsRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.Form; +namespace BuildFlow.Host.Endpoints.Workflow.Form; /// /// 版本对比请求体。含两个版本 ID。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormComponentEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormComponentEndpoint.cs index e600794..239130e 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormComponentEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormComponentEndpoint.cs @@ -2,7 +2,7 @@ using MediatR; using Workflow.Application.Form.ComponentRegistry.Commands; using Workflow.Application.Form.ComponentRegistry.DTOs; -namespace BuildFlow.Host.Endpoints.workflow.Form; +namespace BuildFlow.Host.Endpoints.Workflow.Form; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormComponentRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormComponentRequest.cs index d2f9a5b..274b548 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormComponentRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormComponentRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.Form; +namespace BuildFlow.Host.Endpoints.Workflow.Form; /// /// 创建表单组件请求体。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormDefinitionEndpoint.cs index 5dcc0ed..74537e6 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormDefinitionEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormDefinitionEndpoint.cs @@ -2,7 +2,7 @@ using MediatR; using Workflow.Application.Form.DTOs; using Workflow.Application.Form.FormDefinition.Commands; -namespace BuildFlow.Host.Endpoints.workflow.Form; +namespace BuildFlow.Host.Endpoints.Workflow.Form; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormDefinitionRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormDefinitionRequest.cs index f28e99b..728ee53 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormDefinitionRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Form/CreateFormDefinitionRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.Form; +namespace BuildFlow.Host.Endpoints.Workflow.Form; /// /// 创建表单定义请求体。含表单名与字段 schema。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/Form/DeleteFormComponentRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/Form/DeleteFormComponentRequest.cs index ef081fa..7213cc2 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Form/DeleteFormComponentRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Form/DeleteFormComponentRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.Form; +namespace BuildFlow.Host.Endpoints.Workflow.Form; /// /// 删除表单组件请求体(路由参数绑定)。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/Form/DeleteFormDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/Form/DeleteFormDefinitionEndpoint.cs index 0a9eb81..0e9a1bf 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Form/DeleteFormDefinitionEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Form/DeleteFormDefinitionEndpoint.cs @@ -1,7 +1,7 @@ using MediatR; using Workflow.Application.Form.FormDefinition.Commands; -namespace BuildFlow.Host.Endpoints.workflow.Form; +namespace BuildFlow.Host.Endpoints.Workflow.Form; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/Form/DeleteFormDefinitionRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/Form/DeleteFormDefinitionRequest.cs index 1541a4f..39f0bf9 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Form/DeleteFormDefinitionRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Form/DeleteFormDefinitionRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.Form; +namespace BuildFlow.Host.Endpoints.Workflow.Form; /// /// 删除表单定义请求体(路由参数绑定)。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/Form/GetFormComponentByIdEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/Form/GetFormComponentByIdEndpoint.cs index 01c38b9..eb5c02f 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Form/GetFormComponentByIdEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Form/GetFormComponentByIdEndpoint.cs @@ -2,7 +2,7 @@ using MediatR; using Workflow.Application.Form.ComponentRegistry.DTOs; using Workflow.Application.Form.ComponentRegistry.Queries; -namespace BuildFlow.Host.Endpoints.workflow.Form; +namespace BuildFlow.Host.Endpoints.Workflow.Form; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/Form/GetFormDefinitionByIdRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/Form/GetFormDefinitionByIdRequest.cs index c231d60..d09c45c 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Form/GetFormDefinitionByIdRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Form/GetFormDefinitionByIdRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.Form; +namespace BuildFlow.Host.Endpoints.Workflow.Form; /// /// 表单定义详情查询请求体(路由参数绑定)。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/Form/GetFormDefinitionListRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/Form/GetFormDefinitionListRequest.cs index 5d06220..803692a 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Form/GetFormDefinitionListRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Form/GetFormDefinitionListRequest.cs @@ -1,6 +1,6 @@ using Workflow.Domain.Enums; -namespace BuildFlow.Host.Endpoints.workflow.Form; +namespace BuildFlow.Host.Endpoints.Workflow.Form; /// /// 表单定义列表查询请求体。含分页与状态过滤。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/Form/SubmitFormDataEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/Form/SubmitFormDataEndpoint.cs index 3fec1f0..e2c3a43 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Form/SubmitFormDataEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Form/SubmitFormDataEndpoint.cs @@ -1,7 +1,7 @@ using MediatR; using Workflow.Application.Form.FormData.Commands; -namespace BuildFlow.Host.Endpoints.workflow.Form; +namespace BuildFlow.Host.Endpoints.Workflow.Form; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/Form/UpdateFormComponentEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/Form/UpdateFormComponentEndpoint.cs index 7a010f5..6034fc2 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Form/UpdateFormComponentEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Form/UpdateFormComponentEndpoint.cs @@ -2,7 +2,7 @@ using MediatR; using Workflow.Application.Form.ComponentRegistry.Commands; using Workflow.Application.Form.ComponentRegistry.DTOs; -namespace BuildFlow.Host.Endpoints.workflow.Form; +namespace BuildFlow.Host.Endpoints.Workflow.Form; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/Form/UpdateFormDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/Form/UpdateFormDefinitionEndpoint.cs index 4fa7fcf..649cc43 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Form/UpdateFormDefinitionEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Form/UpdateFormDefinitionEndpoint.cs @@ -2,7 +2,7 @@ using MediatR; using Workflow.Application.Form.DTOs; using Workflow.Application.Form.FormDefinition.Commands; -namespace BuildFlow.Host.Endpoints.workflow.Form; +namespace BuildFlow.Host.Endpoints.Workflow.Form; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkAllNotificationsReadEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkAllNotificationsReadEndpoint.cs index aa4a58b..30ffa1a 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkAllNotificationsReadEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkAllNotificationsReadEndpoint.cs @@ -3,7 +3,7 @@ using BuildFlow.Shared.Domain.Common; using MediatR; using Workflow.Application.Features.Notifications; -namespace BuildFlow.Host.Endpoints.workflow.Notification; +namespace BuildFlow.Host.Endpoints.Workflow.Notification; /// 标记当前用户所有通知为已读。 public class MarkAllNotificationsReadEndpoint(IMediator mediator, ICurrentUserContext userContext) : EndpointWithoutRequest diff --git a/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkNotificationReadEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkNotificationReadEndpoint.cs index 59a498f..c1875e4 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkNotificationReadEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Notification/MarkNotificationReadEndpoint.cs @@ -3,7 +3,7 @@ using BuildFlow.Shared.Domain.Common; using MediatR; using Workflow.Application.Features.Notifications; -namespace BuildFlow.Host.Endpoints.workflow.Notification; +namespace BuildFlow.Host.Endpoints.Workflow.Notification; /// 标记单条通知为已读。 public class MarkNotificationReadEndpoint(IMediator mediator, ICurrentUserContext userContext) : EndpointWithoutRequest diff --git a/src/BuildFlow.Host/Endpoints/workflow/Notification/NotificationClaimsExtensions.cs b/src/BuildFlow.Host/Endpoints/workflow/Notification/NotificationClaimsExtensions.cs index e551f5b..c4a8355 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/Notification/NotificationClaimsExtensions.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/Notification/NotificationClaimsExtensions.cs @@ -1,6 +1,6 @@ using System.Security.Claims; -namespace BuildFlow.Host.Endpoints.workflow.Notification; +namespace BuildFlow.Host.Endpoints.Workflow.Notification; /// ClaimsPrincipal 扩展。从 JWT claims 提取用户角色列表(兼容短名 role 与长名 ClaimTypes.Role)。 internal static class NotificationClaimsExtensions diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateEdgeRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateEdgeRequest.cs index c603d33..eaeca1e 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateEdgeRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateEdgeRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowDefinition; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; /// /// 创建边请求体。含源/目标节点与条件。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateNodeEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateNodeEndpoint.cs index 1ed82ec..ebd6ee0 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateNodeEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateNodeEndpoint.cs @@ -3,7 +3,7 @@ using Workflow.Application.Features.WorkflowDefinitions.Commands; using Workflow.Application.Features.WorkflowDefinitions.DTOs; using Workflow.Domain.Enums; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowDefinition; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateNodeRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateNodeRequest.cs index 3f15f1a..8906a40 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateNodeRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateNodeRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowDefinition; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; /// /// 创建节点请求体。含节点类型与配置。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateWorkflowDefinitionRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateWorkflowDefinitionRequest.cs index 67356d0..06fa64e 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateWorkflowDefinitionRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/CreateWorkflowDefinitionRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowDefinition; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; /// /// 创建流程定义请求体。含名称与节点/边。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/DeleteEdgeRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/DeleteEdgeRequest.cs index 8d345b1..b04fc0f 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/DeleteEdgeRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/DeleteEdgeRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowDefinition; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; /// /// 删除边请求体(路由参数绑定)。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/DeleteNodeRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/DeleteNodeRequest.cs index c2891c7..41c430f 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/DeleteNodeRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/DeleteNodeRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowDefinition; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; /// /// 删除节点请求体(路由参数绑定)。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/DeleteWorkflowDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/DeleteWorkflowDefinitionEndpoint.cs index 0a2adf2..3955e53 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/DeleteWorkflowDefinitionEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/DeleteWorkflowDefinitionEndpoint.cs @@ -1,7 +1,7 @@ using MediatR; using Workflow.Application.Features.WorkflowDefinitions.Commands; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowDefinition; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/GetWorkflowDefinitionListEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/GetWorkflowDefinitionListEndpoint.cs index 7c8a05c..99688b6 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/GetWorkflowDefinitionListEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/GetWorkflowDefinitionListEndpoint.cs @@ -3,7 +3,7 @@ using Workflow.Application.Common; using Workflow.Application.Features.WorkflowDefinitions.DTOs; using Workflow.Application.Features.WorkflowDefinitions.Queries; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowDefinition; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/UpdateEdgeEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/UpdateEdgeEndpoint.cs index c640237..7512154 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/UpdateEdgeEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/UpdateEdgeEndpoint.cs @@ -3,7 +3,7 @@ using Workflow.Application.Features.WorkflowDefinitions.Commands; using Workflow.Application.Features.WorkflowDefinitions.DTOs; using Workflow.Domain.Enums; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowDefinition; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/UpdateEdgeRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/UpdateEdgeRequest.cs index 2a85693..80b6d7f 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/UpdateEdgeRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/UpdateEdgeRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowDefinition; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; /// /// 更新边请求体。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/UpdateWorkflowDefinitionEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/UpdateWorkflowDefinitionEndpoint.cs index 4b1007b..a83a7ab 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/UpdateWorkflowDefinitionEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowDefinition/UpdateWorkflowDefinitionEndpoint.cs @@ -2,7 +2,7 @@ using MediatR; using Workflow.Application.Features.WorkflowDefinitions.Commands; using Workflow.Application.Features.WorkflowDefinitions.DTOs; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowDefinition; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowDefinition; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/GetWorkflowInstanceByIdEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/GetWorkflowInstanceByIdEndpoint.cs index 5fe7a20..223a21b 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/GetWorkflowInstanceByIdEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/GetWorkflowInstanceByIdEndpoint.cs @@ -2,7 +2,7 @@ using MediatR; using Workflow.Application.Features.WorkflowInstances.DTOs; using Workflow.Application.Features.WorkflowInstances.Queries; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowInstance; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowInstance; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/StartWorkflowInstanceEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/StartWorkflowInstanceEndpoint.cs index ebd9f8f..208d7d0 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/StartWorkflowInstanceEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/StartWorkflowInstanceEndpoint.cs @@ -1,7 +1,7 @@ using MediatR; using Workflow.Application.Features.WorkflowInstances.Commands; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowInstance; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowInstance; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/StartWorkflowInstanceRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/StartWorkflowInstanceRequest.cs index 988b492..87e5336 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/StartWorkflowInstanceRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowInstance/StartWorkflowInstanceRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowInstance; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowInstance; /// /// 发起实例请求体。含流程定义 ID 与表单数据。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/AddSignerEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/AddSignerEndpoint.cs index ebb7d55..b94b93c 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/AddSignerEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/AddSignerEndpoint.cs @@ -1,7 +1,7 @@ using MediatR; using Workflow.Application.Features.WorkflowTasks.Commands; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// /// 加签端点。审批人在审批前临时增加审批人(前加签/后加签)。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/AddSignerRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/AddSignerRequest.cs index 708a2d0..cb5f4e9 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/AddSignerRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/AddSignerRequest.cs @@ -1,6 +1,6 @@ using Workflow.Domain.Enums; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// 加签请求 DTO。 /// 操作人用户 ID。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/DelegateTaskRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/DelegateTaskRequest.cs index e6eff64..b0c8700 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/DelegateTaskRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/DelegateTaskRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// /// 委派请求体。含任务 ID 与被委派人 ID。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetCcTasksEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetCcTasksEndpoint.cs index cc7b51a..3776beb 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetCcTasksEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetCcTasksEndpoint.cs @@ -3,7 +3,7 @@ using Workflow.Application.Common; using Workflow.Application.Features.WorkflowTasks.DTOs; using Workflow.Application.Features.WorkflowTasks.Queries; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetCcTasksRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetCcTasksRequest.cs index 0e54bdc..00cc954 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetCcTasksRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetCcTasksRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// /// 抄送任务查询请求体。含分页参数。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetOverdueTasksRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetOverdueTasksRequest.cs index 006987b..233e9a2 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetOverdueTasksRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetOverdueTasksRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// /// 逾期任务查询请求体。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetPendingTasksEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetPendingTasksEndpoint.cs index 558946a..4d7e755 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetPendingTasksEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetPendingTasksEndpoint.cs @@ -3,7 +3,7 @@ using Workflow.Application.Common; using Workflow.Application.Features.WorkflowTasks.DTOs; using Workflow.Application.Features.WorkflowTasks.Queries; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetTaskByIdEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetTaskByIdEndpoint.cs index b87fa5a..194987a 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetTaskByIdEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetTaskByIdEndpoint.cs @@ -2,7 +2,7 @@ using MediatR; using Workflow.Application.Features.WorkflowTasks.DTOs; using Workflow.Application.Features.WorkflowTasks.Queries; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetTaskByIdRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetTaskByIdRequest.cs index 198f74e..a5f746e 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetTaskByIdRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/GetTaskByIdRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// /// 任务详情查询请求体(路由参数绑定)。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/MarkCcTaskReadEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/MarkCcTaskReadEndpoint.cs index 5ca5c0f..7f785bc 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/MarkCcTaskReadEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/MarkCcTaskReadEndpoint.cs @@ -1,7 +1,7 @@ using MediatR; using Workflow.Application.Features.WorkflowTasks.Commands; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/MarkCcTaskReadRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/MarkCcTaskReadRequest.cs index 4e65328..d2b582d 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/MarkCcTaskReadRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/MarkCcTaskReadRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// /// 标记已读请求体。含任务 ID。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/RejectTaskEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/RejectTaskEndpoint.cs index 60cb5c9..e6d1cea 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/RejectTaskEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/RejectTaskEndpoint.cs @@ -1,7 +1,7 @@ using MediatR; using Workflow.Application.Features.WorkflowTasks.Commands; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/ReturnTaskRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/ReturnTaskRequest.cs index cf3070c..2298c87 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/ReturnTaskRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/ReturnTaskRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// 退回请求 DTO。 /// 操作人用户 ID。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/TransferTaskRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/TransferTaskRequest.cs index abb2a5d..7a4c8ba 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/TransferTaskRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/TransferTaskRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// /// 转交请求体。含任务 ID 与目标用户 ID。 diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/UrgeTaskEndpoint.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/UrgeTaskEndpoint.cs index 2f45bdc..0699983 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/UrgeTaskEndpoint.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/UrgeTaskEndpoint.cs @@ -1,7 +1,7 @@ using MediatR; using Workflow.Application.Features.WorkflowTasks.Commands; -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// diff --git a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/UrgeTaskRequest.cs b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/UrgeTaskRequest.cs index 79bbc9e..f362f9c 100644 --- a/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/UrgeTaskRequest.cs +++ b/src/BuildFlow.Host/Endpoints/workflow/WorkflowTask/UrgeTaskRequest.cs @@ -1,4 +1,4 @@ -namespace BuildFlow.Host.Endpoints.workflow.WorkflowTask; +namespace BuildFlow.Host.Endpoints.Workflow.WorkflowTask; /// /// 催办请求体。含任务 ID。 diff --git a/src/modules/platform/Application/Menus/Commands/CreateMenuCommand.cs b/src/modules/platform/Application/Menus/Commands/CreateMenuCommand.cs index 5f95c2e..4abe700 100644 --- a/src/modules/platform/Application/Menus/Commands/CreateMenuCommand.cs +++ b/src/modules/platform/Application/Menus/Commands/CreateMenuCommand.cs @@ -14,6 +14,7 @@ public record CreateMenuCommand : IRequest public string? Component { get; init; } public string? Redirect { get; init; } public string Title { get; init; } = default!; + public string Code { get; init; } = default!; public string? Icon { get; init; } public string? ActiveIcon { get; init; } public int Order { get; init; } diff --git a/src/modules/platform/Application/Menus/Commands/UpdateMenuCommand.cs b/src/modules/platform/Application/Menus/Commands/UpdateMenuCommand.cs index cbdeea8..59afe35 100644 --- a/src/modules/platform/Application/Menus/Commands/UpdateMenuCommand.cs +++ b/src/modules/platform/Application/Menus/Commands/UpdateMenuCommand.cs @@ -15,6 +15,7 @@ public record UpdateMenuCommand : IRequest public string? Component { get; init; } public string? Redirect { get; init; } public string? Title { get; init; } + public string? Code { get; init; } public string? Icon { get; init; } public string? ActiveIcon { get; init; } public int? Order { get; init; } diff --git a/src/modules/platform/Application/Menus/DTOs/CreateMenuRequest.cs b/src/modules/platform/Application/Menus/DTOs/CreateMenuRequest.cs index fca9829..ee8b60f 100644 --- a/src/modules/platform/Application/Menus/DTOs/CreateMenuRequest.cs +++ b/src/modules/platform/Application/Menus/DTOs/CreateMenuRequest.cs @@ -10,6 +10,7 @@ public record CreateMenuRequest( string? Component, string? Redirect, string Title, + string Code, string? Icon, string? ActiveIcon, int Order, diff --git a/src/modules/platform/Application/Menus/DTOs/MenuDto.cs b/src/modules/platform/Application/Menus/DTOs/MenuDto.cs index 92b663a..e982dfe 100644 --- a/src/modules/platform/Application/Menus/DTOs/MenuDto.cs +++ b/src/modules/platform/Application/Menus/DTOs/MenuDto.cs @@ -12,6 +12,7 @@ public record MenuDto( string? Component, string? Redirect, string Title, + string Code, string? Icon, string? ActiveIcon, int Order, diff --git a/src/modules/platform/Application/Menus/Handlers/CreateMenuCommandHandler.cs b/src/modules/platform/Application/Menus/Handlers/CreateMenuCommandHandler.cs index bc03ef7..76ad290 100644 --- a/src/modules/platform/Application/Menus/Handlers/CreateMenuCommandHandler.cs +++ b/src/modules/platform/Application/Menus/Handlers/CreateMenuCommandHandler.cs @@ -18,6 +18,10 @@ public class CreateMenuCommandHandler(PlatformDbContext db) : IRequestHandler m.Name == request.Name, ct)) throw new BusinessException("菜单路由名称已存在"); + // 菜单编码 Code 全局唯一(点号分层标识,如 system.user)。 + if (await db.Menus.AnyAsync(m => m.Code == request.Code, ct)) + throw new BusinessException("菜单编码已存在"); + // 若指定父菜单,必须真实存在(软删除的也视为不存在)。 if (request.ParentId is not null && !await db.Menus.AnyAsync(m => m.Id == request.ParentId.Value, ct)) @@ -33,6 +37,7 @@ public class CreateMenuCommandHandler(PlatformDbContext db) : IRequestHandler m.Code == request.Code && m.Id != request.Id, ct)) + { + throw new BusinessException("菜单编码已存在"); + } + // 防止把父菜单指向自身,造成自引用环。 if (request.ParentId is not null && request.ParentId == request.Id) throw new BusinessException("不能将菜单的父级指向自身"); @@ -39,6 +46,7 @@ public class UpdateMenuCommandHandler(PlatformDbContext db) : IRequestHandler Children { get; set; } = []; public string Title { get; set; } = default!; + + /// + /// 菜单编码,点号分层(父级 system,子级 system.user),全局唯一。 + /// 用于标识菜单节点与按钮权限归属,区别于路由 Name(Name 是前端路由唯一键)。 + /// + public string Code { get; set; } = default!; + public string? Icon { get; set; } public string? ActiveIcon { get; set; } public int Order { get; set; } diff --git a/src/modules/platform/Infrastructure/Migrations/20260703084733_AddMenuCode.Designer.cs b/src/modules/platform/Infrastructure/Migrations/20260703084733_AddMenuCode.Designer.cs new file mode 100644 index 0000000..c00c5af --- /dev/null +++ b/src/modules/platform/Infrastructure/Migrations/20260703084733_AddMenuCode.Designer.cs @@ -0,0 +1,792 @@ +// +using System; +using BuildFlow.Platform.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Platform.Infrastructure.Migrations +{ + [DbContext(typeof(PlatformDbContext))] + [Migration("20260703084733_AddMenuCode")] + partial class AddMenuCode + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.Menu", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id") + .HasComment("菜单ID"); + + b.Property("ActiveIcon") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("active_icon") + .HasComment("菜单激活状态图标"); + + b.Property("AffixTab") + .HasColumnType("boolean") + .HasColumnName("affix_tab") + .HasComment("是否固定标签页"); + + b.Property("Authority") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("authority") + .HasComment("允许访问的角色名,逗号分隔,为空表示所有已认证用户可访问"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("code") + .HasComment("菜单编码,点号分层(system / system.user),全局唯一"); + + b.Property("Component") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("component") + .HasComment("前端组件路径"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasComment("创建时间"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("created_by") + .HasComment("创建人"); + + b.Property("HideInMenu") + .HasColumnType("boolean") + .HasColumnName("hide_in_menu") + .HasComment("是否在菜单中隐藏"); + + b.Property("Icon") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("icon") + .HasComment("菜单图标"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("is_deleted") + .HasComment("是否已软删除"); + + b.Property("KeepAlive") + .HasColumnType("boolean") + .HasColumnName("keep_alive") + .HasComment("是否缓存页面状态"); + + b.Property("Link") + .HasMaxLength(500) + .HasColumnType("character varying(500)") + .HasColumnName("link") + .HasComment("外链地址"); + + b.Property("MenuVisibleWithForbidden") + .HasColumnType("boolean") + .HasColumnName("menu_visible_with_forbidden") + .HasComment("无权限时是否仍显示菜单"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("name") + .HasComment("菜单名称(路由name)"); + + b.Property("NoBasicLayout") + .HasColumnType("boolean") + .HasColumnName("no_basic_layout") + .HasComment("是否不使用基础布局"); + + b.Property("OperatorIP") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("operator_ip") + .HasComment("操作者IP地址"); + + b.Property("Order") + .HasColumnType("integer") + .HasColumnName("order") + .HasComment("排序序号,值越小越靠前"); + + b.Property("ParentId") + .HasColumnType("uuid") + .HasColumnName("parent_id") + .HasComment("父菜单ID,null表示顶级菜单"); + + b.Property("Path") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("path") + .HasComment("路由路径"); + + b.Property("Redirect") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("redirect") + .HasComment("重定向路径"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("title") + .HasComment("菜单显示标题"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at") + .HasComment("更新时间"); + + b.Property("UpdatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("updated_by") + .HasComment("更新人"); + + b.HasKey("Id") + .HasName("pk_menus"); + + b.HasIndex("Code") + .IsUnique() + .HasDatabaseName("ix_menus_code"); + + b.HasIndex("ParentId") + .HasDatabaseName("ix_menus_parent_id"); + + b.ToTable("menus", (string)null); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.Notification", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id") + .HasComment("通知ID"); + + b.Property("Content") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)") + .HasColumnName("content") + .HasComment("通知正文"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasComment("创建时间"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("created_by") + .HasComment("创建人"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("is_deleted") + .HasComment("是否已软删除"); + + b.Property("IsRead") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("is_read") + .HasComment("是否已读"); + + b.Property("OperatorIP") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("operator_ip") + .HasComment("操作者IP地址"); + + b.Property("ReadAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("read_at") + .HasComment("已读时间"); + + b.Property("RecipientUserId") + .HasColumnType("uuid") + .HasColumnName("recipient_user_id") + .HasComment("接收人用户ID"); + + b.Property("RelatedId") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("related_id") + .HasComment("关联业务对象ID"); + + b.Property("RelatedType") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("related_type") + .HasComment("关联业务对象类型"); + + b.Property("Source") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("source") + .HasComment("来源业务系统"); + + b.Property("Title") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("title") + .HasComment("通知标题"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("type") + .HasComment("通知类型"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at") + .HasComment("更新时间"); + + b.Property("UpdatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("updated_by") + .HasComment("更新人"); + + b.HasKey("Id") + .HasName("pk_notifications"); + + b.HasIndex("RecipientUserId", "CreatedAt") + .HasDatabaseName("ix_notifications_recipient_created"); + + b.HasIndex("RecipientUserId", "IsDeleted", "IsRead") + .HasDatabaseName("ix_notifications_recipient_read"); + + b.ToTable("notifications", (string)null); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.Permission", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id") + .HasComment("权限ID"); + + b.Property("Code") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("code") + .HasComment("权限编码,如 user:create,唯一"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasComment("创建时间"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("created_by") + .HasComment("创建人"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("description") + .HasComment("权限描述"); + + b.Property("Group") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("group") + .HasComment("权限分组"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("is_deleted") + .HasComment("是否已软删除"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("name") + .HasComment("权限名称"); + + b.Property("OperatorIP") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("operator_ip") + .HasComment("操作者IP地址"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at") + .HasComment("更新时间"); + + b.Property("UpdatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("updated_by") + .HasComment("更新人"); + + b.HasKey("Id") + .HasName("pk_permissions"); + + b.HasIndex("Code") + .IsUnique() + .HasDatabaseName("ix_permissions_code"); + + b.ToTable("permissions", (string)null); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.RefreshToken", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id") + .HasComment("刷新令牌ID"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasComment("创建时间"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("created_by") + .HasComment("创建人"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("expires_at") + .HasComment("令牌过期时间"); + + b.Property("IsRevoked") + .HasColumnType("boolean") + .HasColumnName("is_revoked") + .HasComment("是否已撤销"); + + b.Property("Token") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("token") + .HasComment("刷新令牌值,唯一"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at") + .HasComment("更新时间"); + + b.Property("UpdatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("updated_by") + .HasComment("更新人"); + + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id") + .HasComment("关联用户ID"); + + b.HasKey("Id") + .HasName("pk_refresh_tokens"); + + b.HasIndex("Token") + .IsUnique() + .HasDatabaseName("ix_refresh_tokens_token"); + + b.HasIndex("UserId") + .HasDatabaseName("ix_refresh_tokens_user_id"); + + b.ToTable("refresh_tokens", (string)null); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.Role", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id") + .HasComment("角色ID"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasComment("创建时间"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("created_by") + .HasComment("创建人"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("description") + .HasComment("角色描述"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("is_deleted") + .HasComment("是否已软删除"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("name") + .HasComment("角色名称,唯一"); + + b.Property("OperatorIP") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("operator_ip") + .HasComment("操作者IP地址"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at") + .HasComment("更新时间"); + + b.Property("UpdatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("updated_by") + .HasComment("更新人"); + + b.HasKey("Id") + .HasName("pk_roles"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_roles_name"); + + b.ToTable("roles", (string)null); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.RolePermission", b => + { + b.Property("RoleId") + .HasColumnType("uuid") + .HasColumnName("role_id") + .HasComment("角色ID"); + + b.Property("PermissionId") + .HasColumnType("uuid") + .HasColumnName("permission_id") + .HasComment("权限ID"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasComment("创建时间"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("created_by") + .HasComment("创建人"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at") + .HasComment("更新时间"); + + b.Property("UpdatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("updated_by") + .HasComment("更新人"); + + b.HasKey("RoleId", "PermissionId") + .HasName("pk_role_permissions"); + + b.HasIndex("PermissionId") + .HasDatabaseName("ix_role_permissions_permission_id"); + + b.ToTable("role_permissions", (string)null); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.User", b => + { + b.Property("Id") + .HasColumnType("uuid") + .HasColumnName("id") + .HasComment("用户ID"); + + b.Property("Avatar") + .HasColumnType("text") + .HasColumnName("avatar"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasComment("创建时间"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("created_by") + .HasComment("创建人"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("email") + .HasComment("邮箱地址,唯一"); + + b.Property("IsActive") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(true) + .HasColumnName("is_active") + .HasComment("是否启用,停用后禁止登录"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("is_deleted") + .HasComment("是否已软删除"); + + b.Property("OperatorIP") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("operator_ip") + .HasComment("操作者IP地址"); + + b.Property("PasswordHash") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("password_hash") + .HasComment("密码哈希值"); + + b.Property("RealName") + .HasColumnType("text") + .HasColumnName("real_name"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at") + .HasComment("更新时间"); + + b.Property("UpdatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("updated_by") + .HasComment("更新人"); + + b.Property("Username") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("username") + .HasComment("用户名,唯一"); + + b.HasKey("Id") + .HasName("pk_users"); + + b.HasIndex("Email") + .IsUnique() + .HasDatabaseName("ix_users_email"); + + b.HasIndex("Username") + .IsUnique() + .HasDatabaseName("ix_users_username"); + + b.ToTable("users", (string)null); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.UserRole", b => + { + b.Property("UserId") + .HasColumnType("uuid") + .HasColumnName("user_id") + .HasComment("用户ID"); + + b.Property("RoleId") + .HasColumnType("uuid") + .HasColumnName("role_id") + .HasComment("角色ID"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at") + .HasComment("创建时间"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("created_by") + .HasComment("创建人"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at") + .HasComment("更新时间"); + + b.Property("UpdatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("updated_by") + .HasComment("更新人"); + + b.HasKey("UserId", "RoleId") + .HasName("pk_user_roles"); + + b.HasIndex("RoleId") + .HasDatabaseName("ix_user_roles_role_id"); + + b.ToTable("user_roles", (string)null); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.Menu", b => + { + b.HasOne("BuildFlow.Platform.Domain.Entities.Menu", "Parent") + .WithMany("Children") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_menus_menus_parent_id"); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.RefreshToken", b => + { + b.HasOne("BuildFlow.Platform.Domain.Entities.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_refresh_tokens_users_user_id"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.RolePermission", b => + { + b.HasOne("BuildFlow.Platform.Domain.Entities.Permission", "Permission") + .WithMany("RolePermissions") + .HasForeignKey("PermissionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_role_permissions_permissions_permission_id"); + + b.HasOne("BuildFlow.Platform.Domain.Entities.Role", "Role") + .WithMany("RolePermissions") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_role_permissions_roles_role_id"); + + b.Navigation("Permission"); + + b.Navigation("Role"); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.UserRole", b => + { + b.HasOne("BuildFlow.Platform.Domain.Entities.Role", "Role") + .WithMany("UserRoles") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_roles_roles_role_id"); + + b.HasOne("BuildFlow.Platform.Domain.Entities.User", "User") + .WithMany("UserRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_user_roles_users_user_id"); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.Menu", b => + { + b.Navigation("Children"); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.Permission", b => + { + b.Navigation("RolePermissions"); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.Role", b => + { + b.Navigation("RolePermissions"); + + b.Navigation("UserRoles"); + }); + + modelBuilder.Entity("BuildFlow.Platform.Domain.Entities.User", b => + { + b.Navigation("UserRoles"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/modules/platform/Infrastructure/Migrations/20260703084733_AddMenuCode.cs b/src/modules/platform/Infrastructure/Migrations/20260703084733_AddMenuCode.cs new file mode 100644 index 0000000..a4d8c9c --- /dev/null +++ b/src/modules/platform/Infrastructure/Migrations/20260703084733_AddMenuCode.cs @@ -0,0 +1,41 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Platform.Infrastructure.Migrations +{ + /// + public partial class AddMenuCode : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "code", + table: "menus", + type: "character varying(100)", + maxLength: 100, + nullable: false, + defaultValue: "", + comment: "菜单编码,点号分层(system / system.user),全局唯一"); + + migrationBuilder.CreateIndex( + name: "ix_menus_code", + table: "menus", + column: "code", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "ix_menus_code", + table: "menus"); + + migrationBuilder.DropColumn( + name: "code", + table: "menus"); + } + } +} diff --git a/src/modules/platform/Infrastructure/Migrations/PlatformDbContextModelSnapshot.cs b/src/modules/platform/Infrastructure/Migrations/PlatformDbContextModelSnapshot.cs index d2d9478..057c5cd 100644 --- a/src/modules/platform/Infrastructure/Migrations/PlatformDbContextModelSnapshot.cs +++ b/src/modules/platform/Infrastructure/Migrations/PlatformDbContextModelSnapshot.cs @@ -46,6 +46,13 @@ namespace Platform.Infrastructure.Migrations .HasColumnName("authority") .HasComment("允许访问的角色名,逗号分隔,为空表示所有已认证用户可访问"); + b.Property("Code") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("code") + .HasComment("菜单编码,点号分层(system / system.user),全局唯一"); + b.Property("Component") .HasMaxLength(200) .HasColumnType("character varying(200)") @@ -162,6 +169,10 @@ namespace Platform.Infrastructure.Migrations b.HasKey("Id") .HasName("pk_menus"); + b.HasIndex("Code") + .IsUnique() + .HasDatabaseName("ix_menus_code"); + b.HasIndex("ParentId") .HasDatabaseName("ix_menus_parent_id"); diff --git a/src/modules/platform/Infrastructure/Persistence/Configurations/MenuConfiguration.cs b/src/modules/platform/Infrastructure/Persistence/Configurations/MenuConfiguration.cs index e55ee8c..b51adca 100644 --- a/src/modules/platform/Infrastructure/Persistence/Configurations/MenuConfiguration.cs +++ b/src/modules/platform/Infrastructure/Persistence/Configurations/MenuConfiguration.cs @@ -21,6 +21,8 @@ public class MenuConfiguration : IEntityTypeConfiguration builder.Property(m => m.Redirect).HasMaxLength(200).HasComment("重定向路径"); builder.Property(m => m.ParentId).HasComment("父菜单ID,null表示顶级菜单"); builder.Property(m => m.Title).HasMaxLength(100).IsRequired().HasComment("菜单显示标题"); + builder.Property(m => m.Code).HasMaxLength(100).IsRequired().HasComment("菜单编码,点号分层(system / system.user),全局唯一"); + builder.HasIndex(m => m.Code).IsUnique(); builder.Property(m => m.Icon).HasMaxLength(100).HasComment("菜单图标"); builder.Property(m => m.ActiveIcon).HasMaxLength(100).HasComment("菜单激活状态图标"); builder.Property(m => m.Order).HasComment("排序序号,值越小越靠前"); diff --git a/src/modules/platform/Infrastructure/Persistence/SeedData.cs b/src/modules/platform/Infrastructure/Persistence/SeedData.cs index 5b49917..299eab9 100644 --- a/src/modules/platform/Infrastructure/Persistence/SeedData.cs +++ b/src/modules/platform/Infrastructure/Persistence/SeedData.cs @@ -13,6 +13,9 @@ public static class SeedData // 权限 await SeedPermissionsAsync(db); + // 菜单(动态菜单种子,前端 backend 模式从此读取) + await SeedMenusAsync(db); + // 清理已废弃的 OrderManagement 分组残留权限及其角色关联。 // 该分组在业务下线后已从种子移除,但历史数据库中仍有残留记录, // 会导致权限管理树出现空分组。此清理幂等,删完后不再命中。 @@ -169,6 +172,99 @@ public static class SeedData await db.SaveChangesAsync(); } + /// + /// 播种菜单数据。供前端 backend 动态菜单模式(GET /menu/all)加载。 + /// 固定 Guid + Code(点号分层)保证幂等:按 Code 去重,已存在的不重复插入; + /// 已存在的菜单不动(不覆盖用户在菜单管理页的改动)。父子关系用 ParentCode 声明,播完后回填 ParentId。 + /// + private static async Task SeedMenusAsync(PlatformDbContext db) + { + var menuSeeds = new[] + { + // ===== 概览 dashboard ===== + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000001"), "dashboard", "", "Dashboard", "/dashboard", null, "/workspace", "概览", "lucide:layout-dashboard", 1, false, null, null, false, false, null), + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000002"), "dashboard.analytics", "dashboard", "Analytics", "/analytics", "/dashboard/analytics/index", null, "分析页", "lucide:area-chart", 1, false, null, true, false, false, null), + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000003"), "dashboard.workspace", "dashboard", "Workspace", "/workspace", "/dashboard/workspace/index", null, "工作台", "carbon:workspace", 2, false, null, null, false, false, null), + + // ===== 平台管理 system ===== + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000010"), "system", "", "System", "/system", null, "/system/user", "平台管理", "lucide:settings", 2, false, null, null, false, false, "Admin"), + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000011"), "system.user", "system", "SystemUser", "/system/user", "/system/user/index", null, "用户管理", "lucide:user-cog", 1, false, null, null, false, false, "Admin"), + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000012"), "system.role", "system", "SystemRole", "/system/role", "/system/role/index", null, "角色管理", "lucide:shield", 2, false, null, null, false, false, "Admin"), + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000013"), "system.permission", "system", "SystemPermission", "/system/permission", "/system/permission/index", null, "权限管理", "lucide:key", 3, false, null, null, false, false, "Admin"), + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000014"), "system.menu", "system", "SystemMenu", "/system/menu", "/system/menu/index", null, "菜单管理", "lucide:menu", 4, false, null, null, false, false, "Admin"), + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000015"), "system.storage", "system", "SystemStorage", "/system/storage", "/system/storage/index", null, "存储设置", "lucide:database", 5, false, null, null, false, false, "Admin"), + + // ===== 文件管理 file ===== + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000020"), "file", "", "FileManager", "/files", null, "/files/list", "文件管理", "lucide:folder-open", 3, false, null, null, false, false, null), + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000021"), "file.list", "file", "FileList", "/files/list", "/file-manager/index", null, "文件列表", "lucide:files", 1, false, null, null, false, false, null), + + // ===== 知识库 ai ===== + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000030"), "ai", "", "Knowledge", "/ai", null, "/ai/chat", "知识库", "lucide:library", 4, false, null, null, false, false, null), + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000031"), "ai.chat", "ai", "AiConversation", "/ai/chat", "/ai-chat/index", null, "AI 对话", "lucide:message-circle", 1, false, true, null, false, false, null), + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000032"), "ai.knowledge", "ai", "KnowledgeBases", "/ai/knowledge", "/ai-chat/knowledge/index", null, "知识库管理", "lucide:book-marked", 2, false, null, null, false, false, null), + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000033"), "ai.documents", "ai", "Documents", "/ai/documents", "/ai-chat/documents/index", null, "文档管理", "lucide:file-text", 3, false, null, null, false, false, null), + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000034"), "ai.models", "ai", "AiModels", "/ai/models", "/ai-chat/models/index", null, "模型管理", "lucide:cpu", 4, false, null, null, false, false, null), + + // ===== 流程管理 workflow ===== + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000040"), "workflow", "", "Workflow", "/workflow", null, "/workflow/list", "流程管理", "lucide:workflow", 5, false, null, null, false, false, "Admin"), + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000041"), "workflow.definition", "workflow", "WorkflowDefinitionList", "/workflow/list", "/workflow/list/index", null, "流程定义", "lucide:list", 1, false, null, null, false, false, "Admin"), + // 流程设计器:hideInMenu,仅作为可路由页面存在,不进侧边栏。 + new SeedMenu(Guid.Parse("40000000-0000-0000-0000-000000000042"), "workflow.designer", "workflow", "WorkflowDesigner", "/workflow/designer/:id", "/workflow/designer/index", null, "流程设计器", null, 2, true, null, null, false, false, "Admin"), + }; + + // 按 Code 去重,仅插入库里不存在的菜单(不覆盖已有,避免覆盖用户改动)。 + var existingCodes = await db.Menus.Select(m => m.Code).ToListAsync(); + var toAdd = menuSeeds + .Where(s => !existingCodes.Contains(s.Code)) + .Select(s => new Menu + { + Id = s.Id, + Code = s.Code, + Name = s.Name, + Path = s.Path, + Component = s.Component, + Redirect = s.Redirect, + Title = s.Title, + Icon = s.Icon, + Order = s.Order, + HideInMenu = s.HideInMenu, + KeepAlive = s.KeepAlive, + AffixTab = s.AffixTab, + NoBasicLayout = s.NoBasicLayout, + MenuVisibleWithForbidden = s.MenuVisibleWithForbidden, + Authority = s.Authority, + }) + .ToList(); + + if (toAdd.Count > 0) + { + await db.Menus.AddRangeAsync(toAdd); + await db.SaveChangesAsync(); + } + + // 回填父子关系:按 ParentCode 把已入库的菜单 ParentId 指向对应父菜单 Id。 + var codeToId = await db.Menus.ToDictionaryAsync(m => m.Code, m => m.Id); + var changed = false; + foreach (var seed in menuSeeds) + { + if (string.IsNullOrEmpty(seed.ParentCode)) continue; + if (!codeToId.TryGetValue(seed.Code, out var menuId)) continue; + if (!codeToId.TryGetValue(seed.ParentCode, out var parentId)) continue; + + var menu = await db.Menus.FirstOrDefaultAsync(m => m.Id == menuId); + if (menu is not null && menu.ParentId != parentId) + { + menu.ParentId = parentId; + changed = true; + } + } + + if (changed) + { + await db.SaveChangesAsync(); + } + } + /// /// 物理清理已废弃的 OrderManagement 分组权限及其角色关联。 /// 业务下线后该分组(历史残留的 order:* 与 menu-item:* "菜品/订单"权限)已从种子移除, diff --git a/src/modules/platform/Infrastructure/Persistence/SeedMenu.cs b/src/modules/platform/Infrastructure/Persistence/SeedMenu.cs new file mode 100644 index 0000000..5409c17 --- /dev/null +++ b/src/modules/platform/Infrastructure/Persistence/SeedMenu.cs @@ -0,0 +1,23 @@ +namespace BuildFlow.Platform.Infrastructure.Persistence; + +/// +/// 菜单种子记录。Id 固定 Guid,保证幂等重跑不重复插入。 +/// ParentCode 为父菜单 Code(点号分层标识),顶级菜单传 null。 +/// +internal sealed record SeedMenu( + Guid Id, + string Code, + string ParentCode, + string Name, + string Path, + string? Component, + string? Redirect, + string Title, + string? Icon, + int Order, + bool HideInMenu, + bool? KeepAlive, + bool? AffixTab, + bool NoBasicLayout, + bool MenuVisibleWithForbidden, + string? Authority); diff --git a/src/modules/workflow/Domain/Entities/WorkflowDefinition.cs b/src/modules/workflow/Domain/Entities/WorkflowDefinition.cs index 0377e40..02b939b 100644 --- a/src/modules/workflow/Domain/Entities/WorkflowDefinition.cs +++ b/src/modules/workflow/Domain/Entities/WorkflowDefinition.cs @@ -6,7 +6,11 @@ namespace Workflow.Domain.Entities; /// /// 工作流定义:流程的模板(蓝图)。一个定义可被多次实例化为 WorkflowInstance。 /// 只有 Published 状态的定义才允许启动实例;Version 支持同 Code 多版本并存。 -/// 节点与边以独立实体存储(Nodes/Edges 导航属性),DefinitionJson 为完整图的冗余快照。 +/// +/// 流程图存储:DefinitionJson(jsonb)是 X6 单一事实源,存完整流程图(nodes/edges/ports/data 业务配置), +/// 前端 graph.toJSON() 整图保存、graph.fromJSON() 整图渲染。发布时把 DefinitionJson 复制成 +/// WorkflowDefinitionSnapshot 的不可变快照,引擎运行时按 DefinitionId+Version 读快照实现版本隔离。 +/// Nodes/Edges 导航属性仅作迁移期只读兼容(P4 将随关系表废弃而移除)。 /// public class WorkflowDefinition : BaseEntity, IFullAudit { diff --git a/src/shared/BuildFlow.Shared/Api/ServiceCollectionExtensions.cs b/src/shared/BuildFlow.Shared/Api/ServiceCollectionExtensions.cs index 1981a7d..52828a1 100644 --- a/src/shared/BuildFlow.Shared/Api/ServiceCollectionExtensions.cs +++ b/src/shared/BuildFlow.Shared/Api/ServiceCollectionExtensions.cs @@ -39,16 +39,25 @@ public static class ServiceCollectionExtensions new SymmetricSecurityKey(Encoding.UTF8.GetBytes(localSigningKey)); } - // SignalR WebSocket 握手无法携带 Authorization 头,对 /hubs/* 路径从 query 取 access_token + // SignalR WebSocket 握手无法携带 Authorization 头,对 /hubs/* 路径从 query 取 access_token; + // 文件预览端点同样需要(img src / window.open 无法带 header),从 token query 参数读 JWT。 options.Events = new JwtBearerEvents { OnMessageReceived = context => { - var token = context.Request.Query["access_token"]; - if (!string.IsNullOrEmpty(token) && + var accessToken = context.Request.Query["access_token"]; + if (!string.IsNullOrEmpty(accessToken) && context.Request.Path.StartsWithSegments("/hubs")) { - context.Token = token; + context.Token = accessToken; + } + + // 文件预览:img src="/api/files/preview?objectKey=...&token=..." 无法带 Authorization header + var previewToken = context.Request.Query["token"]; + if (!string.IsNullOrEmpty(previewToken) && + context.Request.Path.StartsWithSegments("/api/files/preview")) + { + context.Token = previewToken; } return Task.CompletedTask; }