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:
@@ -8,6 +8,8 @@ use crate::dto::{CreateDepartmentReq, DepartmentResp, UpdateDepartmentReq};
|
||||
use crate::entity::department;
|
||||
use crate::entity::organization;
|
||||
use crate::error::{AuthError, AuthResult};
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
|
||||
@@ -124,6 +126,13 @@ impl DeptService {
|
||||
serde_json::json!({ "dept_id": id, "org_id": org_id, "name": req.name }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "department.create", "department")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(DepartmentResp {
|
||||
id,
|
||||
org_id,
|
||||
@@ -195,6 +204,13 @@ impl DeptService {
|
||||
.await
|
||||
.map_err(|e| AuthError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "department.update", "department")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(DepartmentResp {
|
||||
id: updated.id,
|
||||
org_id: updated.org_id,
|
||||
@@ -256,6 +272,14 @@ impl DeptService {
|
||||
tenant_id,
|
||||
serde_json::json!({ "dept_id": id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "department.delete", "department")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ use uuid::Uuid;
|
||||
use crate::dto::{CreateOrganizationReq, OrganizationResp, UpdateOrganizationReq};
|
||||
use crate::entity::organization;
|
||||
use crate::error::{AuthError, AuthResult};
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
|
||||
@@ -110,6 +112,13 @@ impl OrgService {
|
||||
serde_json::json!({ "org_id": id, "name": req.name }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "organization.create", "organization")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(OrganizationResp {
|
||||
id,
|
||||
name: req.name.clone(),
|
||||
@@ -177,6 +186,13 @@ impl OrgService {
|
||||
.await
|
||||
.map_err(|e| AuthError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "organization.update", "organization")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(OrganizationResp {
|
||||
id: updated.id,
|
||||
name: updated.name.clone(),
|
||||
@@ -235,6 +251,14 @@ impl OrgService {
|
||||
tenant_id,
|
||||
serde_json::json!({ "org_id": id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "organization.delete", "organization")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ use crate::dto::{CreatePositionReq, PositionResp, UpdatePositionReq};
|
||||
use crate::entity::department;
|
||||
use crate::entity::position;
|
||||
use crate::error::{AuthError, AuthResult};
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
|
||||
@@ -109,6 +111,13 @@ impl PositionService {
|
||||
serde_json::json!({ "position_id": id, "dept_id": dept_id, "name": req.name }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "position.create", "position")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(PositionResp {
|
||||
id,
|
||||
dept_id,
|
||||
@@ -177,6 +186,13 @@ impl PositionService {
|
||||
.await
|
||||
.map_err(|e| AuthError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "position.update", "position")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(PositionResp {
|
||||
id: updated.id,
|
||||
dept_id: updated.dept_id,
|
||||
@@ -219,6 +235,14 @@ impl PositionService {
|
||||
tenant_id,
|
||||
serde_json::json!({ "position_id": id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "position.delete", "position")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ use crate::dto::{PermissionResp, RoleResp};
|
||||
use crate::entity::{permission, role, role_permission};
|
||||
use crate::error::AuthError;
|
||||
use crate::error::AuthResult;
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::types::Pagination;
|
||||
@@ -131,6 +133,13 @@ impl RoleService {
|
||||
serde_json::json!({ "role_id": id, "code": code }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "role.create", "role")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(RoleResp {
|
||||
id,
|
||||
name: name.to_string(),
|
||||
@@ -180,6 +189,13 @@ impl RoleService {
|
||||
.await
|
||||
.map_err(|e| AuthError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "role.update", "role")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(RoleResp {
|
||||
id: updated.id,
|
||||
name: updated.name.clone(),
|
||||
@@ -227,6 +243,14 @@ impl RoleService {
|
||||
tenant_id,
|
||||
serde_json::json!({ "role_id": id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "role.delete", "role")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ use uuid::Uuid;
|
||||
use crate::dto::{CreateUserReq, RoleResp, UpdateUserReq, UserResp};
|
||||
use crate::entity::{role, user, user_credential, user_role};
|
||||
use crate::error::AuthError;
|
||||
use erp_core::audit::AuditLog;
|
||||
use erp_core::audit_service;
|
||||
use erp_core::error::check_version;
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::types::Pagination;
|
||||
@@ -94,6 +96,13 @@ impl UserService {
|
||||
serde_json::json!({ "user_id": user_id, "username": req.username }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "user.create", "user")
|
||||
.with_resource_id(user_id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(UserResp {
|
||||
id: user_id,
|
||||
username: req.username.clone(),
|
||||
@@ -215,6 +224,13 @@ impl UserService {
|
||||
.await
|
||||
.map_err(|e| AuthError::Validation(e.to_string()))?;
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "user.update", "user")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
let roles = Self::fetch_user_role_resps(id, tenant_id, db).await?;
|
||||
Ok(model_to_resp(&updated, roles))
|
||||
}
|
||||
@@ -250,6 +266,14 @@ impl UserService {
|
||||
tenant_id,
|
||||
serde_json::json!({ "user_id": id }),
|
||||
));
|
||||
|
||||
audit_service::record(
|
||||
AuditLog::new(tenant_id, Some(operator_id), "user.delete", "user")
|
||||
.with_resource_id(id),
|
||||
db,
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user