Cursor 老项目实战
接手已有仓库:先理解系统,再做一次最小修改。不是把老项目重做成新项目。
阶段含义见 AI Coding 工作流。文件正文只在 项目落地包。概念见 Context & Rules。
适用:Java / Spring 外包接手、二开、加一个小功能。
下文用工单列表说明。你的仓库把 ticket / biz_ticket 换成真实名字即可,不要改章节标题。
最大的风险不是 AI 不会写代码,而是它不知道这段代码为什么这样写。
先理解,再修改。 不因为旧代码不漂亮,就顺手重做架构。
代码 → 理解 → Context → Rules → Spec
→ 最小修改 → 测试 → Review → Debug / 回归 → 交付架构整段跳过。 架构已经在仓库里。这次要读懂它,不是用 AI 再设计一套。发现架构问题只记下来;真要重构,另开任务、另写 Spec。
0. 第一天不要做的事
- 不要让 AI「重构整个项目」
- 不要先装一堆 Skill
- 没有
99-gotchas.md时,不要改对外接口 - 扫描结果没经人改过,不要写业务代码
1. 扫描:只弄清这一条链
不比谁扫的文件多。这次要回答:
从哪进入 → 经过哪些层 → 碰什么数据 → 得出什么结果工单示例只碰已有列表:GET /api/tickets。沿 Controller → Service → Mapper / SQL → 表 biz_ticket。配置和依赖只记与这条链有关的。Entity 里对不上的字段写「待确认」。
AI 可以扫描、整理。扫出来的只是候选,不是事实。一次只写一个文件,你删掉猜错的句子。
概览 → docs/ai-context/00-overview.md
根据仓库依赖和启动类,写 docs/ai-context/00-overview.md。
标题只许有:项目概览、做什么、技术栈、本地启动、本阶段不做。
只写代码里能看到的事实。看不出的启动方式写「待确认」。不要编业务背景。模块 → docs/ai-context/01-modules.md
根据 Controller 写 docs/ai-context/01-modules.md。
只写这次会碰的那一条调用链和相关表。
字段必须能在 Entity 或 XML 里对上,对不上写「待确认」,不要猜。坑 → docs/ai-context/99-gotchas.md
人写,不让 AI 编。能填则填:不能改的路径、历史脏数据、不要模仿的写法。
工单示例里,人至少要写下「/api/tickets 已被外部调用,路径不能改」。历史数据里的小写 open 这类兼容,也由人写。
2. Context
上一步三个文件,经你改完,才是 Context:从代码、表、配置、接口和实际行为里抽出的事实。不是「这次要加过滤」。
看不出的保持「待确认」。AI 的猜测删掉再往下走。
3. Rules
把落地包里的 AGENTS.md 和 00-core.mdc 放进仓库,技术栈改成扫描结果。不在这里贴全文。
AGENTS.md:项目卡。不是这次过滤的任务书。- Rules:所有任务都遵守。不擅自改表,不擅自改已有 API,不扩大范围,沿现有调用链和写法,不确定就停。
「加 status 参数、不传参数要与改前一致」是 Spec,不要写进 00-core.mdc。
4. Spec
人确认这份 Spec 之后,才许改代码。
写入 docs/ai-context/specs/list-status-filter.md。有任务再新建,不预建空目录。只有这四个标题。
# 列表增加 status 过滤
## 目标
已有 GET /api/tickets 增加可选参数 status。
## 范围
- 做:这一条列表查询
- 模块:扫描确认的那一条 Controller → Service → Mapper
- 不做:新接口、新表、改状态机、改 URL、改其他模块
## 做到什么
- 不传 status:结果与改前一致
- status=OPEN:只返回 OPEN
- 已有的其他状态:按该状态查
- 非法值:按项目现有方式失败,不要当成查全部
## 验收
- 不传参数与改前一致
- status=OPEN 只有 OPEN这是一次修改的约定,不是重做工单系统。
人冻结。AI可以起草。
5. 最小修改
Spec 已确认
→ 沿已有调用链找改点
→ 只改这一处
→ 人看 Diff工单列表应落在现有链上:Controller → Service → Mapper → SQL。条件加在已有查询上。
不要新建一套 Service,不要另开查询接口,不要改 URL,不要重构状态,不要顺手统一风格或升级框架。Spec 没写的都不做。
阅读 docs/ai-context/specs/list-status-filter.md
和 docs/ai-context/01-modules.md、99-gotchas.md。
只改 Spec「范围」里的那一条查询。
不要做「不做」里的事。提问方式见 Prompt Pattern · 实现。
人看 Diff 是否只动了查询。AI按 Spec 改。
6. 测试
新项目只要证明功能做出来了。老项目还要证明原来的行为还在。
对照 Spec:
- 不传
status:与改前一致 status=OPEN:只有 OPEN
有单测就跑单测。没有就固定这两支 curl。不在这里写测试理论。见 Prompt Pattern · 测试。
人判定过不过。创建、改状态这次没要求重测一遍,放到回归里抽查。
7. Review
测试之后看 Diff。AI 初检,人判断。
- 是否只做了 Spec 里的过滤
- 是否违反 Rules(改表、改 URL、加依赖)
- 是否出现顺手重构、无关文件
- 不传参数的行为是否还在
| 现象 | 处理 |
|---|---|
| Diff 里出现登录、Redis、顺手优化 | 禁令补进 00-core.mdc,回到 Spec,不要接着写 |
| 字段和表对不上 | 先改 01-modules.md,停止写功能 |
| 无关文件 | 回滚那些文件,收紧范围再改 |
做法在 AI Code Review。本页不复制 Prompt。
第 5 步没通过之前,不接更大的需求。
8. Debug / 回归
测试或 Review 没失败,就跳过。不要为了走流程找茬。
若失败,例如不传 status 时列表变了:复现这条请求,缩小到这次加的 SQL 条件,看 Diff,不要重写查询方法。改完再测「不传」和「OPEN」两支。
回归不是把系统重测一遍。Spec 没点名的旧行为要抽查:创建、改状态、99-gotchas.md 里写过的路径和兼容(例如历史小写 open 仍能读)。证明这次没有偷偷改掉它们。
人决定修到哪。AI帮着定位,不整段重写。见 Prompt Pattern · Debug。
9. 交付
- Spec 里的验收过了
- 不传
status与改前一致 - Diff 里没有无关修改
- 说得清改了哪一条链、怎么验
[ ] 00-overview 的技术栈和本地启动是真的
[ ] 01-modules 的表字段和代码一致
[ ] 99-gotchas 写了不能动的接口
[ ] AGENTS.md 与 00-core.mdc 已提交
[ ] specs/list-status-filter.md 与实际改动一致
[ ] 第 6 节两支请求自己打过没有新的 Spec,就不重构。不写发布流程。
和新项目的差别
新项目从需求和架构进入,见 新项目实战。
老项目从代码进入,不重新设计架构。看不到架构一节,是有意跳过。
新项目:需求 → 拆解 → 架构 → Context → Rules → Spec → 实现
老项目:代码 → 理解 → Context → Rules → Spec → 修改汇合之后才相同:
Context → Rules → Spec → 实现或修改
→ 测试 → Review → Debug / 回归 → 交付Context 的来源不同:新项目是人写下的已知事实;老项目是扫出来、再由人删掉猜测。