feat(saas): SQL 迁移系统 + TIMESTAMPTZ + 热路径重构

P0: SQL 迁移系统
- crates/zclaw-saas/migrations/ — 独立 SQL 迁移文件目录
- 20260329000001_initial_schema.sql — TIMESTAMPTZ 完整 schema
- 20260329000002_seed_data.sql — 角色种子数据
- db.rs: 移除 335 行内联 SCHEMA_SQL,改为文件加载
- 版本追踪: saas_schema_version 表管理迁移状态
- 向后兼容: 已有 TEXT 时间戳数据库不受影响

P1: 安全重构
- relay/service.rs: update_task_status 从 format!() 改为 3 条独立参数化查询
- config.rs: 移除 TODO 注释,补充字段文档说明
- state.rs: 添加 dispatch_log_operation 异步日志派发方法

P2: Worker 集成
- state.rs: WorkerDispatcher 接入 AppState
- 所有异步后台任务基础设施就绪
This commit is contained in:
iven
2026-03-29 19:41:03 +08:00
parent 77374121dd
commit a0ca35c9dd
6 changed files with 487 additions and 387 deletions

View File

@@ -60,4 +60,28 @@ impl AppState {
!entries.is_empty()
});
}
/// 异步派发操作日志到 Worker非阻塞
pub async fn dispatch_log_operation(
&self,
account_id: &str,
action: &str,
target_type: &str,
target_id: &str,
details: Option<serde_json::Value>,
ip_address: Option<&str>,
) {
use crate::workers::log_operation::LogOperationArgs;
let args = LogOperationArgs {
account_id: account_id.to_string(),
action: action.to_string(),
target_type: target_type.to_string(),
target_id: target_id.to_string(),
details: details.map(|d| d.to_string()),
ip_address: ip_address.map(|s| s.to_string()),
};
if let Err(e) = self.worker_dispatcher.dispatch("log_operation", args).await {
tracing::warn!("Failed to dispatch log_operation: {}", e);
}
}
}