feat(core): add audit logging to all mutation operations
Create audit_log SeaORM entity and audit_service::record() helper. Integrate audit recording into 35 mutation endpoints across all modules: - erp-auth: user/role/organization/department/position CRUD (15 actions) - erp-config: dictionary/menu/setting/numbering_rule CRUD (15 actions) - erp-workflow: definition/instance/task operations (8 actions) - erp-message: send/system/mark_read/delete (5 actions) Uses fire-and-forget pattern — audit failures logged but non-blocking.
This commit is contained in:
27
crates/erp-core/src/audit_service.rs
Normal file
27
crates/erp-core/src/audit_service.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use crate::audit::AuditLog;
|
||||
use crate::entity::audit_log;
|
||||
use sea_orm::{ActiveModelTrait, Set};
|
||||
use tracing;
|
||||
|
||||
/// 持久化审计日志到 audit_logs 表。
|
||||
///
|
||||
/// 使用 fire-and-forget 模式:失败仅记录 warning 日志,不影响业务操作。
|
||||
pub async fn record(log: AuditLog, db: &sea_orm::DatabaseConnection) {
|
||||
let model = audit_log::ActiveModel {
|
||||
id: Set(log.id),
|
||||
tenant_id: Set(log.tenant_id),
|
||||
user_id: Set(log.user_id),
|
||||
action: Set(log.action),
|
||||
resource_type: Set(log.resource_type),
|
||||
resource_id: Set(log.resource_id),
|
||||
old_value: Set(log.old_value),
|
||||
new_value: Set(log.new_value),
|
||||
ip_address: Set(log.ip_address),
|
||||
user_agent: Set(log.user_agent),
|
||||
created_at: Set(log.created_at),
|
||||
};
|
||||
|
||||
if let Err(e) = model.insert(db).await {
|
||||
tracing::warn!(error = %e, "审计日志写入失败");
|
||||
}
|
||||
}
|
||||
25
crates/erp-core/src/entity/audit_log.rs
Normal file
25
crates/erp-core/src/entity/audit_log.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// 审计日志实体 — 映射 audit_logs 表。
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
|
||||
#[sea_orm(table_name = "audit_logs")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key, auto_increment = false)]
|
||||
pub id: Uuid,
|
||||
pub tenant_id: Uuid,
|
||||
pub user_id: Option<Uuid>,
|
||||
pub action: String,
|
||||
pub resource_type: String,
|
||||
pub resource_id: Option<Uuid>,
|
||||
pub old_value: Option<serde_json::Value>,
|
||||
pub new_value: Option<serde_json::Value>,
|
||||
pub ip_address: Option<String>,
|
||||
pub user_agent: Option<String>,
|
||||
pub created_at: DateTimeUtc,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
1
crates/erp-core/src/entity/mod.rs
Normal file
1
crates/erp-core/src/entity/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod audit_log;
|
||||
@@ -1,4 +1,6 @@
|
||||
pub mod audit;
|
||||
pub mod audit_service;
|
||||
pub mod entity;
|
||||
pub mod error;
|
||||
pub mod events;
|
||||
pub mod module;
|
||||
|
||||
Reference in New Issue
Block a user