docs: 添加项目文档包括总览、架构、流程引擎和服务层

新增以下文档文件:
- PROJECT_OVERVIEW.md 项目总览文档
- BACKEND_ARCHITECTURE.md 后端架构文档
- FRONTEND_ARCHITECTURE.md 前端架构文档
- FLOW_ENGINE.md 流程引擎文档
- SERVICES.md 服务层文档
- ERROR_HANDLING.md 错误处理模块文档

文档内容涵盖项目整体介绍、技术架构、核心模块设计和实现细节
This commit is contained in:
2025-09-24 20:21:45 +08:00
parent 6ff587dc23
commit a3f2f99a68
13 changed files with 11803 additions and 0 deletions

View File

@ -0,0 +1,308 @@
# 后端架构文档
## 概述
后端采用 Rust + Axum 构建,遵循分层架构设计,包含数据访问层、业务逻辑层、路由层和中间件层。
## 核心模块
### 1. 应用入口 (main.rs)
**职责**: 应用启动、服务配置、中间件注册
**主要功能**:
- 数据库连接初始化
- Redis 连接配置
- CORS 跨域设置
- 多端口服务启动 (HTTP/WebSocket/SSE)
- 日志中间件注册
**服务端口**:
- HTTP API: 9898 (默认)
- WebSocket: 8877 (默认)
- SSE: 8866 (默认)
### 2. 数据库层 (db.rs)
**职责**: 数据库连接管理和配置
**特性**:
- 支持多种数据库 (MySQL/PostgreSQL/SQLite)
- 连接池管理
- 事务支持
- 自动迁移
### 3. 错误处理 (error.rs)
**职责**: 统一错误类型定义和处理
**错误类型**:
- `DatabaseError`: 数据库操作错误
- `ValidationError`: 数据验证错误
- `AuthenticationError`: 认证错误
- `AuthorizationError`: 授权错误
- `NotFoundError`: 资源不存在
- `InternalServerError`: 内部服务器错误
### 4. 响应格式 (response.rs)
**职责**: 统一 API 响应格式
**响应结构**:
```rust
pub struct ApiResponse<T> {
pub code: i32,
pub message: String,
pub data: Option<T>,
}
pub struct PageResponse<T> {
pub items: Vec<T>,
pub total: u64,
pub page: u64,
pub page_size: u64,
}
```
## 业务模块
### Models (数据模型层)
**位置**: `src/models/`
**模型列表**:
- `user.rs`: 用户模型
- `role.rs`: 角色模型
- `menu.rs`: 菜单模型
- `department.rs`: 部门模型
- `position.rs`: 职位模型
- `flow.rs`: 流程模型
- `schedule_job.rs`: 定时任务模型
- `flow_run_log.rs`: 流程运行日志
- `request_log.rs`: 请求日志
- `refresh_token.rs`: 刷新令牌
**特性**:
- 使用 SeaORM 宏自动生成
- 支持关联查询
- 自动时间戳管理
- 软删除支持
### Services (业务逻辑层)
**位置**: `src/services/`
**服务列表**:
- `auth_service.rs`: 认证服务
- `user_service.rs`: 用户管理服务
- `role_service.rs`: 角色管理服务
- `menu_service.rs`: 菜单管理服务
- `department_service.rs`: 部门管理服务
- `position_service.rs`: 职位管理服务
- `flow_service.rs`: 流程管理服务
- `schedule_job_service.rs`: 定时任务服务
- `flow_run_log_service.rs`: 流程日志服务
- `log_service.rs`: 系统日志服务
**设计原则**:
- 单一职责原则
- 依赖注入
- 异步处理
- 事务管理
### Routes (路由层)
**位置**: `src/routes/`
**路由模块**:
- `auth.rs`: 认证相关路由
- `users.rs`: 用户管理路由
- `roles.rs`: 角色管理路由
- `menus.rs`: 菜单管理路由
- `departments.rs`: 部门管理路由
- `positions.rs`: 职位管理路由
- `flows.rs`: 流程管理路由
- `schedule_jobs.rs`: 定时任务路由
- `flow_run_logs.rs`: 流程日志路由
- `logs.rs`: 系统日志路由
- `dynamic_api.rs`: 动态 API 路由
**路由特性**:
- RESTful API 设计
- 参数验证
- 权限检查
- 分页支持
- 错误处理
### Middlewares (中间件层)
**位置**: `src/middlewares/`
**中间件列表**:
- `jwt.rs`: JWT 认证中间件
- `logging.rs`: 请求日志中间件
- `http_client.rs`: HTTP 客户端中间件
- `ws.rs`: WebSocket 服务中间件
- `sse.rs`: SSE 服务中间件
**功能特性**:
- 请求/响应拦截
- 认证授权
- 日志记录
- 跨域处理
- 实时通信
### Utils (工具模块)
**位置**: `src/utils/`
**工具列表**:
- `ids.rs`: ID 生成器 (Snowflake 算法)
- `password.rs`: 密码哈希工具
- `scheduler.rs`: 任务调度器
**特性**:
- 分布式 ID 生成
- 安全密码处理
- 定时任务管理
## 流程引擎
**位置**: `src/flow/`
### 核心组件
#### 1. 领域模型 (domain.rs)
- `ChainDef`: 流程链定义
- `NodeDef`: 节点定义
- `LinkDef`: 连接定义
- `NodeKind`: 节点类型枚举
#### 2. DSL 解析 (dsl.rs)
- `FlowDSL`: 流程 DSL 结构
- `NodeDSL`: 节点 DSL 结构
- `DesignSyntax`: 设计语法结构
- 校验和构建函数
#### 3. 执行引擎 (engine.rs)
- `FlowEngine`: 流程执行引擎
- `TaskRegistry`: 任务注册表
- `DriveOptions`: 执行选项
- 并发执行支持
#### 4. 执行器 (executors/)
- `http.rs`: HTTP 请求执行器
- `db.rs`: 数据库操作执行器
- `condition.rs`: 条件判断执行器
- `script_js.rs`: JavaScript 脚本执行器
- `script_python.rs`: Python 脚本执行器
- `script_rhai.rs`: Rhai 脚本执行器
- `variable.rs`: 变量操作执行器
#### 5. 上下文管理 (context.rs)
- `StreamEvent`: 流事件定义
- 执行上下文管理
- 事件流处理
#### 6. 日志处理 (log_handler.rs)
- 流程执行日志
- 错误日志记录
- 性能监控
## 数据库设计
### 核心表结构
#### 用户权限相关
- `users`: 用户表
- `roles`: 角色表
- `menus`: 菜单表
- `departments`: 部门表
- `positions`: 职位表
- `user_roles`: 用户角色关联表
- `role_menus`: 角色菜单关联表
- `user_departments`: 用户部门关联表
- `user_positions`: 用户职位关联表
#### 流程相关
- `flows`: 流程表
- `flow_run_logs`: 流程运行日志表
- `schedule_jobs`: 定时任务表
#### 系统相关
- `request_logs`: 请求日志表
- `refresh_tokens`: 刷新令牌表
### 索引策略
- 主键索引
- 外键索引
- 查询优化索引
- 复合索引
## 安全机制
### 认证授权
- JWT 令牌机制
- 刷新令牌支持
- 权限中间件验证
- 角色基础访问控制 (RBAC)
### 数据安全
- Argon2 密码哈希
- SQL 注入防护
- XSS 防护
- CSRF 防护
### 通信安全
- HTTPS 支持
- CORS 配置
- 请求限流
- 日志审计
## 性能优化
### 数据库优化
- 连接池管理
- 查询优化
- 索引策略
- 分页查询
### 缓存策略
- Redis 缓存
- 查询结果缓存
- 会话缓存
### 并发处理
- 异步 I/O
- 任务队列
- 连接复用
- 资源池管理
## 监控和日志
### 日志系统
- 结构化日志 (tracing)
- 分级日志记录
- 请求链路追踪
- 错误堆栈记录
### 监控指标
- 请求响应时间
- 数据库连接状态
- 内存使用情况
- 错误率统计
## 部署配置
### 环境变量
- 数据库连接配置
- Redis 连接配置
- JWT 密钥配置
- 服务端口配置
- CORS 配置
### 容器化
- Docker 支持
- 多阶段构建
- 健康检查
- 资源限制

1056
docs/DATABASE.md Normal file

File diff suppressed because it is too large Load Diff

878
docs/ERROR_HANDLING.md Normal file
View File

@ -0,0 +1,878 @@
# UdminAI 错误处理模块文档
## 概述
UdminAI 项目的错误处理模块提供了统一的错误定义、处理和响应机制。该模块基于 Rust 的 `Result` 类型和 `thiserror` 库构建,确保错误信息的一致性、可追踪性和用户友好性。
## 设计原则
### 核心理念
- **统一性**: 所有模块使用统一的错误类型
- **可追踪性**: 错误包含足够的上下文信息
- **用户友好**: 面向用户的错误消息清晰易懂
- **开发友好**: 面向开发者的错误信息详细准确
- **类型安全**: 编译时错误类型检查
### 错误分层
1. **应用层错误**: 业务逻辑错误
2. **服务层错误**: 服务调用错误
3. **数据层错误**: 数据库和缓存错误
4. **网络层错误**: HTTP 和网络通信错误
5. **系统层错误**: 系统资源和配置错误
## 错误类型定义 (error.rs)
### 主要错误类型
```rust
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
use serde::{Deserialize, Serialize};
use std::fmt;
use thiserror::Error;
use tracing::error;
/// 应用主错误类型
#[derive(Error, Debug, Clone, Serialize, Deserialize)]
pub enum AppError {
// 认证和授权错误
#[error("认证失败: {message}")]
AuthenticationFailed { message: String },
#[error("授权失败: {message}")]
AuthorizationFailed { message: String },
#[error("令牌无效: {message}")]
InvalidToken { message: String },
#[error("令牌已过期")]
TokenExpired,
// 验证错误
#[error("验证失败: {field} - {message}")]
ValidationFailed { field: String, message: String },
#[error("请求参数无效: {message}")]
InvalidRequest { message: String },
#[error("必需字段缺失: {field}")]
MissingField { field: String },
// 资源错误
#[error("资源未找到: {resource}")]
NotFound(String),
#[error("资源已存在: {resource}")]
AlreadyExists(String),
#[error("资源冲突: {message}")]
Conflict { message: String },
// 业务逻辑错误
#[error("业务规则违反: {message}")]
BusinessRuleViolation { message: String },
#[error("操作不被允许: {message}")]
OperationNotAllowed { message: String },
#[error("状态无效: 当前状态 {current}, 期望状态 {expected}")]
InvalidState { current: String, expected: String },
// 数据库错误
#[error("数据库错误: {0}")]
DatabaseError(String),
#[error("数据库连接失败: {message}")]
DatabaseConnectionFailed { message: String },
#[error("事务失败: {message}")]
TransactionFailed { message: String },
// 缓存错误
#[error("缓存错误: {0}")]
CacheError(String),
#[error("缓存连接失败: {message}")]
CacheConnectionFailed { message: String },
// 网络和外部服务错误
#[error("网络错误: {message}")]
NetworkError { message: String },
#[error("外部服务错误: {service} - {message}")]
ExternalServiceError { service: String, message: String },
#[error("HTTP 请求失败: {status} - {message}")]
HttpRequestFailed { status: u16, message: String },
// 文件和 I/O 错误
#[error("文件操作失败: {message}")]
FileOperationFailed { message: String },
#[error("文件未找到: {path}")]
FileNotFound { path: String },
#[error("文件权限不足: {path}")]
FilePermissionDenied { path: String },
// 配置和环境错误
#[error("配置错误: {message}")]
ConfigurationError { message: String },
#[error("环境变量缺失: {variable}")]
MissingEnvironmentVariable { variable: String },
// 序列化和反序列化错误
#[error("序列化失败: {message}")]
SerializationFailed { message: String },
#[error("反序列化失败: {message}")]
DeserializationFailed { message: String },
#[error("JSON 格式错误: {message}")]
JsonFormatError { message: String },
// 流程引擎错误
#[error("流程执行失败: {flow_id} - {message}")]
FlowExecutionFailed { flow_id: String, message: String },
#[error("流程解析失败: {message}")]
FlowParsingFailed { message: String },
#[error("节点执行失败: {node_id} - {message}")]
NodeExecutionFailed { node_id: String, message: String },
// 调度任务错误
#[error("任务调度失败: {job_id} - {message}")]
JobSchedulingFailed { job_id: String, message: String },
#[error("Cron 表达式无效: {expression}")]
InvalidCronExpression { expression: String },
#[error("任务执行超时: {job_id}")]
JobExecutionTimeout { job_id: String },
// 系统错误
#[error("内部服务器错误: {message}")]
InternalServerError { message: String },
#[error("服务不可用: {message}")]
ServiceUnavailable { message: String },
#[error("请求超时: {message}")]
RequestTimeout { message: String },
#[error("资源耗尽: {resource}")]
ResourceExhausted { resource: String },
// 限流和安全错误
#[error("请求频率过高: {message}")]
RateLimitExceeded { message: String },
#[error("请求体过大: 当前大小 {current}, 最大允许 {max}")]
PayloadTooLarge { current: usize, max: usize },
#[error("不支持的媒体类型: {media_type}")]
UnsupportedMediaType { media_type: String },
}
/// 错误响应结构
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ErrorResponse {
pub error: ErrorDetail,
pub timestamp: chrono::DateTime<chrono::Utc>,
pub request_id: Option<String>,
}
/// 错误详情
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ErrorDetail {
pub code: String,
pub message: String,
pub details: Option<serde_json::Value>,
pub field: Option<String>,
}
impl AppError {
/// 获取错误代码
pub fn error_code(&self) -> &'static str {
match self {
// 认证和授权
AppError::AuthenticationFailed { .. } => "AUTH_FAILED",
AppError::AuthorizationFailed { .. } => "AUTHORIZATION_FAILED",
AppError::InvalidToken { .. } => "INVALID_TOKEN",
AppError::TokenExpired => "TOKEN_EXPIRED",
// 验证
AppError::ValidationFailed { .. } => "VALIDATION_FAILED",
AppError::InvalidRequest { .. } => "INVALID_REQUEST",
AppError::MissingField { .. } => "MISSING_FIELD",
// 资源
AppError::NotFound(_) => "NOT_FOUND",
AppError::AlreadyExists(_) => "ALREADY_EXISTS",
AppError::Conflict { .. } => "CONFLICT",
// 业务逻辑
AppError::BusinessRuleViolation { .. } => "BUSINESS_RULE_VIOLATION",
AppError::OperationNotAllowed { .. } => "OPERATION_NOT_ALLOWED",
AppError::InvalidState { .. } => "INVALID_STATE",
// 数据库
AppError::DatabaseError(_) => "DATABASE_ERROR",
AppError::DatabaseConnectionFailed { .. } => "DATABASE_CONNECTION_FAILED",
AppError::TransactionFailed { .. } => "TRANSACTION_FAILED",
// 缓存
AppError::CacheError(_) => "CACHE_ERROR",
AppError::CacheConnectionFailed { .. } => "CACHE_CONNECTION_FAILED",
// 网络
AppError::NetworkError { .. } => "NETWORK_ERROR",
AppError::ExternalServiceError { .. } => "EXTERNAL_SERVICE_ERROR",
AppError::HttpRequestFailed { .. } => "HTTP_REQUEST_FAILED",
// 文件
AppError::FileOperationFailed { .. } => "FILE_OPERATION_FAILED",
AppError::FileNotFound { .. } => "FILE_NOT_FOUND",
AppError::FilePermissionDenied { .. } => "FILE_PERMISSION_DENIED",
// 配置
AppError::ConfigurationError { .. } => "CONFIGURATION_ERROR",
AppError::MissingEnvironmentVariable { .. } => "MISSING_ENV_VAR",
// 序列化
AppError::SerializationFailed { .. } => "SERIALIZATION_FAILED",
AppError::DeserializationFailed { .. } => "DESERIALIZATION_FAILED",
AppError::JsonFormatError { .. } => "JSON_FORMAT_ERROR",
// 流程引擎
AppError::FlowExecutionFailed { .. } => "FLOW_EXECUTION_FAILED",
AppError::FlowParsingFailed { .. } => "FLOW_PARSING_FAILED",
AppError::NodeExecutionFailed { .. } => "NODE_EXECUTION_FAILED",
// 调度任务
AppError::JobSchedulingFailed { .. } => "JOB_SCHEDULING_FAILED",
AppError::InvalidCronExpression { .. } => "INVALID_CRON_EXPRESSION",
AppError::JobExecutionTimeout { .. } => "JOB_EXECUTION_TIMEOUT",
// 系统
AppError::InternalServerError { .. } => "INTERNAL_SERVER_ERROR",
AppError::ServiceUnavailable { .. } => "SERVICE_UNAVAILABLE",
AppError::RequestTimeout { .. } => "REQUEST_TIMEOUT",
AppError::ResourceExhausted { .. } => "RESOURCE_EXHAUSTED",
// 限流和安全
AppError::RateLimitExceeded { .. } => "RATE_LIMIT_EXCEEDED",
AppError::PayloadTooLarge { .. } => "PAYLOAD_TOO_LARGE",
AppError::UnsupportedMediaType { .. } => "UNSUPPORTED_MEDIA_TYPE",
}
}
/// 获取 HTTP 状态码
pub fn status_code(&self) -> StatusCode {
match self {
// 4xx 客户端错误
AppError::AuthenticationFailed { .. } => StatusCode::UNAUTHORIZED,
AppError::AuthorizationFailed { .. } => StatusCode::FORBIDDEN,
AppError::InvalidToken { .. } => StatusCode::UNAUTHORIZED,
AppError::TokenExpired => StatusCode::UNAUTHORIZED,
AppError::ValidationFailed { .. } => StatusCode::BAD_REQUEST,
AppError::InvalidRequest { .. } => StatusCode::BAD_REQUEST,
AppError::MissingField { .. } => StatusCode::BAD_REQUEST,
AppError::NotFound(_) => StatusCode::NOT_FOUND,
AppError::AlreadyExists(_) => StatusCode::CONFLICT,
AppError::Conflict { .. } => StatusCode::CONFLICT,
AppError::BusinessRuleViolation { .. } => StatusCode::BAD_REQUEST,
AppError::OperationNotAllowed { .. } => StatusCode::FORBIDDEN,
AppError::InvalidState { .. } => StatusCode::BAD_REQUEST,
AppError::FileNotFound { .. } => StatusCode::NOT_FOUND,
AppError::FilePermissionDenied { .. } => StatusCode::FORBIDDEN,
AppError::JsonFormatError { .. } => StatusCode::BAD_REQUEST,
AppError::InvalidCronExpression { .. } => StatusCode::BAD_REQUEST,
AppError::RateLimitExceeded { .. } => StatusCode::TOO_MANY_REQUESTS,
AppError::PayloadTooLarge { .. } => StatusCode::PAYLOAD_TOO_LARGE,
AppError::UnsupportedMediaType { .. } => StatusCode::UNSUPPORTED_MEDIA_TYPE,
// 5xx 服务器错误
AppError::DatabaseError(_) => StatusCode::INTERNAL_SERVER_ERROR,
AppError::DatabaseConnectionFailed { .. } => StatusCode::SERVICE_UNAVAILABLE,
AppError::TransactionFailed { .. } => StatusCode::INTERNAL_SERVER_ERROR,
AppError::CacheError(_) => StatusCode::INTERNAL_SERVER_ERROR,
AppError::CacheConnectionFailed { .. } => StatusCode::SERVICE_UNAVAILABLE,
AppError::NetworkError { .. } => StatusCode::BAD_GATEWAY,
AppError::ExternalServiceError { .. } => StatusCode::BAD_GATEWAY,
AppError::HttpRequestFailed { .. } => StatusCode::BAD_GATEWAY,
AppError::FileOperationFailed { .. } => StatusCode::INTERNAL_SERVER_ERROR,
AppError::ConfigurationError { .. } => StatusCode::INTERNAL_SERVER_ERROR,
AppError::MissingEnvironmentVariable { .. } => StatusCode::INTERNAL_SERVER_ERROR,
AppError::SerializationFailed { .. } => StatusCode::INTERNAL_SERVER_ERROR,
AppError::DeserializationFailed { .. } => StatusCode::INTERNAL_SERVER_ERROR,
AppError::FlowExecutionFailed { .. } => StatusCode::INTERNAL_SERVER_ERROR,
AppError::FlowParsingFailed { .. } => StatusCode::BAD_REQUEST,
AppError::NodeExecutionFailed { .. } => StatusCode::INTERNAL_SERVER_ERROR,
AppError::JobSchedulingFailed { .. } => StatusCode::INTERNAL_SERVER_ERROR,
AppError::JobExecutionTimeout { .. } => StatusCode::REQUEST_TIMEOUT,
AppError::InternalServerError { .. } => StatusCode::INTERNAL_SERVER_ERROR,
AppError::ServiceUnavailable { .. } => StatusCode::SERVICE_UNAVAILABLE,
AppError::RequestTimeout { .. } => StatusCode::REQUEST_TIMEOUT,
AppError::ResourceExhausted { .. } => StatusCode::SERVICE_UNAVAILABLE,
}
}
/// 获取错误字段(如果适用)
pub fn error_field(&self) -> Option<String> {
match self {
AppError::ValidationFailed { field, .. } => Some(field.clone()),
AppError::MissingField { field } => Some(field.clone()),
_ => None,
}
}
/// 是否为客户端错误
pub fn is_client_error(&self) -> bool {
self.status_code().is_client_error()
}
/// 是否为服务器错误
pub fn is_server_error(&self) -> bool {
self.status_code().is_server_error()
}
/// 创建错误响应
pub fn to_error_response(&self, request_id: Option<String>) -> ErrorResponse {
ErrorResponse {
error: ErrorDetail {
code: self.error_code().to_string(),
message: self.to_string(),
details: None,
field: self.error_field(),
},
timestamp: chrono::Utc::now(),
request_id,
}
}
/// 记录错误日志
pub fn log_error(&self, request_id: Option<&str>) {
let level = if self.is_server_error() {
tracing::Level::ERROR
} else {
tracing::Level::WARN
};
match level {
tracing::Level::ERROR => {
error!(
target = "udmin",
error_code = %self.error_code(),
error_message = %self,
request_id = ?request_id,
"application.error.server"
);
}
_ => {
tracing::warn!(
target = "udmin",
error_code = %self.error_code(),
error_message = %self,
request_id = ?request_id,
"application.error.client"
);
}
}
}
}
/// 实现 IntoResponse使错误可以直接作为 HTTP 响应返回
impl IntoResponse for AppError {
fn into_response(self) -> Response {
// 从请求上下文获取 request_id实际实现中可能需要通过中间件传递
let request_id = None; // 这里应该从上下文获取
// 记录错误日志
self.log_error(request_id.as_deref());
// 创建错误响应
let error_response = self.to_error_response(request_id);
let status_code = self.status_code();
(status_code, Json(error_response)).into_response()
}
}
/// 应用结果类型别名
pub type AppResult<T> = Result<T, AppError>;
/// 错误转换实现
impl From<sea_orm::DbErr> for AppError {
fn from(err: sea_orm::DbErr) -> Self {
match err {
sea_orm::DbErr::RecordNotFound(_) => AppError::NotFound("记录不存在".to_string()),
sea_orm::DbErr::Custom(msg) => AppError::DatabaseError(msg),
sea_orm::DbErr::Conn(msg) => AppError::DatabaseConnectionFailed { message: msg },
sea_orm::DbErr::Exec(msg) => AppError::DatabaseError(msg),
sea_orm::DbErr::Query(msg) => AppError::DatabaseError(msg),
_ => AppError::DatabaseError("未知数据库错误".to_string()),
}
}
}
impl From<redis::RedisError> for AppError {
fn from(err: redis::RedisError) -> Self {
match err.kind() {
redis::ErrorKind::IoError => AppError::CacheConnectionFailed {
message: err.to_string(),
},
redis::ErrorKind::AuthenticationFailed => AppError::CacheConnectionFailed {
message: "Redis 认证失败".to_string(),
},
_ => AppError::CacheError(err.to_string()),
}
}
}
impl From<reqwest::Error> for AppError {
fn from(err: reqwest::Error) -> Self {
if err.is_timeout() {
AppError::RequestTimeout {
message: "HTTP 请求超时".to_string(),
}
} else if err.is_connect() {
AppError::NetworkError {
message: "网络连接失败".to_string(),
}
} else if let Some(status) = err.status() {
AppError::HttpRequestFailed {
status: status.as_u16(),
message: err.to_string(),
}
} else {
AppError::NetworkError {
message: err.to_string(),
}
}
}
}
impl From<serde_json::Error> for AppError {
fn from(err: serde_json::Error) -> Self {
if err.is_syntax() {
AppError::JsonFormatError {
message: "JSON 语法错误".to_string(),
}
} else if err.is_data() {
AppError::DeserializationFailed {
message: err.to_string(),
}
} else {
AppError::SerializationFailed {
message: err.to_string(),
}
}
}
}
impl From<std::io::Error> for AppError {
fn from(err: std::io::Error) -> Self {
match err.kind() {
std::io::ErrorKind::NotFound => AppError::FileNotFound {
path: "未知路径".to_string(),
},
std::io::ErrorKind::PermissionDenied => AppError::FilePermissionDenied {
path: "未知路径".to_string(),
},
_ => AppError::FileOperationFailed {
message: err.to_string(),
},
}
}
}
impl From<tokio::time::error::Elapsed> for AppError {
fn from(_: tokio::time::error::Elapsed) -> Self {
AppError::RequestTimeout {
message: "操作超时".to_string(),
}
}
}
/// 错误构建器
pub struct ErrorBuilder {
error: AppError,
}
impl ErrorBuilder {
pub fn new(error: AppError) -> Self {
Self { error }
}
pub fn with_details(mut self, details: serde_json::Value) -> Self {
// 这里可以扩展错误以包含更多详情
self
}
pub fn with_field(mut self, field: String) -> Self {
// 设置错误字段
self
}
pub fn build(self) -> AppError {
self.error
}
}
/// 错误宏
#[macro_export]
macro_rules! app_error {
($error_type:ident, $($field:ident = $value:expr),*) => {
AppError::$error_type {
$($field: $value.into()),*
}
};
}
/// 结果扩展 trait
pub trait ResultExt<T> {
/// 将错误转换为 AppError
fn map_app_error<F>(self, f: F) -> AppResult<T>
where
F: FnOnce() -> AppError;
/// 添加错误上下文
fn with_context<F>(self, f: F) -> AppResult<T>
where
F: FnOnce() -> String;
}
impl<T, E> ResultExt<T> for Result<T, E>
where
E: Into<AppError>,
{
fn map_app_error<F>(self, f: F) -> AppResult<T>
where
F: FnOnce() -> AppError,
{
self.map_err(|_| f())
}
fn with_context<F>(self, f: F) -> AppResult<T>
where
F: FnOnce() -> String,
{
self.map_err(|e| {
let context = f();
match e.into() {
AppError::InternalServerError { message } => AppError::InternalServerError {
message: format!("{}: {}", context, message),
},
other => other,
}
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_codes() {
let error = AppError::NotFound("用户".to_string());
assert_eq!(error.error_code(), "NOT_FOUND");
assert_eq!(error.status_code(), StatusCode::NOT_FOUND);
}
#[test]
fn test_error_response() {
let error = AppError::ValidationFailed {
field: "email".to_string(),
message: "格式无效".to_string(),
};
let response = error.to_error_response(Some("req-123".to_string()));
assert_eq!(response.error.code, "VALIDATION_FAILED");
assert_eq!(response.error.field, Some("email".to_string()));
assert_eq!(response.request_id, Some("req-123".to_string()));
}
#[test]
fn test_error_conversion() {
let db_error = sea_orm::DbErr::RecordNotFound("test".to_string());
let app_error: AppError = db_error.into();
match app_error {
AppError::NotFound(_) => assert!(true),
_ => assert!(false, "Expected NotFound error"),
}
}
#[test]
fn test_error_macro() {
let error = app_error!(ValidationFailed,
field = "username",
message = "用户名已存在"
);
match error {
AppError::ValidationFailed { field, message } => {
assert_eq!(field, "username");
assert_eq!(message, "用户名已存在");
}
_ => assert!(false, "Expected ValidationFailed error"),
}
}
#[test]
fn test_result_ext() {
let result: Result<i32, &str> = Err("test error");
let app_result = result.map_app_error(|| AppError::InternalServerError {
message: "转换错误".to_string(),
});
assert!(app_result.is_err());
}
}
```
## 错误处理策略
### 错误传播
```rust
/// 错误传播示例
pub async fn create_user(req: CreateUserReq) -> AppResult<UserDoc> {
// 验证请求
validate_create_user_request(&req)?;
// 检查用户是否已存在
if user_exists(&req.email).await? {
return Err(AppError::AlreadyExists("用户邮箱已存在".to_string()));
}
// 创建用户
let user = User::create(req).await
.with_context(|| "创建用户失败")?;
Ok(user.into())
}
```
### 错误恢复
```rust
/// 错误恢复示例
pub async fn get_user_with_fallback(id: &str) -> AppResult<UserDoc> {
// 首先尝试从缓存获取
match get_user_from_cache(id).await {
Ok(user) => return Ok(user),
Err(AppError::CacheError(_)) => {
// 缓存错误,尝试从数据库获取
tracing::warn!("缓存获取用户失败,尝试数据库");
}
Err(e) => return Err(e),
}
// 从数据库获取
let user = get_user_from_db(id).await?;
// 尝试更新缓存(忽略错误)
if let Err(e) = set_user_cache(id, &user).await {
tracing::warn!(error = %e, "更新用户缓存失败");
}
Ok(user)
}
```
### 错误聚合
```rust
/// 错误聚合示例
pub struct ValidationErrors {
pub errors: Vec<AppError>,
}
impl ValidationErrors {
pub fn new() -> Self {
Self { errors: Vec::new() }
}
pub fn add(&mut self, error: AppError) {
self.errors.push(error);
}
pub fn is_empty(&self) -> bool {
self.errors.is_empty()
}
pub fn into_result(self) -> AppResult<()> {
if self.errors.is_empty() {
Ok(())
} else {
// 返回第一个错误,或者可以创建一个聚合错误类型
Err(self.errors.into_iter().next().unwrap())
}
}
}
pub fn validate_user_data(data: &CreateUserReq) -> AppResult<()> {
let mut errors = ValidationErrors::new();
if data.email.is_empty() {
errors.add(AppError::MissingField { field: "email".to_string() });
}
if data.password.len() < 8 {
errors.add(AppError::ValidationFailed {
field: "password".to_string(),
message: "密码长度至少8位".to_string(),
});
}
errors.into_result()
}
```
## 中间件集成
### 错误处理中间件
```rust
use axum::{
extract::Request,
middleware::Next,
response::Response,
};
use uuid::Uuid;
/// 错误处理中间件
pub async fn error_handler_middleware(
mut request: Request,
next: Next,
) -> Response {
// 生成请求 ID
let request_id = Uuid::new_v4().to_string();
request.extensions_mut().insert(request_id.clone());
// 执行请求
let response = next.run(request).await;
// 如果响应是错误,添加请求 ID
if response.status().is_client_error() || response.status().is_server_error() {
// 这里可以修改响应头,添加请求 ID
tracing::info!(
target = "udmin",
request_id = %request_id,
status = %response.status(),
"request.completed.error"
);
}
response
}
```
## 监控和告警
### 错误指标收集
```rust
use prometheus::{Counter, Histogram, Registry};
use std::sync::Arc;
/// 错误指标收集器
#[derive(Clone)]
pub struct ErrorMetrics {
error_counter: Counter,
error_duration: Histogram,
}
impl ErrorMetrics {
pub fn new(registry: &Registry) -> Self {
let error_counter = Counter::new(
"app_errors_total",
"Total number of application errors"
).unwrap();
let error_duration = Histogram::new(
"error_handling_duration_seconds",
"Time spent handling errors"
).unwrap();
registry.register(Box::new(error_counter.clone())).unwrap();
registry.register(Box::new(error_duration.clone())).unwrap();
Self {
error_counter,
error_duration,
}
}
pub fn record_error(&self, error: &AppError) {
self.error_counter.inc();
// 可以根据错误类型添加标签
tracing::info!(
target = "udmin",
error_code = %error.error_code(),
error_type = %std::any::type_name::<AppError>(),
"metrics.error.recorded"
);
}
}
```
## 最佳实践
### 错误设计原则
1. **明确性**: 错误消息应该清楚地说明发生了什么
2. **可操作性**: 错误消息应该告诉用户如何解决问题
3. **一致性**: 相同类型的错误应该有一致的格式和处理方式
4. **安全性**: 不要在错误消息中泄露敏感信息
### 错误处理模式
1. **快速失败**: 尽早检测和报告错误
2. **优雅降级**: 在可能的情况下提供备选方案
3. **错误隔离**: 防止错误在系统中传播
4. **错误恢复**: 在适当的时候尝试从错误中恢复
### 日志记录
1. **结构化日志**: 使用结构化格式记录错误信息
2. **上下文信息**: 包含足够的上下文信息用于调试
3. **敏感信息**: 避免在日志中记录敏感信息
4. **日志级别**: 根据错误严重程度选择合适的日志级别
## 总结
UdminAI 的错误处理模块提供了完整的错误管理解决方案,具有以下特点:
- **类型安全**: 编译时错误类型检查
- **统一处理**: 所有错误使用统一的类型和格式
- **用户友好**: 清晰的错误消息和适当的 HTTP 状态码
- **可观测性**: 完整的错误日志和指标收集
- **可扩展性**: 易于添加新的错误类型和处理逻辑
通过合理的错误处理设计,确保了系统的稳定性、可维护性和用户体验。

484
docs/FLOW_ENGINE.md Normal file
View File

@ -0,0 +1,484 @@
# 流程引擎文档
## 概述
流程引擎是 UdminAI 的核心模块,提供可视化流程设计、执行和监控功能。支持多种节点类型、条件分支、循环控制和并发执行。
## 架构设计
### 核心组件
```
flow/
├── domain.rs # 领域模型定义
├── dsl.rs # DSL 解析和构建
├── engine.rs # 流程执行引擎
├── context.rs # 执行上下文管理
├── task.rs # 任务抽象接口
├── log_handler.rs # 日志处理
├── mappers.rs # 数据映射器
├── executors/ # 执行器实现
└── mappers/ # 具体映射器
```
## 领域模型 (domain.rs)
### 核心数据结构
#### ChainDef - 流程链定义
```rust
pub struct ChainDef {
pub nodes: Vec<NodeDef>, // 节点列表
pub links: Vec<LinkDef>, // 连接列表
}
```
#### NodeDef - 节点定义
```rust
pub struct NodeDef {
pub id: NodeId, // 节点唯一标识
pub kind: NodeKind, // 节点类型
pub data: serde_json::Value, // 节点配置数据
}
```
#### NodeKind - 节点类型
```rust
pub enum NodeKind {
Start, // 开始节点
End, // 结束节点
Condition, // 条件节点
Http, // HTTP 请求节点
Database, // 数据库操作节点
ScriptJs, // JavaScript 脚本节点
ScriptPython, // Python 脚本节点
ScriptRhai, // Rhai 脚本节点
Variable, // 变量操作节点
Task, // 通用任务节点
}
```
#### LinkDef - 连接定义
```rust
pub struct LinkDef {
pub from: NodeId, // 源节点
pub to: NodeId, // 目标节点
pub condition: Option<String>, // 连接条件
}
```
## DSL 解析 (dsl.rs)
### DSL 结构
#### FlowDSL - 流程 DSL
```rust
pub struct FlowDSL {
pub nodes: Vec<NodeDSL>, // 节点列表
pub edges: Vec<EdgeDSL>, // 边列表
}
```
#### DesignSyntax - 设计语法
```rust
pub struct DesignSyntax {
pub nodes: Vec<NodeSyntax>, // 节点语法
pub edges: Vec<EdgeSyntax>, // 边语法
}
```
### 核心功能
#### 1. 设计验证
```rust
pub fn validate_design(design: &DesignSyntax) -> anyhow::Result<()>
```
**验证规则**:
- 节点 ID 唯一性
- 至少包含一个 start 节点
- 至少包含一个 end 节点
- 边的引用合法性
- 条件节点配置完整性
#### 2. 链构建
```rust
pub fn build_chain_from_design(design: &DesignSyntax) -> anyhow::Result<ChainDef>
```
**构建过程**:
1. 节点类型推断
2. 条件节点处理
3. 边关系建立
4. 数据完整性检查
#### 3. 兼容性处理
```rust
pub fn chain_from_design_json(input: &str) -> anyhow::Result<ChainDef>
```
**兼容特性**:
- 字符串/对象输入支持
- 字段回填
- 版本兼容
- 错误恢复
## 执行引擎 (engine.rs)
### FlowEngine - 流程执行引擎
#### 核心结构
```rust
pub struct FlowEngine {
tasks: TaskRegistry, // 任务注册表
}
```
#### 执行选项
```rust
pub struct DriveOptions {
pub max_steps: Option<usize>, // 最大执行步数
pub timeout_ms: Option<u64>, // 超时时间
pub parallel: bool, // 并发执行
pub stream_events: bool, // 流事件支持
}
```
### 执行流程
#### 1. 起点选择
- 优先选择 Start 节点
- 其次选择入度为 0 的节点
- 最后选择第一个节点
#### 2. 执行策略
- **串行执行**: 按依赖顺序逐个执行
- **并发执行**: 无依赖节点并行执行
- **条件分支**: 根据条件选择执行路径
- **循环控制**: 支持循环节点执行
#### 3. 状态管理
- 节点执行状态跟踪
- 上下文数据传递
- 错误状态处理
- 执行结果收集
### 任务注册表 (TaskRegistry)
#### 注册机制
```rust
pub struct TaskRegistry {
executors: HashMap<NodeKind, Box<dyn Executor>>,
}
```
#### 执行器接口
```rust
#[async_trait]
pub trait Executor: Send + Sync {
async fn execute(
&self,
node_id: &NodeId,
node: &NodeDef,
ctx: &mut serde_json::Value,
) -> anyhow::Result<()>;
}
```
## 执行器实现 (executors/)
### HTTP 执行器 (http.rs)
**功能**: 执行 HTTP 请求
**配置参数**:
- `method`: 请求方法 (GET/POST/PUT/DELETE)
- `url`: 请求 URL
- `headers`: 请求头
- `query`: 查询参数
- `body`: 请求体
- `timeout_ms`: 超时时间
- `insecure`: 忽略 SSL 验证
**执行流程**:
1. 解析 HTTP 配置
2. 构建请求参数
3. 发送 HTTP 请求
4. 处理响应结果
5. 更新执行上下文
### 数据库执行器 (db.rs)
**功能**: 执行数据库操作
**支持操作**:
- `SELECT`: 查询数据
- `INSERT`: 插入数据
- `UPDATE`: 更新数据
- `DELETE`: 删除数据
- `TRANSACTION`: 事务操作
**配置参数**:
- `sql`: SQL 语句
- `params`: 参数绑定
- `connection`: 连接配置
- `transaction`: 事务控制
### 条件执行器 (condition.rs)
**功能**: 条件判断和分支控制
**条件类型**:
- 简单比较 (==, !=, >, <, >=, <=)
- 逻辑运算 (AND, OR, NOT)
- 正则匹配
- 自定义表达式
**执行逻辑**:
1. 解析条件表达式
2. 从上下文获取变量值
3. 执行条件计算
4. 返回布尔结果
### 脚本执行器
#### JavaScript 执行器 (script_js.rs)
**功能**: 执行 JavaScript 代码
**引擎**: V8 引擎 (通过 rusty_v8)
#### Python 执行器 (script_python.rs)
**功能**: 执行 Python 代码
**引擎**: Python 解释器 (通过 pyo3)
#### Rhai 执行器 (script_rhai.rs)
**功能**: 执行 Rhai 脚本
**引擎**: Rhai 脚本引擎
**通用特性**:
- 沙箱执行环境
- 上下文变量注入
- 执行结果获取
- 错误处理和日志
### 变量执行器 (variable.rs)
**功能**: 变量操作和数据转换
**操作类型**:
- `SET`: 设置变量值
- `GET`: 获取变量值
- `TRANSFORM`: 数据转换
- `MERGE`: 数据合并
- `EXTRACT`: 数据提取
## 上下文管理 (context.rs)
### StreamEvent - 流事件
```rust
pub enum StreamEvent {
NodeStart { node_id: String }, // 节点开始
NodeComplete { node_id: String }, // 节点完成
NodeError { node_id: String, error: String }, // 节点错误
FlowComplete, // 流程完成
FlowError { error: String }, // 流程错误
}
```
### 上下文结构
```rust
pub struct ExecutionContext {
pub variables: serde_json::Value, // 变量存储
pub node_results: HashMap<String, serde_json::Value>, // 节点结果
pub execution_log: Vec<LogEntry>, // 执行日志
pub start_time: DateTime<Utc>, // 开始时间
}
```
### 上下文操作
- **变量管理**: 设置、获取、更新变量
- **结果存储**: 保存节点执行结果
- **日志记录**: 记录执行过程
- **状态跟踪**: 跟踪执行状态
## 数据映射器 (mappers/)
### HTTP 映射器 (http.rs)
**功能**: HTTP 请求/响应数据映射
### 数据库映射器 (db.rs)
**功能**: 数据库查询结果映射
### 脚本映射器 (script.rs)
**功能**: 脚本执行结果映射
### 变量映射器 (variable.rs)
**功能**: 变量数据类型映射
## 日志处理 (log_handler.rs)
### 日志类型
```rust
pub enum LogLevel {
Debug,
Info,
Warn,
Error,
}
pub struct LogEntry {
pub level: LogLevel,
pub message: String,
pub timestamp: DateTime<Utc>,
pub node_id: Option<String>,
pub context: serde_json::Value,
}
```
### 日志功能
- **执行日志**: 记录节点执行过程
- **错误日志**: 记录执行错误信息
- **性能日志**: 记录执行时间和资源使用
- **调试日志**: 记录调试信息
## 流程执行模式
### 1. 同步执行
- 阻塞式执行
- 顺序执行节点
- 立即返回结果
- 适用于简单流程
### 2. 异步执行
- 非阻塞执行
- 后台执行流程
- 通过回调获取结果
- 适用于长时间运行的流程
### 3. 流式执行
- 实时事件推送
- 执行过程可视化
- 支持中断和恢复
- 适用于交互式流程
### 4. 批量执行
- 批量处理多个流程
- 资源优化
- 并发控制
- 适用于批处理场景
## 错误处理
### 错误类型
```rust
pub enum FlowError {
ParseError(String), // 解析错误
ValidationError(String), // 验证错误
ExecutionError(String), // 执行错误
TimeoutError, // 超时错误
ResourceError(String), // 资源错误
}
```
### 错误处理策略
- **重试机制**: 自动重试失败的节点
- **降级处理**: 执行备用逻辑
- **错误传播**: 将错误传播到上层
- **日志记录**: 详细记录错误信息
## 性能优化
### 执行优化
- **并发执行**: 无依赖节点并行执行
- **资源池**: 复用执行器实例
- **缓存机制**: 缓存执行结果
- **懒加载**: 按需加载执行器
### 内存优化
- **上下文清理**: 及时清理不需要的数据
- **流式处理**: 大数据流式处理
- **对象池**: 复用对象实例
- **垃圾回收**: 主动触发垃圾回收
### 网络优化
- **连接复用**: HTTP 连接复用
- **请求合并**: 合并相似请求
- **超时控制**: 合理设置超时时间
- **重试策略**: 智能重试机制
## 监控和调试
### 执行监控
- **执行状态**: 实时监控执行状态
- **性能指标**: 收集执行性能数据
- **资源使用**: 监控内存和 CPU 使用
- **错误统计**: 统计错误发生情况
### 调试支持
- **断点调试**: 支持节点断点
- **单步执行**: 逐步执行节点
- **变量查看**: 查看执行上下文
- **日志输出**: 详细的执行日志
## 扩展机制
### 自定义执行器
```rust
#[derive(Default)]
pub struct CustomExecutor;
#[async_trait]
impl Executor for CustomExecutor {
async fn execute(
&self,
node_id: &NodeId,
node: &NodeDef,
ctx: &mut serde_json::Value,
) -> anyhow::Result<()> {
// 自定义执行逻辑
Ok(())
}
}
```
### 插件系统
- **执行器插件**: 扩展新的节点类型
- **中间件插件**: 扩展执行过程
- **映射器插件**: 扩展数据映射
- **日志插件**: 扩展日志处理
## 最佳实践
### 流程设计
- **模块化设计**: 将复杂流程拆分为子流程
- **错误处理**: 为关键节点添加错误处理
- **性能考虑**: 避免不必要的数据传递
- **可维护性**: 添加适当的注释和文档
### 节点配置
- **参数验证**: 验证节点配置参数
- **默认值**: 为可选参数提供默认值
- **类型安全**: 使用强类型配置
- **版本兼容**: 保持配置向后兼容
### 执行优化
- **并发控制**: 合理设置并发度
- **资源限制**: 设置合理的资源限制
- **超时设置**: 为长时间运行的节点设置超时
- **监控告警**: 添加关键指标监控

View File

@ -0,0 +1,439 @@
# 前端架构文档
## 概述
前端采用 React 18 + TypeScript 构建,使用现代化的组件化架构,集成了强大的流程可视化编辑器。
## 技术栈
### 核心框架
- **React 18**: 前端框架,支持并发特性
- **TypeScript**: 类型安全的 JavaScript 超集
- **Vite**: 现代化构建工具
### UI 组件库
- **Semi Design**: 主要 UI 组件库
- **Ant Design**: 补充 UI 组件
- **Styled Components**: CSS-in-JS 样式解决方案
### 流程编辑器
- **@flowgram.ai/free-layout-editor**: 自由布局编辑器核心
- **@flowgram.ai/form-materials**: 表单物料组件
- **@flowgram.ai/runtime-js**: 流程运行时
- **@flowgram.ai/minimap-plugin**: 小地图插件
- **@flowgram.ai/panel-manager-plugin**: 面板管理插件
### 状态管理和路由
- **React Context**: 状态管理
- **React Router v6**: 客户端路由
- **Axios**: HTTP 客户端
## 项目结构
```
frontend/src/
├── App.tsx # 应用根组件
├── main.tsx # 应用入口
├── vite-env.d.ts # Vite 类型声明
├── assets/ # 静态资源
├── components/ # 通用组件
├── flows/ # 流程编辑器模块
├── layouts/ # 布局组件
├── pages/ # 页面组件
├── styles/ # 全局样式
└── utils/ # 工具函数
```
## 核心模块
### 1. 应用入口 (main.tsx)
**职责**: 应用初始化和根组件渲染
**功能**:
- React 18 严格模式启用
- 路由配置
- 全局样式导入
- 错误边界设置
### 2. 应用根组件 (App.tsx)
**职责**: 应用路由配置和布局管理
**功能**:
- 路由定义和保护
- 认证状态管理
- 全局错误处理
- 主题配置
### 3. 布局系统 (layouts/)
#### MainLayout.tsx
**职责**: 主要页面布局
**功能**:
- 侧边栏导航
- 顶部导航栏
- 面包屑导航
- 用户信息显示
- 响应式布局
**布局结构**:
```tsx
<Layout>
<Sider>侧边栏</Sider>
<Layout>
<Header>顶部导航</Header>
<Content>页面内容</Content>
<Footer>页脚</Footer>
</Layout>
</Layout>
```
### 4. 页面组件 (pages/)
#### 管理页面
- `Dashboard.tsx`: 仪表板页面
- `Users.tsx`: 用户管理页面
- `Roles.tsx`: 角色管理页面
- `Menus.tsx`: 菜单管理页面
- `Departments.tsx`: 部门管理页面
- `Positions.tsx`: 职位管理页面
- `Permissions.tsx`: 权限管理页面
#### 流程相关页面
- `FlowList.tsx`: 流程列表页面
- `FlowRunLogs.tsx`: 流程运行日志页面
- `ScheduleJobs.tsx`: 定时任务页面
#### 系统页面
- `Login.tsx`: 登录页面
- `Logs.tsx`: 系统日志页面
**页面特性**:
- 统一的 CRUD 操作
- 表格分页和搜索
- 表单验证
- 权限控制
- 响应式设计
### 5. 通用组件 (components/)
#### PageHeader.tsx
**职责**: 页面头部组件
**功能**:
- 页面标题显示
- 面包屑导航
- 操作按钮区域
- 统一样式
### 6. 工具函数 (utils/)
#### axios.ts
**职责**: HTTP 客户端配置
**功能**:
- 请求/响应拦截器
- 自动 Token 添加
- 错误统一处理
- 请求重试机制
#### token.ts
**职责**: 令牌管理
**功能**:
- Token 存储和获取
- Token 过期检查
- 自动刷新机制
- 登出清理
#### permission.tsx
**职责**: 权限控制
**功能**:
- 权限检查组件
- 路由权限保护
- 按钮级权限控制
- 角色权限验证
#### sse.ts
**职责**: 服务端推送事件
**功能**:
- SSE 连接管理
- 事件监听
- 自动重连
- 错误处理
#### datetime.ts
**职责**: 日期时间处理
**功能**:
- 日期格式化
- 时区转换
- 相对时间显示
- 日期计算
#### config.ts
**职责**: 应用配置
**功能**:
- 环境变量管理
- API 端点配置
- 应用常量定义
- 功能开关
## 流程编辑器模块
**位置**: `src/flows/`
### 核心组件
#### 1. 编辑器入口 (editor.tsx)
**职责**: 流程编辑器主组件
**功能**:
- 编辑器初始化
- 插件注册
- 事件处理
- 数据同步
#### 2. 应用容器 (app.tsx)
**职责**: 编辑器应用容器
**功能**:
- 编辑器配置
- 工具栏管理
- 侧边栏控制
- 快捷键支持
#### 3. 初始数据 (initial-data.ts)
**职责**: 编辑器初始化数据
**功能**:
- 默认节点配置
- 画布初始状态
- 工具栏配置
- 插件配置
### 节点系统 (nodes/)
#### 节点类型
- `start/`: 开始节点
- `end/`: 结束节点
- `condition/`: 条件节点
- `http/`: HTTP 请求节点
- `db/`: 数据库操作节点
- `code/`: 代码执行节点
- `variable/`: 变量操作节点
- `loop/`: 循环节点
- `comment/`: 注释节点
- `group/`: 分组节点
#### 节点特性
- 可视化配置界面
- 参数验证
- 实时预览
- 拖拽支持
- 连接点管理
### 组件系统 (components/)
#### 核心组件
- `base-node/`: 基础节点组件
- `node-panel/`: 节点配置面板
- `sidebar/`: 侧边栏组件
- `tools/`: 工具栏组件
- `testrun/`: 测试运行组件
#### 交互组件
- `add-node/`: 添加节点组件
- `node-menu/`: 节点菜单
- `line-add-button/`: 连线添加按钮
- `selector-box-popover/`: 选择框弹窗
### 表单系统 (form-components/)
#### 表单组件
- `form-header/`: 表单头部
- `form-content/`: 表单内容
- `form-inputs/`: 表单输入组件
- `form-item/`: 表单项组件
- `feedback.tsx`: 反馈组件
### 插件系统 (plugins/)
#### 插件列表
- `context-menu-plugin/`: 右键菜单插件
- `runtime-plugin/`: 运行时插件
- `variable-panel-plugin/`: 变量面板插件
### 快捷键系统 (shortcuts/)
#### 快捷键功能
- `copy/`: 复制功能
- `paste/`: 粘贴功能
- `delete/`: 删除功能
- `select-all/`: 全选功能
- `zoom-in/`: 放大功能
- `zoom-out/`: 缩小功能
- `collapse/`: 折叠功能
- `expand/`: 展开功能
### 上下文管理 (context/)
#### 上下文类型
- `node-render-context.ts`: 节点渲染上下文
- `sidebar-context.ts`: 侧边栏上下文
### Hooks 系统 (hooks/)
#### 自定义 Hooks
- `use-editor-props.tsx`: 编辑器属性 Hook
- `use-is-sidebar.ts`: 侧边栏状态 Hook
- `use-node-render-context.ts`: 节点渲染上下文 Hook
- `use-port-click.ts`: 端口点击 Hook
### 工具函数 (utils/)
#### 工具函数
- `yaml.ts`: YAML 处理工具
- `on-drag-line-end.ts`: 拖拽连线结束处理
- `toggle-loop-expanded.ts`: 循环节点展开切换
## 状态管理
### Context 设计
#### 全局状态
- 用户认证状态
- 权限信息
- 主题配置
- 语言设置
#### 页面状态
- 表格数据
- 分页信息
- 搜索条件
- 选中项
#### 编辑器状态
- 画布数据
- 选中节点
- 编辑模式
- 工具栏状态
### 状态更新模式
- 不可变更新
- 批量更新
- 异步状态处理
- 错误状态管理
## 路由设计
### 路由结构
```
/
├── /login # 登录页面
├── /dashboard # 仪表板
├── /users # 用户管理
├── /roles # 角色管理
├── /menus # 菜单管理
├── /departments # 部门管理
├── /positions # 职位管理
├── /permissions # 权限管理
├── /flows # 流程列表
├── /flows/:id/edit # 流程编辑
├── /flows/logs # 流程日志
├── /schedule-jobs # 定时任务
└── /logs # 系统日志
```
### 路由保护
- 认证检查
- 权限验证
- 角色控制
- 重定向处理
## 样式系统
### CSS 架构
- 全局样式 (`global.css`)
- 组件样式 (CSS Modules)
- 主题变量
- 响应式断点
### 设计系统
- 颜色规范
- 字体规范
- 间距规范
- 组件规范
## 性能优化
### 代码分割
- 路由级别分割
- 组件懒加载
- 动态导入
- Bundle 分析
### 渲染优化
- React.memo 使用
- useMemo 缓存
- useCallback 优化
- 虚拟滚动
### 资源优化
- 图片懒加载
- 资源压缩
- CDN 加速
- 缓存策略
## 测试策略
### 测试类型
- 单元测试
- 集成测试
- E2E 测试
- 视觉回归测试
### 测试工具
- Jest: 单元测试框架
- React Testing Library: 组件测试
- Cypress: E2E 测试
- Storybook: 组件文档
## 构建和部署
### 构建配置
- Vite 配置优化
- 环境变量管理
- 代码分割策略
- 资源优化
### 部署策略
- 静态资源部署
- CDN 配置
- 缓存策略
- 版本管理
## 开发规范
### 代码规范
- ESLint 配置
- Prettier 格式化
- TypeScript 严格模式
- 提交规范
### 组件规范
- 组件命名
- Props 定义
- 事件处理
- 样式组织
### 文件组织
- 目录结构
- 文件命名
- 导入导出
- 类型定义

2227
docs/MIDDLEWARES.md Normal file

File diff suppressed because it is too large Load Diff

1650
docs/MODELS.md Normal file

File diff suppressed because it is too large Load Diff

137
docs/PROJECT_OVERVIEW.md Normal file
View File

@ -0,0 +1,137 @@
# UdminAI 项目总览
## 项目简介
UdminAI 是一个基于 Rust + React 的现代化流程管理和自动化平台,提供可视化流程编辑、定时任务调度、用户权限管理等功能。
## 技术架构
### 后端技术栈
- **框架**: Axum (异步 Web 框架)
- **数据库**: SeaORM (支持 MySQL/PostgreSQL/SQLite)
- **缓存**: Redis
- **认证**: JWT + Argon2 密码哈希
- **定时任务**: tokio-cron-scheduler
- **流程引擎**: 自研流程执行引擎
- **实时通信**: WebSocket + SSE
### 前端技术栈
- **框架**: React 18 + TypeScript
- **UI 库**: Semi Design + Ant Design
- **流程编辑器**: @flowgram.ai 系列组件
- **状态管理**: React Context
- **路由**: React Router v6
- **HTTP 客户端**: Axios
## 项目结构
```
udmin_ai/
├── backend/ # Rust 后端服务
│ ├── src/
│ │ ├── flow/ # 流程引擎核心
│ │ ├── models/ # 数据模型
│ │ ├── services/ # 业务逻辑层
│ │ ├── routes/ # API 路由
│ │ ├── middlewares/ # 中间件
│ │ └── utils/ # 工具函数
│ └── migration/ # 数据库迁移
├── frontend/ # React 前端应用
│ └── src/
│ ├── flows/ # 流程编辑器
│ ├── pages/ # 页面组件
│ ├── components/ # 通用组件
│ └── utils/ # 工具函数
├── docs/ # 项目文档
├── scripts/ # 部署脚本
└── README.md
```
## 核心功能模块
### 1. 用户权限管理
- 用户管理 (Users)
- 角色管理 (Roles)
- 菜单权限 (Menus)
- 部门管理 (Departments)
- 职位管理 (Positions)
### 2. 流程管理
- 可视化流程编辑器
- 流程执行引擎
- 流程运行日志
- 多种节点类型支持 (HTTP、数据库、脚本、条件等)
### 3. 定时任务
- Cron 表达式支持
- 任务调度管理
- 执行状态监控
### 4. 系统监控
- 请求日志记录
- 系统运行状态
- 实时通信支持
## 部署架构
### 服务端口分配
- **HTTP API**: 9898 (可配置)
- **WebSocket**: 8877 (可配置)
- **SSE**: 8866 (可配置)
- **前端开发服务器**: 8888
### 环境配置
- 开发环境: `.env`
- 生产环境: `.env.prod`
- 测试环境: `.env.staging`
## 开发指南
### 后端开发
```bash
cd backend
cargo run # 开发模式
cargo build --release # 生产构建
```
### 前端开发
```bash
cd frontend
npm install
npm run dev # 开发服务器
npm run build # 生产构建
```
### 数据库迁移
```bash
cd backend/migration
cargo run
```
## API 文档
项目集成了 Swagger UI启动后端服务后可访问
- Swagger UI: `http://localhost:9898/swagger-ui/`
- OpenAPI JSON: `http://localhost:9898/api-docs/openapi.json`
## 安全特性
- JWT 令牌认证
- Argon2 密码哈希
- CORS 跨域保护
- 请求日志记录
- 权限中间件验证
## 扩展性设计
- 模块化架构,易于扩展新功能
- 插件化流程节点,支持自定义执行器
- 微服务友好的设计
- 支持水平扩展
## 监控和日志
- 结构化日志 (tracing)
- 请求链路追踪
- 性能监控
- 错误处理和报告

1161
docs/RESPONSE.md Normal file

File diff suppressed because it is too large Load Diff

1201
docs/ROUTES.md Normal file

File diff suppressed because it is too large Load Diff

853
docs/SERVICES.md Normal file
View File

@ -0,0 +1,853 @@
# 服务层文档
## 概述
服务层是 UdminAI 的业务逻辑核心,负责处理各种业务操作,包括用户管理、权限控制、流程管理、定时任务、系统监控等功能。
## 架构设计
### 服务模块结构
```
services/
├── mod.rs # 服务模块导出
├── user_service.rs # 用户服务
├── role_service.rs # 角色服务
├── permission_service.rs # 权限服务
├── flow_service.rs # 流程服务
├── schedule_job_service.rs # 定时任务服务
├── system_service.rs # 系统服务
├── log_service.rs # 日志服务
└── notification_service.rs # 通知服务
```
### 设计原则
- **单一职责**: 每个服务专注于特定业务领域
- **依赖注入**: 通过参数传递数据库连接等依赖
- **错误处理**: 统一的错误处理和返回格式
- **异步支持**: 所有服务方法都是异步的
- **事务支持**: 支持数据库事务操作
## 用户服务 (user_service.rs)
### 核心功能
#### 1. 用户认证
```rust
/// 用户登录验证
pub async fn authenticate(
db: &DatabaseConnection,
username: &str,
password: &str,
) -> Result<UserDoc, AppError>
```
**功能**:
- 用户名/密码验证
- 密码哈希比较
- 登录状态更新
- 登录日志记录
#### 2. 用户管理
```rust
/// 创建用户
pub async fn create_user(
db: &DatabaseConnection,
req: CreateUserReq,
) -> Result<UserDoc, AppError>
/// 更新用户信息
pub async fn update_user(
db: &DatabaseConnection,
id: &str,
req: UpdateUserReq,
) -> Result<UserDoc, AppError>
/// 删除用户
pub async fn delete_user(
db: &DatabaseConnection,
id: &str,
) -> Result<(), AppError>
```
#### 3. 用户查询
```rust
/// 分页查询用户列表
pub async fn list_users(
db: &DatabaseConnection,
page: u64,
page_size: u64,
filters: Option<UserFilters>,
) -> Result<PageResp<UserDoc>, AppError>
/// 根据ID获取用户
pub async fn get_user_by_id(
db: &DatabaseConnection,
id: &str,
) -> Result<Option<UserDoc>, AppError>
```
### 数据传输对象
#### UserDoc - 用户文档
```rust
#[derive(Debug, Serialize, Deserialize)]
pub struct UserDoc {
pub id: String,
pub username: String,
pub email: Option<String>,
pub display_name: Option<String>,
pub avatar: Option<String>,
pub status: UserStatus,
pub roles: Vec<String>,
pub created_at: DateTime<FixedOffset>,
pub updated_at: DateTime<FixedOffset>,
}
```
#### CreateUserReq - 创建用户请求
```rust
#[derive(Debug, Deserialize, Validate)]
pub struct CreateUserReq {
#[validate(length(min = 3, max = 50))]
pub username: String,
#[validate(length(min = 6))]
pub password: String,
#[validate(email)]
pub email: Option<String>,
pub display_name: Option<String>,
pub roles: Vec<String>,
}
```
### 安全特性
- **密码加密**: 使用 bcrypt 进行密码哈希
- **输入验证**: 使用 validator 进行参数验证
- **权限检查**: 集成权限服务进行访问控制
- **审计日志**: 记录用户操作日志
## 角色服务 (role_service.rs)
### 核心功能
#### 1. 角色管理
```rust
/// 创建角色
pub async fn create_role(
db: &DatabaseConnection,
req: CreateRoleReq,
) -> Result<RoleDoc, AppError>
/// 更新角色
pub async fn update_role(
db: &DatabaseConnection,
id: &str,
req: UpdateRoleReq,
) -> Result<RoleDoc, AppError>
/// 删除角色
pub async fn delete_role(
db: &DatabaseConnection,
id: &str,
) -> Result<(), AppError>
```
#### 2. 权限分配
```rust
/// 为角色分配权限
pub async fn assign_permissions(
db: &DatabaseConnection,
role_id: &str,
permission_ids: Vec<String>,
) -> Result<(), AppError>
/// 移除角色权限
pub async fn remove_permissions(
db: &DatabaseConnection,
role_id: &str,
permission_ids: Vec<String>,
) -> Result<(), AppError>
```
#### 3. 用户角色管理
```rust
/// 为用户分配角色
pub async fn assign_user_roles(
db: &DatabaseConnection,
user_id: &str,
role_ids: Vec<String>,
) -> Result<(), AppError>
/// 获取用户角色
pub async fn get_user_roles(
db: &DatabaseConnection,
user_id: &str,
) -> Result<Vec<RoleDoc>, AppError>
```
### 数据传输对象
#### RoleDoc - 角色文档
```rust
#[derive(Debug, Serialize, Deserialize)]
pub struct RoleDoc {
pub id: String,
pub name: String,
pub description: Option<String>,
pub permissions: Vec<String>,
pub is_system: bool,
pub created_at: DateTime<FixedOffset>,
pub updated_at: DateTime<FixedOffset>,
}
```
## 权限服务 (permission_service.rs)
### 核心功能
#### 1. 权限检查
```rust
/// 检查用户权限
pub async fn check_user_permission(
db: &DatabaseConnection,
user_id: &str,
resource: &str,
action: &str,
) -> Result<bool, AppError>
/// 检查角色权限
pub async fn check_role_permission(
db: &DatabaseConnection,
role_id: &str,
resource: &str,
action: &str,
) -> Result<bool, AppError>
```
#### 2. 权限管理
```rust
/// 创建权限
pub async fn create_permission(
db: &DatabaseConnection,
req: CreatePermissionReq,
) -> Result<PermissionDoc, AppError>
/// 获取权限树
pub async fn get_permission_tree(
db: &DatabaseConnection,
) -> Result<Vec<PermissionTreeNode>, AppError>
```
### 权限模型
#### 资源-动作模型
- **资源 (Resource)**: 系统中的实体 (user, role, flow, job)
- **动作 (Action)**: 对资源的操作 (create, read, update, delete)
- **权限 (Permission)**: 资源和动作的组合
#### 权限继承
- 角色权限继承
- 用户权限继承
- 权限组合计算
## 流程服务 (flow_service.rs)
### 核心功能
#### 1. 流程管理
```rust
/// 创建流程
pub async fn create_flow(
db: &DatabaseConnection,
req: CreateFlowReq,
) -> Result<FlowDoc, AppError>
/// 更新流程
pub async fn update_flow(
db: &DatabaseConnection,
id: &str,
req: UpdateFlowReq,
) -> Result<FlowDoc, AppError>
/// 发布流程
pub async fn publish_flow(
db: &DatabaseConnection,
id: &str,
) -> Result<FlowDoc, AppError>
```
#### 2. 流程执行
```rust
/// 执行流程
pub async fn execute_flow(
db: &DatabaseConnection,
flow_id: &str,
input: serde_json::Value,
options: ExecuteOptions,
) -> Result<ExecutionResult, AppError>
/// 获取执行状态
pub async fn get_execution_status(
db: &DatabaseConnection,
execution_id: &str,
) -> Result<ExecutionStatus, AppError>
```
#### 3. 流程版本管理
```rust
/// 创建流程版本
pub async fn create_flow_version(
db: &DatabaseConnection,
flow_id: &str,
version_data: FlowVersionData,
) -> Result<FlowVersionDoc, AppError>
/// 获取流程版本列表
pub async fn list_flow_versions(
db: &DatabaseConnection,
flow_id: &str,
) -> Result<Vec<FlowVersionDoc>, AppError>
```
### 数据传输对象
#### FlowDoc - 流程文档
```rust
#[derive(Debug, Serialize, Deserialize)]
pub struct FlowDoc {
pub id: String,
pub name: String,
pub description: Option<String>,
pub category: String,
pub status: FlowStatus,
pub version: String,
pub design: serde_json::Value,
pub created_by: String,
pub created_at: DateTime<FixedOffset>,
pub updated_at: DateTime<FixedOffset>,
}
```
#### ExecutionResult - 执行结果
```rust
#[derive(Debug, Serialize, Deserialize)]
pub struct ExecutionResult {
pub execution_id: String,
pub status: ExecutionStatus,
pub result: Option<serde_json::Value>,
pub error: Option<String>,
pub start_time: DateTime<FixedOffset>,
pub end_time: Option<DateTime<FixedOffset>>,
pub duration_ms: Option<u64>,
}
```
## 定时任务服务 (schedule_job_service.rs)
### 核心功能
#### 1. 任务管理
```rust
/// 创建定时任务
pub async fn create_schedule_job(
db: &DatabaseConnection,
req: CreateScheduleJobReq,
) -> Result<ScheduleJobDoc, AppError>
/// 更新任务
pub async fn update_schedule_job(
db: &DatabaseConnection,
id: &str,
req: UpdateScheduleJobReq,
) -> Result<ScheduleJobDoc, AppError>
/// 启用/禁用任务
pub async fn toggle_job_status(
db: &DatabaseConnection,
id: &str,
enabled: bool,
) -> Result<ScheduleJobDoc, AppError>
```
#### 2. 任务调度
```rust
/// 注册任务到调度器
pub async fn register_job_to_scheduler(
scheduler: &JobScheduler,
job: &ScheduleJobDoc,
) -> Result<(), AppError>
/// 从调度器移除任务
pub async fn unregister_job_from_scheduler(
scheduler: &JobScheduler,
job_id: &str,
) -> Result<(), AppError>
```
#### 3. 执行历史
```rust
/// 记录任务执行
pub async fn record_job_execution(
db: &DatabaseConnection,
execution: JobExecutionRecord,
) -> Result<(), AppError>
/// 获取执行历史
pub async fn get_job_execution_history(
db: &DatabaseConnection,
job_id: &str,
page: u64,
page_size: u64,
) -> Result<PageResp<JobExecutionRecord>, AppError>
```
### 调度特性
- **Cron 表达式**: 支持标准 Cron 表达式
- **时区支持**: 支持不同时区的任务调度
- **并发控制**: 防止任务重复执行
- **失败重试**: 支持任务失败重试
- **执行超时**: 支持任务执行超时控制
## 系统服务 (system_service.rs)
### 核心功能
#### 1. 系统信息
```rust
/// 获取系统信息
pub async fn get_system_info() -> Result<SystemInfo, AppError>
/// 获取系统状态
pub async fn get_system_status(
db: &DatabaseConnection,
redis: &RedisConnection,
) -> Result<SystemStatus, AppError>
```
#### 2. 健康检查
```rust
/// 数据库健康检查
pub async fn check_database_health(
db: &DatabaseConnection,
) -> Result<HealthStatus, AppError>
/// Redis 健康检查
pub async fn check_redis_health(
redis: &RedisConnection,
) -> Result<HealthStatus, AppError>
```
#### 3. 系统配置
```rust
/// 获取系统配置
pub async fn get_system_config(
db: &DatabaseConnection,
) -> Result<SystemConfig, AppError>
/// 更新系统配置
pub async fn update_system_config(
db: &DatabaseConnection,
config: SystemConfig,
) -> Result<(), AppError>
```
### 监控指标
#### SystemStatus - 系统状态
```rust
#[derive(Debug, Serialize, Deserialize)]
pub struct SystemStatus {
pub uptime: u64,
pub memory_usage: MemoryUsage,
pub cpu_usage: f64,
pub disk_usage: DiskUsage,
pub database_status: HealthStatus,
pub redis_status: HealthStatus,
pub active_connections: u32,
pub request_count: u64,
pub error_count: u64,
}
```
## 日志服务 (log_service.rs)
### 核心功能
#### 1. 日志记录
```rust
/// 记录操作日志
pub async fn log_operation(
db: &DatabaseConnection,
log: OperationLog,
) -> Result<(), AppError>
/// 记录系统日志
pub async fn log_system_event(
db: &DatabaseConnection,
event: SystemEvent,
) -> Result<(), AppError>
```
#### 2. 日志查询
```rust
/// 查询操作日志
pub async fn query_operation_logs(
db: &DatabaseConnection,
filters: LogFilters,
page: u64,
page_size: u64,
) -> Result<PageResp<OperationLogDoc>, AppError>
/// 查询系统日志
pub async fn query_system_logs(
db: &DatabaseConnection,
filters: LogFilters,
page: u64,
page_size: u64,
) -> Result<PageResp<SystemLogDoc>, AppError>
```
#### 3. 日志分析
```rust
/// 获取日志统计
pub async fn get_log_statistics(
db: &DatabaseConnection,
time_range: TimeRange,
) -> Result<LogStatistics, AppError>
/// 获取错误日志趋势
pub async fn get_error_log_trend(
db: &DatabaseConnection,
time_range: TimeRange,
) -> Result<Vec<ErrorTrendPoint>, AppError>
```
### 日志类型
#### OperationLog - 操作日志
```rust
#[derive(Debug, Serialize, Deserialize)]
pub struct OperationLog {
pub user_id: String,
pub operation: String,
pub resource: String,
pub resource_id: Option<String>,
pub details: serde_json::Value,
pub ip_address: Option<String>,
pub user_agent: Option<String>,
pub timestamp: DateTime<FixedOffset>,
}
```
#### SystemEvent - 系统事件
```rust
#[derive(Debug, Serialize, Deserialize)]
pub struct SystemEvent {
pub event_type: String,
pub level: LogLevel,
pub message: String,
pub details: serde_json::Value,
pub source: String,
pub timestamp: DateTime<FixedOffset>,
}
```
## 通知服务 (notification_service.rs)
### 核心功能
#### 1. 通知发送
```rust
/// 发送邮件通知
pub async fn send_email_notification(
config: &EmailConfig,
notification: EmailNotification,
) -> Result<(), AppError>
/// 发送短信通知
pub async fn send_sms_notification(
config: &SmsConfig,
notification: SmsNotification,
) -> Result<(), AppError>
/// 发送系统通知
pub async fn send_system_notification(
db: &DatabaseConnection,
notification: SystemNotification,
) -> Result<(), AppError>
```
#### 2. 通知模板
```rust
/// 创建通知模板
pub async fn create_notification_template(
db: &DatabaseConnection,
template: NotificationTemplate,
) -> Result<NotificationTemplateDoc, AppError>
/// 渲染通知模板
pub async fn render_notification_template(
template: &NotificationTemplate,
variables: &serde_json::Value,
) -> Result<String, AppError>
```
#### 3. 通知历史
```rust
/// 记录通知历史
pub async fn record_notification_history(
db: &DatabaseConnection,
history: NotificationHistory,
) -> Result<(), AppError>
/// 查询通知历史
pub async fn query_notification_history(
db: &DatabaseConnection,
filters: NotificationFilters,
page: u64,
page_size: u64,
) -> Result<PageResp<NotificationHistoryDoc>, AppError>
```
### 通知渠道
- **邮件通知**: SMTP 邮件发送
- **短信通知**: SMS 短信发送
- **系统通知**: 站内消息通知
- **Webhook**: HTTP 回调通知
- **推送通知**: 移动端推送
## 服务集成
### 依赖注入
```rust
// 服务依赖注入示例
pub struct ServiceContainer {
pub db: DatabaseConnection,
pub redis: RedisConnection,
pub scheduler: JobScheduler,
pub email_config: EmailConfig,
pub sms_config: SmsConfig,
}
impl ServiceContainer {
pub fn user_service(&self) -> UserService {
UserService::new(&self.db)
}
pub fn flow_service(&self) -> FlowService {
FlowService::new(&self.db, &self.redis)
}
}
```
### 事务管理
```rust
/// 事务执行示例
pub async fn create_user_with_roles(
db: &DatabaseConnection,
user_req: CreateUserReq,
role_ids: Vec<String>,
) -> Result<UserDoc, AppError> {
let txn = db.begin().await?;
// 创建用户
let user = user_service::create_user(&txn, user_req).await?;
// 分配角色
role_service::assign_user_roles(&txn, &user.id, role_ids).await?;
txn.commit().await?;
Ok(user)
}
```
### 缓存策略
```rust
/// 缓存使用示例
pub async fn get_user_with_cache(
db: &DatabaseConnection,
redis: &RedisConnection,
user_id: &str,
) -> Result<Option<UserDoc>, AppError> {
// 先从缓存获取
if let Some(cached_user) = redis.get(&format!("user:{}", user_id)).await? {
return Ok(Some(serde_json::from_str(&cached_user)?));
}
// 从数据库获取
if let Some(user) = user_service::get_user_by_id(db, user_id).await? {
// 写入缓存
redis.setex(
&format!("user:{}", user_id),
3600, // 1小时过期
&serde_json::to_string(&user)?,
).await?;
Ok(Some(user))
} else {
Ok(None)
}
}
```
## 错误处理
### 统一错误类型
```rust
#[derive(Debug, thiserror::Error)]
pub enum ServiceError {
#[error("数据库错误: {0}")]
DatabaseError(#[from] sea_orm::DbErr),
#[error("验证错误: {0}")]
ValidationError(String),
#[error("权限不足")]
PermissionDenied,
#[error("资源不存在: {0}")]
ResourceNotFound(String),
#[error("业务逻辑错误: {0}")]
BusinessLogicError(String),
}
```
### 错误处理模式
```rust
/// 统一错误处理
pub async fn handle_service_result<T>(
result: Result<T, ServiceError>,
) -> Result<T, AppError> {
match result {
Ok(value) => Ok(value),
Err(ServiceError::ValidationError(msg)) => {
Err(AppError::BadRequest(msg))
},
Err(ServiceError::PermissionDenied) => {
Err(AppError::Forbidden("权限不足".to_string()))
},
Err(ServiceError::ResourceNotFound(resource)) => {
Err(AppError::NotFound(format!("{}不存在", resource)))
},
Err(e) => Err(AppError::InternalServerError(e.to_string())),
}
}
```
## 性能优化
### 数据库优化
- **连接池**: 使用数据库连接池
- **查询优化**: 优化 SQL 查询语句
- **索引使用**: 合理使用数据库索引
- **批量操作**: 使用批量插入/更新
### 缓存优化
- **热点数据缓存**: 缓存频繁访问的数据
- **查询结果缓存**: 缓存复杂查询结果
- **缓存预热**: 系统启动时预加载缓存
- **缓存更新**: 及时更新过期缓存
### 并发优化
- **异步处理**: 使用异步编程模型
- **并发控制**: 合理控制并发数量
- **锁优化**: 减少锁的使用和持有时间
- **无锁设计**: 使用无锁数据结构
## 测试策略
### 单元测试
```rust
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_create_user() {
let db = setup_test_db().await;
let req = CreateUserReq {
username: "test_user".to_string(),
password: "password123".to_string(),
email: Some("test@example.com".to_string()),
display_name: None,
roles: vec![],
};
let result = create_user(&db, req).await;
assert!(result.is_ok());
let user = result.unwrap();
assert_eq!(user.username, "test_user");
}
}
```
### 集成测试
```rust
#[tokio::test]
async fn test_user_role_integration() {
let container = setup_test_container().await;
// 创建角色
let role = create_test_role(&container.db).await;
// 创建用户
let user = create_test_user(&container.db).await;
// 分配角色
let result = role_service::assign_user_roles(
&container.db,
&user.id,
vec![role.id.clone()],
).await;
assert!(result.is_ok());
// 验证权限
let has_permission = permission_service::check_user_permission(
&container.db,
&user.id,
"user",
"read",
).await.unwrap();
assert!(has_permission);
}
```
## 最佳实践
### 服务设计
- **接口设计**: 设计清晰的服务接口
- **参数验证**: 严格验证输入参数
- **返回值**: 统一返回值格式
- **文档注释**: 为公开方法添加文档注释
### 数据处理
- **数据验证**: 在服务层进行数据验证
- **数据转换**: 合理进行数据类型转换
- **数据清理**: 及时清理无用数据
- **数据备份**: 重要操作前备份数据
### 安全考虑
- **权限检查**: 在服务层进行权限检查
- **输入过滤**: 过滤恶意输入
- **敏感数据**: 保护敏感数据不泄露
- **审计日志**: 记录重要操作的审计日志

1271
docs/UTILS.md Normal file

File diff suppressed because it is too large Load Diff