返回笔记首页

第 13 集:AI 驱动的完整研发生命周期

主题配置

一、本集目标

用一个完整的功能需求(用户积分系统),走完研发生命周期的七个阶段,每个阶段用 AI 参与,串联前面十二集所有的知识点。

七个阶段:需求 → 设计 → 编码 → 测试 → Review → 部署 → 优化


二、演示功能:用户积分系统

原始需求(模拟产品经理给的需求)

plain
用户完成特定行为(下单、评价、邀请)后,给予积分奖励。积分可以用来兑换优惠券。

核心功能:
1. 积分记录:记录每次积分变动(来源、数量、变动后余额)
2. 积分查询:用户能查自己的积分余额和明细
3. 积分发放:下单成功后自动发放积分(1 元 = 10 积分)
4. 积分扣减:用积分兑换时扣减(只做扣减接口,兑换本身不做)

集成到现有的 NestJS 项目里(agent-demo 项目)

三、第一阶段:需求分析

原始需求的问题

产品经理给的需求通常存在以下问题:

  • 字段不完整(积分有没有有效期?)
  • 边界条件模糊(积分能不能为负?)
  • 业务规则不清楚(什么时候触发发放?订单创建还是完成?)

用 AI 做需求澄清

在 Cursor Chat 里输入:

plain
以下是一份用户积分系统的需求概要:

[粘贴原始需求]

作为需求分析专家,请:
1. 识别需求里模糊或有歧义的地方,列出你需要澄清的问题
2. 补全遗漏的需求细节
3. 输出一份完整的 PRD,包含:功能列表、数据字段、接口列表、边界条件

AI 通常会提出以下问题(提前准备好答案):

AI 的问题 回答
积分有没有有效期? 暂时没有
积分能不能为负? 不能,余额不足时抛出异常
什么时候发放积分? 订单状态变为 COMPLETED 时
积分发放是实时的还是异步的? 实时同步发放
积分余额存在哪里?单独表还是 User 表? User 表加 pointsBalance 字段

回答问题后,让 AI 生成完整 PRD:

plain
根据以下补充信息,生成完整的 PRD:
- 积分没有有效期
- 积分不能为负,余额不足时抛出 BadRequestException
- 订单状态变为 COMPLETED 时立即同步发放积分
- 积分余额存在 User 表的 pointsBalance 字段(Int 类型)

生成后的 PRD 内容(保存为 docs/points-prd.md

markdown
# 用户积分系统 PRD

## 数据字段

### User 表新增字段

| 字段          | 类型 | 说明                       |
| ------------- | ---- | -------------------------- |
| pointsBalance | Int  | 积分余额,默认 0,不能为负 |

### PointsRecord 表(新建)

| 字段         | 类型     | 说明                                 |
| ------------ | -------- | ------------------------------------ |
| id           | Int      | 自增主键                             |
| userId       | Int      | 用户 ID(外键)                      |
| amount       | Int      | 变动积分数(正数为增加,负数为减少) |
| balanceAfter | Int      | 变动后余额                           |
| source       | Enum     | ORDER / EXCHANGE / ADMIN             |
| sourceId     | String?  | 来源 ID(订单 ID 等)                |
| remark       | String?  | 备注                                 |
| createdAt    | DateTime | 记录时间                             |

## 接口列表

| 方法 | 路径                | 说明                 | 权限                   |
| ---- | ------------------- | -------------------- | ---------------------- |
| POST | /api/points/add     | 发放积分             | 仅管理员或系统内部调用 |
| POST | /api/points/deduct  | 扣减积分             | 登录用户               |
| GET  | /api/points/balance | 查询当前用户积分余额 | 登录用户               |
| GET  | /api/points/history | 查询积分明细(分页) | 登录用户               |

## 业务规则

1. 积分余额不能为负,扣减前检查余额是否足够
2. 发放和扣减必须在数据库事务中同时更新 pointsBalance 和创建 PointsRecord
3. 发放积分接口需要权限校验,普通用户不能自己给自己发积分
4. 查询接口只能查自己的积分(管理员可以查所有人)

## 边界条件

- 余额不足时:抛出 BadRequestException('积分余额不足')
- 用户不存在时:抛出 NotFoundException('用户不存在')
- amount <= 0 时:抛出 BadRequestException('积分数量必须大于 0')

四、第二阶段:数据库设计

用 AI 设计 Prisma Schema

在 Chat 里输入:

plain
根据 @docs/points-prd.md 里的数据字段设计,完成以下内容:
1. 在 prisma/schema.prisma 里新增 PointsRecord model
2. 在 User model 上新增 pointsBalance 字段
3. 说明索引设计的理由

检查生成的 Schema:

plain
enum PointsSource {
  ORDER
  EXCHANGE
  ADMIN
}

model User {
  // 已有字段...
  pointsBalance  Int            @default(0)
  pointsRecords  PointsRecord[]
}

model PointsRecord {
  id           Int          @id @default(autoincrement())
  userId       Int
  amount       Int
  balanceAfter Int
  source       PointsSource
  sourceId     String?
  remark       String?
  createdAt    DateTime     @default(now())

  user         User         @relation(fields: [userId], references: [id])

  @@index([userId, createdAt])  // 查询某用户的积分历史,常见查询
  @@index([source, sourceId])   // 根据来源查记录(防重复发放)
}

关键设计决策解释

决策 原因
pointsBalance
存在 User 表
查询余额 O(1),不需要 SUM 聚合,性能更好
balanceAfter
存在每条记录里
审计用,能追溯任意时间点的积分余额
联合索引 (userId, createdAt) 查询某用户的历史记录时走索引,不全表扫描
amount
可以是负数
一张表统一记录发放和扣减,正数=发放,负数=扣减

执行 migration:

bash
npx prisma migrate dev --name add-points-system
npx prisma generate

五、第三阶段:编码

用 Agent 生成完整模块

在 Agent 模式(Cmd+I)输入:

plain
根据 @docs/points-prd.md 和 @prisma/schema.prisma,生成完整的 PointsModule。

需要创建的文件:
1. src/modules/points/dto/add-points.dto.ts
2. src/modules/points/dto/deduct-points.dto.ts
3. src/modules/points/dto/find-points-history.dto.ts(分页参数)
4. src/modules/points/points.service.ts
5. src/modules/points/points.controller.ts
6. src/modules/points/points.module.ts

关键实现要求:
- addPoints 和 deductPoints 必须用 prisma.$transaction 包裹,同时更新 pointsBalance 和创建 PointsRecord
- deductPoints 必须先检查余额是否足够,不足抛出 BadRequestException
- addPoints 需要 @Roles(UserRole.ADMIN) 权限校验
- 所有接口加 Swagger 注解

代码审查清单

Agent 完成后,逐一检查:

**points.service.ts**的关键逻辑:

typescript
// 期望看到的 addPoints 实现
async addPoints(addPointsDto: AddPointsDto): Promise<ResponseDto<PointsRecord>> {
  const { userId, amount, source, sourceId, remark } = addPointsDto;

  // 必须用事务,保证余额更新和记录创建的原子性
  const record = await this.prisma.$transaction(async (tx) => {
    const user = await tx.user.findUnique({ where: { id: userId } });
    if (!user) throw new NotFoundException('用户不存在');

    const balanceAfter = user.pointsBalance + amount;

    // 更新余额
    await tx.user.update({
      where: { id: userId },
      data: { pointsBalance: balanceAfter },
    });

    // 创建记录
    return await tx.pointsRecord.create({
      data: { userId, amount, balanceAfter, source, sourceId, remark },
    });
  });

  return { code: 0, data: record, message: 'ok' };
}
typescript
// 期望看到的 deductPoints 实现
async deductPoints(deductPointsDto: DeductPointsDto): Promise<ResponseDto<PointsRecord>> {
  const { userId, amount, source, sourceId, remark } = deductPointsDto;

  const record = await this.prisma.$transaction(async (tx) => {
    const user = await tx.user.findUnique({ where: { id: userId } });
    if (!user) throw new NotFoundException('用户不存在');

    // 关键:余额检查
    if (user.pointsBalance < amount) {
      throw new BadRequestException('积分余额不足');
    }

    const balanceAfter = user.pointsBalance - amount;

    await tx.user.update({
      where: { id: userId },
      data: { pointsBalance: balanceAfter },
    });

    return await tx.pointsRecord.create({
      data: { userId, amount: -amount, balanceAfter, source, sourceId, remark },
    });
  });

  return { code: 0, data: record, message: 'ok' };
}

如果 Agent 生成的代码没有用事务,在 Chat 里说:

plain
points.service.ts 里的 addPoints 方法没有用事务,
更新 pointsBalance 和创建 PointsRecord 是两个独立的数据库操作,
如果第一步成功第二步失败会导致数据不一致。
请改成用 prisma.$transaction 包裹这两个操作

六、第四阶段:测试

生成单元测试

在 Chat 里输入:

plain
@src/modules/points/points.service.ts @src/modules/points/dto/add-points.dto.ts

为 PointsService 生成单元测试 src/modules/points/points.service.spec.ts。

重点测试:
1. addPoints:正常发放,余额正确更新
2. addPoints:用户不存在时抛出 NotFoundException
3. deductPoints:正常扣减,余额正确更新
4. deductPoints:余额不足时抛出 BadRequestException
5. getBalance:正常返回余额
6. getHistory:正常返回分页历史记录

要求:
- Mock PrismaService,包含 $transaction
- $transaction 的 Mock:接受一个回调函数并立即执行
- 测试描述用中文

**$transaction**的 Mock 写法(这是容易出错的地方):

typescript
const mockPrismaService = {
    user: {
        findUnique: jest.fn(),
        update: jest.fn(),
    },
    pointsRecord: {
        create: jest.fn(),
        findMany: jest.fn(),
        count: jest.fn(),
    },
    $transaction: jest.fn().mockImplementation((callback) => {
        // 把 mockPrismaService 自身传给 callback,模拟 tx 参数
        return callback(mockPrismaService)
    }),
}

运行测试:

bash
npm test -- points.service.spec.ts --verbose

七、第五阶段:Code Review

AI 安全扫描

bash
claude "扫描 src/modules/points/ 目录下所有文件,检查以下安全问题:
1. addPoints 接口是否有权限校验(普通用户不能给自己发积分)
2. deductPoints 是否有余额检查
3. 有没有并发安全问题(两个请求同时扣减,可能超扣)
4. 接口参数有没有校验(amount 必须大于 0)
输出问题清单和修复建议"

并发安全问题的处理

AI 可能会指出:如果两个请求同时发起 deductPoints,两个请求都查到余额充足,但实际上总扣减额超过了余额。

这个问题的解决方案:

typescript
// 方案一:数据库层面的原子更新(推荐)
// 用 Prisma 的 updateMany + where 条件,利用数据库的行锁
await tx.user.updateMany({
    where: {
        id: userId,
        pointsBalance: { gte: amount }, // 只有余额足够才更新
    },
    data: {
        pointsBalance: { decrement: amount },
    },
})

// 检查是否真的更新成功(如果没有更新,说明余额不足或并发冲突)
const updatedUser = await tx.user.findUnique({ where: { id: userId } })
if (updatedUser!.pointsBalance < 0) {
    throw new BadRequestException('积分余额不足')
}

规范检查

plain
@src/modules/points/ @docs/engineering/code-style.md

检查 points 模块的代码是否符合 code-style.md 里的规范,
列出不符合的地方

八、第六阶段:部署配置

生成 Dockerfile

在 Chat 里输入:

plain
为这个 NestJS 项目生成 Dockerfile,要求:
1. 多阶段构建(build 阶段 + production 阶段)
2. production 镜像只包含运行时文件,不包含 devDependencies
3. 使用 node:20-alpine 基础镜像
4. 暴露 3000 端口

期望生成的 Dockerfile:

dockerfile
# 第一阶段:构建
FROM node:20-alpine AS builder

WORKDIR /app

# 先复制 package.json,利用 Docker 层缓存
COPY package*.json ./
COPY prisma ./prisma/

RUN npm ci

COPY . .

RUN npm run build
RUN npx prisma generate

# 第二阶段:运行
FROM node:20-alpine AS production

WORKDIR /app

COPY package*.json ./

# 只安装 production 依赖
RUN npm ci --only=production

# 从构建阶段复制编译产物
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules/.prisma ./node_modules/.prisma
COPY prisma ./prisma/

EXPOSE 3000

CMD ["node", "dist/main"]

生成 docker-compose.yml

plain
生成 docker-compose.yml,包含两个服务:
1. app:这个 NestJS 应用
2. postgres:PostgreSQL 16 数据库

app 依赖 postgres,等 postgres 健康后才启动
所有配置通过环境变量传入,不硬编码

期望生成的 docker-compose.yml

yaml
version: '3.8'

services:
    postgres:
        image: postgres:16-alpine
        environment:
            POSTGRES_DB: ${POSTGRES_DB:-agent_demo}
            POSTGRES_USER: ${POSTGRES_USER:-postgres}
            POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
        volumes:
            - postgres_data:/var/lib/postgresql/data
        ports:
            - '5432:5432'
        healthcheck:
            test: ['CMD-SHELL', 'pg_isready -U postgres']
            interval: 10s
            timeout: 5s
            retries: 5

    app:
        build: .
        ports:
            - '3000:3000'
        environment:
            DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-agent_demo}
            JWT_SECRET: ${JWT_SECRET}
            NODE_ENV: production
        depends_on:
            postgres:
                condition: service_healthy
        command: >
            sh -c "npx prisma migrate deploy && node dist/main"

volumes:
    postgres_data:

生成 CI/CD 配置

plain
生成 .github/workflows/deploy.yml,实现:
1. main 分支有 push 时触发
2. 运行测试,测试不通过就停止
3. 构建 Docker 镜像
4. 推送镜像到 Docker Hub
5. SSH 到服务器,拉新镜像并重启容器

九、第七阶段:优化建议

基于日志分析(模拟场景)

假设项目上线后,日志里出现以下情况:

plain
积分查询接口 /api/points/history 的平均响应时间:800ms
积分余额查询接口 /api/points/balance 的平均响应时间:50ms

在 Chat 里输入:

plain
@src/modules/points/points.service.ts

积分历史查询接口的响应时间是 800ms,余额查询只有 50ms。
分析 getHistory 方法,找出可能的性能瓶颈,并给出优化方案

AI 通常会给出以下建议:

问题 优化方案
每次查询都做 COUNT(两次查询) 用游标分页代替 offset 分页,去掉 COUNT
没有索引 确认 (userId, createdAt)
索引存在
返回了不需要的字段 用 select 只返回必要字段
频繁查询热点用户 引入 Redis 缓存余额,TTL 5 分钟

十、完整流程回顾

阶段 AI 做的事 人做的事
需求 识别模糊点、生成 PRD 回答澄清问题、确认 PRD 正确
设计 设计 Schema、解释索引逻辑 审查设计决策、确认业务规则
编码 生成 DTO、Service、Controller 审查事务逻辑、权限校验
测试 生成测试用例、运行测试 检查覆盖场景是否足够
Review 安全扫描、规范检查 确认修复方案合理
部署 生成 Dockerfile、CI/CD 配置 审查配置参数、执行部署
优化 分析性能瓶颈、提建议 判断哪个方案合适、决策

AI 做:生成、执行、扫描

人做:决策、审查、确认


十一、演示操作步骤汇总

bash
# 第一阶段:需求分析
# 在 Cursor Chat 里用需求澄清 Prompt
mkdir -p docs
touch docs/points-prd.md
# 把 AI 生成的 PRD 内容写入文件

# 第二阶段:数据库设计
# 在 Chat 里生成 Schema,检查字段和索引
npx prisma migrate dev --name add-points-system
npx prisma generate

# 第三阶段:编码
# 在 Agent 模式里生成完整模块
# 审查事务逻辑
npm run start:dev
# 访问 http://localhost:3000/api 验证 Swagger 文档

# 第四阶段:测试
# 在 Chat 里生成测试文件
npm test -- points.service.spec.ts --verbose
npm test -- --coverage

# 第五阶段:Review
claude "扫描 src/modules/points/ 检查安全问题"

# 第六阶段:部署
mkdir -p .github/workflows
touch Dockerfile docker-compose.yml .github/workflows/deploy.yml
# 用 AI 生成三个文件内容

# 验证 Docker 构建
docker build -t agent-demo:latest .
docker-compose up -d

# 第七阶段:优化
# 模拟日志分析场景,用 AI 给出优化建议

Spec Coding 实战补充:13 AI 驱动的完整研发生命周期

来源:Spec Coding实战/13 AI 驱动的完整研发生命周期.md,已合并到本章节。

概述

这一节把前面所有内容串联起来,走一遍完整的研发生命周期,展示 AI 在每个阶段具体能做什么、怎么做。

以一个真实场景为例:为电商系统新增"优惠券"功能模块


阶段一:需求分析(AI 深度生成 PRD)

输入

产品经理的原始需求(往往很模糊):

plain
我们需要一个优惠券系统,用户可以领取优惠券,
下单时可以使用,要支持满减和折扣两种类型。

AI 辅助需求深化

plain
基于以下初步需求,帮我生成一份完整的 PRD 草稿:

"用户可以领取优惠券,下单时可以使用,
 支持满减和折扣两种类型"

请深化以下方面:
1. 优惠券的完整属性(有效期、使用条件、限领次数等)
2. 用户领取的流程和限制
3. 下单使用时的校验逻辑
4. 边界情况(券过期、已用完、不满足使用条件)
5. 管理后台需要的功能(发券、停用、查看使用情况)

输出结构化 PRD,包含功能列表和验收标准。

AI 生成的 PRD 片段

markdown
## 优惠券系统 PRD

### 优惠券核心属性

- code: 唯一码(用户兑换码)
- type: FIXED_AMOUNT(满减)| PERCENTAGE(折扣)
- value: 优惠金额(满减时为减免元数,折扣时为折扣率 0-1)
- minOrderAmount: 最低使用门槛(0 表示无门槛)
- totalQuantity: 总发放量(null 表示不限量)
- perUserLimit: 每人限领次数(默认 1)
- startAt / expiredAt: 有效期
- status: ACTIVE | PAUSED | EXPIRED

### 验收标准

- [ ] 券过期时,领取接口返回 COUPON_EXPIRED 错误
- [ ] 超出总量时,领取接口返回 COUPON_OUT_OF_STOCK 错误
- [ ] 超出个人限领次数,返回 COUPON_LIMIT_EXCEEDED
- [ ] 下单金额不满足门槛时,使用接口返回 COUPON_CONDITION_NOT_MET
- [ ] 同一张券不能在同一订单中使用两次

人工核对的重点: 验收标准是否覆盖了所有边界场景,业务规则描述是否准确,对照产品经理确认。


阶段二:系统设计(AI 辅助架构设计)

输入

确认后的 PRD

AI 辅助生成设计文档

plain
基于 @docs/coupon-prd.md 的需求,帮我设计优惠券系统的技术方案:

1. 数据模型设计(Prisma Schema)
   - 需要哪些表?表之间的关系?
   - 关键字段的类型和约束
   - 需要哪些索引?

2. 接口设计
   - 用户侧接口(领取、查看、使用)
   - 管理侧接口(创建、发放、停用)
   - 每个接口的请求/响应格式

3. 并发处理方案
   - 高并发领券如何防止超发?
   - 使用时如何防止重复使用?

4. 与订单模块的集成点
   - 在订单创建的哪个步骤校验优惠券?
   - 订单取消时优惠券如何处理?

生成的数据模型

plain
model Coupon {
  id              String       @id @default(uuid())
  code            String       @unique
  name            String
  type            CouponType
  value           Decimal      @db.Decimal(10, 2)
  minOrderAmount  Decimal      @default(0) @db.Decimal(10, 2) @map("min_order_amount")
  totalQuantity   Int?         @map("total_quantity")
  claimedCount    Int          @default(0) @map("claimed_count")
  perUserLimit    Int          @default(1) @map("per_user_limit")
  startAt         DateTime     @map("start_at")
  expiredAt       DateTime     @map("expired_at")
  status          CouponStatus @default(ACTIVE)
  createdAt       DateTime     @default(now()) @map("created_at")
  updatedAt       DateTime     @updatedAt @map("updated_at")

  userCoupons     UserCoupon[]

  @@index([code])
  @@index([status, expiredAt])
  @@map("coupons")
}

model UserCoupon {
  id         String           @id @default(uuid())
  userId     String           @map("user_id")
  couponId   String           @map("coupon_id")
  status     UserCouponStatus @default(UNUSED)
  usedAt     DateTime?        @map("used_at")
  orderId    String?          @map("order_id")
  claimedAt  DateTime         @default(now()) @map("claimed_at")

  coupon     Coupon @relation(fields: [couponId], references: [id])

  @@unique([userId, couponId])  // 同一用户同一券只能有一条记录(配合 perUserLimit)
  @@index([userId, status])
  @@map("user_coupons")
}

enum CouponType   { FIXED_AMOUNT  PERCENTAGE }
enum CouponStatus { ACTIVE PAUSED EXPIRED }
enum UserCouponStatus { UNUSED USED EXPIRED }

人工核对的重点: 并发场景下的数据一致性(领券超发问题)、与订单表的关联方式、索引是否足够。


阶段三:编码实现(AI 生成代码快速迭代)

基于 spec 生成代码

先把设计文档整理成 spec/coupon.md,然后:

plain
按照 @spec/coupon.md 实现优惠券模块:

src/modules/coupon/
- coupon.module.ts
- coupon.controller.ts(用户侧接口)
- coupon.service.ts
- admin-coupon.controller.ts(管理侧接口)
- dto/claim-coupon.dto.ts
- dto/use-coupon.dto.ts
- dto/create-coupon.dto.ts

重点注意:
1. 领券接口需要用数据库事务+乐观锁防止超发
2. 使用优惠券时要校验有效期、门槛、使用状态
3. 订单取消时调用 releaseCoupon(orderId) 方法归还券

遵循 .cursorrules,完整 import。

防超发的关键实现

这是并发场景下最重要的逻辑,需要人工验证 AI 的实现是否正确:

typescript
async claimCoupon(userId: string, code: string): Promise<UserCoupon> {
  return this.prisma.$transaction(async (tx) => {
    // 悲观锁查询(SELECT ... FOR UPDATE)
    const coupon = await tx.$queryRaw<Coupon[]>`
      SELECT * FROM coupons
      WHERE code = ${code} AND status = 'ACTIVE'
      FOR UPDATE
    `
    if (!coupon[0]) throw new BusinessException(ErrorCode.COUPON_NOT_FOUND)

    const c = coupon[0]

    // 有效期校验
    const now = new Date()
    if (now < c.startAt || now > c.expiredAt) {
      throw new BusinessException(ErrorCode.COUPON_EXPIRED)
    }

    // 总量校验
    if (c.totalQuantity !== null && c.claimedCount >= c.totalQuantity) {
      throw new BusinessException(ErrorCode.COUPON_OUT_OF_STOCK)
    }

    // 个人限领校验
    const userClaimedCount = await tx.userCoupon.count({
      where: { userId, couponId: c.id },
    })
    if (userClaimedCount >= c.perUserLimit) {
      throw new BusinessException(ErrorCode.COUPON_LIMIT_EXCEEDED)
    }

    // 领取:原子性扣减库存
    await tx.coupon.update({
      where: { id: c.id },
      data: { claimedCount: { increment: 1 } },
    })

    return tx.userCoupon.create({
      data: { userId, couponId: c.id },
    })
  })
}

阶段四:测试验证(AI 生成测试自动化执行)

plain
为 @src/modules/coupon/coupon.service.ts 生成完整单元测试。

重点覆盖:
- claimCoupon:正常领取、过期券、超出总量、超出个人限额
- useCoupon:正常使用、券已使用、不满足金额门槛、券不属于该用户
- releaseCoupon:订单取消归还、只归还 USED 状态的券

Mock Prisma 的 $transaction 方法,
写完后运行 npm test,不通过就修,直到全部通过。

阶段五:代码审查(AI Review 质量把关)

bash
git diff main...HEAD | claude "
  Review 优惠券模块的实现:

  必须检查:
  1. 领券防超发逻辑是否正确(并发安全)
  2. 使用券时是否有权限校验(用户只能用自己的券)
  3. 有没有遗漏的边界条件

  性能检查:
  1. 用户优惠券列表查询是否有合理索引
  2. 是否有不必要的全表扫描

  输出发现的问题和修复建议。
"

阶段六:部署发布(AI 辅助持续交付)

AI 辅助生成部署配置

plain
帮我生成优惠券模块上线所需的配置:

1. 数据库迁移检查清单
   - 新增了哪些表和字段
   - 迁移是否向后兼容(不影响旧版本在线实例)
   - 是否需要数据回填

2. 部署前检查项
   - 环境变量是否有新增
   - 是否需要清除缓存

3. 回滚方案
   - 如果上线后发现严重 bug,如何快速回滚
   - 回滚时数据库怎么处理

检查迁移兼容性

plain
读取 @prisma/migrations/ 下最新的迁移文件,
分析这次迁移是否向后兼容:
- 是否有删除列或重命名列的操作?
- 新增的 NOT NULL 列是否有默认值?
- 如果当前版本代码和新版本代码同时运行(蓝绿部署),会不会有问题?

阶段七:运维监控(AI 异常检测智能告警)

接入生产日志分析

bash
# 分析最近一小时的错误日志
tail -1000 /var/log/app/error.log | claude "
  分析这些错误日志:
  1. 出现频率最高的错误是什么?
  2. 有没有和优惠券相关的异常(COUPON_*)?
  3. 有没有数据库超时或连接失败的迹象?
  4. 有没有需要立即处理的高危错误?

  按紧急程度排序输出。
"

异常流量识别

plain
分析这段 nginx 访问日志,找出异常流量模式:
- 是否有针对 /coupons/claim 接口的刷量行为(同一 IP 高频请求)
- 是否有异常的错误率峰值
- 响应时间 P99 是否有突升

[粘贴日志片段]

阶段八:持续优化(AI 分析反馈持续改进)

性能分析

plain
查看 @src/modules/coupon/coupon.service.ts 的 claimCoupon 方法,
结合以下慢查询日志,分析为什么在高并发下响应变慢,
给出优化方案:

慢查询日志:
[粘贴 PostgreSQL 慢查询日志]

用户反馈分析

plain
以下是用户关于优惠券功能的反馈,
帮我分类整理,识别出哪些是 bug、哪些是体验问题、
哪些是新功能需求,并按优先级排序:

[粘贴用户反馈列表]

整个生命周期的 AI 参与度总结

阶段 AI 参与度 人工核心工作
需求分析 中:深化需求,生成 PRD 草稿 业务判断、与产品对齐
系统设计 中:生成数据模型和接口设计 架构决策、并发方案
编码实现 高:生成完整模块代码 核心算法验证、安全逻辑审查
测试验证 高:生成并执行测试 验收标准制定、边界场景补充
代码审查 高:安全扫描、质量检查 业务逻辑正确性
部署发布 中:生成配置、检查兼容性 上线决策、风险判断
运维监控 中:日志分析、异常识别 处置决策、升级响应
持续优化 中:性能分析、反馈整理 优先级决策、方向把控

规律:越是规律性、重复性、模式化的工作,AI 参与度越高;越是需要业务判断和全局决策的工作,人工参与度越高。


小结

AI 驱动的研发生命周期不是把人替换掉,而是让人从大量机械性工作中解放出来,聚焦在真正需要人类判断的地方

  • 需求正确不正确
  • 架构是否合适
  • 这个风险该不该接受
  • 这个 bug 的优先级

这些判断依然是人的核心价值所在。