---
name: user-stories
description: 把一个功能想法或 PRD 中的一节拆成“作为……，我想要……，以便……”格式的用户故事，每个故事都有用 Given/When/Then（假如/当/那么）场景写的验收标准、边界情况和不在范围内的说明，再逐个用 INVEST 检查。用于有人要用户故事、工单、验收标准、待办拆解，或者说“把这个功能拆成故事”，用在 Jira、Linear 或某个迭代里的时候。
---

# 带验收标准的用户故事

好的用户故事写清谁得到什么、为什么，验收标准则准确说明团队怎么判断它已经完成。“以便”这一句不是装饰：如果写不出来，这个故事可能就不值得做。每个故事都应该小到一个迭代内能完成，并且不用问作者就能测试。

## 适用场景

- PRD 或功能简报已经定下来，工作需要进入待办列表。
- 已经有工单，但没人说得清什么时候算完成。
- 一个大功能需要在估算之前先拆分。
- 不适用于决定要不要做这个功能：先用 prd-from-notes 或 feature-prioritization。

## 需要准备

- 功能描述、PRD 中的相关章节或笔记。
- 涉及的用户类型（客户、管理员、访客）。没有的话问一次；仍然没有就写“用户”，并标注“[假设：角色]”。
- 已知的规则和限制（权限、套餐限制、格式）。没有给出的都列为待确认问题，而不是编造规则。

## 步骤

1. **列出角色及其目标。** 为每个角色写出他们想用这个功能完成什么。一个故事只对应一个角色；“用户和管理员”的故事就是 2 个故事。
2. **每个故事都按“作为……，我想要……，以便……”来写。** Dan North 认为这个模板逼着作者写明价值。“以便”写的是用户在乎的结果，而不是把功能再说一遍。如果老实写出来的“以便”只是“因为我们说要做”，就把这个故事标为考虑砍掉。
3. **按用户能看到的切片拆分。** 按工作流步骤、业务规则的不同情形、数据类型拆，或者先做正常路径、再做异常情况。绝不按技术层拆分（“后端故事”“前端故事”）：每个故事都必须交付用户能试用的东西。
4. **用 Given/When/Then 写验收标准。** 假如（Given）= 起始状态。当（When）= 那一个动作。那么（Then）= 可观察到的结果。额外条件用“并且”连接。每个故事写 2 到 5 个场景（本技能的默认值）：正常路径、至少 1 条失败路径，以及所有规则边界。
5. **列出边界情况。** 逐个故事检查：数据为空、输入超长、重复、没有权限、连接中断、同一操作做两次，以及对现有数据有什么影响。每个边界情况要么变成一个场景，要么列入不在范围内。
6. **写不在范围内的说明。** 写明这个故事有意不做什么，免得评审的人有错误预期。
7. **做 INVEST 检查。** Bill Wake 的 INVEST：独立（Independent）、可协商（Negotiable）、有价值（Valuable）、可估算（Estimable）、小（Small）、可测试（Testable）。每个字母标通过或不通过。S 不通过就继续拆。T 不通过说明验收标准太模糊。I 不通过就写明依赖关系。

## 输出格式

```markdown
# 用户故事：[功能]

## 故事 [n]：[简短标题]
**作为** [角色]，**我想要** [能力]，**以便** [结果]。

**验收标准**
- **场景：[名称]**
  假如 [起始状态]
  当 [动作]
  那么 [可观察到的结果]

**边界情况**
- [情况] → [由场景 x 覆盖 / 不在范围内]

**不在范围内**
- [这个故事不做的事]

**INVEST：** I [通过/不通过] · N [通过/不通过] · V [通过/不通过] · E [通过/不通过] · S [通过/不通过] · T [通过/不通过] — [对不通过项的说明]

## 待确认问题
- [输入中没有说明的规则或限制]
```

## 示例

**输入：**“所有者应该可以把自己的会计邀请为只读用户。只读用户不能修改任何东西。所有者可以移除他们。”

**输出：**

```markdown
# 用户故事：给会计的只读席位

## 故事 1：邀请只读用户
**作为** 账户所有者，**我想要** 通过邮箱以只读身份邀请某人，**以便** 我的会计不用等我导出文件就能查看我的数据。

**验收标准**
- **场景：所有者发送邀请**
  假如 我是账户所有者，正在“团队”页面
  当 我输入一个邮箱地址，选择“只读”，然后点击“发送邀请”
  那么 对方会收到一封邀请邮件
  并且 对方出现在团队列表中，显示为“只读，已邀请”
- **场景：该邮箱已在团队中**
  假如 这个邮箱属于一位现有团队成员
  当 我向它发送只读邀请
  那么 我看到“此人已在你的团队中”，并且不会发出邀请

**边界情况**
- 邮箱格式无效 → 在输入框旁显示错误，由表单现有的校验覆盖 [假设]
- 邀请一直没有被接受 → 不在范围内（是否过期是待确认问题）

**不在范围内**
- 把现有成员的角色改为只读。

**INVEST：** I 通过 · N 通过 · V 通过 · E 通过 · S 通过 · T 通过

## 故事 2：只读用户可以查看但不能修改
**作为** 拥有只读权限的会计，**我想要** 看到所有者能看到的每一个页面，**以便** 我能核对账目，而不用担心改动任何内容。

**验收标准**
- **场景：查看发票**
  假如 我以只读用户身份登录
  当 我打开“发票”页面
  那么 我能看到所有发票
  并且 页面上不显示“新建”“编辑”或“删除”按钮
- **场景：修改被拦截**
  假如 我以只读用户身份登录
  当 我通过收藏的编辑页链接尝试修改一张发票
  那么 我看到“你只有查看权限”，并且没有任何内容被保存

**边界情况**
- 导出为 CSV → 待确认问题：导出算不算“修改”？

**不在范围内**
- 只读用户发表评论或备注。

**INVEST：** I 通过 · N 通过 · V 通过 · E 通过 · S 不通过 · T 通过 — 涉及每一个页面；如果估算超过一个迭代，就按页面分组（发票、客户、设置）拆分。

## 故事 3：移除只读用户
**作为** 账户所有者，**我想要** 移除一位只读用户，**以便** 不再合作的会计失去访问权限。

**验收标准**
- **场景：所有者移除访问权限**
  假如 我的团队里有一位只读用户
  当 我点击“移除”并确认
  那么 对方在 [待确认：多久之内？] 内被登出，并且无法再登录这个账户
- **场景：被移除的用户尝试重新登录**
  假如 某位只读用户已被移除
  当 对方尝试登录这个账户
  那么 登录被拒绝，并且看不到这个账户的任何数据

**不在范围内**
- 向被移除的人发送移除通知。

**INVEST：** I 不通过（需要故事 1） · N 通过 · V 通过 · E 通过 · S 通过 · T 通过 — 依赖故事 1。

## 待确认问题
- 邀请会过期吗？多久过期？
- 只读用户能导出数据吗？
- 每个账户最多可以有多少个只读用户？
```

## 发送前检查

- [ ] 每个故事只有一个角色，“以便”写的是用户在乎的结果。
- [ ] 每个故事至少有 1 个失败路径场景。
- [ ] 每个“那么”都能在屏幕上或数据里观察到，而不是“正常运行”。
- [ ] 没有输入中不存在的规则、限制或数字；缺失的都列为待确认问题。
- [ ] 每个故事都有 INVEST 一行，每个不通过项都有说明。
- [ ] 没有按技术层拆分的故事。

## 常见错误

- “作为用户，我想要一个按钮”这样的故事。写结果，而不是写控件。
- 验收标准只是把故事复述一遍。每个场景都必须是测试人员可能测出不通过的东西。
- 把 3 个功能藏在一个故事的场景里。如果场景需要不同的角色或界面，就拆开。
