跳转至

用户故事实现细节

本文件与 user-story.csv 通过 story_id 关联。 CSV 负责状态和索引,本文件负责业务规则、边界、接口、数据和测试。 每个故事一节,并使用显式 HTML 锚点,保证 CSV 里的 details_ref(如 #us-001)始终能跳转:

<a id="us-001"></a>
## US-001 用户登录

US-001 用户登录

1. 目标

注册用户可以使用邮箱和密码登录系统,获得访问令牌,进入工作台。

2. 角色与权限

  • 已注册且状态为 active 的用户可以登录。
  • 被封禁/未验证用户不能登录。
  • 登录失败不暴露“邮箱是否存在”。

3. 入口与界面

  • 页面:/login
  • 字段:
字段 类型 必填 校验
邮箱 email 是 合法邮箱格式,≤ 254 字符
密码 password 是 8-72 字符
  • 状态:默认 / 提交中 / 错误 / 账号锁定
  • 交互:
  • 提交时禁用按钮,显示 loading。
  • 失败时保留邮箱,清空密码。
  • 成功后跳转到 redirect 参数指定页面,默认 /projects。

4. 业务规则

  1. 邮箱大小写不敏感,存储时统一小写。
  2. 密码使用 Argon2id 或 bcrypt 哈希校验。
  3. 连续 5 次失败锁定 15 分钟。
  4. 登录成功返回 access token(15 分钟)和 refresh token(7 天)。
  5. 所有登录尝试写审计日志(成功/失败/锁定)。
  6. 不在日志中记录密码或完整令牌。

5. 数据模型

  • 读:users
  • 写:audit_logs
  • 关键字段:id, email, password_hash, status, failed_login_count, locked_until

6. API

  • POST /api/v1/auth/login
  • 请求:
{
  "email": "user@example.com",
  "password": "********"
}
  • 成功:200
{
  "access_token": "...",
  "refresh_token": "...",
  "expires_in": 900,
  "user": {
    "id": "uuid",
    "email": "user@example.com",
    "display_name": "张三"
  }
}
  • 失败:
  • 400 VALIDATION_ERROR
  • 401 AUTH_INVALID_CREDENTIALS
  • 423 AUTH_ACCOUNT_LOCKED
  • 403 AUTH_ACCOUNT_DISABLED

7. 验收标准

AC-1 正常登录 Given 我是已注册且状态正常的用户 When 我输入正确邮箱和密码并提交 Then 返回 200,跳转到 /projects And 审计日志记录登录成功

AC-2 密码错误 Given 我是已注册用户 When 我输入错误密码 Then 返回 401 AUTH_INVALID_CREDENTIALS And 页面显示“邮箱或密码不正确”

AC-3 连续失败锁定 Given 我已经连续失败 5 次 When 我再次尝试登录 Then 返回 423 AUTH_ACCOUNT_LOCKED And 页面显示剩余锁定时间

AC-4 账号禁用 Given 我的账号状态为 disabled When 我尝试登录 Then 返回 403 AUTH_ACCOUNT_DISABLED And 页面提示联系管理员

8. 边界与异常

  • 邮箱不存在:返回与密码错误相同的提示。
  • 密码超长:400,不进行哈希计算。
  • 数据库不可用:503,记录 request_id。
  • 并发登录:允许多设备,刷新令牌可分别撤销。
  • 时区:锁定时间使用 UTC 存储。

9. 可观测性

  • 日志:request_id, user_id(成功时), result, duration_ms
  • 指标:login_total{result}, login_locked_total
  • 审计:action=auth.login, result=success/failure/locked

10. 依赖

  • 依赖:无。
  • 被依赖:所有需要登录的故事。

11. 完成定义

  • 单元测试:密码校验、锁定、禁用、错误码
  • 集成测试:数据库读写、审计
  • E2E:正常登录、密码错误、锁定
  • 实现报告
  • CSV 状态 qa_pass

US-xxx <标题>

1. 目标

<...>

2. 角色与权限

<...>

3. 入口与界面

  • 页面:<路由>
  • 字段:
字段 类型 必填 校验
<...> <...> <...> <...>
  • 状态:<默认/加载/空/错误/无权限>
  • 交互:<...>

4. 业务规则

  1. <...>
  2. <...>

5. 数据模型

  • 读:<表>
  • 写:<表>
  • 关键字段:<...>
  • 索引:<...>

6. API

  • <METHOD> <path>
  • 请求:
  • 成功:<状态码 / 示例>
  • 失败:<错误码列表>

7. 验收标准

AC-1 <名称> Given <...> When <...> Then <...> And <...>

AC-2 <异常> Given <...> When <...> Then <...>

AC-3 <权限> Given <...> When <...> Then <...>

8. 边界与异常

  • <空数据>
  • <超长/非法格式>
  • <权限不足>
  • <并发冲突>
  • <第三方失败>
  • <时区/编码>

9. 可观测性

  • 日志:<字段>
  • 指标:<指标名>
  • 审计:

10. 依赖

  • 依赖:
  • 被依赖:

11. 完成定义

  • 单元测试
  • 集成测试
  • E2E
  • 实现报告
  • CSV 状态更新

通用检查清单

每个故事在标记 qa_pass 前,确认:

  • 正常路径、异常路径、权限边界都有验收标准
  • 所有规则可测试
  • API 与 OpenAPI 一致
  • 数据表与 schema 一致
  • 错误码与统一错误模型一致
  • 前端状态齐全
  • 测试数据可清理
  • 依赖关系无环
  • 实现报告路径已写入 CSV
  • E2E manifest 路径已写入 CSV