Skip to Content

28c - Spec-Driven 业务逻辑

本文是《AI Agent 实战手册》第 28 章第 3 节。 上一节:28b-API设计与生成 | 下一节:28d-AI辅助认证实现

概述

业务逻辑是后端系统的核心——它决定了数据如何流转、规则如何执行、状态如何变迁。在 AI 辅助开发时代,“随意对话生成代码”的 Vibe Coding 方式在业务逻辑层暴露出严重问题:逻辑遗漏、边界条件缺失、事务不一致。Spec-Driven 开发方法论通过”先规约、后生成”的结构化流程,将业务逻辑实现从”AI 猜测意图”升级为”AI 按规约执行”。本节系统覆盖 Spec-Driven 开发方法论、从需求到代码的结构化流程、领域模型 AI 生成(DDD 概念)、服务层模式(Repository/Service/Controller)、AI 辅助业务规则实现、事务管理与数据一致性,以及 Kiro Spec 工作流实战。


1. Spec-Driven 开发方法论

1.1 什么是 Spec-Driven Development

Spec-Driven Development(SDD,规约驱动开发)是一种以规约(Specification)为核心制品的开发方法论。与传统的”先写代码再补文档”或 Vibe Coding 的”对话式生成”不同,SDD 要求在编写任何代码之前,先产出结构化的规约文档,然后由 AI Agent 按照规约生成、验证和维护实现代码。

核心公式:

Spec(需求 + 设计 + 任务) + AI Agent + Human Review = 生产级代码

SDD 与其他方法论的对比:

维度Vibe Coding传统敏捷Spec-Driven Development
规划投入几乎为零中等(Sprint Planning)前置 15-30 分钟结构化规划
需求表达自然语言对话User Story + ACEARS 格式验收标准
设计产出可选的设计文档强制的技术设计文档
任务分解AI 自行决定人工分解AI 生成 + 人工审核
代码质量不可预测依赖开发者水平可追溯、可验证
适用场景原型、探索团队协作项目AI 辅助的生产级开发
上下文持久性会话结束即丢失在 Jira/Confluence 中在 Spec 文件中持久化

1.2 为什么业务逻辑需要 Spec-Driven

业务逻辑是 AI 生成代码中最容易出错的部分,原因在于:

  1. 隐含规则多:业务规则往往存在大量隐含条件(“VIP 用户免运费”、“库存不足时自动预订”),AI 无法从简单描述中推断所有规则
  2. 边界条件复杂:金额计算的精度、时区处理、并发冲突——这些边界条件需要明确规约
  3. 状态转换严格:订单状态机、审批流程、支付状态——状态转换必须遵循严格的业务规则
  4. 一致性要求高:跨表、跨服务的数据一致性不能靠 AI “猜测”
  5. 可审计性:金融、医疗等领域的业务逻辑需要可追溯的实现依据

Spec-Driven 如何解决这些问题:

传统 Vibe Coding 流程: "帮我写一个订单系统" → AI 生成代码 → 发现缺少退款逻辑 → 补丁式修复 → 发现并发问题 → 再修复... Spec-Driven 流程: 需求规约(所有业务规则) → 设计文档(领域模型 + 服务层) → 任务分解(原子任务) → AI 按任务生成 → 人工审核

1.3 SDD 的三阶段流程

Spec-Driven Development 将开发过程分为三个明确的阶段:

┌─────────────────────────────────────────────────────────────┐ │ Spec-Driven Development 流程 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 阶段 1:需求规约(Requirements) │ │ ┌─────────────────────────────────────────────┐ │ │ │ • 用户故事(User Story) │ │ │ │ • EARS 格式验收标准 │ │ │ │ • 业务规则清单 │ │ │ │ • 边界条件和异常场景 │ │ │ └─────────────────────────────────────────────┘ │ │ ↓ │ │ 阶段 2:技术设计(Design) │ │ ┌─────────────────────────────────────────────┐ │ │ │ • 领域模型(Entity/Value Object/Aggregate) │ │ │ │ • 服务层架构(Repository/Service/Controller) │ │ │ │ • 数据流图和序列图 │ │ │ │ • 接口定义(TypeScript Interface/Type) │ │ │ │ • 数据库 Schema │ │ │ └─────────────────────────────────────────────┘ │ │ ↓ │ │ 阶段 3:任务执行(Tasks) │ │ ┌─────────────────────────────────────────────┐ │ │ │ • 原子化任务列表(可独立执行和验证) │ │ │ │ • 每个任务关联需求和设计 │ │ │ │ • AI Agent 逐任务执行 │ │ │ │ • 人工审核每个任务的输出 │ │ │ └─────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘

1.4 工具推荐

工具用途核心能力价格适用场景
KiroAgentic IDE内置 Spec 工作流(需求→设计→任务),EARS 格式验收标准,Steering 规则,Hooks 自动化免费(预览期)Spec-Driven 业务逻辑开发的首选工具
Claude CodeCLI AI 工具全项目理解,Plan Mode 规划,Subagent 并行执行,CLAUDE.md 规则文件$20/月(Max 5x)/ API 按量CLI 偏好的 Spec-Driven 开发,复杂重构
CursorAI IDEComposer 多文件编辑,Agent 模式,.cursorrules 规则文件免费 / $20/月(Pro)日常业务逻辑编码,快速迭代
OpenAI Codex云端 Agent沙箱自主执行,自动测试,GitHub 集成ChatGPT Pro 订阅内含独立业务模块的自主实现
PrismaORM声明式 Schema,类型安全查询,自动迁移,AI 友好的 schema 语法免费(开源)/ $29/月(Accelerate)TypeScript 后端的领域模型层
Drizzle ORM轻量 ORMSQL-like API,零依赖,类型推断,声明式 schema免费(开源)追求性能的 TypeScript 后端
TypeORMORM装饰器模式,Active Record/Data Mapper,迁移工具免费(开源)企业级 TypeScript/Node.js 项目
SQLAlchemyORM(Python)声明式映射,Unit of Work,复杂查询构建免费(开源)Python 后端的领域模型层
Zod验证库TypeScript-first schema 验证,类型推断,可组合免费(开源)业务规则输入验证
Pydantic验证库(Python)数据验证,序列化,Settings 管理免费(开源)Python 业务逻辑的数据验证

2. 从需求到代码的结构化流程

2.1 阶段一:需求规约编写

需求规约是 Spec-Driven 业务逻辑的起点。好的需求规约应该让 AI Agent 能够准确理解每一条业务规则,不留歧义。

EARS 格式验收标准

EARS(Easy Approach to Requirements Syntax)是 Kiro 采用的需求编写格式,它通过结构化的语法消除自然语言的歧义:

EARS 格式模板: WHEN [触发条件], THE [系统/组件] SHALL [行为描述] 示例: WHEN a customer places an order with total amount > $100, THE OrderService SHALL apply a 10% discount automatically AND record the discount reason as "bulk_order_discount" WHEN a customer attempts to cancel an order that is already shipped, THE OrderService SHALL reject the cancellation AND return error code ORDER_ALREADY_SHIPPED with HTTP 409

操作步骤:编写业务逻辑需求规约

步骤 1:识别业务领域和核心实体

列出你的业务领域中的核心实体: - 用户(User) - 订单(Order) - 商品(Product) - 支付(Payment) - 库存(Inventory)

步骤 2:梳理业务规则清单

为每个实体列出所有业务规则: 【订单规则】 1. 订单总金额 = Σ(商品单价 × 数量) - 折扣 + 运费 2. VIP 用户(等级 ≥ 3)免运费 3. 订单金额 > 100 元自动享受 9 折 4. 库存不足时不允许下单 5. 同一用户 24 小时内最多下 10 单(防刷单) 6. 订单创建后 30 分钟未支付自动取消 【状态转换规则】 创建 → 待支付 → 已支付 → 备货中 → 已发货 → 已签收 → 已完成 ↘ 退货中 → 已退货 待支付 → 已取消(用户主动/超时自动) 已支付 → 退款中 → 已退款(发货前可退款)

步骤 3:用 EARS 格式编写验收标准

提示词模板:生成业务逻辑需求规约

你是一位资深业务分析师。请根据以下业务描述,生成结构化的需求规约文档。 ## 业务描述 [在此粘贴你的业务需求描述] ## 输出要求 1. 使用 EARS 格式编写验收标准(WHEN...THE...SHALL...) 2. 每条规则必须包含: - 触发条件(WHEN) - 执行主体(THE) - 预期行为(SHALL) - 异常情况处理 3. 列出所有状态转换规则(用状态机图表示) 4. 列出所有边界条件: - 数值边界(最大值、最小值、精度) - 时间边界(超时、有效期) - 并发边界(竞态条件、幂等性) 5. 列出所有业务约束: - 唯一性约束 - 引用完整性约束 - 业务规则约束 ## 格式 使用 Markdown,按实体分组组织规则。

2.2 阶段二:技术设计文档

技术设计文档将业务需求转化为可实现的技术方案,是 AI Agent 生成代码的蓝图。

设计文档核心内容

技术设计文档结构: 1. 领域模型(Domain Model) - Entity 定义(含属性和类型) - Value Object 定义 - Aggregate Root 识别 - 领域事件(Domain Event) 2. 服务层架构 - Repository 接口定义 - Service 层职责划分 - Controller 路由映射 3. 数据模型 - 数据库 Schema(表结构) - 索引策略 - 关联关系 4. 接口定义 - TypeScript Interface / Type - API 请求/响应类型 - 错误码定义 5. 序列图 - 核心业务流程的时序图 - 异常处理流程

提示词模板:生成技术设计文档

你是一位资深后端架构师。请根据以下需求规约,生成技术设计文档。 ## 需求规约 [粘贴阶段一产出的需求规约] ## 技术栈 - 语言:[TypeScript / Python / Go / Java] - 框架:[Express / NestJS / FastAPI / Gin / Spring Boot] - ORM:[Prisma / Drizzle / SQLAlchemy / GORM] - 数据库:[PostgreSQL / MySQL / MongoDB] ## 输出要求 1. **领域模型**:使用 DDD 概念,识别 Entity、Value Object、Aggregate Root 2. **TypeScript 接口定义**:为每个实体和值对象定义完整的类型 3. **服务层架构**:定义 Repository 接口、Service 类、Controller 路由 4. **数据库 Schema**:使用 [ORM] 语法定义表结构 5. **序列图**:使用 Mermaid 语法绘制核心业务流程 6. **错误处理**:定义业务错误码和异常类型 ## 架构原则 - 遵循 Clean Architecture / 六边形架构 - Repository 模式隔离数据访问 - Service 层包含所有业务逻辑 - Controller 层只负责 HTTP 协议转换 - 使用依赖注入

2.3 阶段三:任务分解与执行

将设计文档分解为原子化的实现任务,每个任务可独立执行和验证。

任务分解原则

好的任务分解: ✅ 1.1 创建 Order Entity 和 OrderItem Value Object 的 TypeScript 类型定义 ✅ 1.2 创建 orders 和 order_items 数据库表的 Prisma Schema ✅ 1.3 实现 OrderRepository 接口和 Prisma 实现 ✅ 1.4 实现 OrderService.createOrder() 方法(含库存检查和金额计算) ✅ 1.5 实现 OrderService.cancelOrder() 方法(含状态验证和退款触发) ✅ 1.6 为 OrderService 编写单元测试 ✅ 1.7 实现 OrderController 的 POST /orders 和 DELETE /orders/:id 路由 坏的任务分解: ❌ 1.1 实现订单系统(太大,不可原子化验证) ❌ 1.2 写所有测试(没有明确范围)

提示词模板:生成任务列表

你是一位技术项目经理。请根据以下技术设计文档,生成实现任务列表。 ## 技术设计 [粘贴阶段二产出的设计文档] ## 任务分解要求 1. 每个任务必须是原子化的(可在 30 分钟内完成) 2. 每个任务必须有明确的输入和输出 3. 每个任务必须关联到需求规约中的验收标准 4. 任务之间的依赖关系必须明确 5. 每个任务包含验证标准(如何确认任务完成) ## 输出格式 - [ ] 1. [模块名] - [ ] 1.1 [具体任务描述] - 输入:[前置条件] - 输出:[产出物] - 验证:[如何验证完成] - _Requirements: [关联的需求编号]_

3. 领域模型 AI 生成(DDD 概念)

3.1 DDD 核心概念速览

领域驱动设计(Domain-Driven Design,DDD)是构建复杂业务逻辑的经典方法论。在 AI 辅助开发中,DDD 的概念为 AI 提供了清晰的建模框架。

DDD 概念定义AI 生成要点示例
Entity(实体)有唯一标识的领域对象,生命周期内标识不变必须定义 ID 类型和生成策略Order、User、Product
Value Object(值对象)无唯一标识,通过属性值定义相等性,不可变必须实现 equals() 和不可变性Money、Address、DateRange
Aggregate(聚合)一组相关对象的集合,通过 Aggregate Root 访问定义聚合边界和一致性规则Order(含 OrderItem)
Aggregate Root(聚合根)聚合的入口点,外部只能通过它访问聚合内部所有修改必须通过聚合根Order 是 OrderItem 的聚合根
Domain Event(领域事件)领域中发生的有意义的事件定义事件名、载荷、发布时机OrderCreated、PaymentCompleted
Repository(仓储)提供聚合的持久化和检索接口接口在领域层,实现在基础设施层OrderRepository
Domain Service(领域服务)不属于任何实体的领域逻辑跨实体的业务规则PricingService、InventoryService
Application Service(应用服务)编排领域对象完成用例事务管理、权限检查、事件发布OrderApplicationService

3.2 AI 生成领域模型的结构化流程

┌──────────────────────────────────────────────────────┐ │ AI 生成领域模型的 4 步流程 │ ├──────────────────────────────────────────────────────┤ │ │ │ Step 1:识别核心实体和值对象 │ │ ┌────────────────────────────────────────┐ │ │ │ 输入:业务需求描述 │ │ │ │ 输出:实体列表 + 值对象列表 + 属性定义 │ │ │ └────────────────────────────────────────┘ │ │ ↓ │ │ Step 2:划定聚合边界 │ │ ┌────────────────────────────────────────┐ │ │ │ 输入:实体关系图 │ │ │ │ 输出:聚合划分 + 聚合根标识 │ │ │ │ 原则:一个事务只修改一个聚合 │ │ │ └────────────────────────────────────────┘ │ │ ↓ │ │ Step 3:定义领域事件 │ │ ┌────────────────────────────────────────┐ │ │ │ 输入:状态转换规则 │ │ │ │ 输出:事件名 + 载荷类型 + 发布时机 │ │ │ └────────────────────────────────────────┘ │ │ ↓ │ │ Step 4:生成 TypeScript/Python 类型定义 │ │ ┌────────────────────────────────────────┐ │ │ │ 输入:以上所有产出 │ │ │ │ 输出:完整的类型定义文件 │ │ │ └────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────┘

提示词模板:AI 生成领域模型

你是一位 DDD 领域建模专家。请根据以下业务需求,生成完整的领域模型。 ## 业务需求 [粘贴业务需求描述] ## 建模要求 ### 1. 实体识别 - 列出所有 Entity,标注唯一标识类型(UUID / 自增 ID / 业务编号) - 列出所有 Value Object,说明为什么它是值对象而非实体 - 为每个实体/值对象定义完整属性(名称、类型、是否必填、默认值、约束) ### 2. 聚合划分 - 标识每个 Aggregate Root - 说明聚合边界的划分理由 - 确保每个聚合内的一致性规则 ### 3. 领域事件 - 列出所有领域事件(命名格式:{Entity}{PastTenseVerb},如 OrderCreated) - 定义每个事件的载荷类型 - 说明事件的发布时机和消费者 ### 4. 类型定义 - 使用 [TypeScript / Python dataclass] 语法 - Entity 必须包含 id、createdAt、updatedAt - Value Object 必须是 readonly/frozen - 使用枚举定义所有状态值 ## 输出格式 使用代码块输出类型定义,使用 Mermaid 类图展示实体关系。

3.3 领域模型代码示例

以电商订单系统为例,展示 AI 生成的领域模型:

TypeScript 领域模型

// ============================================ // Value Objects(值对象) // ============================================ /** 金额值对象 —— 避免浮点数精度问题 */ interface Money { readonly amount: number; // 以"分"为单位存储(整数) readonly currency: 'CNY' | 'USD' | 'EUR'; } /** 地址值对象 */ interface Address { readonly province: string; readonly city: string; readonly district: string; readonly street: string; readonly zipCode: string; } /** 订单项值对象 */ interface OrderItem { readonly productId: string; readonly productName: string; readonly unitPrice: Money; readonly quantity: number; readonly subtotal: Money; // unitPrice.amount * quantity } // ============================================ // Enums(枚举) // ============================================ enum OrderStatus { PENDING_PAYMENT = 'pending_payment', PAID = 'paid', PREPARING = 'preparing', SHIPPED = 'shipped', DELIVERED = 'delivered', COMPLETED = 'completed', CANCELLED = 'cancelled', REFUNDING = 'refunding', REFUNDED = 'refunded', } enum DiscountType { BULK_ORDER = 'bulk_order', // 满减 VIP_DISCOUNT = 'vip_discount', // VIP 折扣 COUPON = 'coupon', // 优惠券 PROMOTION = 'promotion', // 促销活动 } // ============================================ // Entities(实体) // ============================================ /** 订单实体 —— Aggregate Root */ interface Order { readonly id: string; // UUID readonly orderNumber: string; // 业务编号:ORD-20250615-XXXX readonly customerId: string; readonly items: readonly OrderItem[]; readonly shippingAddress: Address; readonly subtotal: Money; // 商品小计 readonly shippingFee: Money; // 运费 readonly discount: Money; // 折扣金额 readonly totalAmount: Money; // 最终金额 readonly discountType: DiscountType | null; readonly status: OrderStatus; readonly paidAt: Date | null; readonly shippedAt: Date | null; readonly cancelledAt: Date | null; readonly cancelReason: string | null; readonly createdAt: Date; readonly updatedAt: Date; readonly expiresAt: Date; // 支付截止时间 } // ============================================ // Domain Events(领域事件) // ============================================ interface OrderCreatedEvent { readonly type: 'OrderCreated'; readonly orderId: string; readonly customerId: string; readonly totalAmount: Money; readonly occurredAt: Date; } interface OrderPaidEvent { readonly type: 'OrderPaid'; readonly orderId: string; readonly paymentId: string; readonly amount: Money; readonly occurredAt: Date; } interface OrderCancelledEvent { readonly type: 'OrderCancelled'; readonly orderId: string; readonly reason: string; readonly cancelledBy: 'customer' | 'system' | 'admin'; readonly occurredAt: Date; } type OrderDomainEvent = | OrderCreatedEvent | OrderPaidEvent | OrderCancelledEvent;

Python 领域模型(对比参考)

from dataclasses import dataclass, field from datetime import datetime from decimal import Decimal from enum import Enum from typing import Optional from uuid import UUID, uuid4 # ============================================ # Value Objects # ============================================ @dataclass(frozen=True) class Money: """金额值对象 —— 使用 Decimal 避免精度问题""" amount: Decimal currency: str = "CNY" def __add__(self, other: "Money") -> "Money": assert self.currency == other.currency return Money(amount=self.amount + other.amount, currency=self.currency) def __mul__(self, factor: int) -> "Money": return Money(amount=self.amount * factor, currency=self.currency) @dataclass(frozen=True) class Address: province: str city: str district: str street: str zip_code: str @dataclass(frozen=True) class OrderItem: product_id: UUID product_name: str unit_price: Money quantity: int @property def subtotal(self) -> Money: return self.unit_price * self.quantity # ============================================ # Enums # ============================================ class OrderStatus(str, Enum): PENDING_PAYMENT = "pending_payment" PAID = "paid" PREPARING = "preparing" SHIPPED = "shipped" DELIVERED = "delivered" COMPLETED = "completed" CANCELLED = "cancelled" REFUNDING = "refunding" REFUNDED = "refunded" # ============================================ # Entity (Aggregate Root) # ============================================ @dataclass class Order: """订单聚合根""" id: UUID = field(default_factory=uuid4) order_number: str = "" customer_id: UUID = field(default_factory=uuid4) items: list[OrderItem] = field(default_factory=list) shipping_address: Optional[Address] = None status: OrderStatus = OrderStatus.PENDING_PAYMENT total_amount: Money = field(default_factory=lambda: Money(Decimal("0"))) shipping_fee: Money = field(default_factory=lambda: Money(Decimal("0"))) discount: Money = field(default_factory=lambda: Money(Decimal("0"))) paid_at: Optional[datetime] = None cancelled_at: Optional[datetime] = None cancel_reason: Optional[str] = None created_at: datetime = field(default_factory=datetime.utcnow) updated_at: datetime = field(default_factory=datetime.utcnow) # 领域事件收集 _domain_events: list = field(default_factory=list, repr=False) def add_item(self, item: OrderItem) -> None: """添加订单项 —— 业务规则在聚合根内执行""" self.items.append(item) self._recalculate_total() def cancel(self, reason: str, cancelled_by: str = "customer") -> None: """取消订单 —— 包含状态验证""" allowed = {OrderStatus.PENDING_PAYMENT, OrderStatus.PAID} if self.status not in allowed: raise ValueError(f"Cannot cancel order in status: {self.status}") self.status = OrderStatus.CANCELLED self.cancelled_at = datetime.utcnow() self.cancel_reason = reason self._domain_events.append({ "type": "OrderCancelled", "order_id": str(self.id), "reason": reason, "cancelled_by": cancelled_by, }) def _recalculate_total(self) -> None: subtotal = sum( (item.subtotal.amount for item in self.items), Decimal("0") ) self.total_amount = Money( subtotal + self.shipping_fee.amount - self.discount.amount )

3.4 聚合边界划分的 AI 辅助决策

聚合边界的划分是 DDD 中最关键也最容易出错的决策。以下是让 AI 辅助划分聚合边界的提示词模板:

提示词模板:聚合边界划分

你是一位 DDD 架构师。请分析以下实体关系,划分聚合边界。 ## 实体列表 [列出所有实体及其关系] ## 划分原则 1. **事务一致性**:一个事务只修改一个聚合 2. **业务不变量**:聚合内的所有不变量必须在一次操作中保证 3. **最小化聚合**:聚合应尽可能小,只包含必须一起修改的对象 4. **引用规则**:聚合之间通过 ID 引用,不直接持有对象引用 ## 分析要求 对于每个聚合,请说明: 1. 聚合根是谁? 2. 聚合内包含哪些实体/值对象? 3. 聚合的不变量(invariant)是什么? 4. 聚合之间如何通信(领域事件 vs 直接调用)? ## 常见陷阱提醒 - 不要把所有相关实体放在一个大聚合里("上帝聚合"反模式) - 不要让聚合跨越数据库表的自然边界 - 考虑并发修改的场景:如果两个用户同时修改同一个聚合,会发生什么?

4. 服务层模式(Repository / Service / Controller)

4.1 三层架构概览

┌─────────────────────────────────────────────────────────┐ │ 三层服务架构 │ ├─────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ Controller 层(HTTP 协议转换) │ │ │ │ • 解析请求参数 │ │ │ │ • 调用 Service 层 │ │ │ │ • 格式化响应 │ │ │ │ • 错误码映射 │ │ │ └──────────────────┬──────────────────────────┘ │ │ │ │ │ ┌──────────────────▼──────────────────────────┐ │ │ │ Service 层(业务逻辑编排) │ │ │ │ • 业务规则执行 │ │ │ │ • 事务管理 │ │ │ │ • 权限检查 │ │ │ │ • 领域事件发布 │ │ │ │ • 跨聚合协调 │ │ │ └──────────────────┬──────────────────────────┘ │ │ │ │ │ ┌──────────────────▼──────────────────────────┐ │ │ │ Repository 层(数据访问抽象) │ │ │ │ • CRUD 操作 │ │ │ │ • 查询构建 │ │ │ │ • 数据映射(DB Record ↔ Domain Entity) │ │ │ │ • 接口在领域层,实现在基础设施层 │ │ │ └─────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘

4.2 Repository 模式

Repository 模式将数据访问逻辑从业务逻辑中隔离出来,使业务逻辑不依赖具体的数据库实现。

TypeScript Repository 示例(Prisma)

// ============================================ // Repository 接口(领域层) // ============================================ interface OrderRepository { findById(id: string): Promise<Order | null>; findByCustomerId(customerId: string, options?: { status?: OrderStatus; limit?: number; offset?: number; }): Promise<Order[]>; findByOrderNumber(orderNumber: string): Promise<Order | null>; save(order: Order): Promise<Order>; update(order: Order): Promise<Order>; countByCustomerIdInPeriod( customerId: string, startTime: Date, endTime: Date ): Promise<number>; } // ============================================ // Repository 实现(基础设施层 —— Prisma) // ============================================ class PrismaOrderRepository implements OrderRepository { constructor(private readonly prisma: PrismaClient) {} async findById(id: string): Promise<Order | null> { const record = await this.prisma.order.findUnique({ where: { id }, include: { items: true }, }); return record ? this.toDomain(record) : null; } async findByCustomerId( customerId: string, options?: { status?: OrderStatus; limit?: number; offset?: number } ): Promise<Order[]> { const records = await this.prisma.order.findMany({ where: { customerId, ...(options?.status && { status: options.status }), }, include: { items: true }, take: options?.limit ?? 20, skip: options?.offset ?? 0, orderBy: { createdAt: 'desc' }, }); return records.map(r => this.toDomain(r)); } async save(order: Order): Promise<Order> { const record = await this.prisma.order.create({ data: this.toPersistence(order), include: { items: true }, }); return this.toDomain(record); } async countByCustomerIdInPeriod( customerId: string, startTime: Date, endTime: Date ): Promise<number> { return this.prisma.order.count({ where: { customerId, createdAt: { gte: startTime, lte: endTime }, }, }); } // 数据映射:DB Record → Domain Entity private toDomain(record: any): Order { return { id: record.id, orderNumber: record.orderNumber, customerId: record.customerId, items: record.items.map((item: any) => ({ productId: item.productId, productName: item.productName, unitPrice: { amount: item.unitPriceCents, currency: 'CNY' }, quantity: item.quantity, subtotal: { amount: item.unitPriceCents * item.quantity, currency: 'CNY' }, })), status: record.status as OrderStatus, totalAmount: { amount: record.totalAmountCents, currency: 'CNY' }, shippingFee: { amount: record.shippingFeeCents, currency: 'CNY' }, discount: { amount: record.discountCents, currency: 'CNY' }, // ... 其他字段映射 createdAt: record.createdAt, updatedAt: record.updatedAt, } as Order; } // 数据映射:Domain Entity → DB Record private toPersistence(order: Order): any { return { id: order.id, orderNumber: order.orderNumber, customerId: order.customerId, status: order.status, totalAmountCents: order.totalAmount.amount, shippingFeeCents: order.shippingFee.amount, discountCents: order.discount.amount, items: { create: order.items.map(item => ({ productId: item.productId, productName: item.productName, unitPriceCents: item.unitPrice.amount, quantity: item.quantity, })), }, }; } }

4.3 Service 层模式

Service 层是业务逻辑的核心所在,负责编排领域对象、执行业务规则、管理事务。

TypeScript Service 示例

// ============================================ // Application Service(应用服务) // ============================================ interface CreateOrderInput { customerId: string; items: Array<{ productId: string; quantity: number; }>; shippingAddress: Address; couponCode?: string; } interface CreateOrderResult { order: Order; events: OrderDomainEvent[]; } class OrderService { constructor( private readonly orderRepo: OrderRepository, private readonly productRepo: ProductRepository, private readonly customerRepo: CustomerRepository, private readonly inventoryService: InventoryService, private readonly pricingService: PricingService, private readonly eventBus: EventBus, ) {} /** * 创建订单 —— 核心业务流程 * * 业务规则: * 1. 验证客户存在且状态正常 * 2. 验证所有商品存在且上架中 * 3. 检查库存是否充足 * 4. 计算订单金额(含折扣) * 5. 检查防刷单限制(24h 内最多 10 单) * 6. 创建订单并预扣库存 * 7. 发布 OrderCreated 事件 */ async createOrder(input: CreateOrderInput): Promise<CreateOrderResult> { // 1. 验证客户 const customer = await this.customerRepo.findById(input.customerId); if (!customer) { throw new BusinessError('CUSTOMER_NOT_FOUND', '客户不存在'); } if (customer.status === 'suspended') { throw new BusinessError('CUSTOMER_SUSPENDED', '账户已被冻结'); } // 2. 验证商品并获取价格 const products = await this.productRepo.findByIds( input.items.map(i => i.productId) ); const orderItems = this.buildOrderItems(input.items, products); // 3. 检查库存 for (const item of orderItems) { const available = await this.inventoryService.checkAvailability( item.productId, item.quantity ); if (!available) { throw new BusinessError( 'INSUFFICIENT_INVENTORY', `商品 ${item.productName} 库存不足` ); } } // 4. 计算金额 const pricing = await this.pricingService.calculate({ items: orderItems, customerId: input.customerId, customerLevel: customer.vipLevel, couponCode: input.couponCode, }); // 5. 防刷单检查 const now = new Date(); const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000); const recentOrderCount = await this.orderRepo.countByCustomerIdInPeriod( input.customerId, oneDayAgo, now ); if (recentOrderCount >= 10) { throw new BusinessError( 'ORDER_RATE_LIMIT_EXCEEDED', '24 小时内下单次数已达上限(10 单)' ); } // 6. 创建订单 const order: Order = { id: generateUUID(), orderNumber: generateOrderNumber(), customerId: input.customerId, items: orderItems, shippingAddress: input.shippingAddress, subtotal: pricing.subtotal, shippingFee: pricing.shippingFee, discount: pricing.discount, totalAmount: pricing.totalAmount, discountType: pricing.discountType, status: OrderStatus.PENDING_PAYMENT, paidAt: null, shippedAt: null, cancelledAt: null, cancelReason: null, createdAt: now, updatedAt: now, expiresAt: new Date(now.getTime() + 30 * 60 * 1000), // 30 分钟后过期 }; const savedOrder = await this.orderRepo.save(order); // 7. 预扣库存 for (const item of orderItems) { await this.inventoryService.reserve(item.productId, item.quantity, savedOrder.id); } // 8. 发布领域事件 const event: OrderCreatedEvent = { type: 'OrderCreated', orderId: savedOrder.id, customerId: savedOrder.customerId, totalAmount: savedOrder.totalAmount, occurredAt: now, }; await this.eventBus.publish(event); return { order: savedOrder, events: [event] }; } /** * 取消订单 * * 业务规则: * 1. 只有 pending_payment 和 paid 状态可以取消 * 2. 已发货的订单不能取消(需走退货流程) * 3. 取消后释放预扣库存 * 4. 如果已支付,触发退款流程 */ async cancelOrder( orderId: string, reason: string, cancelledBy: 'customer' | 'system' | 'admin' = 'customer' ): Promise<Order> { const order = await this.orderRepo.findById(orderId); if (!order) { throw new BusinessError('ORDER_NOT_FOUND', '订单不存在'); } // 状态验证 const cancellableStatuses = [OrderStatus.PENDING_PAYMENT, OrderStatus.PAID]; if (!cancellableStatuses.includes(order.status)) { throw new BusinessError( 'ORDER_CANNOT_CANCEL', `当前状态 ${order.status} 不允许取消` ); } // 更新订单状态 const updatedOrder: Order = { ...order, status: OrderStatus.CANCELLED, cancelledAt: new Date(), cancelReason: reason, updatedAt: new Date(), }; await this.orderRepo.update(updatedOrder); // 释放库存 for (const item of order.items) { await this.inventoryService.release(item.productId, item.quantity, orderId); } // 如果已支付,触发退款 if (order.status === OrderStatus.PAID) { await this.eventBus.publish({ type: 'RefundRequested', orderId: order.id, amount: order.totalAmount, reason, occurredAt: new Date(), }); } // 发布取消事件 await this.eventBus.publish({ type: 'OrderCancelled', orderId: order.id, reason, cancelledBy, occurredAt: new Date(), }); return updatedOrder; } private buildOrderItems( inputItems: Array<{ productId: string; quantity: number }>, products: Product[] ): OrderItem[] { return inputItems.map(input => { const product = products.find(p => p.id === input.productId); if (!product) { throw new BusinessError('PRODUCT_NOT_FOUND', `商品 ${input.productId} 不存在`); } if (product.status !== 'active') { throw new BusinessError('PRODUCT_NOT_AVAILABLE', `商品 ${product.name} 已下架`); } return { productId: product.id, productName: product.name, unitPrice: product.price, quantity: input.quantity, subtotal: { amount: product.price.amount * input.quantity, currency: product.price.currency, }, }; }); } }

4.4 Controller 层模式

Controller 层只负责 HTTP 协议转换,不包含任何业务逻辑。

// ============================================ // Controller 层(Express / NestJS 风格) // ============================================ // Express 风格 const orderController = { async createOrder(req: Request, res: Response, next: NextFunction) { try { // 1. 解析和验证请求参数 const input = CreateOrderSchema.parse(req.body); // 2. 调用 Service 层 const result = await orderService.createOrder({ customerId: req.user.id, // 从认证中间件获取 items: input.items, shippingAddress: input.shippingAddress, couponCode: input.couponCode, }); // 3. 格式化响应 res.status(201).json({ success: true, data: { orderId: result.order.id, orderNumber: result.order.orderNumber, totalAmount: result.order.totalAmount, status: result.order.status, expiresAt: result.order.expiresAt, }, }); } catch (error) { next(error); // 交给错误处理中间件 } }, async cancelOrder(req: Request, res: Response, next: NextFunction) { try { const { orderId } = req.params; const { reason } = CancelOrderSchema.parse(req.body); const order = await orderService.cancelOrder(orderId, reason, 'customer'); res.status(200).json({ success: true, data: { orderId: order.id, status: order.status }, }); } catch (error) { next(error); } }, }; // 错误处理中间件 —— 将业务错误映射为 HTTP 状态码 function errorHandler(err: Error, req: Request, res: Response, next: NextFunction) { if (err instanceof BusinessError) { const statusMap: Record<string, number> = { CUSTOMER_NOT_FOUND: 404, ORDER_NOT_FOUND: 404, PRODUCT_NOT_FOUND: 404, CUSTOMER_SUSPENDED: 403, INSUFFICIENT_INVENTORY: 409, ORDER_RATE_LIMIT_EXCEEDED: 429, ORDER_CANNOT_CANCEL: 409, PRODUCT_NOT_AVAILABLE: 422, }; const status = statusMap[err.code] ?? 400; return res.status(status).json({ success: false, error: { code: err.code, message: err.message }, }); } // 未知错误 console.error('Unhandled error:', err); res.status(500).json({ success: false, error: { code: 'INTERNAL_ERROR', message: '服务器内部错误' }, }); }

提示词模板:生成服务层代码

你是一位后端开发专家。请根据以下技术设计,生成完整的服务层代码。 ## 技术设计 [粘贴领域模型和服务层设计] ## 代码生成要求 ### Repository 层 - 定义接口(interface)在领域层 - 实现类使用 [Prisma / Drizzle / SQLAlchemy] - 包含数据映射方法(toDomain / toPersistence) - 所有查询方法返回领域对象,不返回 ORM 对象 ### Service 层 - 每个公开方法对应一个业务用例 - 方法内注释标注对应的业务规则编号 - 所有业务规则验证在 Service 层执行 - 使用依赖注入接收 Repository - 错误使用自定义 BusinessError 类 ### Controller 层 - 只负责 HTTP 协议转换 - 使用 Zod/Pydantic 验证请求参数 - 不包含任何业务逻辑 - 错误映射到合适的 HTTP 状态码 ### 通用要求 - 所有方法包含 JSDoc/docstring 注释 - 标注每个方法关联的需求编号 - 使用 TypeScript 严格模式 / Python type hints

5. AI 辅助业务规则实现

5.1 业务规则的分类与实现策略

规则类型描述AI 生成难度实现位置示例
验证规则输入数据的合法性检查⭐⭐(简单)Controller / Service 入口邮箱格式、金额范围、必填字段
计算规则基于输入计算输出⭐⭐⭐(中等)Service / Domain Service订单金额计算、折扣计算、税费计算
状态转换规则实体状态的合法转换⭐⭐⭐(中等)Entity / Aggregate Root订单状态机、审批流程
授权规则谁可以执行什么操作⭐⭐⭐⭐(较难)Service / Middleware只有订单所有者可以取消、管理员可以退款
跨聚合规则涉及多个聚合的业务约束⭐⭐⭐⭐⭐(困难)Application Service下单时检查库存、支付时检查订单状态
时间规则基于时间的业务逻辑⭐⭐⭐⭐(较难)Scheduled Job / Service超时自动取消、促销活动时间窗口

5.2 状态机模式

状态机是业务逻辑中最常见的模式之一。AI 生成状态机代码时,需要明确定义所有合法的状态转换。

// ============================================ // 状态机实现 // ============================================ /** 状态转换定义 */ const ORDER_TRANSITIONS: Record<OrderStatus, OrderStatus[]> = { [OrderStatus.PENDING_PAYMENT]: [OrderStatus.PAID, OrderStatus.CANCELLED], [OrderStatus.PAID]: [OrderStatus.PREPARING, OrderStatus.CANCELLED, OrderStatus.REFUNDING], [OrderStatus.PREPARING]: [OrderStatus.SHIPPED], [OrderStatus.SHIPPED]: [OrderStatus.DELIVERED], [OrderStatus.DELIVERED]: [OrderStatus.COMPLETED, OrderStatus.REFUNDING], [OrderStatus.COMPLETED]: [], // 终态 [OrderStatus.CANCELLED]: [], // 终态 [OrderStatus.REFUNDING]: [OrderStatus.REFUNDED], [OrderStatus.REFUNDED]: [], // 终态 }; /** 状态转换守卫(额外条件检查) */ type TransitionGuard = (order: Order, context: TransitionContext) => Promise<boolean>; const TRANSITION_GUARDS: Partial<Record<string, TransitionGuard>> = { // 从 paid 到 cancelled 需要检查是否已发货 [`${OrderStatus.PAID}->${OrderStatus.CANCELLED}`]: async (order) => { // 已开始备货的订单不能直接取消 return order.status === OrderStatus.PAID; }, // 从 delivered 到 refunding 需要在签收后 7 天内 [`${OrderStatus.DELIVERED}->${OrderStatus.REFUNDING}`]: async (order) => { if (!order.shippedAt) return false; const daysSinceDelivery = (Date.now() - order.shippedAt.getTime()) / (1000 * 60 * 60 * 24); return daysSinceDelivery <= 7; }, }; class OrderStateMachine { /** * 执行状态转换 * @throws BusinessError 如果转换不合法 */ async transition( order: Order, targetStatus: OrderStatus, context: TransitionContext ): Promise<Order> { // 1. 检查转换是否合法 const allowedTargets = ORDER_TRANSITIONS[order.status]; if (!allowedTargets.includes(targetStatus)) { throw new BusinessError( 'INVALID_STATUS_TRANSITION', `不允许从 ${order.status} 转换到 ${targetStatus}` ); } // 2. 执行转换守卫 const guardKey = `${order.status}->${targetStatus}`; const guard = TRANSITION_GUARDS[guardKey]; if (guard) { const allowed = await guard(order, context); if (!allowed) { throw new BusinessError( 'TRANSITION_GUARD_FAILED', `状态转换条件不满足:${guardKey}` ); } } // 3. 执行转换 return { ...order, status: targetStatus, updatedAt: new Date(), }; } }

5.3 定价引擎模式

复杂的定价逻辑是 AI 生成业务规则的典型场景。使用策略模式可以让定价规则可扩展、可测试。

// ============================================ // 定价引擎(策略模式) // ============================================ interface PricingContext { items: OrderItem[]; customerId: string; customerLevel: number; // VIP 等级 1-5 couponCode?: string; } interface PricingResult { subtotal: Money; shippingFee: Money; discount: Money; totalAmount: Money; discountType: DiscountType | null; appliedRules: string[]; // 记录应用了哪些规则(可审计) } /** 折扣规则接口 */ interface DiscountRule { name: string; priority: number; // 优先级越高越先执行 canApply(context: PricingContext, subtotal: number): boolean; calculate(context: PricingContext, subtotal: number): number; // 返回折扣金额(分) } /** VIP 免运费规则 */ const vipFreeShippingRule: DiscountRule = { name: 'VIP 免运费', priority: 10, canApply: (ctx) => ctx.customerLevel >= 3, calculate: () => 0, // 运费单独处理 }; /** 满 100 元打 9 折规则 */ const bulkOrderDiscountRule: DiscountRule = { name: '满 100 元 9 折', priority: 20, canApply: (_, subtotal) => subtotal >= 10000, // 10000 分 = 100 元 calculate: (_, subtotal) => Math.round(subtotal * 0.1), // 10% 折扣 }; class PricingService { private rules: DiscountRule[]; constructor(rules: DiscountRule[]) { // 按优先级排序 this.rules = [...rules].sort((a, b) => a.priority - b.priority); } async calculate(context: PricingContext): Promise<PricingResult> { // 1. 计算商品小计 const subtotalCents = context.items.reduce( (sum, item) => sum + item.unitPrice.amount * item.quantity, 0 ); // 2. 计算运费 const shippingFeeCents = context.customerLevel >= 3 ? 0 : 800; // VIP 免运费,否则 8 元 // 3. 应用折扣规则(只应用第一个匹配的规则) let discountCents = 0; let discountType: DiscountType | null = null; const appliedRules: string[] = []; for (const rule of this.rules) { if (rule.canApply(context, subtotalCents)) { discountCents = rule.calculate(context, subtotalCents); appliedRules.push(rule.name); break; // 只应用优先级最高的规则 } } // 4. 计算总金额 const totalCents = subtotalCents + shippingFeeCents - discountCents; return { subtotal: { amount: subtotalCents, currency: 'CNY' }, shippingFee: { amount: shippingFeeCents, currency: 'CNY' }, discount: { amount: discountCents, currency: 'CNY' }, totalAmount: { amount: Math.max(totalCents, 0), currency: 'CNY' }, discountType, appliedRules, }; } }

6. 事务管理与数据一致性

6.1 事务管理策略

事务管理是 AI 生成业务逻辑中最容易被忽略的部分。AI 倾向于生成”快乐路径”代码,忽略失败回滚和并发冲突。

策略适用场景复杂度AI 生成质量
数据库事务单数据库、单服务内的操作⭐⭐⭐⭐(较好)
乐观锁读多写少、冲突概率低⭐⭐⭐(一般)
悲观锁写多读少、冲突概率高⭐⭐⭐(一般)
Saga 模式跨服务的分布式事务⭐⭐(较差,需人工审核)
事件溯源需要完整审计轨迹⭐⭐(较差,需人工审核)
幂等性设计所有写操作⭐⭐⭐(一般)

6.2 数据库事务实现

TypeScript + Prisma 事务

class OrderService { /** * 创建订单 —— 使用数据库事务确保一致性 * * 事务范围: * 1. 创建订单记录 * 2. 创建订单项记录 * 3. 预扣库存 * 4. 记录操作日志 * * 如果任何步骤失败,所有操作回滚 */ async createOrderWithTransaction(input: CreateOrderInput): Promise<Order> { return this.prisma.$transaction(async (tx) => { // 1. 在事务内检查库存(使用 SELECT FOR UPDATE 防止并发超卖) for (const item of input.items) { const inventory = await tx.inventory.findUnique({ where: { productId: item.productId }, }); if (!inventory || inventory.available < item.quantity) { throw new BusinessError('INSUFFICIENT_INVENTORY', '库存不足'); } } // 2. 创建订单 const order = await tx.order.create({ data: { id: generateUUID(), orderNumber: generateOrderNumber(), customerId: input.customerId, status: 'pending_payment', totalAmountCents: input.totalAmountCents, items: { create: input.items.map(item => ({ productId: item.productId, quantity: item.quantity, unitPriceCents: item.unitPriceCents, })), }, }, include: { items: true }, }); // 3. 预扣库存 for (const item of input.items) { await tx.inventory.update({ where: { productId: item.productId }, data: { available: { decrement: item.quantity }, reserved: { increment: item.quantity }, }, }); } // 4. 记录操作日志 await tx.auditLog.create({ data: { entityType: 'order', entityId: order.id, action: 'create', performedBy: input.customerId, details: JSON.stringify({ items: input.items }), }, }); return order; }, { // 事务配置 maxWait: 5000, // 最大等待时间 5 秒 timeout: 10000, // 事务超时 10 秒 isolationLevel: 'Serializable', // 最高隔离级别防止并发问题 }); } }

Python + SQLAlchemy 事务

from sqlalchemy.orm import Session from contextlib import contextmanager class OrderService: def __init__(self, session_factory): self.session_factory = session_factory @contextmanager def _transaction(self): """事务上下文管理器""" session: Session = self.session_factory() try: yield session session.commit() except Exception: session.rollback() raise finally: session.close() def create_order(self, input_data: CreateOrderInput) -> Order: """创建订单 —— 使用事务确保一致性""" with self._transaction() as session: # 1. 检查库存(使用 FOR UPDATE 锁定行) for item in input_data.items: inventory = ( session.query(InventoryModel) .filter_by(product_id=item.product_id) .with_for_update() # 悲观锁 .first() ) if not inventory or inventory.available < item.quantity: raise BusinessError("INSUFFICIENT_INVENTORY", "库存不足") # 2. 创建订单 order = OrderModel( id=str(uuid4()), customer_id=input_data.customer_id, status=OrderStatus.PENDING_PAYMENT, total_amount=input_data.total_amount, ) session.add(order) # 3. 预扣库存 for item in input_data.items: session.query(InventoryModel).filter_by( product_id=item.product_id ).update({ "available": InventoryModel.available - item.quantity, "reserved": InventoryModel.reserved + item.quantity, }) # 事务在 with 块结束时自动提交 return self._to_domain(order)

6.3 乐观锁实现

// ============================================ // 乐观锁 —— 使用版本号防止并发冲突 // ============================================ // Prisma Schema // model Order { // id String @id // version Int @default(0) // 版本号 // status String // ... // } class OrderRepository { /** * 使用乐观锁更新订单 * 如果版本号不匹配(被其他事务修改过),抛出冲突错误 */ async updateWithOptimisticLock(order: Order): Promise<Order> { const result = await this.prisma.order.updateMany({ where: { id: order.id, version: order.version, // 只有版本号匹配才更新 }, data: { ...this.toPersistence(order), version: { increment: 1 }, // 版本号 +1 }, }); if (result.count === 0) { throw new ConcurrencyError( 'ORDER_CONCURRENT_MODIFICATION', '订单已被其他操作修改,请重试' ); } return { ...order, version: order.version + 1 }; } } // Service 层使用重试机制处理乐观锁冲突 class OrderService { async updateOrderWithRetry( orderId: string, updateFn: (order: Order) => Order, maxRetries: number = 3 ): Promise<Order> { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { const order = await this.orderRepo.findById(orderId); if (!order) throw new BusinessError('ORDER_NOT_FOUND', '订单不存在'); const updatedOrder = updateFn(order); return await this.orderRepo.updateWithOptimisticLock(updatedOrder); } catch (error) { if (error instanceof ConcurrencyError && attempt < maxRetries) { // 等待随机时间后重试(指数退避) await sleep(Math.pow(2, attempt) * 100 + Math.random() * 100); continue; } throw error; } } throw new BusinessError('MAX_RETRIES_EXCEEDED', '操作重试次数已达上限'); } }

6.4 幂等性设计

// ============================================ // 幂等性 —— 确保重复请求不会产生副作用 // ============================================ class IdempotentOrderService { constructor( private readonly orderService: OrderService, private readonly idempotencyStore: IdempotencyStore, ) {} /** * 幂等创建订单 * 使用 idempotencyKey 确保同一请求只执行一次 */ async createOrder( idempotencyKey: string, input: CreateOrderInput ): Promise<CreateOrderResult> { // 1. 检查是否已处理过 const existing = await this.idempotencyStore.get(idempotencyKey); if (existing) { return existing as CreateOrderResult; // 返回之前的结果 } // 2. 标记为处理中(防止并发重复请求) const locked = await this.idempotencyStore.lock(idempotencyKey, 60); // 60 秒锁 if (!locked) { throw new BusinessError('REQUEST_IN_PROGRESS', '请求正在处理中,请稍后'); } try { // 3. 执行业务逻辑 const result = await this.orderService.createOrder(input); // 4. 存储结果(24 小时过期) await this.idempotencyStore.set(idempotencyKey, result, 86400); return result; } catch (error) { // 5. 失败时释放锁,允许重试 await this.idempotencyStore.unlock(idempotencyKey); throw error; } } } // Controller 层从请求头获取幂等键 async function createOrderHandler(req: Request, res: Response) { const idempotencyKey = req.headers['idempotency-key'] as string; if (!idempotencyKey) { return res.status(400).json({ error: '缺少 Idempotency-Key 请求头' }); } const result = await idempotentOrderService.createOrder(idempotencyKey, req.body); res.status(201).json(result); }

提示词模板:生成事务管理代码

你是一位后端架构师,擅长数据一致性设计。请为以下业务场景生成事务管理代码。 ## 业务场景 [描述需要事务保护的业务操作] ## 一致性要求 1. 哪些操作必须在同一个事务中? 2. 失败时如何回滚? 3. 并发场景下如何处理冲突? 4. 是否需要幂等性保证? ## 技术约束 - 数据库:[PostgreSQL / MySQL] - ORM:[Prisma / Drizzle / SQLAlchemy] - 是否涉及跨服务调用:[是/否] ## 输出要求 1. 事务边界明确标注 2. 包含错误处理和回滚逻辑 3. 如果涉及并发,使用乐观锁或悲观锁 4. 如果需要幂等性,实现幂等键机制 5. 包含重试逻辑(指数退避) 6. 添加审计日志记录

7. Kiro Spec 工作流实战

7.1 Kiro Spec 工作流概述

Kiro 是目前唯一内置 Spec-Driven 工作流的 IDE。它将 SDD 的三阶段流程(需求→设计→任务)直接集成到开发环境中,开发者只需描述业务需求,Kiro 自动生成结构化的 Spec 文件。

Kiro Spec 工作流: 1. 开发者输入业务需求描述 2. Kiro 生成 requirements.md(EARS 格式验收标准) 3. 开发者审核并修改需求 4. Kiro 生成 design.md(技术设计文档) 5. 开发者审核并修改设计 6. Kiro 生成 tasks.md(原子化任务列表) 7. 开发者逐任务执行,Kiro Agent 辅助实现 8. 每个任务完成后人工审核

7.2 Kiro Spec 文件结构

.kiro/ └── specs/ └── order-system/ # 一个 Spec 对应一个功能模块 ├── requirements.md # 需求规约 ├── design.md # 技术设计 └── tasks.md # 任务列表

requirements.md 示例

# Requirements: 订单系统 ## Introduction 实现电商平台的核心订单系统,支持下单、支付、取消、退款等完整订单生命周期管理。 ## Requirements ### Requirement 1: 创建订单 **User Story:** As a 客户, I want 将购物车中的商品下单, so that 我能购买所需商品。 #### Acceptance Criteria 1. WHEN a customer submits an order with valid items, THE OrderService SHALL create an order with status "pending_payment" AND generate a unique order number in format ORD-YYYYMMDD-XXXX 2. WHEN a customer submits an order with items exceeding available inventory, THE OrderService SHALL reject the order AND return error INSUFFICIENT_INVENTORY 3. WHEN a customer has placed 10 or more orders in the past 24 hours, THE OrderService SHALL reject the new order AND return error ORDER_RATE_LIMIT_EXCEEDED 4. WHEN an order is created successfully, THE system SHALL reserve inventory for all order items AND set payment expiration to 30 minutes from creation time ### Requirement 2: 取消订单 **User Story:** As a 客户, I want 取消未发货的订单, so that 我能在改变主意时获得退款。 #### Acceptance Criteria 1. WHEN a customer cancels an order with status "pending_payment", THE OrderService SHALL update status to "cancelled" AND release reserved inventory 2. WHEN a customer cancels an order with status "paid", THE OrderService SHALL update status to "cancelled" AND release reserved inventory AND trigger a refund process 3. WHEN a customer attempts to cancel an order with status "shipped", THE OrderService SHALL reject the cancellation AND return error ORDER_ALREADY_SHIPPED with HTTP 409

design.md 示例(关键片段)

# Design: 订单系统 ## Architecture ### 领域模型 - **Order(聚合根)**:订单实体,包含订单项、状态、金额 - **OrderItem(值对象)**:订单项,包含商品信息和数量 - **Money(值对象)**:金额,以分为单位存储 ### 服务层 - **OrderRepository**:订单数据访问接口 - **OrderService**:订单业务逻辑编排 - **PricingService**:定价计算 - **InventoryService**:库存管理 ### 数据库 Schema | 表名 | 字段 | 类型 | 说明 | |------|------|------|------| | orders | id | UUID | 主键 | | orders | order_number | VARCHAR(20) | 业务编号,唯一索引 | | orders | customer_id | UUID | 外键 → customers | | orders | status | VARCHAR(20) | 订单状态枚举 | | orders | total_amount_cents | INTEGER | 总金额(分) | | orders | version | INTEGER | 乐观锁版本号 | | order_items | id | UUID | 主键 | | order_items | order_id | UUID | 外键 → orders | | order_items | product_id | UUID | 外键 → products | | order_items | quantity | INTEGER | 数量 | | order_items | unit_price_cents | INTEGER | 单价(分) |

tasks.md 示例

# Tasks: 订单系统 - [ ] 1. 领域模型层 - [ ] 1.1 创建 Order Entity 和 OrderItem Value Object 的 TypeScript 类型定义 - _Requirements: 1.1_ - [ ] 1.2 创建 Money Value Object 和 OrderStatus 枚举 - _Requirements: 1.1_ - [ ] 1.3 定义 OrderDomainEvent 类型(OrderCreated, OrderCancelled) - _Requirements: 1.1, 2.1_ - [ ] 2. 数据访问层 - [ ] 2.1 创建 Prisma Schema(orders, order_items 表) - _Requirements: 1.1_ - [ ] 2.2 实现 OrderRepository 接口和 Prisma 实现 - _Requirements: 1.1, 1.2_ - [ ] 3. 业务逻辑层 - [ ] 3.1 实现 PricingService(金额计算、折扣规则) - _Requirements: 1.1_ - [ ] 3.2 实现 OrderService.createOrder()(含库存检查、防刷单) - _Requirements: 1.1, 1.2, 1.3, 1.4_ - [ ] 3.3 实现 OrderService.cancelOrder()(含状态验证、退款触发) - _Requirements: 2.1, 2.2, 2.3_ - [ ] 4. API 层 - [ ] 4.1 实现 POST /orders 路由和请求验证 - _Requirements: 1.1_ - [ ] 4.2 实现 DELETE /orders/:id 路由 - _Requirements: 2.1_ - [ ] 5. 测试 - [ ] 5.1 OrderService.createOrder() 单元测试 - _Requirements: 1.1, 1.2, 1.3, 1.4_ - [ ] 5.2 OrderService.cancelOrder() 单元测试 - _Requirements: 2.1, 2.2, 2.3_

7.3 Steering 规则配合 Spec 工作流

Kiro 的 Steering 规则可以引导 AI Agent 在执行 Spec 任务时遵循特定的架构模式和编码规范。

# .kiro/steering/backend-architecture.md ## 架构规则 ### 服务层架构 - 所有业务逻辑必须在 Service 层实现,Controller 层禁止包含业务逻辑 - Repository 接口定义在 src/domain/ 目录,实现在 src/infrastructure/ 目录 - Service 层使用构造函数注入依赖,不使用全局单例 ### 领域模型规则 - Entity 必须包含 id、createdAt、updatedAt 字段 - Value Object 必须是 readonly(TypeScript)或 frozen(Python) - 所有金额使用整数(分)存储,不使用浮点数 - 状态枚举使用 string enum,不使用数字 ### 事务规则 - 所有写操作必须在事务中执行 - 跨聚合的操作使用领域事件,不在同一事务中修改多个聚合 - 所有写 API 必须支持幂等性(通过 Idempotency-Key 请求头) ### 错误处理 - 使用自定义 BusinessError 类,包含 code 和 message - 错误码使用 UPPER_SNAKE_CASE 格式 - Controller 层的错误处理中间件负责将 BusinessError 映射为 HTTP 状态码 ### 测试要求 - 每个 Service 方法必须有对应的单元测试 - 测试覆盖正常路径和所有异常路径 - 使用 Repository 接口的 mock 实现进行单元测试

7.4 Hooks 自动化

Kiro Hooks 可以在特定事件触发时自动执行操作,配合 Spec 工作流实现自动化质量保证。

# .kiro/hooks/backend-quality.yaml # 当 Service 文件被修改时,自动运行相关测试 - name: "Auto Test on Service Change" event: fileEdited filePatterns: "src/services/**/*.ts" action: askAgent prompt: "运行与修改文件相关的单元测试,报告测试结果" # 当创建新的 Repository 实现时,检查是否遵循接口 - name: "Repository Interface Check" event: fileCreated filePatterns: "src/infrastructure/repositories/**/*.ts" action: askAgent prompt: "检查新创建的 Repository 实现是否完整实现了对应的接口,是否包含 toDomain 和 toPersistence 映射方法" # 提交前检查业务逻辑是否有事务保护 - name: "Transaction Check" event: fileEdited filePatterns: "src/services/**/*.ts" action: askAgent prompt: "检查修改的 Service 方法中,所有写操作是否在事务中执行"

实战案例:用 Kiro Spec 工作流构建 SaaS 订阅计费系统

案例背景

一个 SaaS 产品需要实现订阅计费系统,支持多种计费模式(月付/年付)、试用期、升降级、按量计费附加项。这是一个典型的复杂业务逻辑场景。

步骤 1:在 Kiro 中创建 Spec

在 Kiro 中输入业务需求描述:

我需要一个 SaaS 订阅计费系统,支持以下功能: 1. 计划管理:Free / Pro / Enterprise 三个计划,支持月付和年付 2. 订阅生命周期:创建、激活、暂停、取消、过期 3. 试用期:Pro 计划提供 14 天免费试用 4. 升降级:支持计划间的升降级,按比例计算差价 5. 按量计费:API 调用次数超出计划配额后按量计费 6. 发票生成:每月自动生成发票

步骤 2:Kiro 生成需求规约(requirements.md)

Kiro 自动生成 EARS 格式的验收标准:

### Requirement 1: 订阅创建 **User Story:** As a 用户, I want 选择并订阅一个计划, so that 我能使用对应的产品功能。 #### Acceptance Criteria 1. WHEN a user selects the Pro plan with monthly billing, THE SubscriptionService SHALL create a subscription with: - status: "trialing" (if first-time Pro subscriber) - trial_ends_at: current_time + 14 days - billing_cycle: "monthly" - amount: 2900 cents ($29/month) 2. WHEN a user selects the Enterprise plan, THE SubscriptionService SHALL create a subscription with: - status: "active" (no trial for Enterprise) - billing_cycle: as selected (monthly: $99, yearly: $990) 3. WHEN a trial period ends without payment method on file, THE system SHALL update subscription status to "expired" AND downgrade user to Free plan features

步骤 3:审核需求并生成设计

开发者审核需求后,Kiro 生成技术设计:

## 领域模型 ### Subscription(聚合根) - id: UUID - userId: UUID - planId: string (free / pro / enterprise) - status: SubscriptionStatus - billingCycle: 'monthly' | 'yearly' - currentPeriodStart: Date - currentPeriodEnd: Date - trialEndsAt: Date | null - cancelledAt: Date | null - amountCents: number - version: number (乐观锁) ### UsageRecord(值对象) - subscriptionId: UUID - metric: string (api_calls / storage_gb / team_members) - quantity: number - recordedAt: Date ### Invoice(实体) - id: UUID - subscriptionId: UUID - periodStart: Date - periodEnd: Date - subtotalCents: number - taxCents: number - totalCents: number - status: 'draft' | 'open' | 'paid' | 'void'

步骤 4:逐任务执行

Kiro 生成任务列表后,开发者逐任务执行。以”实现升降级逻辑”为例:

// Task 3.4: 实现 SubscriptionService.changePlan() // Requirements: 4.1, 4.2 class SubscriptionService { /** * 变更订阅计划(升级或降级) * * 业务规则: * - 升级立即生效,按剩余天数计算差价 * - 降级在当前计费周期结束时生效 * - Free → Pro/Enterprise:视为新订阅 * - Enterprise → Pro:降级,周期结束生效 * - 任何计划 → Free:等同于取消订阅 */ async changePlan( subscriptionId: string, newPlanId: string, newBillingCycle: 'monthly' | 'yearly' ): Promise<SubscriptionChangeResult> { const subscription = await this.subscriptionRepo.findById(subscriptionId); if (!subscription) { throw new BusinessError('SUBSCRIPTION_NOT_FOUND', '订阅不存在'); } const currentPlan = PLANS[subscription.planId]; const newPlan = PLANS[newPlanId]; if (!newPlan) { throw new BusinessError('INVALID_PLAN', '无效的计划'); } // 判断是升级还是降级 const isUpgrade = newPlan.tier > currentPlan.tier; const isDowngrade = newPlan.tier < currentPlan.tier; if (isUpgrade) { return this.handleUpgrade(subscription, newPlan, newBillingCycle); } else if (isDowngrade) { return this.handleDowngrade(subscription, newPlan, newBillingCycle); } else { // 同级别切换计费周期 return this.handleBillingCycleChange(subscription, newBillingCycle); } } private async handleUpgrade( subscription: Subscription, newPlan: Plan, billingCycle: 'monthly' | 'yearly' ): Promise<SubscriptionChangeResult> { // 计算剩余天数的差价 const now = new Date(); const remainingDays = Math.ceil( (subscription.currentPeriodEnd.getTime() - now.getTime()) / (1000 * 60 * 60 * 24) ); const totalDays = Math.ceil( (subscription.currentPeriodEnd.getTime() - subscription.currentPeriodStart.getTime()) / (1000 * 60 * 60 * 24) ); const oldDailyRate = subscription.amountCents / totalDays; const newAmount = billingCycle === 'monthly' ? newPlan.monthlyPriceCents : newPlan.yearlyPriceCents; const newDailyRate = newAmount / (billingCycle === 'monthly' ? 30 : 365); const proratedCredit = Math.round(oldDailyRate * remainingDays); const proratedCharge = Math.round(newDailyRate * remainingDays); const amountDue = Math.max(proratedCharge - proratedCredit, 0); // 立即生效 const updatedSubscription = { ...subscription, planId: newPlan.id, billingCycle, amountCents: newAmount, updatedAt: now, }; await this.subscriptionRepo.updateWithOptimisticLock(updatedSubscription); return { subscription: updatedSubscription, effectiveDate: now, proratedAmountCents: amountDue, type: 'upgrade', }; } private async handleDowngrade( subscription: Subscription, newPlan: Plan, billingCycle: 'monthly' | 'yearly' ): Promise<SubscriptionChangeResult> { // 降级在当前周期结束时生效 const scheduledChange = { subscriptionId: subscription.id, newPlanId: newPlan.id, newBillingCycle: billingCycle, effectiveDate: subscription.currentPeriodEnd, createdAt: new Date(), }; await this.scheduledChangeRepo.save(scheduledChange); return { subscription, effectiveDate: subscription.currentPeriodEnd, proratedAmountCents: 0, type: 'downgrade_scheduled', }; } }

步骤 5:人工审核

每个任务完成后,开发者审核 AI 生成的代码,重点检查:

审核清单: ✅ 业务规则是否完整覆盖了需求规约中的验收标准? ✅ 边界条件是否处理?(金额为 0、剩余天数为 0、同计划切换) ✅ 事务是否正确?(升级的扣费和状态更新是否在同一事务中?) ✅ 并发安全?(两个请求同时升级同一订阅会怎样?) ✅ 错误处理是否完善?(每个失败路径都有明确的错误码?) ✅ 可审计性?(计费变更是否记录了审计日志?)

案例总结

维度Vibe Coding 方式Spec-Driven 方式
需求遗漏高(AI 猜测意图)低(EARS 格式明确每条规则)
边界条件经常遗漏在需求阶段就明确
代码可追溯性无(对话历史丢失)高(每行代码关联需求编号)
重构安全性低(缺少规约参照)高(Spec 文件持久化)
团队协作困难(上下文在个人会话中)容易(Spec 文件可共享)
开发时间初始快,后期慢(返工多)初始慢 15 分钟,后期快(返工少)

避坑指南

❌ 常见错误

  1. 跳过 Spec 直接让 AI 写业务逻辑

    • 问题:AI 会遗漏隐含的业务规则,生成的代码看起来能运行但逻辑不完整。例如订单系统缺少防刷单检查、缺少超时自动取消、缺少并发库存扣减保护
    • 正确做法:先花 15-30 分钟编写需求规约,明确所有业务规则和边界条件,再让 AI 按规约生成代码
  2. 把所有实体放在一个大聚合里(“上帝聚合”反模式)

    • 问题:AI 倾向于将所有相关实体放在一起(Order 包含 User、Product、Inventory),导致聚合过大、事务范围过广、并发冲突严重
    • 正确做法:遵循”一个事务只修改一个聚合”原则,聚合之间通过 ID 引用和领域事件通信
  3. 在 Controller 层编写业务逻辑

    • 问题:AI 经常将验证逻辑、计算逻辑、状态转换逻辑直接写在路由处理函数中,导致代码不可测试、不可复用
    • 正确做法:在 Steering 规则中明确禁止 Controller 包含业务逻辑,所有业务规则必须在 Service 层实现
  4. 忽略事务管理

    • 问题:AI 生成的代码通常只处理”快乐路径”,不考虑部分失败的回滚。例如创建订单成功但库存扣减失败,导致数据不一致
    • 正确做法:在 Spec 的设计文档中明确事务边界,要求 AI 在事务中执行所有相关写操作
  5. 使用浮点数存储金额

    • 问题:AI 默认使用 number 类型存储金额(如 price: 29.99),浮点数精度问题会导致计算错误(0.1 + 0.2 ≠ 0.3)
    • 正确做法:在 Steering 规则中要求所有金额以整数(分/cents)存储,使用 amountCents: number 或 Python 的 Decimal 类型
  6. 缺少幂等性设计

    • 问题:网络重试、用户重复点击会导致重复创建订单、重复扣款。AI 生成的 API 通常不考虑幂等性
    • 正确做法:所有写操作 API 要求客户端传递 Idempotency-Key 请求头,服务端实现幂等性检查
  7. 状态转换缺少守卫条件

    • 问题:AI 生成的状态机只检查”当前状态是否允许转换到目标状态”,不检查额外的业务条件(如”签收后 7 天内才能退货”)
    • 正确做法:为每个状态转换定义守卫条件(Guard),在 Spec 中明确列出
  8. 领域事件丢失

    • 问题:AI 在 Service 方法中直接调用其他 Service(如 OrderService 直接调用 InventoryService),导致紧耦合和事务边界混乱
    • 正确做法:跨聚合的操作通过领域事件解耦,使用事件总线或消息队列

✅ 最佳实践

  1. “15 分钟瀑布”规划法:每个功能模块开始前,花 15 分钟编写 Spec(需求 5 分钟 + 设计 5 分钟 + 任务 5 分钟),这 15 分钟的投入可以节省数小时的返工时间

  2. Steering 规则前置:在项目开始时就编写后端架构的 Steering 规则,确保 AI 从第一行代码就遵循正确的架构模式

  3. 金额计算使用整数:所有金额以”分”为单位存储和计算,只在展示层转换为”元”。这是金融系统的行业标准

  4. 每个 Service 方法对应一个用例:Service 方法的粒度应该与用户故事一一对应,方法名使用业务语言(createOrdercancelOrder),不使用技术语言(insertRecordupdateStatus

  5. 测试驱动验证:每个 Spec 任务完成后,先运行测试验证业务规则的正确性,再进行人工代码审查

  6. 版本化 Spec 文件:将 .kiro/specs/ 目录纳入 Git 版本控制,Spec 文件的变更历史就是业务规则的演进历史

  7. 聚合边界 = 微服务边界:如果未来需要拆分微服务,聚合边界就是天然的服务边界。在 Spec 阶段就做好聚合划分,为未来的架构演进打好基础


相关资源与延伸阅读

  1. Spec-Driven Development: Building Software in the AI Era  — SDD 方法论的系统介绍,涵盖从概念到实践的完整指南
  2. Why Spec-Driven Development Will Shape Elite Engineers  — 分析 SDD 如何改变工程师角色,从代码编写者到规约架构师
  3. Kiro: AWS’s Spec-Driven Agentic IDE  — Kiro IDE 的深度分析,包括 Spec 工作流和 Hooks 机制
  4. How to Enforce Architectural Patterns When AI Generates Your Code  — 当 AI 生成代码时如何维护架构一致性,包括 Repository 模式违规的实际案例
  5. Domain-Driven Design Reference  — Eric Evans 的 DDD 参考手册,领域建模的权威资源
  6. Spec-Driven Development for Tech Companies  — SDD 在企业团队中的实践,包括将交付时间从 6 个月缩短到 6 周的案例
  7. Prisma ORM Documentation  — Prisma ORM 官方文档,TypeScript 后端领域模型层的首选工具
  8. Patterns of Enterprise Application Architecture  — Martin Fowler 的企业应用架构模式目录,Repository、Service Layer、Unit of Work 等模式的权威参考

参考来源


📖 返回 总览与导航 | 上一节:28b-API设计与生成 | 下一节:28d-AI辅助认证实现

Last updated on