96SEO 2026-09-04 01:56 10
项目用事件溯源 + CQRS,订单、排班、服务需求各有一个投影监听器。上一篇写了投影挂了怎么重试,这篇聊聊投影在正常工作的时候。顺手干的一件大事——审计日志。
说到提前声明。这是我自己项目的实践,不代表常用方法,仅供参考。

一开始的想法很朴素:每次改订单,顺手写一条日志。
// 伪代码:千万别这么干
fn update_order {
let old = get_order;db.execute,db.execute(
"INSERT INTO logs VALUES "。order_id,"update_amount",old.amount,new_amount,);}
看着还行对吧?但订单有六个操作——创建、编辑、状态变更、取消、派工、结算。每个操作散在不同的 service 里六个地方都要记。
痛点一: 手工写日志极易遗漏。一旦忘记,在代码审查中几乎无法被发现,一条关键变更瞬间消失在黑洞里。
痛点二: 维护成本高。因为业务 每个 service 都要同步更新日志逻辑,耦合度继续提高。
搞了两天我就把手工日志全删了。项目用了事件溯源,我想:能不能让基础设施自动记?老实说,
事件溯源不直接改数据库状态。而是记录“发生了什么”,状态是事件算出来的。
项目里订单有六个事件类型:
// backend/src/domain/crm/order/mod.rs
pub enum OrderEventEnvelope {
OrderCreated { /* 创建时的所有字段 */ },OrderDetailsUpdated { /* 变更的字段 */ }。OrderStatusChanged { /* 新状态 */ },OrderCancelled { /* 取消原因 */ },OrderAssignmentUpdated { /* 派工变更 */ },OrderSettlementUpdated { /* 结算变更 */ },}
每个业务操作都会产生一个事件。事件本身,说白了就是审计线索——谁在什么时候做了什么。我只需要在投影层消费事件的时候,顺手把变更前后的状态拍个快照存下来。
主要是 OrderProjection一个 EventListener,每 250ms 轮询事件表。拿到新事件后处理流程固定四步:
snapshot_order_model 序列化成 JSONbefore/after 双 JSON 写进 order_change_logs 表P.S. 若你担心性能,这种方式只在投影层跑一次序列化和插入,对主业务方法几乎无影响。
// backend/src/infrastructure/projections/crm/order_projection.rs
OrderEventEnvelope::OrderDetailsUpdated {
merchant_id。order_uuid,operator_uuid,customer_uuid,amount_cents,notes,updated_at,} => {
// 查出当前订单
let Some = orders::Entity::find
.filter)
.one.await?else { return Ok);},// 拍变更前快照
let before = snapshot_order_model;// 应用变更
let mut active = model.into_active_model;
active.customer_uuid = Set;active.amount_cents = Set;active.notes = Set;active.updated_at = Set;// 更新读模型
let updated = active.update.await?,// 拍变更后快照,双快照写入日志
insert_change_log(
txn,merchant_uuid,updated.uuid。"details_updated",operator_uuid,Some,Some),updated_at,).await?,}
SIX 个事件类型的处理结构一样,只是各自应用字段不同。OrderCreated* 特殊些——没有 before。只存 after,订单刚出生嘛。
// backend/src/infrastructure/projections/crm/order_projection.rs
fn snapshot_order_model -> Value {
serde_json::json!({
至于"uuid",model.uuid.to_string,"customer_uuid": model.customer_uuid.map),"status": model.status,"amount_cents": model.amount_cents,"paid_amount_cents": model.paid_amount_cents。"payment_method": model.payment_method,"notes": model.notes,// ... 其它字段如 dispatch_note,settlement_status 等
})
}
为什么全量拍而不是只记变更字段? 排查问题时你永远不知道哪个字段会是关键线索。全量快照多占一点存储,但查起来零死角。
// backend/src/infrastructure/projections/crm/order_projection.rs
async fn insert_change_log(txn:&C,merchant_uuid: Uuid,order_uuid: Uuid,action:&str,operator_uuid: Option,before_data: Option。after_data: Option,created_at:
DateTime) -> Result<, String>
where C : sea_orm::ConnectionTrait {
let active=order_change_logs::ActiveModel{
至于uuid,Set),merchant_id:Set),order_uuid:Set,action:Set),operator_uuid:Set,before_data:Set),after_data:Set),created_at:Set,};active.insert.await?,Ok)
}
A chain of events from business logic → event emission → projection consumption → snapshot → log insertion makes auditing an *invisible* side‑effect. Developers just emit events and keep coding.
A simple field‑level diff on UI makes it obvious what changed:
// app/src/pages/orders.rs
fn order_log_diff_items -> Vec<>{
let before=item.before_data.as_ref.and_n);let after=item.after_data.as_ref.and_n);let keys=,let mut result=vec!,for key in keys{
let before_val=before.and_n);let after_val=after.and_n);if before_val==after_val{continue;}
result.push,format_value。format_value));话说回来,}
result}
| 字段名 | 变更前 | 变更后 | |||
|---|---|---|---|---|---|
| … | |||||
| … | |||||
| 操作类型 | 时间 | 执行者 | 说明 |
|---|---|---|---|
| … | |||
This article was last updated on September 03 2026 – happy coding!`
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback