graph LR
A[接收供应商数据] --> B{商品存在?}
B -->|否| C[创建新商品 - 走上架流程]
B -->|是| D[计算差异]
D --> E{需要审核?}
E -->|否| F[直接更新]
E -->|是| G[创建变更审批单]
G --> H[推送审核队列]
H --> I{审核结果}
I -->|通过| F
I -->|驳回| J[记录驳回原因]
2.3 运营编辑(日常维护)
运营编辑是指运营人员对已上线商品进行日常维护和批量管理的过程。
业务语义
已上线商品的日常维护,包括:
单品编辑:修改商品标题、描述、价格、库存等
批量操作:批量调价、批量上下架、批量修改类目
触发方式
graph LR
A[运营后台手动操作] --> C[批量操作服务]
B[批量Excel导入] --> C
C --> D[生成操作批次ID]
D --> E[流式解析数据]
E --> F[Worker Pool 并发处理]
graph TD
A[批量操作提交] --> B[解析数据]
B --> C[Worker Pool 并发处理]
C --> D{需要审核?}
D -->|否| E[直接更新]
D -->|是| F[创建变更审批单]
F --> G[审核流程]
G --> H{审核结果}
H -->|通过| E
H -->|驳回| I[记录失败原因]
E --> J[更新批量操作状态]
I --> J
graph TD
A[商品变更] --> B{风险评估}
B -->|风险极低| C[免审核 - 直接生效]
B -->|风险低| D[自动审核 - 规则引擎]
B -->|风险中| E[人工审核 - 推送审核队列]
B -->|风险高| F[严格审核 - 多级审核]
C --> G[更新数据库]
D --> H{规则通过?}
H -->|是| G
H -->|否| E
E --> I[审核员认领]
I --> J{审核通过?}
J -->|是| G
J -->|否| K[驳回]
F --> L[一级审核]
L --> M[二级审核]
M --> J
graph LR
A[商品变更] --> B[风险评估]
B --> C{需要审核?}
C -->|否| D[直接更新]
C -->|是| E[创建审批单]
E --> F[推送 Kafka 队列]
F --> G[审核 Worker 消费]
G --> H[分配审核员]
H --> I[审核员审核]
I --> J{审核结果}
J -->|通过| K[应用变更]
J -->|驳回| L[记录驳回原因]
K --> M[发送通知]
L --> M
graph LR
A[商品状态变更] --> B[发布生命周期事件]
B --> C[Kafka Topic]
C --> D[搜索引擎 ES]
C --> E[缓存系统 Redis]
C --> F[推荐系统]
C --> G[通知系统]
D --> H[同步商品索引]
E --> I[更新热点商品缓存]
F --> J[更新推荐池]
G --> K[发送商家通知]
graph TD
A[幂等性设计] --> B[请求层幂等]
A --> C[任务层幂等]
A --> D[数据层幂等]
B --> B1[HTTP 幂等性 Key]
B --> B2[API 限流]
C --> C1[唯一任务标识符]
C --> C2[任务状态判断]
D --> D1[唯一索引]
D --> D2[乐观锁 version]
D --> D3[状态机校验]
graph TD
A[商品中心] --> A1[商品主数据管理]
A --> A2[生命周期管理]
A --> A3[审核流程]
A --> A4[数据分发]
B[定价引擎] --> B1[促销价格计算]
B --> B2[阶梯价格计算]
B --> B3[动态定价]
C[库存系统] --> C1[库存扣减]
C --> C2[库存预占]
C --> C3[库存对账]
D[营销系统] --> D1[满减活动]
D --> D2[优惠券]
D --> D3[拼团活动]
E[搜索引擎] --> E1[全文检索]
E --> E2[相关性排序]
A -.事件.-> B
A -.事件.-> C
A -.事件.-> D
A -.事件.-> E
职责边界划分原则
单一数据源(Single Source of Truth):
商品基础信息:商品中心
价格信息:定价引擎
库存信息:库存系统
促销信息:营销系统
避免职责重叠:
商品中心只存储商品基础价格(base_price),不负责促销价格计算
商品中心只缓存库存快照,不负责库存扣减
通过事件解耦:
商品中心发布事件,下游系统监听并更新本地数据
避免直接调用下游系统的修改接口
6.2 与定价引擎的协作
协作场景
商品中心与定价引擎的协作场景包括:
商品上架时初始化价格:新商品上架时,需要在定价引擎中创建价格记录
运营批量调价:运营批量修改商品价格,需要同步到定价引擎
供应商同步价格变更:供应商同步价格变更,需要通知定价引擎
查询最终价格:用户浏览商品时,需要查询促销后的最终价格
协作模式
sequenceDiagram
participant OP as 运营系统
participant PC as 商品中心
participant PE as 定价引擎
participant Kafka as Kafka
participant Cache as Redis缓存
Note over OP,Cache: 场景1:商品上架时初始化价格
OP->>PC: 1. 创建商品(含基础价格)
PC->>PC: 2. 保存商品到数据库
PC->>PE: 3. 同步调用:初始化价格
PE->>PE: 4. 创建价格记录
PE-->>PC: 5. 返回成功
PC->>Kafka: 6. 发布 ProductCreated 事件
Note over OP,Cache: 场景2:价格变更
OP->>PC: 1. 修改商品基础价格
PC->>PC: 2. 更新商品表
PC->>Kafka: 3. 发布 ProductPriceChanged 事件
Kafka->>PE: 4. 定价引擎消费事件
PE->>PE: 5. 更新价格记录
PE->>Kafka: 6. 发布 PriceUpdated 事件
Kafka->>Cache: 7. 缓存系统更新缓存
Note over OP,Cache: 场景3:查询最终价格
OP->>PC: 1. 查询商品详情
PC->>Cache: 2. 查询缓存
alt 缓存命中
Cache-->>PC: 3a. 返回缓存数据
else 缓存未命中
PC->>PE: 3b. RPC 调用:查询最终价格
PE-->>PC: 4b. 返回促销价格
PC->>Cache: 5b. 更新缓存
end
PC-->>OP: 6. 返回商品详情(含最终价格)
graph TD
A[商品数据变更需求] --> B{商品是否存在?}
B -->|不存在| C[商品上架流程]
B -->|存在| D{数据来源?}
D -->|供应商系统| E{商品是否存在?}
E -->|不存在| F[供应商同步 - 创建]
E -->|存在| G[供应商同步 - 更新]
D -->|运营后台| H[运营编辑流程]
D -->|商家Portal| I{商品状态?}
I -->|DRAFT/REJECTED| C
I -->|其他状态| H
-- 1. 获取普通库存和营销库存 local available = tonumber(redis.call('HGET', key, 'available') or0) local promo = tonumber(redis.call('HGET', key, promotion_id) or0) local total = available + promo
-- 2. 检查库存 if book_num > total thenreturn-1end
-- 3. 优先扣营销库存,不足时扣普通库存 if promo >= book_num then redis.call('HINCRBY', key, promotion_id, -book_num) else redis.call('HSET', key, promotion_id, 0) redis.call('HINCRBY', key, 'available', -(book_num - promo)) end
// BAD: one struct serves two contexts with conflicting meanings type Product struct { ID string Title string PriceCent int64// pricing in order context WarehouseQty int// stock in inventory context — coupling contexts }
合规 sketch:不同 BC 使用不同模型与防腐层翻译;集成通过 API、消息或显式 ACL。
1 2 3 4 5 6 7 8 9 10 11 12 13
// GOOD: separate models + explicit mapping at boundary type catalog.ProductView struct { ID, Title string }
type ordering.OrderLine struct { ProductID string UnitPrice Money SnapshotTitle string// captured at order time, not live catalog coupling }
type inventory.StockUnit struct { SKU string OnHand int }
评审追问:若两个 BC 必须共享标识符,是共享 ID 还是共享 富模型?前者常见且可接受,后者往往是边界溃缩的信号。
// BAD: line exported and mutated from outside aggregate type Order struct { ID string Lines []*OrderLine // exported slice of mutable lines } type OrderLine struct { SKU string Qty int }
funcSomeHandler() { o := &Order{ID: "1", Lines: []*OrderLine{{SKU: "A", Qty: 1}}} o.Lines[0].Qty = 999// invariant broken: no route through Order root }
funcNewClient(host string, port int, opts ...clientOption) *Client { c := &Client{host: host, port: port, timeout: 5 * time.Second} for _, o := range opts { o(c) } return c }
# 动态规划 asyncdefhandle_alert(alert): for i inrange(max_iterations): action = await llm.decide_next_action(context) if action == "final_answer": return result result = await execute_tool(action) context.append(result)
关键差异:
传统后端:编译时确定流程
Agent 系统:运行时动态规划
应对策略:
设置最大迭代次数
检测循环和死锁
提供流程可视化
7.2 后端工程师的优势
作为后端工程师,你在 Agent 开发中有独特的优势:
优势 1:系统设计能力
1 2 3 4 5 6 7 8
传统后端技能 → Agent 应用
分布式系统设计 → Multi-Agent 协调 消息队列 → Agent 异步处理 缓存策略 → Semantic Cache 限流熔断 → LLM 调用保护 数据库设计 → Memory System API 设计 → Tool System
Claude Code是Anthropic推出的AI编程助手,与传统IDE集成的AI工具不同,它直接在终端运行,能够自主规划步骤、读写代码、执行命令、操作git,完成完整的开发循环。Boris Cherny(Claude Code创建者)公开表示,使用Opus 4.5后就再也没有手写过一行代码,47天里有46天都在使用。
func(p *CircuitBreakerProcessor) Process(ctx context.Context, fsCtx *FlashSaleContext) error { // 检查熔断器状态 if p.circuitBreaker.IsOpen() { return fmt.Errorf("circuit breaker is open for %s", p.wrapped.Name()) } // 执行原始 Processor err := p.wrapped.Process(ctx, fsCtx) // 记录结果 if err != nil { p.circuitBreaker.RecordFailure() } else { p.circuitBreaker.RecordSuccess() } return err }
// 熔断器实现 type CircuitBreaker struct { failureCount int failureThreshold int state string// "closed", "open", "half_open" lastFailureTime time.Time timeout time.Duration mu sync.Mutex }
// internal/infrastructure/persistence/model/activity_po.go package model
type ActivityPO struct { ID int64`gorm:"column:id;primaryKey"` Name string`gorm:"column:name"` StartTime time.Time `gorm:"column:start_time"` EndTime time.Time `gorm:"column:end_time"` Status int`gorm:"column:status"` MaxDraws int`gorm:"column:max_draws"` }
flowchart TD
A[识别子域] --> B{直接影响收入/利润/核心指标?}
B -->|是| C{竞品难以模仿?}
B -->|否| D{业务必需?}
C -->|是| E[核心域候选]
C -->|否| F{变化频繁?}
D -->|是| G{有业务特色?}
D -->|否| H[通用域]
F -->|是| I[支撑域]
F -->|否| H
G -->|是| I
G -->|否| H
E --> J{团队投入意愿高?}
J -->|是| K[确认:核心域]
J -->|否| L[降级:支撑域]
style K fill:#ffcdd2,stroke:#c62828,stroke-width:3px
style I fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
style H fill:#bbdefb,stroke:#1565c0,stroke-width:2px
sequenceDiagram
participant App as Application
participant DB as MySQL
participant Relay as Outbox Relay
participant MQ as Kafka
App->>DB: BEGIN TX
App->>DB: INSERT orders (聚合数据)
App->>DB: INSERT outbox (领域事件)
App->>DB: COMMIT TX
loop 定期轮询
Relay->>DB: SELECT * FROM outbox WHERE status='pending'
Relay->>MQ: Publish(event)
MQ-->>Relay: ACK
Relay->>DB: UPDATE outbox SET status='sent'
end
flowchart LR
subgraph 写路径 Command Side
A[Client] -->|Command| B[Command Handler]
B --> C[Domain Model / Aggregate]
C --> D[(Write DB - MySQL)]
C -->|Domain Event| E[Event Bus]
end
subgraph 读路径 Query Side
E -->|同步/异步投影| F[Read Model Builder]
F --> G[(Read DB - ES/Redis)]
H[Client] -->|Query| I[Query Handler]
I --> G
end
flowchart LR
A[Event Store / MQ] --> B[Projector]
B --> C[(Read DB)]
B --> D{事件类型路由}
D -->|OrderPlaced| E[创建订单读模型]
D -->|ItemAdded| F[更新商品明细]
D -->|OrderCancelled| G[标记订单取消]
graph TB
subgraph "Clean Architecture 提供分层骨架"
direction TB
E[Entity Layer]
U[Use Case Layer]
A[Adapter Layer]
F[Framework Layer]
F --> A --> U --> E
end
subgraph "DDD 填充业务建模"
direction TB
AG[Aggregate Root]
VO[Value Object]
DE[Domain Event]
DS[Domain Service]
end
subgraph "CQRS 优化数据流转"
direction TB
CMD[Command Path]
QRY[Query Path]
end
E --- AG
E --- VO
U --- CMD
U --- QRY
U --- DE
U --- DS
角色
职责
Clean Architecture(架构底座)
定义目录结构和依赖方向,确保领域层位于中心,不依赖外部技术
DDD(核心建模)
在 Entity 和 Use Cases 层中,利用聚合根、实体和领域服务编写复杂的业务逻辑
CQRS(数据流转)
在 Use Cases 层进行读写拆分:写操作走 DDD 的领域模型(Command),读操作绕过复杂的领域模型,直接通过 DTO 投影(Query)到前端
adapter/outbound/ ├── persistence/ # Write DB (MySQL) ├── readmodel/ # Read DB (ES/Redis) └── projection/ # Event → Read Model
收益:写操作保证事务一致性,读操作针对查询优化。两者可以独立扩展。
演进决策树
flowchart TD
A[当前是三层架构] --> B{测试困难? 换存储/框架?}
B -->|是| C[阶段 1: Clean Architecture]
B -->|否| A
C --> D{业务规则复杂? Service 层膨胀?}
D -->|是| E[阶段 2: + DDD]
D -->|否| C
E --> F{读写矛盾? 查询需要宽表?}
F -->|是| G[阶段 3: + CQRS]
F -->|否| E
funcUpdateStatus(taskID int64, fromStatus, toStatus int, action string)error { result, err := db.Exec(` UPDATE listing_task_tab SET status = ?, version = version + 1, updated_at = NOW() WHERE id = ? AND status = ? AND version = ? `, toStatus, taskID, fromStatus, currentVersion)
if result.RowsAffected() == 0 { return errors.New("concurrent modification or status changed") }
funcUpdateStatus(taskID int64, fromStatus, toStatus int, action string)error { result, err := db.Exec(` UPDATE listing_task_tab SET status = ?, version = version + 1, updated_at = NOW() WHERE id = ? AND status = ? AND version = ? `, toStatus, taskID, fromStatus, currentVersion)
if result.RowsAffected() == 0 { return errors.New("concurrent modification or status changed") }
graph LR
A[第三方回调] --> B{签名校验}
B -->|失败| C[拒绝并记录]
B -->|成功| D{幂等检查}
D -->|已处理| E[直接返回 SUCCESS]
D -->|未处理| F[更新支付状态]
F --> G[发布事件到 Kafka]
G --> H[返回 SUCCESS]
// 定时任务扫描并发送消息 funcScanAndSendMessages() { messages := db.Query(` SELECT * FROM local_message WHERE status = 'PENDING' AND retry_count < 3 ORDER BY created_at ASC LIMIT 100 `) for _, msg := range messages { // 发送到 Kafka if err := kafka.Publish("order_paid", msg); err == nil { db.Exec(` UPDATE local_message SET status = 'SENT' WHERE id = ? `, msg.ID) } else { db.Exec(` UPDATE local_message SET retry_count = retry_count + 1 WHERE id = ? `, msg.ID) } } }
graph LR
A[T 日交易] --> B[T+1 日凌晨定时任务]
B --> C[计算分账金额]
C --> D[生成结算单]
D --> E[商家确认]
E --> F[提现申请]
F --> G[打款到银行账户]
G --> H[更新账户余额]
6.2 对账系统
6.2.1 为什么需要对账
系统与第三方的交易数据可能存在以下问题:
长款:第三方有,本地无(用户已支付,但系统未记录)
短款:本地有,第三方无(系统记录已支付,但第三方未收到)
金额不符:订单号一致,但金额不一致
6.2.2 对账维度
对账维度
对账内容
数据来源
交易对账
订单号、金额、状态
第三方对账文件 vs 本地支付流水
资金对账
入账金额、手续费
第三方结算单 vs 本地账户流水
6.2.3 对账流程
graph LR
A[每日凌晨 2:00] --> B[拉取第三方对账文件]
B --> C[解析对账文件]
C --> D[与本地流水对比]
D --> E[生成差错报告]
E --> F{有差错?}
F -->|是| G[人工复核]
F -->|否| H[记录对账结果]
G --> I[差错处理]
type OrderState interface { OnEvent(ctx context.Context, o *Order, e Event) (OrderState, error) }
type PendingState struct{} func(PendingState) OnEvent(ctx context.Context, o *Order, e Event) (OrderState, error) { if e == EventPayOK { o.Status = OrderPaid return PaidState{}, nil } returnnil, ErrIllegalTransition }
type StateMachine struct{ cur OrderState } func(sm *StateMachine) Fire(ctx context.Context, o *Order, e Event) error { next, err := sm.cur.OnEvent(ctx, o, e) if err != nil { return err } sm.cur = next returnnil }
方案 3:状态机引擎 / 规则表 —— 适合多团队扩展、可视化配置(业界有 Spring State Machine、自研 JSON 规则等)。用迁移表描述 (from, event) -> to:
funcEngineTransition(o *Order, e Event)error { for _, r := range rules { if r.From == o.Status && r.Event == e { o.Status = r.To returnnil } } return ErrIllegalTransition }