@chenguangyao/devflow-kit 0.1.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +232 -0
- package/LICENSE +21 -0
- package/README.md +539 -0
- package/bin/devflow.js +9 -0
- package/docs/RFC-001-devflow-kit.md +617 -0
- package/docs/RFC-002-workflow-kernel.md +134 -0
- package/docs/enterprise-integration-supplement.md +274 -0
- package/docs/internal-gitlab-setup.md +426 -0
- package/docs/marketplace-skills.md +231 -0
- package/docs/migration-from-arb.md +232 -0
- package/docs/tooling-overview.md +774 -0
- package/docs/workflow-orchestration.md +695 -0
- package/docs/workflow-ui-prototype.html +271 -0
- package/package.json +52 -0
- package/schemas/config.schema.json +51 -0
- package/schemas/delta.schema.json +22 -0
- package/schemas/state.schema.json +130 -0
- package/schemas/status-surface.schema.json +197 -0
- package/schemas/workflow-confirmation-surface.schema.json +70 -0
- package/schemas/workflow-picker.schema.json +94 -0
- package/scripts/postinstall.js +101 -0
- package/scripts/render-workflow-ui-prototype.js +271 -0
- package/skills/apply/SKILL.md +313 -0
- package/skills/apply/references/discipline-checklist.md +145 -0
- package/skills/apply/references/subagent-implementer-prompt.md +113 -0
- package/skills/apply/references/subagent-orchestration.md +150 -0
- package/skills/apply/references/subagent-reviewer-prompt.md +180 -0
- package/skills/apply/references/tdd-loop.md +287 -0
- package/skills/apply/references/when-plan-is-wrong.md +279 -0
- package/skills/apply/references/worktree-swarm.md +292 -0
- package/skills/archive/SKILL.md +229 -0
- package/skills/archive/references/conflict-resolution.md +336 -0
- package/skills/archive/references/knowledge-deposit.md +381 -0
- package/skills/archive/references/spec-merge.md +365 -0
- package/skills/brainstorm/SKILL.md +123 -0
- package/skills/brainstorm/references/proposal-template.md +244 -0
- package/skills/brainstorm/references/question-catalog.md +168 -0
- package/skills/brainstorm/references/session-template.md +184 -0
- package/skills/ci-fix/SKILL.md +63 -0
- package/skills/ci-fix/references/loop.md +25 -0
- package/skills/code-review/SKILL.md +279 -0
- package/skills/code-review/references/escalation-playbook.md +192 -0
- package/skills/code-review/references/language-cheatsheets/go.md +175 -0
- package/skills/code-review/references/language-cheatsheets/java-spring-mybatis.md +246 -0
- package/skills/code-review/references/language-cheatsheets/python.md +170 -0
- package/skills/code-review/references/language-cheatsheets/vue.md +199 -0
- package/skills/code-review/references/output-template.md +275 -0
- package/skills/code-review/references/review-checklist.md +251 -0
- package/skills/complexity-grading/SKILL.md +259 -0
- package/skills/deliver/SKILL.md +271 -0
- package/skills/deliver/references/delivery-modes.md +299 -0
- package/skills/deliver/references/notify.md +359 -0
- package/skills/deliver/references/pr-description.md +319 -0
- package/skills/dependency-upgrade/SKILL.md +57 -0
- package/skills/dependency-upgrade/references/risk-matrix.md +38 -0
- package/skills/df-orchestrator/SKILL.md +407 -0
- package/skills/df-orchestrator/references/complexity-grading.md +177 -0
- package/skills/df-orchestrator/references/escalation-matrix.md +191 -0
- package/skills/df-orchestrator/references/routing-rules.md +290 -0
- package/skills/df-orchestrator/references/workflow-state-machine.md +208 -0
- package/skills/frontend-quality/SKILL.md +61 -0
- package/skills/frontend-quality/references/checklist.md +35 -0
- package/skills/handoff-resume/SKILL.md +59 -0
- package/skills/handoff-resume/references/handoff-template.md +54 -0
- package/skills/plan/SKILL.md +166 -0
- package/skills/plan/references/task-breakdown.md +207 -0
- package/skills/plan/references/task-sequencing.md +143 -0
- package/skills/plan/references/task-template.md +248 -0
- package/skills/requirement-analysis/SKILL.md +499 -0
- package/skills/requirement-analysis/references/acceptance-criteria.md +183 -0
- package/skills/requirement-analysis/references/code-recon.md +151 -0
- package/skills/requirement-analysis/references/edge-case-catalog.md +164 -0
- package/skills/requirement-analysis/references/requirement-template.md +339 -0
- package/skills/requirement-analysis/references/scope-negotiation.md +162 -0
- package/skills/security-hardening/SKILL.md +60 -0
- package/skills/security-hardening/references/checklist.md +42 -0
- package/skills/tech-spec/SKILL.md +388 -0
- package/skills/tech-spec/references/api-contract-design.md +172 -0
- package/skills/tech-spec/references/decision-records.md +110 -0
- package/skills/tech-spec/references/design-template.md +301 -0
- package/skills/tech-spec/references/rollout-and-rollback.md +203 -0
- package/skills/tech-spec/references/spec-delta-conventions.md +250 -0
- package/skills/tech-spec/references/transaction-patterns.md +212 -0
- package/skills/test-spec/SKILL.md +219 -0
- package/skills/test-spec/references/coverage-strategy.md +218 -0
- package/skills/test-spec/references/edge-case-to-test.md +143 -0
- package/skills/test-spec/references/test-case-template.md +276 -0
- package/skills/verify/SKILL.md +232 -0
- package/skills/verify/references/nfr-verification.md +292 -0
- package/skills/verify/references/report-templates.md +510 -0
- package/skills/verify/references/self-test-guide.md +240 -0
- package/skills/verify/references/verify-rollback-map.md +247 -0
- package/src/cli/commands/_helpers.js +108 -0
- package/src/cli/commands/_submit.js +718 -0
- package/src/cli/commands/apply.js +198 -0
- package/src/cli/commands/archive.js +180 -0
- package/src/cli/commands/checkpoint.js +113 -0
- package/src/cli/commands/deliver.js +377 -0
- package/src/cli/commands/deploy.js +504 -0
- package/src/cli/commands/design.js +158 -0
- package/src/cli/commands/disable.js +21 -0
- package/src/cli/commands/doctor.js +178 -0
- package/src/cli/commands/enable.js +21 -0
- package/src/cli/commands/flow.js +645 -0
- package/src/cli/commands/help.js +93 -0
- package/src/cli/commands/ingest.js +602 -0
- package/src/cli/commands/init.js +341 -0
- package/src/cli/commands/knowledge.js +523 -0
- package/src/cli/commands/logs.js +43 -0
- package/src/cli/commands/new.js +202 -0
- package/src/cli/commands/plan.js +49 -0
- package/src/cli/commands/propose.js +27 -0
- package/src/cli/commands/provider.js +698 -0
- package/src/cli/commands/report.js +143 -0
- package/src/cli/commands/requirement.js +227 -0
- package/src/cli/commands/review.js +301 -0
- package/src/cli/commands/skills.js +457 -0
- package/src/cli/commands/status.js +925 -0
- package/src/cli/commands/switch.js +27 -0
- package/src/cli/commands/sync.js +47 -0
- package/src/cli/commands/test.js +366 -0
- package/src/cli/commands/uninstall.js +32 -0
- package/src/cli/commands/update.js +74 -0
- package/src/cli/commands/verify.js +354 -0
- package/src/cli/commands/worktree.js +78 -0
- package/src/cli/index.js +72 -0
- package/src/cli/parse-args.js +102 -0
- package/src/core/autodetect.js +271 -0
- package/src/core/change.js +208 -0
- package/src/core/checkpoint.js +217 -0
- package/src/core/config.js +60 -0
- package/src/core/delta.js +290 -0
- package/src/core/markers.js +59 -0
- package/src/core/paths.js +173 -0
- package/src/core/plan-tasks.js +36 -0
- package/src/core/project-routing.js +285 -0
- package/src/core/projects.js +200 -0
- package/src/core/state.js +200 -0
- package/src/core/workflow-check.js +177 -0
- package/src/core/workflow-init.js +34 -0
- package/src/core/workflow-picker.js +154 -0
- package/src/core/workflow-policy.js +119 -0
- package/src/core/workflow-suggest.js +181 -0
- package/src/core/workflow-verify.js +88 -0
- package/src/core/workflow.js +433 -0
- package/src/core/worktree.js +241 -0
- package/src/knowledge/categories.js +107 -0
- package/src/knowledge/classify.js +125 -0
- package/src/knowledge/deposit.js +414 -0
- package/src/knowledge/migrate.js +149 -0
- package/src/knowledge/mr.js +219 -0
- package/src/knowledge/query.js +131 -0
- package/src/knowledge/registry.js +151 -0
- package/src/knowledge/sync.js +179 -0
- package/src/providers/base.js +74 -0
- package/src/providers/drivers/api-yapi.js +78 -0
- package/src/providers/drivers/ci-jenkins.js +109 -0
- package/src/providers/drivers/intake-confluence.js +544 -0
- package/src/providers/drivers/kb-git.js +549 -0
- package/src/providers/drivers/kb-weknora.js +472 -0
- package/src/providers/drivers/notify-smtp.js +515 -0
- package/src/providers/drivers/observability-oss.js +43 -0
- package/src/providers/drivers/observability-sls.js +50 -0
- package/src/providers/lifecycle.js +135 -0
- package/src/providers/loader.js +132 -0
- package/src/providers/local.js +190 -0
- package/src/providers/userconfig.js +283 -0
- package/src/reports/aggregate.js +185 -0
- package/src/reports/coverage.js +163 -0
- package/src/reports/detect.js +143 -0
- package/src/reports/parse.js +236 -0
- package/src/templates/files/ci/github.yml +38 -0
- package/src/templates/files/ci/gitlab.yml +27 -0
- package/src/templates/files/design.md +63 -0
- package/src/templates/files/ide/devflow-workflow.md +58 -0
- package/src/templates/files/ide/project-overview-reference.md +1 -0
- package/src/templates/files/ide/project-overview.md +27 -0
- package/src/templates/files/knowledge-index.json +17 -0
- package/src/templates/files/knowledge.md +28 -0
- package/src/templates/files/meta.json +8 -0
- package/src/templates/files/plan.md +38 -0
- package/src/templates/files/proposal.md +33 -0
- package/src/templates/files/reports/contract-test.md +40 -0
- package/src/templates/files/reports/e2e-test.md +30 -0
- package/src/templates/files/reports/integration-test.md +36 -0
- package/src/templates/files/reports/joint-test.md +58 -0
- package/src/templates/files/reports/perf.md +24 -0
- package/src/templates/files/reports/regression.md +20 -0
- package/src/templates/files/reports/remote-test.md +55 -0
- package/src/templates/files/reports/self-test.md +43 -0
- package/src/templates/files/reports/smoke-test.md +22 -0
- package/src/templates/files/reports/unit-test.md +36 -0
- package/src/templates/files/requirement.md +51 -0
- package/src/templates/files/review.md +38 -0
- package/src/templates/files/tests.md +36 -0
- package/src/templates/files/verify.md +32 -0
- package/src/templates/index.js +21 -0
- package/src/utils/log.js +37 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# requirement-analysis / code-recon
|
|
2
|
+
|
|
3
|
+
Round 2 的代码侦察方法论。目的:**把 agent 能自己回答的问题先答了,不要扔给用户**。侦察得好 = Round 2 问用户的问题从 10 个变成 2 个。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 侦察范围(侦察什么)
|
|
8
|
+
|
|
9
|
+
从 Round 1 的功能需求 + 用户故事里提取关键词,按下面维度扫:
|
|
10
|
+
|
|
11
|
+
| 维度 | 侦察目标 | 用什么 |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| **入口层** | 已有相关的 Controller / Handler / Route? | `Grep "<功能名>|<模块名>"` + `Glob` |
|
|
14
|
+
| **服务层** | 已有相关的 Service / Manager? | `Grep "class.*Service"` |
|
|
15
|
+
| **数据层** | 已有相关的 DAO / Mapper / ORM model? | `Grep "<表名>Repository|<Entity>"` |
|
|
16
|
+
| **契约** | 已有 DTO / Request / Response? | `Glob "**/dto/**"` / OpenAPI 文件 |
|
|
17
|
+
| **事件 / 消息** | 已有相关 event / topic? | `Grep "@EventListener|@KafkaListener"` |
|
|
18
|
+
| **测试** | 已有相关的单元测试?(作为反向文档) | `Glob "**/<keyword>*Test*"` |
|
|
19
|
+
| **配置** | 相关的 feature flag / config? | `Grep "<module>.enabled"` |
|
|
20
|
+
| **文档** | README / ADR / runbook 里有没有约束? | `Grep -r "<keyword>" docs/` |
|
|
21
|
+
|
|
22
|
+
## 侦察深度(侦察到什么程度)
|
|
23
|
+
|
|
24
|
+
**按 level 决定**:
|
|
25
|
+
|
|
26
|
+
| Level | 侦察深度 |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| **L1** | 读 1-2 个核心文件即可(主要看是否有兼容约束) |
|
|
29
|
+
| **L2** | 绘制出"入口 → Service → DAO"一层调用链 + 找到复用点 |
|
|
30
|
+
| **L3** | 绘制出完整跨模块调用关系 + 标注并发 / 事务边界 |
|
|
31
|
+
|
|
32
|
+
不要**读全仓库**;侦察是"带问题去读",不是"读完再说"。
|
|
33
|
+
|
|
34
|
+
## 侦察产物(怎么写进 requirement.md)
|
|
35
|
+
|
|
36
|
+
侦察结果写进 `§5. 数据 / 接口影响` 的 "代码侦察结论" 子节:
|
|
37
|
+
|
|
38
|
+
```markdown
|
|
39
|
+
### 代码侦察结论
|
|
40
|
+
- 主要改动位于: `<module>/<path>/<file>`
|
|
41
|
+
- 复用的现有能力: `<ExistingService.method>`(行号 + 一句话用途)
|
|
42
|
+
- 注意项:
|
|
43
|
+
- <事务 / 并发 / 兼容性坑>
|
|
44
|
+
- <已有的兼容逻辑不能破坏>
|
|
45
|
+
- <同类功能的 2 个实现要选一个>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**关键**:侦察结论要**可被 design.md 直接用**,而不是"我大概看了一下"。
|
|
49
|
+
|
|
50
|
+
## 侦察后的追问(Round 2 问题)
|
|
51
|
+
|
|
52
|
+
侦察会暴露 3 类只能问用户的问题:
|
|
53
|
+
|
|
54
|
+
### 1. "多选一"(代码里有 ≥ 2 个同类实现)
|
|
55
|
+
|
|
56
|
+
- 例:`GrantService` 和 `LegacyGrantService` 并存 → "本次在哪个上扩?"
|
|
57
|
+
- 例:两个 `CouponController` 版本 → "v1 弃用了还是要兼容?"
|
|
58
|
+
|
|
59
|
+
### 2. "契约语义"(代码里字段含义模糊,注释缺)
|
|
60
|
+
|
|
61
|
+
- 例:`status` 字段的取值 1,2,3 含义不明 → "状态 1 是待发放还是已发放?"
|
|
62
|
+
- 例:`batch_id` 是必填还是可空 → "NULL 语义是什么?"
|
|
63
|
+
|
|
64
|
+
### 3. "跨系统依赖"(侦察到调用外部服务,但不知道能不能用)
|
|
65
|
+
|
|
66
|
+
- 例:GrantService 调了 `billing.feign.GrantFeignClient` → "billing 服务对外接口是否已稳定?有没有 TTL?"
|
|
67
|
+
|
|
68
|
+
## 侦察的停止条件(何时停)
|
|
69
|
+
|
|
70
|
+
- 所有 F-ID 都能对应到现有代码(能扩) 或 确认不存在(全新)
|
|
71
|
+
- "多选一" / "契约语义" / "跨系统依赖" 已经列出所有待问项
|
|
72
|
+
- 读过的文件总数 ≤ 10(L2)或 ≤ 20(L3);超过说明偏题
|
|
73
|
+
|
|
74
|
+
## 侦察时不要做的事
|
|
75
|
+
|
|
76
|
+
- **不要改代码**:requirement 阶段就是读,不要一边读一边想动手
|
|
77
|
+
- **不要越级**:不要试图在侦察中设计方案,那是 tech-spec 的事
|
|
78
|
+
- **不要往 requirement 里塞实现细节**:requirement 只写"有啥、怎样配合",不写"Service 怎么拆"
|
|
79
|
+
- **不要把 tests 当权威**:现有测试可能过时 / 低覆盖,仅做参考
|
|
80
|
+
|
|
81
|
+
## 完整侦察示例(L2 新功能 `add-coupon-batch-grant`)
|
|
82
|
+
|
|
83
|
+
### Step 1:从 F-ID 抽关键词
|
|
84
|
+
|
|
85
|
+
F-01: 批量发放接口 → 关键词: `coupon`, `grant`, `batch`
|
|
86
|
+
F-02: 风控逐条应用 → 关键词: `RiskService`
|
|
87
|
+
F-03: 后台批量选择 → 关键词: `admin`, `upload`
|
|
88
|
+
|
|
89
|
+
### Step 2:按维度扫
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
Grep "couponGrant" --glob "**/*.java" --type java
|
|
93
|
+
Grep "class.*CouponController"
|
|
94
|
+
Grep "class.*GrantService"
|
|
95
|
+
Grep "class.*RiskService"
|
|
96
|
+
Glob "**/coupon/controller/**"
|
|
97
|
+
Glob "**/coupon/service/**"
|
|
98
|
+
Grep "@Transactional" --glob "**/GrantService.java"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Step 3:逐文件读关键段
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
Read coupon-service/src/main/java/.../GrantController.java # 50 lines 起
|
|
105
|
+
Read coupon-service/src/main/java/.../GrantService.java # 看 grantOne 方法
|
|
106
|
+
Read coupon-service/src/main/java/.../RiskService.java # 看 check 方法签名
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Step 4:产出结论(写进 requirement.md §5)
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
### 代码侦察结论
|
|
113
|
+
- 主要改动:
|
|
114
|
+
- 新增 `BatchGrantController`(在 controller/ 下)
|
|
115
|
+
- `GrantService.grantOne`(L125-L180)已有单发,复用
|
|
116
|
+
- 复用:
|
|
117
|
+
- `RiskService.check(userId, templateId)`(L45-L72) 行为契约清楚,直接复用
|
|
118
|
+
- 注意项:
|
|
119
|
+
- `GrantService.grantOne` 目前带 @Transactional,批量时**不要**继承外层事务(否则 N 倍 DB 连接占用)
|
|
120
|
+
- 历史有 `LegacyGrantController`,前端已不调用,本次不动
|
|
121
|
+
- `Coupon` 表没有 `batch_id` 字段,需要 DDL 加列
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Step 5:Round 2 追问(只问不能自己回答的)
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
Q1: GrantService.grantOne 的 @Transactional 在批量时建议如何处理?不继承外层事务,逐条独立提交?
|
|
128
|
+
A1: 确认,逐条独立提交,部分失败的用户返回 failedUsers。
|
|
129
|
+
|
|
130
|
+
Q2: 运营后台的 CSV 上传大小?
|
|
131
|
+
A2: 1000 行上限,超出拒绝。
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 侦察的"轻量 / 重量"决策
|
|
137
|
+
|
|
138
|
+
| 信号 | 轻量(读 < 3 文件) | 重量(读 ≥ 5 文件 + 绘链路) |
|
|
139
|
+
| --- | --- | --- |
|
|
140
|
+
| L1 bug fix | ✓ | — |
|
|
141
|
+
| L2 新功能,纯追加 | ✓ | — |
|
|
142
|
+
| L2 修改现有逻辑 | — | ✓ |
|
|
143
|
+
| L3 任何 | — | ✓ |
|
|
144
|
+
| 触碰并发 / 事务路径 | — | ✓ |
|
|
145
|
+
| 触碰跨服务契约 | — | ✓ |
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 本文与 SKILL.md 的关系
|
|
150
|
+
|
|
151
|
+
SKILL.md 只提了"先 Grep / Glob 再问"。本文给完整侦察套路:侦察什么、侦察到多深、侦察产物怎么写、侦察后该问哪类问题、何时停、何时轻量 / 重量。agent 做 Round 2 前应读本文。
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# requirement-analysis / edge-case-catalog
|
|
2
|
+
|
|
3
|
+
需求阶段 edge case 挖掘 catalog。按 8 个维度扫描,每个维度给常见问题 + 对应 AC 骨架。requirement.md §8 的边界场景就按这里选。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 为什么在 requirement 阶段就挖?
|
|
8
|
+
|
|
9
|
+
- 边界没挖透 → design 时漏考虑 → code-review 发现 MUST → 返工
|
|
10
|
+
- 有些边界需要**业务确认**(如"部分失败算成功还是失败"),这是 business decision,不能在 apply 阶段临时拍
|
|
11
|
+
- verify 阶段的 self-test 表按边界场景组织,没挖边界 = self-test 写不满
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 8 个维度
|
|
16
|
+
|
|
17
|
+
1. 空 / 零 / null(Empty / Zero / Null)
|
|
18
|
+
2. 极值 / 溢出(Extreme / Overflow)
|
|
19
|
+
3. 重复 / 幂等(Duplicate / Idempotency)
|
|
20
|
+
4. 并发 / 竞态(Concurrency / Race)
|
|
21
|
+
5. 部分失败(Partial failure)
|
|
22
|
+
6. 权限 / 越权(Authorization)
|
|
23
|
+
7. 时区 / 本地化(Timezone / Locale)
|
|
24
|
+
8. 依赖不可用(Dependency unavailable)
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 维度 1:空 / 零 / null
|
|
29
|
+
|
|
30
|
+
| 问法 | 常见 AC 骨架 |
|
|
31
|
+
| --- | --- |
|
|
32
|
+
| 传空集合 | `Given [] → 400 EMPTY_INPUT`(不要返回 200 空) |
|
|
33
|
+
| 必填字段为 null | `Given {name: null} → 400 FIELD_REQUIRED:name` |
|
|
34
|
+
| 可选字段为 null | `Given {nickname: null} → 200(默认值或 null 沿用)` |
|
|
35
|
+
| 0 值 | `Given {qty: 0} → 400 OR 视业务(如退款可 0?)` |
|
|
36
|
+
| 空字符串 vs null | 统一:"", null, " " 都视为空?要明确 |
|
|
37
|
+
| 默认值 | 不传字段与显式传 null 区别? |
|
|
38
|
+
|
|
39
|
+
**常见坑**:后端 DTO 反序列化时 `null` 和"缺字段"不同,需业务明确。
|
|
40
|
+
|
|
41
|
+
## 维度 2:极值 / 溢出
|
|
42
|
+
|
|
43
|
+
| 问法 | 常见 AC 骨架 |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| 上限 | `Given N > 上限 → 400 OVER_LIMIT` |
|
|
46
|
+
| 下限 | `Given N < 下限 → 400` |
|
|
47
|
+
| 负数 | `Given -1 → 400 OR 视业务` |
|
|
48
|
+
| 超大字符串 | `Given str.length > 1024 → 400 FIELD_TOO_LONG` |
|
|
49
|
+
| 数字溢出 | `Given amount > Long.MAX → 400`(用 BigDecimal 替) |
|
|
50
|
+
| Payload 过大 | `Given body > 1MB → 413 PAYLOAD_TOO_LARGE` |
|
|
51
|
+
| 时间极值 | `Given time > 9999-12-31 → 400`(常见在解析时) |
|
|
52
|
+
|
|
53
|
+
**常见坑**:单元测试不覆盖 INT_MAX / LONG_MAX → 线上压力测试才暴露。
|
|
54
|
+
|
|
55
|
+
## 维度 3:重复 / 幂等
|
|
56
|
+
|
|
57
|
+
| 问法 | 常见 AC 骨架 |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| 同参数 2 次调用 | 幂等接口:`Given 相同请求 → 第 2 次返回第 1 次的结果,不产生重复副作用` |
|
|
60
|
+
| 非幂等接口重复 | 有唯一键:`Given 重复 payNo → 409 DUPLICATE`;无唯一键:业务决定 |
|
|
61
|
+
| 批次内重复 | `Given batch 中有 2 个相同 userId → 去重处理,只产生一条 grant_log` |
|
|
62
|
+
| 不同请求恰好相同 | 区分"业务重复" vs "网络重试";用 requestId / nonce 判 |
|
|
63
|
+
|
|
64
|
+
**常见坑**:支付 / 扣款类接口未做幂等 → 重复扣款事故。
|
|
65
|
+
|
|
66
|
+
## 维度 4:并发 / 竞态
|
|
67
|
+
|
|
68
|
+
| 问法 | 常见 AC 骨架 |
|
|
69
|
+
| --- | --- |
|
|
70
|
+
| 同时扣减 | `Given qty=10 + 同时 -1 → 最终 qty=8(UPDATE ... SET qty=qty-1 WHERE qty>=1)` |
|
|
71
|
+
| 乐观锁 | `Given 同时 UPDATE 同行 → 晚者 409 VERSION_CONFLICT` |
|
|
72
|
+
| 分布式锁 | `Given 两节点同时处理 → 后者等待 OR 拒绝` |
|
|
73
|
+
| 读写并发 | `Given 读时另一 session 改 → 读到一致快照(隔离级别)` |
|
|
74
|
+
| 缓存一致性 | `Given DB 改后 → 缓存 N 秒后一致` |
|
|
75
|
+
|
|
76
|
+
**常见坑**:单机测能过,多实例 / 多线程下炸。
|
|
77
|
+
|
|
78
|
+
## 维度 5:部分失败
|
|
79
|
+
|
|
80
|
+
**这是最常被用户忽略的维度**。批量、异步、外部调用都涉及。
|
|
81
|
+
|
|
82
|
+
| 问法 | 常见 AC 骨架 |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| 批量里部分条目失败 | `Given 1000 人中 10 人失败 → 200 + grantedCount=990 + failedUsers=[{userId,reason}...]` |
|
|
85
|
+
| 外部调用失败 | `Given 下游 timeout → 返回 500 + 记日志 + 不重试(避免雪崩)` |
|
|
86
|
+
| 事务中途失败 | `Given step3 fail → 回滚 step1+2 所有副作用,metric 上报 rollback` |
|
|
87
|
+
| 异步任务失败 | `Given 消费失败 → 重试 3 次 + 死信队列 + 告警 on-call` |
|
|
88
|
+
| 长任务中途崩溃 | `Given 崩溃 → 可恢复:保存 checkpoint + 重启接续` |
|
|
89
|
+
|
|
90
|
+
**业务要决策**:部分失败算"整体成功"还是"整体失败"?返回 200 还是 207 Multi-Status?前端怎么展示?
|
|
91
|
+
|
|
92
|
+
## 维度 6:权限 / 越权
|
|
93
|
+
|
|
94
|
+
| 问法 | 常见 AC 骨架 |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| 无 token | `401 UNAUTHORIZED` |
|
|
97
|
+
| 过期 token | `401 TOKEN_EXPIRED + 前端自动跳登录` |
|
|
98
|
+
| 无此权限 | `403 FORBIDDEN + errorCode=INSUFFICIENT_ROLE` |
|
|
99
|
+
| 越权访问他人数据 | `403(不 404,避免泄漏资源存在)` |
|
|
100
|
+
| 越权修改数据 | 同上 + audit log |
|
|
101
|
+
| 越权提升权限 | `403 + trigger 安全告警` |
|
|
102
|
+
| 特权账号日志 | 高权限操作(批量发放、改价、清数据) 必须 audit log |
|
|
103
|
+
|
|
104
|
+
## 维度 7:时区 / 本地化
|
|
105
|
+
|
|
106
|
+
| 问法 | 常见 AC 骨架 |
|
|
107
|
+
| --- | --- |
|
|
108
|
+
| 过期时间 | `过期时间基准 UTC 还是用户本地?必须明确` |
|
|
109
|
+
| 跨时区查询 | `"今天" 按谁的时区定义?` |
|
|
110
|
+
| 夏令时 | `涉及美国 / 欧洲时要小心 DST 跳跃` |
|
|
111
|
+
| 字符集 | `Given emoji / 中文 → 不乱码(UTF-8)` |
|
|
112
|
+
| 货币 | `金额单位:元还是分?int 还是 BigDecimal?` |
|
|
113
|
+
| 日期格式 | `UI 显示按 locale,API 传输固定 ISO 8601` |
|
|
114
|
+
|
|
115
|
+
## 维度 8:依赖不可用
|
|
116
|
+
|
|
117
|
+
| 问法 | 常见 AC 骨架 |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| DB 不可用 | `Given DB down → 503 + 指标上报 + 不重试 / 快速失败` |
|
|
120
|
+
| 缓存不可用 | `Given Redis down → 降级直连 DB(性能降) 或 快速失败(SLO 优先)` |
|
|
121
|
+
| 下游超时 | `timeout 3s → 500 SERVICE_TIMEOUT + log + 不 block 用户` |
|
|
122
|
+
| 下游 5xx | `下游返回 500 → 本接口如何处理?(重试 / 降级 / 透传)` |
|
|
123
|
+
| 消息队列积压 | `消息积压 > N → 告警;消费延迟 > M → 告警` |
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 挖掘清单(每级任务的最少条数)
|
|
128
|
+
|
|
129
|
+
| Level | §8 最少边界条数 | 必覆盖维度 |
|
|
130
|
+
| --- | --- | --- |
|
|
131
|
+
| **L1** | 4 | 空/null + 极值 + 权限 + 其他 1 个 |
|
|
132
|
+
| **L2** | 8 | 前 6 个维度至少各 1 条 + 2 个自选 |
|
|
133
|
+
| **L3** | 12 | 8 个维度全覆盖 + 4 个自选(重点:部分失败 / 并发 / 依赖不可用) |
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 挖掘流程(推荐)
|
|
138
|
+
|
|
139
|
+
1. 读 requirement.md §3 功能需求表的每条 F-ID
|
|
140
|
+
2. 对每个 F-ID,按维度 1-8 问一遍"这个场景下会怎样"
|
|
141
|
+
3. 把相关的场景记到 §8 表里;不相关的**不要硬塞**(维度不适用时跳过)
|
|
142
|
+
4. 对 **部分失败** 维度,主动问用户 → 这不是 agent 能替决策的
|
|
143
|
+
5. 完成后对照"挖掘清单"看是否达到 Level 要求
|
|
144
|
+
|
|
145
|
+
## 完整挖掘示例(add-coupon-batch-grant L2)
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
| 维度 | 场景 | 期望 | F-ID |
|
|
149
|
+
| --- | --- | --- | --- |
|
|
150
|
+
| 空 | userIds 空 | 400 EMPTY_BATCH | F-01 |
|
|
151
|
+
| 极值 | 1001 人 | 400 BATCH_TOO_LARGE | F-01 |
|
|
152
|
+
| 极值 | 0 人(意味着 userIds=[]) | 400 EMPTY_BATCH(同上) | F-01 |
|
|
153
|
+
| 重复 | batch 内 userId 重复 | 去重,发一次 | F-01 |
|
|
154
|
+
| 重复 | 同 batch 提交 2 次(网络重试) | 幂等:requestId 去重,第 2 次回 1 次结果 | F-01 |
|
|
155
|
+
| 并发 | 两运营同一模板同一用户同时发 | 风控去重(同 userId 24h 内不重发) | F-02 |
|
|
156
|
+
| 部分失败 | 10/1000 人风控拦截 | 200 + failedUsers 含 hitCode | F-02 |
|
|
157
|
+
| 权限 | 普通运营(无 coupon:batch_grant) | 403 FORBIDDEN | F-01 |
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 本文与 SKILL.md 的关系
|
|
163
|
+
|
|
164
|
+
SKILL.md 列了 8 个维度表作为提醒。本文给每个维度的完整问法 + AC 骨架 + 挖掘密度要求。agent 在写 `§8 边界与异常` 时应逐个维度扫一遍。
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# requirement-analysis / requirement-template
|
|
2
|
+
|
|
3
|
+
`requirement.md` 的 9 段详细模板 + 字段语义 + 正反例 + 完整示例。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 模板
|
|
8
|
+
|
|
9
|
+
```markdown
|
|
10
|
+
---
|
|
11
|
+
slug: <slug>
|
|
12
|
+
createdAt: <ISO>
|
|
13
|
+
level: L1 | L2 | L3
|
|
14
|
+
source: proposal | ingest
|
|
15
|
+
refs:
|
|
16
|
+
- <refs/source.md 或 proposal.md>
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Requirement: <one-line title>
|
|
20
|
+
|
|
21
|
+
## 1. 业务背景
|
|
22
|
+
<从 proposal / refs 提炼;1-2 段文字,不要粘贴整个 Wiki>
|
|
23
|
+
|
|
24
|
+
## 2. 用户故事
|
|
25
|
+
- As a <角色>, I want <能力>, so that <收益>.
|
|
26
|
+
- ...
|
|
27
|
+
|
|
28
|
+
## 3. 功能需求
|
|
29
|
+
| F-ID | 标题 | 描述 | AC(可验收) |
|
|
30
|
+
| --- | --- | --- | --- |
|
|
31
|
+
| F-01 | <一句话标题> | <更详细描述> | <Given...When...Then...> |
|
|
32
|
+
| F-02 | ... | ... | ... |
|
|
33
|
+
|
|
34
|
+
## 4. 非功能需求
|
|
35
|
+
### 性能
|
|
36
|
+
- <具体数值 + 场景>
|
|
37
|
+
|
|
38
|
+
### 安全 / 合规
|
|
39
|
+
- <涉及的敏感数据 + 合规要求>
|
|
40
|
+
|
|
41
|
+
### 可观测性
|
|
42
|
+
- <要加的指标 / 告警>
|
|
43
|
+
|
|
44
|
+
### 可用性 / 灰度 / 回滚
|
|
45
|
+
- <SLO / 灰度比例 / 回滚步骤>(L3 必填)
|
|
46
|
+
|
|
47
|
+
## 5. 数据 / 接口影响
|
|
48
|
+
### DDL 变更
|
|
49
|
+
- <新表 / 新列 / 索引调整>
|
|
50
|
+
|
|
51
|
+
### 契约变更
|
|
52
|
+
| 接口 | 类型 | 变更点 |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| POST /xxx | 新增 | ... |
|
|
55
|
+
| PUT /yyy | 修改 | 新增字段 z |
|
|
56
|
+
|
|
57
|
+
### 事件 / 消息
|
|
58
|
+
- <新增事件 / 修改 topic 语义>
|
|
59
|
+
|
|
60
|
+
### 代码侦察结论(Round 2 后填)
|
|
61
|
+
- 主要改动位于: `<module>/<path>/<file>`
|
|
62
|
+
- 复用的现有能力: `<ExistingService.method>`
|
|
63
|
+
- 注意项: <已有的兼容逻辑 / 坑点>
|
|
64
|
+
|
|
65
|
+
## 6. Round 1 Q&A(业务侧)
|
|
66
|
+
| # | 问题 | 回答 | 结论影响到的 section |
|
|
67
|
+
| --- | --- | --- | --- |
|
|
68
|
+
| Q1 | ... | ... | §3 F-01 |
|
|
69
|
+
| Q2 | ... | ... | §4 perf |
|
|
70
|
+
|
|
71
|
+
## 7. Round 2 Q&A(实现侧)
|
|
72
|
+
| # | 问题 | 回答 | 结论 |
|
|
73
|
+
| --- | --- | --- | --- |
|
|
74
|
+
| Q1 | ... | ... | ... |
|
|
75
|
+
|
|
76
|
+
## 8. 边界与异常
|
|
77
|
+
| 维度 | 场景 | 期望行为 | 对应 F-ID |
|
|
78
|
+
| --- | --- | --- | --- |
|
|
79
|
+
| 空输入 | 传空用户列表 | 返回 400 BAD_REQUEST, code=EMPTY_BATCH | F-01 |
|
|
80
|
+
| 超限 | 传入 1001 人 | 返回 400, code=BATCH_TOO_LARGE | F-01 |
|
|
81
|
+
| 部分失败 | 10/1000 被风控拦截 | 返回 200 + partialSuccess:true, hitList:[...] | F-02 |
|
|
82
|
+
| ... | ... | ... | ... |
|
|
83
|
+
|
|
84
|
+
## 9. 风险与遗留(Risks & Open issues)
|
|
85
|
+
- **[Open]** <未解决的问题,带 owner 和 deadline>
|
|
86
|
+
- **[Risk]** <已知的风险 + 缓解策略>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 字段语义详述
|
|
92
|
+
|
|
93
|
+
### 1. 业务背景(Business background)
|
|
94
|
+
|
|
95
|
+
**目的**:帮 downstream phase(特别是 code-review 和 archive)理解**为什么要做这事**,不是复述 PRD。
|
|
96
|
+
|
|
97
|
+
**好**:1-2 段,含关键数据(现状、痛点、预期改善)。
|
|
98
|
+
|
|
99
|
+
**反例**:
|
|
100
|
+
|
|
101
|
+
> ~~~
|
|
102
|
+
> 业务需要一个批量发券功能。详情见 PRD 链接 xxx。
|
|
103
|
+
> ~~~
|
|
104
|
+
> (没有提炼,相当于没写。)
|
|
105
|
+
|
|
106
|
+
**正例**:
|
|
107
|
+
|
|
108
|
+
> 现状:Q3 优惠券运营以单发接口为主,平均每场活动需手动发 300-500 次,耗时 1-2 小时 / 场。
|
|
109
|
+
> 痛点:大促期间单场次发放峰值可达 1000+,人肉不可能完成;运营只能放弃或提前拉 DBA 脚本。
|
|
110
|
+
> 本次目标:提供批量发放接口 + 运营后台,把单场耗时压到 ≤ 10 分钟。
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### 2. 用户故事
|
|
115
|
+
|
|
116
|
+
**格式**:`As a <角色>, I want <能力>, so that <收益>`(INVEST 原则,详见 acceptance-criteria.md)。
|
|
117
|
+
|
|
118
|
+
**反例**:
|
|
119
|
+
|
|
120
|
+
> ~~作为开发,我想写这个接口~~
|
|
121
|
+
> (开发不是最终用户)
|
|
122
|
+
|
|
123
|
+
**正例**:
|
|
124
|
+
|
|
125
|
+
> - As a 运营专员, I want 在管理后台选择用户列表并一次发放优惠券, so that 不用手动操作 300 次。
|
|
126
|
+
> - As a 风控管理员, I want 批量发放仍逐条应用风控规则, so that 活动合规不破口。
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
### 3. 功能需求
|
|
131
|
+
|
|
132
|
+
**F-ID 规范**:
|
|
133
|
+
|
|
134
|
+
- 格式 `F-<NN>`,F-01 起编号
|
|
135
|
+
- **一旦创建,永不重用**(即使后来删除,也不要把 F-07 重新分配给新功能 —— 避免引用歧义)
|
|
136
|
+
- 可以扩展为 `F-01.1` / `F-01.2` 表示子项
|
|
137
|
+
|
|
138
|
+
**AC 写法**:每条都是可自动化验证的单句(或 Given-When-Then 三段式)。详见 acceptance-criteria.md §2。
|
|
139
|
+
|
|
140
|
+
**最小完整度**:L1 ≥ 1 条 F-;L2 ≥ 3 条;L3 ≥ 5 条。少于此数意味着 requirement 拆得太粗。
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### 4. 非功能需求
|
|
145
|
+
|
|
146
|
+
四个常见维度(按 level 要求):
|
|
147
|
+
|
|
148
|
+
| 维度 | L1 | L2 | L3 |
|
|
149
|
+
| --- | --- | --- | --- |
|
|
150
|
+
| 性能 | 可略(不劣化) | 具体数值 | SLO + 压测 |
|
|
151
|
+
| 安全 | 无敏感数据可略 | 校验 + 脱敏 | + 合规审计 + 数据流图 |
|
|
152
|
+
| 可观测性 | 现有日志即可 | 新增指标 + 告警 | 指标 + 告警 + runbook |
|
|
153
|
+
| 可用性 / 灰度 | 可略 | 简单 flag | 分批灰度 + 回滚预案 |
|
|
154
|
+
|
|
155
|
+
**反例**:
|
|
156
|
+
|
|
157
|
+
> ~~性能要好,安全要严~~
|
|
158
|
+
|
|
159
|
+
**正例**:
|
|
160
|
+
|
|
161
|
+
> ### 性能
|
|
162
|
+
> - 批量接口 P99 ≤ 3s(1000 人场景)
|
|
163
|
+
> - 批量接口 QPS 峰值 20,不退化现有单发的 TP99
|
|
164
|
+
>
|
|
165
|
+
> ### 安全
|
|
166
|
+
> - 批量接口鉴权沿用现有 token,并额外校验运营角色权限 `coupon:batch_grant`
|
|
167
|
+
> - 日志中用户手机号 / 身份证 脱敏到后 4 位
|
|
168
|
+
>
|
|
169
|
+
> ### 可观测性
|
|
170
|
+
> - 新增指标 `coupon.batch_grant.latency`(histogram,P99 告警阈值 5s)
|
|
171
|
+
> - 新增指标 `coupon.batch_grant.success_rate`(gauge,告警阈值 < 99%)
|
|
172
|
+
>
|
|
173
|
+
> ### 可用性 / 灰度
|
|
174
|
+
> - 灰度 1% → 10% → 50% → 100%,各阶段观测 2 小时
|
|
175
|
+
> - 回滚预案:关闭 feature flag `coupon.batch.enabled`
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
### 5. 数据 / 接口影响
|
|
180
|
+
|
|
181
|
+
**DDL 原则**:
|
|
182
|
+
|
|
183
|
+
- 列出所有新表 / 新列 / 索引变更;每个带类型、长度、NOT NULL、COMMENT
|
|
184
|
+
- 标注幂等性(`CREATE TABLE IF NOT EXISTS` / `ALTER TABLE ADD COLUMN IF NOT EXISTS`)
|
|
185
|
+
|
|
186
|
+
**契约原则**:
|
|
187
|
+
|
|
188
|
+
- 每个变更接口一行,标"新增 / 修改 / 删除"
|
|
189
|
+
- 兼容性:是否 breaking?旧客户端是否受影响?
|
|
190
|
+
|
|
191
|
+
**事件 / 消息**:
|
|
192
|
+
|
|
193
|
+
- 新增 topic:列出 schema
|
|
194
|
+
- 修改已有 topic:标注是否 wire-compatible
|
|
195
|
+
|
|
196
|
+
**代码侦察结论**:Round 2 的结果,让 design 阶段直接可用。详见 `code-recon.md`。
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
### 6-7. Round 1 / Round 2 Q&A
|
|
201
|
+
|
|
202
|
+
**目的**:审计留档,**不是摘要**。每条记下来:
|
|
203
|
+
|
|
204
|
+
- 原始问题(不改写)
|
|
205
|
+
- 用户原始回答
|
|
206
|
+
- 结论影响到的 section(F-ID / 具体非功能项)
|
|
207
|
+
|
|
208
|
+
**反例**:
|
|
209
|
+
|
|
210
|
+
> ~~Round 1: 问了业务相关问题,都明确了~~
|
|
211
|
+
> (没留档无法审计)
|
|
212
|
+
|
|
213
|
+
**正例**:
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
## 6. Round 1 Q&A
|
|
217
|
+
| # | 问题 | 回答 | 影响 section |
|
|
218
|
+
| --- | --- | --- | --- |
|
|
219
|
+
| Q1 | 单次批量上限? | 1000(运营最大需求),超出走多次调用 | §3 F-01 + §8 超限 |
|
|
220
|
+
| Q2 | 部分失败怎么返回? | 返回 200 + 每用户状态列表,运营自行重试 | §3 F-02 + §8 部分失败 |
|
|
221
|
+
| Q3 | 需要独立风控放行吗? | 不需要,沿用单发同规则 | §3 F-02 + §4 安全 |
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
### 8. 边界与异常
|
|
227
|
+
|
|
228
|
+
完整 catalog 见 `edge-case-catalog.md`。
|
|
229
|
+
|
|
230
|
+
**最小完整度**:L1 ≥ 4 条,L2 ≥ 8 条,L3 ≥ 12 条。
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
### 9. 风险与遗留
|
|
235
|
+
|
|
236
|
+
两个子类:
|
|
237
|
+
|
|
238
|
+
- **[Open]**:当前未解决的问题,写 owner + deadline;若 Open issue 属于 P0,Round 1 不允许结束
|
|
239
|
+
- **[Risk]**:已知风险 + 缓解策略(如"下游 grant API 9/25 才 ready,若延迟将影响提测")
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## 完整示例(L2 新功能)
|
|
244
|
+
|
|
245
|
+
```markdown
|
|
246
|
+
---
|
|
247
|
+
slug: add-coupon-batch-grant
|
|
248
|
+
createdAt: 2026-04-24T10:15:00+08:00
|
|
249
|
+
level: L2
|
|
250
|
+
source: proposal
|
|
251
|
+
refs:
|
|
252
|
+
- devflow/changes/add-coupon-batch-grant/proposal.md
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
# Requirement: 批量发放优惠券
|
|
256
|
+
|
|
257
|
+
## 1. 业务背景
|
|
258
|
+
现状:Q3 起运营使用单发接口发放活动券,平均 1 场活动 300-500 次手动操作,耗时 1-2h/场。
|
|
259
|
+
痛点:Q4 大促预计峰值 1000+/场,人工不可完成。
|
|
260
|
+
目标:提供批量发放接口 + 管理后台,单场 ≤ 10 分钟。
|
|
261
|
+
|
|
262
|
+
## 2. 用户故事
|
|
263
|
+
- As a 运营专员, I want 选择用户清单一次性发券, so that 单场操作 ≤ 10 分钟。
|
|
264
|
+
- As a 风控管理员, I want 批量发放每条走同一风控, so that 活动合规不破口。
|
|
265
|
+
|
|
266
|
+
## 3. 功能需求
|
|
267
|
+
| F-ID | 标题 | 描述 | AC |
|
|
268
|
+
| --- | --- | --- | --- |
|
|
269
|
+
| F-01 | 批量发放接口 | POST /api/v2/coupon/batch-grant | Given 1000 个 userId + 一个 couponTemplateId, When 调用, Then 返回 200,body 含 grantedCount/failedCount/failedUsers,耗时 ≤ 3s |
|
|
270
|
+
| F-02 | 风控逐条应用 | 每个 user 走单发的同风控路径 | Given 100 用户中有 10 个命中风控, When 批量发放, Then failedUsers 含这 10 人 + hitCode;成功 90 人 |
|
|
271
|
+
| F-03 | 运营后台批量选择 | 支持文件导入 CSV / 查询条件圈选 | Given 运营上传 1000 行 CSV, When 点击"发放", Then 展示确认页 + 预估命中风控数 + 点击确认后调用 F-01 |
|
|
272
|
+
|
|
273
|
+
## 4. 非功能需求
|
|
274
|
+
### 性能
|
|
275
|
+
- F-01 P99 ≤ 3s(1000 人场景);QPS 峰值 20
|
|
276
|
+
|
|
277
|
+
### 安全
|
|
278
|
+
- 运营需权限 `coupon:batch_grant`(新增),仅高级运营可操作
|
|
279
|
+
- 日志手机号脱敏
|
|
280
|
+
|
|
281
|
+
### 可观测性
|
|
282
|
+
- 指标 `coupon.batch.latency` P99 告警 5s
|
|
283
|
+
- 指标 `coupon.batch.error_rate` 告警 1%
|
|
284
|
+
|
|
285
|
+
### 可用性 / 灰度
|
|
286
|
+
- Feature flag `coupon.batch.enabled`
|
|
287
|
+
- 回滚:关闭 flag
|
|
288
|
+
|
|
289
|
+
## 5. 数据 / 接口影响
|
|
290
|
+
### DDL
|
|
291
|
+
- 新增索引 `idx_grant_batch_id` 在 `coupon_grant(batch_id)`(IF NOT EXISTS)
|
|
292
|
+
- 新增列 `batch_id VARCHAR(36) NULL COMMENT '批次号'`(IF NOT EXISTS)
|
|
293
|
+
|
|
294
|
+
### 契约
|
|
295
|
+
| 接口 | 类型 | 变更点 |
|
|
296
|
+
| --- | --- | --- |
|
|
297
|
+
| POST /api/v2/coupon/batch-grant | 新增 | 全新接口 |
|
|
298
|
+
| POST /api/v1/coupon/grant | 不变 | 保持兼容 |
|
|
299
|
+
|
|
300
|
+
### 代码侦察结论
|
|
301
|
+
- 主要改动:`coupon-service/BatchGrantController`(新增)、`coupon-service/GrantService.grantOne`(已有,复用)
|
|
302
|
+
- 复用:`RiskService.check`(已有,不动)
|
|
303
|
+
- 注意:`GrantService.grantOne` 目前带 `@Transactional`,批量时要改调用方式,详见 design.md
|
|
304
|
+
|
|
305
|
+
## 6. Round 1 Q&A
|
|
306
|
+
| # | 问题 | 回答 | 影响 |
|
|
307
|
+
| --- | --- | --- | --- |
|
|
308
|
+
| Q1 | 单次上限? | 1000 | §3 F-01 + §8 |
|
|
309
|
+
| Q2 | 部分失败如何返回? | 200 + failedUsers 列表 | §3 F-01 + §8 |
|
|
310
|
+
| Q3 | 需独立风控? | 否,沿用 | §3 F-02 |
|
|
311
|
+
| Q4 | 灰度策略? | 上线先 1% flag,运营后台先内测 5 人 | §4 灰度 |
|
|
312
|
+
|
|
313
|
+
## 7. Round 2 Q&A
|
|
314
|
+
| # | 问题 | 回答 |
|
|
315
|
+
| --- | --- | --- |
|
|
316
|
+
| Q1 | GrantService.grantOne 目前是 @Transactional,批量时怎么处理? | 不继承事务,逐条独立提交 |
|
|
317
|
+
| Q2 | 运营后台文件导入支持多大? | CSV 1000 行上限 |
|
|
318
|
+
|
|
319
|
+
## 8. 边界与异常
|
|
320
|
+
| 维度 | 场景 | 期望行为 | F-ID |
|
|
321
|
+
| --- | --- | --- | --- |
|
|
322
|
+
| 空输入 | 传空 userIds | 400 EMPTY_BATCH | F-01 |
|
|
323
|
+
| 超限 | 1001 人 | 400 BATCH_TOO_LARGE | F-01 |
|
|
324
|
+
| 无权限 | 普通运营调接口 | 403 FORBIDDEN | F-01 |
|
|
325
|
+
| 部分失败 | 10/1000 命中风控 | 200 + 部分成功 | F-02 |
|
|
326
|
+
| 重复 | 同一 userId 在 batch 内出现 2 次 | 去重后发一次,返回一次 | F-01 |
|
|
327
|
+
| 不存在 template | templateId 不存在 | 400 TEMPLATE_NOT_FOUND | F-01 |
|
|
328
|
+
| 并发 | 两运营同时批量发同模板给同人 | 风控去重 | F-02 |
|
|
329
|
+
|
|
330
|
+
## 9. 风险与遗留
|
|
331
|
+
- **[Risk]** CSV 编码若是 GBK 可能解析错;本次要求 UTF-8 only,文案提示。
|
|
332
|
+
- **[Open]** 运营后台是否需要"发放历史回查"?Q: Alice @ PM,A: 本次不做,下期(SCRUM-15901)。
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## 本文与 SKILL.md 的关系
|
|
338
|
+
|
|
339
|
+
SKILL.md 给了 9 个 section 标题和 Level 要求表。本文给完整模板、每段的字段语义、正反例、完整示例。所有 agent 在写 `requirement.md` 时应以本文的完整示例为参照。
|