@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,172 @@
|
|
|
1
|
+
# tech-spec / api-contract-design
|
|
2
|
+
|
|
3
|
+
API 契约设计原则(REST / GraphQL / gRPC / 事件)、版本化、字段演进。这是 design.md §5 的写作依据。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 通用原则
|
|
8
|
+
|
|
9
|
+
1. **契约是外部承诺**:签了就要兑现;改契约要按版本化流程,不要就地改语义
|
|
10
|
+
2. **只加字段,不删不改**:客户端忽略未知字段,所以加字段是**非 breaking**;删字段 / 改语义必然 breaking
|
|
11
|
+
3. **字段默认可空 + 默认值明确**:新增必填字段 = breaking;新增可空字段 = 非 breaking
|
|
12
|
+
4. **错误码集中管理**:不要每个 Controller 各自定义一套,集中到 `ErrorCode` enum 或 yaml
|
|
13
|
+
5. **幂等性显式标注**:文档里写清楚 GET/DELETE 幂等、POST 是否幂等(通过什么 key)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## REST 契约
|
|
18
|
+
|
|
19
|
+
### URL 设计
|
|
20
|
+
|
|
21
|
+
- 资源用名词复数:`/api/v1/coupons`,不是 `/api/v1/getCoupon`
|
|
22
|
+
- 层级反映归属:`/api/v1/users/{userId}/coupons`
|
|
23
|
+
- 动作用 HTTP 动词表达:POST 创建 / GET 读 / PUT 替换 / PATCH 改 / DELETE 删
|
|
24
|
+
- 不得已的动作类路径:`/api/v1/coupons/{id}:revoke`(冒号分隔,RFC 7320 允许)
|
|
25
|
+
|
|
26
|
+
### 版本化
|
|
27
|
+
|
|
28
|
+
- URL 路径版本:`/api/v1/`(简单,推荐)
|
|
29
|
+
- Header 版本:`Accept: application/vnd.company.v1+json`(复杂,不推荐)
|
|
30
|
+
- **新能力开 v2**:`/api/v2/coupon/batch-grant`;v1 /v2 并存一段时间,v1 加 Sunset header
|
|
31
|
+
- **破坏性改动不要就地改 v1**
|
|
32
|
+
|
|
33
|
+
### 状态码语义
|
|
34
|
+
|
|
35
|
+
| code | 含义 | 例 |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| 200 | 成功 | 正常返回 |
|
|
38
|
+
| 201 | 已创建 | POST 资源成功 + Location header |
|
|
39
|
+
| 204 | 无内容 | DELETE / PUT 成功不需要 body |
|
|
40
|
+
| 400 | 客户端错(请求无效) | 参数错、逻辑冲突 |
|
|
41
|
+
| 401 | 未认证 | 缺 token / token 无效 |
|
|
42
|
+
| 403 | 无权限 | token 有效但角色不够 |
|
|
43
|
+
| 404 | 不存在 | 注意:越权访问他人数据返回 403 而非 404(避免泄漏存在性) |
|
|
44
|
+
| 409 | 冲突 | 唯一键、乐观锁失败 |
|
|
45
|
+
| 410 | 已删除 | 资源已被移除,永久 |
|
|
46
|
+
| 413 | Payload 过大 | body 超限 |
|
|
47
|
+
| 429 | 限流 | 带 Retry-After header |
|
|
48
|
+
| 500 | 服务端错 | 兜底 |
|
|
49
|
+
| 503 | 服务不可用 | 降级 / 维护 / flag 关闭 |
|
|
50
|
+
|
|
51
|
+
### 错误 body 格式(推荐统一)
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"code": "BATCH_TOO_LARGE",
|
|
56
|
+
"message": "批量上限 1000,当前 1001",
|
|
57
|
+
"traceId": "a1b2c3",
|
|
58
|
+
"details": {
|
|
59
|
+
"limit": 1000,
|
|
60
|
+
"actual": 1001
|
|
61
|
+
},
|
|
62
|
+
"suggestion": "拆分为多次调用"
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
统一格式的好处:客户端可写通用错误处理;测试容易断言。
|
|
67
|
+
|
|
68
|
+
### 分页 / 排序 / 筛选
|
|
69
|
+
|
|
70
|
+
- 分页:`?cursor=xxx&limit=50`(cursor 优于 offset,大 offset 慢)
|
|
71
|
+
- 排序:`?sort=-createdAt,name`(前缀 `-` 降序)
|
|
72
|
+
- 筛选:`?status=active&tag=vip`(简单 eq) 或 `?filter=status eq 'active'`(复杂 DSL)
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## gRPC 契约
|
|
77
|
+
|
|
78
|
+
### Proto 演进规则
|
|
79
|
+
|
|
80
|
+
- **字段 tag 永远不重用**:删了字段标 `reserved 5;`,新字段用下一个 tag
|
|
81
|
+
- **只加新字段,不删旧字段**(删了会 breaking)
|
|
82
|
+
- **enum 加值**:放在最末,不要插中间;protobuf 未知值自动设为 0,要小心默认值语义
|
|
83
|
+
|
|
84
|
+
### 不要做的事
|
|
85
|
+
|
|
86
|
+
- 改字段 name(序列化按 tag,但 stub 代码会 breaking)
|
|
87
|
+
- 改字段 type(bool → int 等)
|
|
88
|
+
- 把 `optional` 变 `required`(proto3 已没 required,proto2 别改)
|
|
89
|
+
- 重用已 deprecated 的 tag 号
|
|
90
|
+
|
|
91
|
+
### 错误模型
|
|
92
|
+
|
|
93
|
+
- 用 `google.rpc.Status` 标准(code + message + details[])
|
|
94
|
+
- details 里塞 `ErrorInfo`、`BadRequest.FieldViolation`、`RetryInfo` 等标准类型
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## GraphQL 契约
|
|
99
|
+
|
|
100
|
+
- Schema 里**加字段 / 加类型 / 加参数** 都不 breaking
|
|
101
|
+
- 删字段 / 改类型 / 改 non-null 性都 breaking
|
|
102
|
+
- 弃用用 `@deprecated(reason: "...")`,不要删
|
|
103
|
+
- 查询深度限制 / 复杂度限制(防 N+1 查询攻击)
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 事件 / 消息契约
|
|
108
|
+
|
|
109
|
+
### 基本字段(建议每个事件都有)
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"eventId": "evt_<uuid>", // 幂等 key
|
|
114
|
+
"eventType": "coupon.granted", // 类型,形如 <bounded-context>.<past-tense-verb>
|
|
115
|
+
"eventVersion": "v1", // schema 版本
|
|
116
|
+
"occurredAt": "<ISO>", // 事件发生时间
|
|
117
|
+
"producer": "coupon-service", // 生产者
|
|
118
|
+
"traceId": "<...>", // 追踪
|
|
119
|
+
"payload": { ... } // 业务字段
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 事件版本化
|
|
124
|
+
|
|
125
|
+
- schema 只加字段,不删不改
|
|
126
|
+
- 重大变更 → 新 topic(`coupon.granted.v2`),旧 topic 沉默直到无消费者
|
|
127
|
+
- 消费者**必须**能忽略未知字段(forward-compat)
|
|
128
|
+
|
|
129
|
+
### 幂等消费
|
|
130
|
+
|
|
131
|
+
- `eventId` 做消费者的幂等 key:已处理过直接跳过
|
|
132
|
+
- 消费者要能处理重复投递(at-least-once 是常态)
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 字段设计常见陷阱
|
|
137
|
+
|
|
138
|
+
| 陷阱 | 好做法 |
|
|
139
|
+
| --- | --- |
|
|
140
|
+
| `status: "active"` 字符串 enum | 用真正的 enum 类型(proto)或明确值列表(OpenAPI) |
|
|
141
|
+
| 金额用 float / double | 用 decimal / BigDecimal / long(最小单位"分") |
|
|
142
|
+
| 时间戳用 int 秒 | 明确时区;用 ISO-8601 字符串或 unix millis long |
|
|
143
|
+
| 布尔字段歧义(`isEnabled` vs `isDisabled`) | 用正向命名(enabled),避免双重否定 |
|
|
144
|
+
| 手机号 / 身份证用 int / long | 用 string(保留前导 0 + 避免溢出) |
|
|
145
|
+
| 错误信息放 `message` 字段但没有 `code` | 永远先给 code(机器可读),再给 message(人可读) |
|
|
146
|
+
| 把 list 字段命名成单数 | list 字段复数(users),scalar 字段单数(userId) |
|
|
147
|
+
| 时间段用 startDate+endDate 但语义模糊 | 明确 "左闭右开 [start, end)" 还是 "闭区间 [start, end]" |
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 版本共存策略
|
|
152
|
+
|
|
153
|
+
| 场景 | 策略 |
|
|
154
|
+
| --- | --- |
|
|
155
|
+
| 旧 v1 仍有流量 | v1/v2 并行;v1 逐步灰度减量 |
|
|
156
|
+
| v1 完全没流量 | v1 标 deprecated,6 个月后删除(留足客户端升级时间) |
|
|
157
|
+
| 灰度切换 | 按 userId hash 或 feature flag 分流(一个用户一直走同一版,防抖动) |
|
|
158
|
+
| 内部服务切换 | 双写 + 对账期 + 切读 + 下线旧路径 |
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 契约 / 代码 / 文档一致性
|
|
163
|
+
|
|
164
|
+
- **Contract-first**:先定义 spec(OpenAPI / proto / GraphQL schema),再生成代码
|
|
165
|
+
- **Single source of truth**:spec 文件 check in 仓库,CI 校验"实现与 spec 一致"
|
|
166
|
+
- **Review 时对 spec 改动严格**:spec 改动 = API breaking 警告,要 ADR 级审查
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 本文与 SKILL.md 的关系
|
|
171
|
+
|
|
172
|
+
SKILL.md 给了契约设计 4 条原则。本文扩展为 REST / gRPC / GraphQL / 事件的具体规则 + 版本化策略 + 字段设计陷阱。tech-spec 写 §5 契约时应按本文规则校对每个接口。
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# tech-spec / decision-records
|
|
2
|
+
|
|
3
|
+
ADR-lite(Architecture Decision Record)在 design.md 里的嵌入式写法。不是"每个设计都写 ADR",只对**值得未来回顾的关键决策**写。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 什么决策值得记 ADR
|
|
8
|
+
|
|
9
|
+
| 值得 | 不值得(用默认) |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| 选了数据库 / 存储 / 中间件(Redis vs Memcached、MySQL vs PG) | 选了哪个 JSON 解析库 |
|
|
12
|
+
| 一致性模型(强一致 / 最终 / Saga / TCC) | 每个方法的命名 |
|
|
13
|
+
| 同步 / 异步 / 消息驱动 | 日志格式 |
|
|
14
|
+
| 通信协议(REST vs gRPC vs GraphQL) | 变量命名风格 |
|
|
15
|
+
| 容错策略(重试 / 降级 / 快速失败) | 缩进 |
|
|
16
|
+
| 鉴权模型(JWT vs session、自建 vs SSO) | — |
|
|
17
|
+
| 分片 / 分表 / 分库方案 | — |
|
|
18
|
+
| 灰度方案(flag vs 分流 vs 机房切) | — |
|
|
19
|
+
|
|
20
|
+
**判据**:如果 6 个月后团队换人问"当时为啥这么做",答不出就写 ADR。
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## ADR-lite 模板(内嵌在 design.md §11 或独立章节)
|
|
25
|
+
|
|
26
|
+
```markdown
|
|
27
|
+
### ADR-<NN>: <一句话结论>
|
|
28
|
+
|
|
29
|
+
**Context**:<为什么要做这个决策;关键约束>
|
|
30
|
+
**Decision**:<选了什么>
|
|
31
|
+
**Alternatives considered**:
|
|
32
|
+
- <备选 1>:<为什么没选>
|
|
33
|
+
- <备选 2>:<为什么没选>
|
|
34
|
+
**Consequences**:
|
|
35
|
+
- 正面:<好处>
|
|
36
|
+
- 负面:<我们知道的代价 / 未来要承担的成本>
|
|
37
|
+
**Reversal trigger**:<什么情况下我们会回过头推翻这个决策>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 示例 ADR
|
|
43
|
+
|
|
44
|
+
### ADR-01: 批量发放用同步 API 而非异步任务
|
|
45
|
+
|
|
46
|
+
**Context**:运营需要批量发券,峰值预估 1000 人/批、20 QPS。当前无运营侧的"任务中心"UI,做异步需要新增前端组件与后端任务状态机。
|
|
47
|
+
**Decision**:同步 HTTP API + 内部循环 grantOne(每条独立事务)。
|
|
48
|
+
**Alternatives considered**:
|
|
49
|
+
- 方案 B(异步 + 消息队列):吞吐更好,但 UI 成本 + 状态机复杂,放弃
|
|
50
|
+
- 方案 C(客户端并发调单发):风控会误判,放弃
|
|
51
|
+
**Consequences**:
|
|
52
|
+
- 正面:开发 1 周;无 UI 变更;运营立即可用
|
|
53
|
+
- 负面:1000 人场景 P99 ≈ 3s,接口超时时间必须 ≥ 5s;单实例批量 QPS 有限(≤ 20)
|
|
54
|
+
**Reversal trigger**:峰值 > 50 QPS 或单批 > 5000 时需切异步;届时方案 B 可无损迁移(API 外观不变)。
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
### ADR-02: RiskService 失败时批量整体降级为"全部跳过风控 + 单独告警"
|
|
59
|
+
|
|
60
|
+
**Context**:批量发放场景下,如 RiskService 偶发不稳定,是"直接整批失败"还是"允许跳过风控 + 告警"?业务方希望活动不中断。
|
|
61
|
+
**Decision**:当本批 RiskService 连续 5 次超时,切换到"skip 风控"模式,所有用户不经风控直接发券,但**所有 skip 的记录打标**并触发告警;直到 RiskService 恢复前保持 skip。
|
|
62
|
+
**Alternatives considered**:
|
|
63
|
+
- A:整批失败(最安全,但业务中断)
|
|
64
|
+
- B:按用户单独重试 3 次后 skip(折中,但代码复杂)
|
|
65
|
+
**Consequences**:
|
|
66
|
+
- 正面:业务连续性有保证
|
|
67
|
+
- 负面:风控被短暂跳过的用户需要事后对账;加了一个"降级状态"要维护
|
|
68
|
+
**Reversal trigger**:若合规要求零 skip(如金融业务),改为 A。
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 写 ADR 的常见误区
|
|
73
|
+
|
|
74
|
+
1. **光写 Decision 不写 Alternatives**:看不到"为什么不是别的",无法审计
|
|
75
|
+
2. **Alternatives 全是稻草人**(故意列很差的选项衬托)→ reviewer 能看出来
|
|
76
|
+
3. **不写 Reversal trigger**:决策没有"退出条件",未来很难推翻
|
|
77
|
+
4. **把 ADR 写成很长的设计稿**:ADR 是决策**摘要**,每条 ≤ 10 行;细节放 design.md 正文
|
|
78
|
+
5. **一个设计堆 10 个 ADR**:2-3 个关键决策就够了;不重要的决策用默认,不写
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## ADR 与 design.md §11 alternatives 的关系
|
|
83
|
+
|
|
84
|
+
**两种可合并**:把 ADR 当作 §11 的结构化形式。
|
|
85
|
+
**也可独立**:L3 或长期项目,ADR 单独放 `devflow/changes/<slug>/adr/ADR-01-<slug>.md`;默认 workspace 模式放到 `~/.devflow/workspace/changes/<feature-xx>/adr/`。archive 阶段再归档到当前需求的 `knowledge/架构决策/` 存底。
|
|
86
|
+
|
|
87
|
+
推荐:
|
|
88
|
+
|
|
89
|
+
| Level | 建议 |
|
|
90
|
+
| --- | --- |
|
|
91
|
+
| L1 | 无 ADR(决策都是琐碎的) |
|
|
92
|
+
| L2 | ≤ 2 个 ADR,内嵌在 §11 |
|
|
93
|
+
| L3 | 2-5 个 ADR,默认放 `~/.devflow/workspace/changes/<feature-xx>/adr/`;历史 in-repo 模式可放 `devflow/changes/<slug>/adr/` |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 归档到 knowledge/架构决策/
|
|
98
|
+
|
|
99
|
+
`devflow archive` 时:
|
|
100
|
+
|
|
101
|
+
- 若 design.md / `adr/*.md` 里有 "Reversal trigger" 字段 → 把 ADR 抽出来复制到当前需求知识目录:
|
|
102
|
+
- 单服务:`<repo>/devflow/knowledge/架构决策/ADR-<slug>-<NN>.md`
|
|
103
|
+
- 默认 workspace:`~/.devflow/workspace/changes/<feature-xx>/knowledge/架构决策/ADR-<slug>-<NN>.md`
|
|
104
|
+
- 这样下次别人做类似决策时可以 `devflow knowledge query "异步 vs 同步"` 找到历史依据
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 本文与 SKILL.md 的关系
|
|
109
|
+
|
|
110
|
+
SKILL.md 提了"决策 vs 记账"方法论;本文给 ADR-lite 的具体模板、示例、常见误区。写 design.md §11 alternatives 时直接用本文的 ADR 模板,不要自由发挥。
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# tech-spec / design-template
|
|
2
|
+
|
|
3
|
+
`design.md` 的 11 段详细模板、每段字段语义、正反例。附一个 L2 完整示例。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 模板
|
|
8
|
+
|
|
9
|
+
```markdown
|
|
10
|
+
---
|
|
11
|
+
slug: <slug>
|
|
12
|
+
createdAt: <ISO>
|
|
13
|
+
level: L1 | L2 | L3
|
|
14
|
+
version: v1
|
|
15
|
+
revisionLog:
|
|
16
|
+
- v1: 初始版本
|
|
17
|
+
refs:
|
|
18
|
+
- requirement.md
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# 技术方案: <一句话标题>
|
|
22
|
+
|
|
23
|
+
## 1. 方案摘要
|
|
24
|
+
<一段话,最多 5 句;一个完全不了解本事的人读完能说出"原来是这样做的">
|
|
25
|
+
|
|
26
|
+
## 2. 目标 / 非目标
|
|
27
|
+
### 目标(重申 requirement 的目标,不增不减)
|
|
28
|
+
- ...
|
|
29
|
+
### 非目标(从 Out of scope + 本次不解决的隐含需求)
|
|
30
|
+
- ...
|
|
31
|
+
|
|
32
|
+
## 3. 架构影响(组件)
|
|
33
|
+
<mermaid 或 ASCII 组件图。只画变化的边;用星号标出新建/修改/删除>
|
|
34
|
+
|
|
35
|
+
## 4. 改动点汇总
|
|
36
|
+
| 文件 / 类 / 方法 | 类型 | 对应 F-ID | 说明 |
|
|
37
|
+
| --- | --- | --- | --- |
|
|
38
|
+
| coupon-service/BatchGrantController(新建) | 新建 | F-01 | 新增接口入口 |
|
|
39
|
+
| coupon-service/GrantService#grantOne | 复用 | F-02 | 复用 |
|
|
40
|
+
| ... | ... | ... | ... |
|
|
41
|
+
|
|
42
|
+
## 5. 契约定义
|
|
43
|
+
### 请求 / 响应
|
|
44
|
+
```http
|
|
45
|
+
POST /api/v2/coupon/batch-grant
|
|
46
|
+
Content-Type: application/json
|
|
47
|
+
|
|
48
|
+
{
|
|
49
|
+
"userIds": ["u1","u2",...], // required, 1-1000
|
|
50
|
+
"couponTemplateId": "ct_123", // required
|
|
51
|
+
"batchId": "b_uuid" // optional, 幂等 key
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
→ 200 OK
|
|
55
|
+
{
|
|
56
|
+
"grantedCount": 990,
|
|
57
|
+
"failedCount": 10,
|
|
58
|
+
"failedUsers": [{"userId":"u10", "reason":"RISK_HIT", "hitCode":"R001"}]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 错误码
|
|
63
|
+
| code | http | 含义 |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| EMPTY_BATCH | 400 | 空输入 |
|
|
66
|
+
| BATCH_TOO_LARGE | 400 | > 1000 |
|
|
67
|
+
| TEMPLATE_NOT_FOUND | 400 | 不存在 |
|
|
68
|
+
| FORBIDDEN | 403 | 无权限 |
|
|
69
|
+
| INSUFFICIENT_STOCK | 409 | 券库存不足 |
|
|
70
|
+
| SERVICE_DISABLED | 503 | flag 关闭 |
|
|
71
|
+
|
|
72
|
+
### 事件 / 消息
|
|
73
|
+
- <新增 topic schema,或复用现有 topic 并说明>
|
|
74
|
+
|
|
75
|
+
### YAPI / OpenAPI 同步
|
|
76
|
+
- 契约文件:<openapi.json / swagger.json / api.md>
|
|
77
|
+
- 同步命令:`devflow sync yapi --file=<file> --dry-run`
|
|
78
|
+
- 同步策略:新增 / 覆盖 / 合并;说明分类(category)和 owner
|
|
79
|
+
|
|
80
|
+
## 6. 数据层
|
|
81
|
+
### DDL
|
|
82
|
+
```sql
|
|
83
|
+
ALTER TABLE coupon_grant ADD COLUMN IF NOT EXISTS batch_id VARCHAR(36) NULL
|
|
84
|
+
COMMENT '批次号,null 表示单发';
|
|
85
|
+
|
|
86
|
+
CREATE INDEX IF NOT EXISTS idx_grant_batch_id ON coupon_grant(batch_id);
|
|
87
|
+
```
|
|
88
|
+
- 幂等:✓
|
|
89
|
+
- 回滚:`DROP COLUMN IF EXISTS` + `DROP INDEX IF EXISTS`
|
|
90
|
+
- 容量评估:新列 VARCHAR(36) × 当前 1 亿行 ≈ 3.6 GB(可接受)
|
|
91
|
+
|
|
92
|
+
### 数据迁移
|
|
93
|
+
<若涉及双写 / 回填,详见 rollout-and-rollback.md>
|
|
94
|
+
|
|
95
|
+
## 7. 关键流程
|
|
96
|
+
### 成功路径
|
|
97
|
+
```mermaid
|
|
98
|
+
sequenceDiagram
|
|
99
|
+
Client->>+BatchGrantController: POST /batch-grant (1000 userIds)
|
|
100
|
+
BatchGrantController->>+GrantService: for each userId: grantOne
|
|
101
|
+
GrantService->>+RiskService: check(userId, templateId)
|
|
102
|
+
RiskService-->>-GrantService: pass/hit
|
|
103
|
+
alt pass
|
|
104
|
+
GrantService->>+DB: INSERT grant_log + batch_id
|
|
105
|
+
DB-->>-GrantService: ok
|
|
106
|
+
end
|
|
107
|
+
GrantService-->>-BatchGrantController: result
|
|
108
|
+
BatchGrantController-->>-Client: 200 {granted, failed}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 失败路径:下游 RiskService 超时
|
|
112
|
+
<sequence diagram;展示 timeout → 降级 → 指标上报 的流程>
|
|
113
|
+
|
|
114
|
+
### 调用链一致性验证
|
|
115
|
+
- traceId / requestId 传递点:<入口 / 服务调用 / 回调 / 异步消息 / 前端轮询>
|
|
116
|
+
- 调用方一致性:<字段 / 枚举 / 状态语义 / redirect/query / callback>
|
|
117
|
+
- 日志检索:`devflow logs query --trace-id=<id>` 或 `--request-id=<id>`,provider 可为 SLS / OSS
|
|
118
|
+
- 报告:`devflow test contract --cmd="<contract/check command>"`
|
|
119
|
+
|
|
120
|
+
## 8. 错误处理 / 事务 / 回滚
|
|
121
|
+
- 批量接口**不使用**外层事务;每个 userId 独立 try-catch 独立 commit
|
|
122
|
+
- 理由:部分失败语义 + 避免 1000 条连一个事务(长事务 + 行锁压力)
|
|
123
|
+
- 重复 batchId:DB `UNIQUE (batch_id, userId)` 约束 + upsert 幂等
|
|
124
|
+
- 下游超时:3s 超时 + 快速失败 + 落 failedUsers reason=DOWNSTREAM_TIMEOUT
|
|
125
|
+
- 数据不一致容忍:允许 grant_log 落库成功但缓存未刷新(1 分钟后一致)
|
|
126
|
+
|
|
127
|
+
## 9. 可观测性
|
|
128
|
+
### 指标
|
|
129
|
+
| name | type | 触发点 | 告警阈值 |
|
|
130
|
+
| --- | --- | --- | --- |
|
|
131
|
+
| coupon.batch.latency | histogram | 接口返回 | P99 > 5s 5min |
|
|
132
|
+
| coupon.batch.error_rate | gauge | 接口返回 | > 1% 5min |
|
|
133
|
+
| coupon.batch.partial_success | counter | 有 failedUsers | — |
|
|
134
|
+
|
|
135
|
+
### 日志
|
|
136
|
+
- INFO:请求入参摘要(batch_id, size, templateId, operator)
|
|
137
|
+
- WARN:单条失败(userId, reason, hitCode)
|
|
138
|
+
- ERROR:全量失败或非预期异常(含 stack + traceId)
|
|
139
|
+
|
|
140
|
+
### 处置手册(L3 必填)
|
|
141
|
+
- <告警时第一步怎么办;二层升级给谁>
|
|
142
|
+
|
|
143
|
+
## 10. 兼容性 / 灰度 / 回滚
|
|
144
|
+
### 灰度
|
|
145
|
+
- feature flag `coupon.batch.enabled`(Apollo)
|
|
146
|
+
- 阶段:内部 5 个运营账号白名单 → 1% 灰度 → 10% → 100%
|
|
147
|
+
- 每阶段观测 P99 + error_rate ≥ 2 小时
|
|
148
|
+
|
|
149
|
+
### 回滚
|
|
150
|
+
- flag=0 立即生效;正在进行的请求沿用新路径完成
|
|
151
|
+
- DB 变更不需要回滚(新增列不影响旧代码)
|
|
152
|
+
|
|
153
|
+
### 兼容性
|
|
154
|
+
- 单发接口 `/api/v1/coupon/grant` 不动,前端/他方不感知
|
|
155
|
+
- Legacy 客户端不调批量接口
|
|
156
|
+
|
|
157
|
+
## 11. 备选方案
|
|
158
|
+
### 方案 A(已选):API 同步批量 + 内部循环 grantOne
|
|
159
|
+
- 优点:复用风控 / 复杂度低 / 上线快
|
|
160
|
+
- 缺点:1000 人 P99 ≈ 3s,单实例 QPS 有限
|
|
161
|
+
|
|
162
|
+
### 方案 B:异步任务 + 消息队列
|
|
163
|
+
- 优点:高吞吐 / 耐堆积
|
|
164
|
+
- 缺点:异步语义复杂 / 运营需轮询结果 / 当前无运营轮询 UI
|
|
165
|
+
- 放弃理由:当前规模(峰值 QPS ≤ 20)同步可扛,换异步增加运营心智成本
|
|
166
|
+
|
|
167
|
+
### 方案 C:客户端并发调单发
|
|
168
|
+
- 优点:服务端无改动
|
|
169
|
+
- 缺点:风控容易把批量操作当刷子;运营体验差;无批次语义
|
|
170
|
+
- 放弃理由:风控坑大
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## 字段语义补充
|
|
176
|
+
|
|
177
|
+
### §3 架构影响
|
|
178
|
+
|
|
179
|
+
图的原则:
|
|
180
|
+
|
|
181
|
+
1. **只画变化的边**,不要把全系统架构图贴上来
|
|
182
|
+
2. 新增组件标 `*(新建)*`,改动组件标 `*(修改)*`,删除标 `*(删除)*`
|
|
183
|
+
3. ASCII 和 mermaid 都 OK,优先 mermaid(更可维护)
|
|
184
|
+
4. **关键依赖的方向必须正确**(新组件的 inbound / outbound 都画)
|
|
185
|
+
|
|
186
|
+
**反例**:
|
|
187
|
+
|
|
188
|
+
> ~~(把整个 microservices 架构图贴过来)~~
|
|
189
|
+
|
|
190
|
+
**正例**:
|
|
191
|
+
|
|
192
|
+
> ```mermaid
|
|
193
|
+
> graph LR
|
|
194
|
+
> Client -->|*新建*| BatchGrantCtrl[BatchGrantController *(新建)*]
|
|
195
|
+
> BatchGrantCtrl --> GrantService[GrantService *(复用)*]
|
|
196
|
+
> GrantService --> RiskService
|
|
197
|
+
> GrantService --> DB[(coupon_grant *(ddl: +batch_id)*)]
|
|
198
|
+
> ```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
### §4 改动点汇总
|
|
203
|
+
|
|
204
|
+
每行要写**类型**,不要只写"改":
|
|
205
|
+
|
|
206
|
+
| 类型 | 含义 |
|
|
207
|
+
| --- | --- |
|
|
208
|
+
| 新建 | 新建类 / 方法 / 表 |
|
|
209
|
+
| 修改 | 改已有类 / 方法 |
|
|
210
|
+
| 复用 | 调用现有,无修改 |
|
|
211
|
+
| 删除 | 删除(注明原因) |
|
|
212
|
+
| 配置 | 配置 / feature flag |
|
|
213
|
+
|
|
214
|
+
**为什么每行要标对应 F-ID**:验证 F-ID coverage、下游 plan 拆 task、code-review 能扫完整度。
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
### §5 契约
|
|
219
|
+
|
|
220
|
+
必须有的内容:
|
|
221
|
+
|
|
222
|
+
- HTTP method + path(含版本)
|
|
223
|
+
- Request/Response 完整 JSON 例子
|
|
224
|
+
- 必需 / 可选字段、类型 / 长度
|
|
225
|
+
- 错误码表(code + http + 含义)
|
|
226
|
+
- 幂等性(是否幂等 + 幂等 key)
|
|
227
|
+
|
|
228
|
+
契约的**版本化与兼容性**见 `api-contract-design.md`。
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
### §6 数据层
|
|
233
|
+
|
|
234
|
+
硬规则:
|
|
235
|
+
|
|
236
|
+
1. **所有 DDL 幂等**:`IF NOT EXISTS` / `IF EXISTS`
|
|
237
|
+
2. **不要 DROP COLUMN**(除非用户明确同意 + 有数据迁移方案)
|
|
238
|
+
3. 新增索引要评估写放大(写热点表多一个索引成本)
|
|
239
|
+
4. 大表 DDL 需说明 online vs offline(MySQL 5.6+ online DDL / 大表加列可能要 pt-osc)
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
### §7 关键流程
|
|
244
|
+
|
|
245
|
+
至少画 **2 条**:
|
|
246
|
+
|
|
247
|
+
1. **Happy path**:最常见的成功路径
|
|
248
|
+
2. **至少 1 条 failure path**:下游超时 / 部分失败 / 幂等重试 之一
|
|
249
|
+
|
|
250
|
+
**反例**:
|
|
251
|
+
|
|
252
|
+
> 1. 接收请求 2. 处理 3. 返回
|
|
253
|
+
> (这不是流程,是废话)
|
|
254
|
+
|
|
255
|
+
**正例**:
|
|
256
|
+
|
|
257
|
+
> - 接收请求 → 校验(参数 + 权限) → 读 RiskService 配置 → 循环 grantOne(每条独立事务)→ 聚合结果 → 返回
|
|
258
|
+
> - 单条 grantOne = RiskService.check → 若 pass:INSERT grant_log;若 hit:记 failedUsers
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
### §8 错误处理 / 事务
|
|
263
|
+
|
|
264
|
+
必须说清楚:
|
|
265
|
+
|
|
266
|
+
- 事务边界(哪些步骤同一事务,哪些独立)
|
|
267
|
+
- 事务传播(嵌套事务怎么处理)
|
|
268
|
+
- 幂等策略(重复请求怎么办)
|
|
269
|
+
- 失败分类(可恢复 / 不可恢复 / 需人工)
|
|
270
|
+
- 数据一致性等级(强一致 / 最终一致 / 允许脏读)
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
### §11 Alternatives
|
|
275
|
+
|
|
276
|
+
每个备选要有:
|
|
277
|
+
|
|
278
|
+
1. **方案名 + 核心思路**
|
|
279
|
+
2. **优缺点**
|
|
280
|
+
3. **放弃 / 选中理由**(要有决策信号,不能 "就选了 A")
|
|
281
|
+
|
|
282
|
+
**反例**:
|
|
283
|
+
|
|
284
|
+
> 方案 B:MQ。不选,因为复杂。
|
|
285
|
+
> (不足以支持决策)
|
|
286
|
+
|
|
287
|
+
**正例**:
|
|
288
|
+
|
|
289
|
+
> 方案 B:异步任务 + 消息队列
|
|
290
|
+
> - 优点:高吞吐 / 耐堆积 / 能轻易做历史查询
|
|
291
|
+
> - 缺点:
|
|
292
|
+
> - 异步语义让运营要轮询或等通知(当前无 UI)
|
|
293
|
+
> - 部分失败返回语义复杂(多 event 收集)
|
|
294
|
+
> - 开发量 + 2 人周(要加消费者 + 任务表 + 状态机)
|
|
295
|
+
> - 放弃:当前峰值 QPS ≤ 20,同步可扛;异步的好处在未来 10x 规模才显现,届时可演进(方案 A 可无损平迁到 B,因为 API 外观不变)
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## 本文与 SKILL.md 的关系
|
|
300
|
+
|
|
301
|
+
SKILL.md 给了 11 段表 + 每段的 L1/L2/L3 级别差异。本文给每段完整模板、字段语义、正反例、L2 完整示例。agent 写 design.md 时应复制本文模板开始。
|