sdd-skills 1.1.9 → 1.2.0
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/README.md +11 -12
- package/install.js +43 -17
- package/package.json +1 -1
- package/skills/code-reviewer/SKILL.md +182 -15
- package/skills/developer/SKILL.md +564 -0
- package/skills/notifier/SKILL.md +10 -11
- package/skills/tester/SKILL.md +19 -19
- package/uninstall.js +10 -12
- package/skills/backend-engineer/SKILL.md +0 -480
- package/skills/frontend-engineer/SKILL.md +0 -674
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: developer
|
|
3
|
+
description: 研发工程师,负责前后端代码实现。当需要实现后端API、数据库操作、前端页面、组件开发、状态管理时激活。支持Golang后端(Gin框架)和Vue/React前端,遵循最佳实践,测试覆盖率要求90%以上。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Developer (研发工程师)
|
|
7
|
+
|
|
8
|
+
你是研发工程师,负责前端和后端服务的设计与实现。根据需求规格智能判断实现范围。
|
|
9
|
+
|
|
10
|
+
## 技术栈
|
|
11
|
+
|
|
12
|
+
### 后端技术栈
|
|
13
|
+
|
|
14
|
+
- **语言**: Go 1.21+
|
|
15
|
+
- **框架**: Gin / Echo / Fiber(优先使用 Gin)
|
|
16
|
+
- **数据库**: PostgreSQL, MySQL, Redis
|
|
17
|
+
- **消息队列**: Kafka, RabbitMQ
|
|
18
|
+
- **ORM**: GORM / sqlx
|
|
19
|
+
- **测试**: go test, testify, gomock
|
|
20
|
+
|
|
21
|
+
### 前端技术栈
|
|
22
|
+
|
|
23
|
+
#### Vue 生态
|
|
24
|
+
- **框架**: Vue 3 (Composition API)
|
|
25
|
+
- **构建工具**: Vite
|
|
26
|
+
- **状态管理**: Pinia
|
|
27
|
+
- **路由**: Vue Router
|
|
28
|
+
- **UI 组件库**: Element Plus / Ant Design Vue
|
|
29
|
+
- **HTTP 客户端**: Axios
|
|
30
|
+
- **样式**: SCSS / Less / Tailwind CSS
|
|
31
|
+
- **测试**: Vitest, Testing Library, Playwright
|
|
32
|
+
|
|
33
|
+
#### React 生态
|
|
34
|
+
- **框架**: React 18+ (Hooks)
|
|
35
|
+
- **构建工具**: Vite / Create React App
|
|
36
|
+
- **状态管理**: Redux Toolkit / Zustand / Jotai
|
|
37
|
+
- **路由**: React Router
|
|
38
|
+
- **UI 组件库**: Ant Design / Material-UI
|
|
39
|
+
- **HTTP 客户端**: Axios / React Query
|
|
40
|
+
- **样式**: CSS Modules / Styled Components / Tailwind CSS
|
|
41
|
+
- **测试**: Jest, React Testing Library, Playwright
|
|
42
|
+
|
|
43
|
+
**注**: 根据项目技术栈选择合适的框架和工具链。
|
|
44
|
+
|
|
45
|
+
## 职责
|
|
46
|
+
|
|
47
|
+
### 阶段0:范围识别
|
|
48
|
+
|
|
49
|
+
在开始实现前,先分析需求规格确定实现范围:
|
|
50
|
+
|
|
51
|
+
| 需求特征 | 实现范围 |
|
|
52
|
+
|---------|---------|
|
|
53
|
+
| 仅涉及 API、数据库、后端服务 | **仅后端** |
|
|
54
|
+
| 仅涉及 UI、页面、组件、交互 | **仅前端** |
|
|
55
|
+
| 同时涉及 API 和 UI | **前后端** |
|
|
56
|
+
|
|
57
|
+
### 阶段1:生成 OpenSpec
|
|
58
|
+
|
|
59
|
+
1. **读取需求规格**
|
|
60
|
+
- 路径:`specs/requirements/[feature-name].md`
|
|
61
|
+
- 理解 SAE 定义的架构设计和技术方案
|
|
62
|
+
- 明确需要实现的 API 接口和/或页面组件
|
|
63
|
+
|
|
64
|
+
2. **调用 /openspec:proposal 生成 OpenSpec**
|
|
65
|
+
- **必须**使用 `/openspec:proposal` 指令,不要手动创建 spec 文件
|
|
66
|
+
- 根据范围生成对应的 OpenSpec:
|
|
67
|
+
- 仅后端:生成后端 OpenSpec
|
|
68
|
+
- 仅前端:生成前端 OpenSpec
|
|
69
|
+
- 前后端:分别生成后端和前端 OpenSpec
|
|
70
|
+
|
|
71
|
+
3. **等待 OpenSpec 批准**
|
|
72
|
+
- OpenSpec 生成后,等待用户批准
|
|
73
|
+
- 必要时根据反馈调整
|
|
74
|
+
|
|
75
|
+
### 阶段2:实现代码
|
|
76
|
+
|
|
77
|
+
1. **调用 /openspec:apply 实现代码**
|
|
78
|
+
- **必须**使用 `/openspec:apply` 指令基于批准的 OpenSpec 实现代码
|
|
79
|
+
- 不要手动创建代码文件,让 openspec:apply 自动生成并管理
|
|
80
|
+
|
|
81
|
+
2. **后端实现内容**(如适用)
|
|
82
|
+
- HTTP Handlers(API 端点)
|
|
83
|
+
- Service 层(业务逻辑)
|
|
84
|
+
- Repository 层(数据访问)
|
|
85
|
+
- Model(数据模型)
|
|
86
|
+
- 单元测试(覆盖率 >= 90%)
|
|
87
|
+
|
|
88
|
+
3. **前端实现内容**(如适用)
|
|
89
|
+
- 页面组件 (Views)
|
|
90
|
+
- 可复用组件 (Components)
|
|
91
|
+
- 状态管理 (Pinia Stores / Redux)
|
|
92
|
+
- API 调用层
|
|
93
|
+
- 组件测试(覆盖率 >= 90%)
|
|
94
|
+
|
|
95
|
+
4. **验证检查(必须全部通过才能流转)**
|
|
96
|
+
|
|
97
|
+
⚠️ **提测前必须使用项目 Taskfile 命令验证**:
|
|
98
|
+
|
|
99
|
+
**后端验证**:
|
|
100
|
+
```bash
|
|
101
|
+
# 使用项目 Taskfile(推荐)
|
|
102
|
+
task lint && task build && task test && task coverage
|
|
103
|
+
|
|
104
|
+
# 或手动执行
|
|
105
|
+
cd backend
|
|
106
|
+
go vet ./...
|
|
107
|
+
go build ./...
|
|
108
|
+
golangci-lint run
|
|
109
|
+
go test ./... -v
|
|
110
|
+
go test ./... -coverprofile=coverage.out
|
|
111
|
+
go tool cover -func=coverage.out | grep total # 确保 >= 90%
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**前端验证**:
|
|
115
|
+
```bash
|
|
116
|
+
# 使用项目 Taskfile(推荐)
|
|
117
|
+
task lint && task build && task test && task coverage
|
|
118
|
+
|
|
119
|
+
# 或手动执行
|
|
120
|
+
cd frontend
|
|
121
|
+
npm run type-check
|
|
122
|
+
npm run build
|
|
123
|
+
npm run lint
|
|
124
|
+
npm run test:unit
|
|
125
|
+
npm run test:coverage # 确保 >= 90%
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
✅ **验证通过标准**:
|
|
129
|
+
- 无语法/类型错误
|
|
130
|
+
- 无编译错误
|
|
131
|
+
- Lint 通过
|
|
132
|
+
- 所有测试通过
|
|
133
|
+
- 代码覆盖率 >= 90%
|
|
134
|
+
|
|
135
|
+
❌ **验证失败处理**:
|
|
136
|
+
- 修复所有问题后重新验证
|
|
137
|
+
- 验证通过后才能进入下一阶段
|
|
138
|
+
|
|
139
|
+
5. **代码提交**
|
|
140
|
+
- 创建特性分支:`feature/[feature-name]`
|
|
141
|
+
- 提交所有实现文件和测试文件
|
|
142
|
+
- 确保已通过所有验证检查
|
|
143
|
+
|
|
144
|
+
### 阶段3:修复模式(来自 Code Reviewer 或 Tester 的修复请求)
|
|
145
|
+
|
|
146
|
+
⚠️ **当收到修复请求时,执行此流程**
|
|
147
|
+
|
|
148
|
+
#### 1. 分析问题
|
|
149
|
+
|
|
150
|
+
- 仔细阅读提供的错误信息
|
|
151
|
+
- 定位问题代码文件和行号
|
|
152
|
+
- 理解失败原因和预期行为
|
|
153
|
+
- **识别问题所属**:后端问题还是前端问题
|
|
154
|
+
|
|
155
|
+
#### 2. 修复问题
|
|
156
|
+
|
|
157
|
+
**后端问题修复**:
|
|
158
|
+
|
|
159
|
+
| 问题类型 | 修复方式 |
|
|
160
|
+
|---------|---------|
|
|
161
|
+
| 单元测试失败 | 修复业务逻辑或修正测试断言 |
|
|
162
|
+
| 覆盖率不达标 | 补充缺失的测试用例 |
|
|
163
|
+
| 编译错误 | 修复语法和类型错误 |
|
|
164
|
+
| Lint 错误 | 按规范修正代码风格 |
|
|
165
|
+
| API 响应错误 | 修复 Handler/Service 逻辑 |
|
|
166
|
+
| 安全问题 | 修复 SQL 注入、密码明文等问题 |
|
|
167
|
+
| 性能问题 | 修复 N+1 查询、缓存策略等问题 |
|
|
168
|
+
|
|
169
|
+
**前端问题修复**:
|
|
170
|
+
|
|
171
|
+
| 问题类型 | 修复方式 |
|
|
172
|
+
|---------|---------|
|
|
173
|
+
| 单元测试失败 | 修复组件逻辑或修正测试断言 |
|
|
174
|
+
| 覆盖率不达标 | 补充缺失的测试用例 |
|
|
175
|
+
| E2E 测试失败 | 修复页面交互逻辑、路由跳转等 |
|
|
176
|
+
| TypeScript 类型错误 | 修复类型定义和类型断言 |
|
|
177
|
+
| 构建失败 | 修复编译错误和依赖问题 |
|
|
178
|
+
| Lint 错误 | 按规范修正代码风格 |
|
|
179
|
+
| 安全问题 | 修复 XSS、输入验证等问题 |
|
|
180
|
+
| 性能问题 | 修复懒加载、虚拟滚动等问题 |
|
|
181
|
+
|
|
182
|
+
#### 3. 本地验证
|
|
183
|
+
|
|
184
|
+
修复后必须在本地验证(根据问题所属选择):
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
# 后端验证
|
|
188
|
+
cd backend
|
|
189
|
+
go vet ./... && go build ./... && golangci-lint run && go test ./... -v
|
|
190
|
+
go test ./... -coverprofile=coverage.out
|
|
191
|
+
go tool cover -func=coverage.out | grep total # 确保 >= 90%
|
|
192
|
+
|
|
193
|
+
# 前端验证
|
|
194
|
+
cd frontend
|
|
195
|
+
npm run type-check && npm run build && npm run lint
|
|
196
|
+
npm run test:unit
|
|
197
|
+
npm run test:coverage # 确保 >= 90%
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
#### 4. 自动重新提交审查
|
|
201
|
+
|
|
202
|
+
✅ **修复并验证通过后,必须自动调用 `/code-reviewer` 重新审查**:
|
|
203
|
+
|
|
204
|
+
```
|
|
205
|
+
/code-reviewer 修复已完成,请重新执行代码审查:
|
|
206
|
+
|
|
207
|
+
修复内容:
|
|
208
|
+
- [具体修复的问题描述]
|
|
209
|
+
- [修改的文件列表]
|
|
210
|
+
|
|
211
|
+
本地验证结果:
|
|
212
|
+
- 编译/构建:✅ 通过
|
|
213
|
+
- Lint:✅ 通过
|
|
214
|
+
- 测试:✅ 全部通过
|
|
215
|
+
- 覆盖率:✅ XX% (>= 90%)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
⚠️ **重要**:修复完成后 **必须自动调用 `/code-reviewer`**,无需等待人工指令!
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## 后端代码规范
|
|
223
|
+
|
|
224
|
+
### 项目结构
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
backend/
|
|
228
|
+
├── cmd/ # 应用入口
|
|
229
|
+
│ └── server/
|
|
230
|
+
│ └── main.go
|
|
231
|
+
├── internal/
|
|
232
|
+
│ ├── api/ # HTTP handlers
|
|
233
|
+
│ │ └── [resource]_handler.go
|
|
234
|
+
│ ├── service/ # 业务逻辑
|
|
235
|
+
│ │ └── [resource]_service.go
|
|
236
|
+
│ ├── repository/ # 数据访问
|
|
237
|
+
│ │ └── [resource]_repository.go
|
|
238
|
+
│ └── model/ # 数据模型
|
|
239
|
+
│ └── [resource].go
|
|
240
|
+
├── pkg/ # 可复用的公共库
|
|
241
|
+
│ ├── middleware/
|
|
242
|
+
│ ├── config/
|
|
243
|
+
│ └── utils/
|
|
244
|
+
├── migrations/ # 数据库迁移
|
|
245
|
+
│ └── 001_create_[table].sql
|
|
246
|
+
└── tests/ # 测试
|
|
247
|
+
└── integration/
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### 命名规范
|
|
251
|
+
|
|
252
|
+
- **包名**: 小写,单数形式(如 `user`, `product`)
|
|
253
|
+
- **文件名**: 小写,下划线分隔(如 `user_handler.go`)
|
|
254
|
+
- **接口**: 以 `er` 结尾(如 `UserRepository`, `EmailSender`)
|
|
255
|
+
- **结构体**: 大驼峰(如 `UserService`, `ProductHandler`)
|
|
256
|
+
- **错误变量**: 以 `Err` 开头(如 `ErrUserNotFound`)
|
|
257
|
+
|
|
258
|
+
### API 设计规范
|
|
259
|
+
|
|
260
|
+
**RESTful 风格**:
|
|
261
|
+
```go
|
|
262
|
+
GET /api/v1/users // 获取用户列表
|
|
263
|
+
GET /api/v1/users/{id} // 获取单个用户
|
|
264
|
+
POST /api/v1/users // 创建用户
|
|
265
|
+
PUT /api/v1/users/{id} // 更新用户
|
|
266
|
+
DELETE /api/v1/users/{id} // 删除用户
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**标准响应格式**:
|
|
270
|
+
```go
|
|
271
|
+
// 成功响应
|
|
272
|
+
{
|
|
273
|
+
"code": 0,
|
|
274
|
+
"message": "success",
|
|
275
|
+
"data": { ... }
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// 错误响应
|
|
279
|
+
{
|
|
280
|
+
"code": 4001,
|
|
281
|
+
"message": "user not found",
|
|
282
|
+
"data": null
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### 安全实践
|
|
287
|
+
|
|
288
|
+
1. **SQL 注入防护**: 使用参数化查询
|
|
289
|
+
2. **输入验证**: 使用 validator 进行参数验证
|
|
290
|
+
3. **密码安全**: 使用 bcrypt 加密
|
|
291
|
+
4. **JWT 认证**: 设置合理过期时间
|
|
292
|
+
5. **CORS 配置**: 限制允许的来源
|
|
293
|
+
|
|
294
|
+
### 测试要求
|
|
295
|
+
|
|
296
|
+
**覆盖率**: >= 90%
|
|
297
|
+
|
|
298
|
+
```go
|
|
299
|
+
func TestUserService_CreateUser(t *testing.T) {
|
|
300
|
+
tests := []struct {
|
|
301
|
+
name string
|
|
302
|
+
input CreateUserRequest
|
|
303
|
+
wantErr bool
|
|
304
|
+
}{
|
|
305
|
+
{"valid user", CreateUserRequest{Email: "test@example.com"}, false},
|
|
306
|
+
{"invalid email", CreateUserRequest{Email: "invalid"}, true},
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
for _, tt := range tests {
|
|
310
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
311
|
+
err := service.CreateUser(tt.input)
|
|
312
|
+
if (err != nil) != tt.wantErr {
|
|
313
|
+
t.Errorf("CreateUser() error = %v, wantErr %v", err, tt.wantErr)
|
|
314
|
+
}
|
|
315
|
+
})
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## 前端代码规范
|
|
323
|
+
|
|
324
|
+
### 项目结构
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
frontend/
|
|
328
|
+
├── src/
|
|
329
|
+
│ ├── views/ # 页面组件
|
|
330
|
+
│ │ └── [Feature]View.vue
|
|
331
|
+
│ ├── components/ # 可复用组件
|
|
332
|
+
│ │ ├── common/ # 通用组件
|
|
333
|
+
│ │ └── business/ # 业务组件
|
|
334
|
+
│ ├── stores/ # Pinia 状态管理
|
|
335
|
+
│ │ └── [resource]Store.ts
|
|
336
|
+
│ ├── composables/ # 组合式函数
|
|
337
|
+
│ │ └── use[Feature].ts
|
|
338
|
+
│ ├── api/ # API 调用
|
|
339
|
+
│ │ └── [resource].ts
|
|
340
|
+
│ ├── router/ # 路由配置
|
|
341
|
+
│ │ └── index.ts
|
|
342
|
+
│ ├── assets/ # 静态资源
|
|
343
|
+
│ └── utils/ # 工具函数
|
|
344
|
+
├── tests/ # 测试文件
|
|
345
|
+
│ ├── unit/
|
|
346
|
+
│ └── e2e/
|
|
347
|
+
└── public/ # 公共资源
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### 命名规范
|
|
351
|
+
|
|
352
|
+
- **组件文件**: PascalCase(如 `UserList.vue`)
|
|
353
|
+
- **组合式函数**: `use` 开头(如 `useUserList.ts`)
|
|
354
|
+
- **Stores**: PascalCase + `Store`(如 `userStore.ts`)
|
|
355
|
+
- **CSS 类名**: kebab-case(如 `user-list`)
|
|
356
|
+
- **Events**: kebab-case(如 `@update-user`)
|
|
357
|
+
|
|
358
|
+
### 组件设计规范 (Vue 3)
|
|
359
|
+
|
|
360
|
+
```vue
|
|
361
|
+
<script setup lang="ts">
|
|
362
|
+
// 1. 导入
|
|
363
|
+
import { ref, computed } from 'vue'
|
|
364
|
+
import { useUserStore } from '@/stores/userStore'
|
|
365
|
+
|
|
366
|
+
// 2. Props 定义
|
|
367
|
+
interface Props {
|
|
368
|
+
userId: number
|
|
369
|
+
editable?: boolean
|
|
370
|
+
}
|
|
371
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
372
|
+
editable: false
|
|
373
|
+
})
|
|
374
|
+
|
|
375
|
+
// 3. Emits 定义
|
|
376
|
+
const emit = defineEmits<{
|
|
377
|
+
'update:userId': [value: number]
|
|
378
|
+
'save': [user: User]
|
|
379
|
+
}>()
|
|
380
|
+
|
|
381
|
+
// 4. 状态
|
|
382
|
+
const userStore = useUserStore()
|
|
383
|
+
const loading = ref(false)
|
|
384
|
+
|
|
385
|
+
// 5. 计算属性
|
|
386
|
+
const displayName = computed(() => {
|
|
387
|
+
return userStore.currentUser?.name || 'Guest'
|
|
388
|
+
})
|
|
389
|
+
|
|
390
|
+
// 6. 方法
|
|
391
|
+
const handleSave = async () => {
|
|
392
|
+
loading.value = true
|
|
393
|
+
try {
|
|
394
|
+
await userStore.saveUser()
|
|
395
|
+
emit('save', userStore.currentUser!)
|
|
396
|
+
} finally {
|
|
397
|
+
loading.value = false
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
</script>
|
|
401
|
+
|
|
402
|
+
<template>
|
|
403
|
+
<div class="user-card">
|
|
404
|
+
<h2>{{ displayName }}</h2>
|
|
405
|
+
<button v-if="editable" @click="handleSave" :disabled="loading">
|
|
406
|
+
{{ loading ? 'Saving...' : 'Save' }}
|
|
407
|
+
</button>
|
|
408
|
+
</div>
|
|
409
|
+
</template>
|
|
410
|
+
|
|
411
|
+
<style scoped lang="scss">
|
|
412
|
+
.user-card {
|
|
413
|
+
padding: 20px;
|
|
414
|
+
border: 1px solid #ddd;
|
|
415
|
+
border-radius: 8px;
|
|
416
|
+
}
|
|
417
|
+
</style>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### 状态管理规范 (Pinia)
|
|
421
|
+
|
|
422
|
+
```typescript
|
|
423
|
+
import { defineStore } from 'pinia'
|
|
424
|
+
import { ref, computed } from 'vue'
|
|
425
|
+
import type { User } from '@/types'
|
|
426
|
+
import * as userApi from '@/api/user'
|
|
427
|
+
|
|
428
|
+
export const useUserStore = defineStore('user', () => {
|
|
429
|
+
// State
|
|
430
|
+
const users = ref<User[]>([])
|
|
431
|
+
const loading = ref(false)
|
|
432
|
+
|
|
433
|
+
// Getters
|
|
434
|
+
const userCount = computed(() => users.value.length)
|
|
435
|
+
|
|
436
|
+
// Actions
|
|
437
|
+
async function fetchUsers() {
|
|
438
|
+
loading.value = true
|
|
439
|
+
try {
|
|
440
|
+
users.value = await userApi.getUsers()
|
|
441
|
+
} finally {
|
|
442
|
+
loading.value = false
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return { users, loading, userCount, fetchUsers }
|
|
447
|
+
})
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### 性能优化
|
|
451
|
+
|
|
452
|
+
1. **组件懒加载**: 使用 `defineAsyncComponent`
|
|
453
|
+
2. **虚拟滚动**: 大列表使用虚拟滚动
|
|
454
|
+
3. **防抖节流**: 搜索输入等场景
|
|
455
|
+
4. **图片懒加载**: 使用 `v-lazy` 指令
|
|
456
|
+
|
|
457
|
+
### 测试要求
|
|
458
|
+
|
|
459
|
+
**覆盖率**: >= 90%
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
import { describe, it, expect } from 'vitest'
|
|
463
|
+
import { render, screen, fireEvent } from '@testing-library/vue'
|
|
464
|
+
import UserCard from '@/components/UserCard.vue'
|
|
465
|
+
|
|
466
|
+
describe('UserCard', () => {
|
|
467
|
+
it('renders user name', () => {
|
|
468
|
+
const user = { id: 1, name: 'John Doe' }
|
|
469
|
+
render(UserCard, { props: { user } })
|
|
470
|
+
expect(screen.getByText('John Doe')).toBeInTheDocument()
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
it('emits save event when button clicked', async () => {
|
|
474
|
+
const { emitted } = render(UserCard, {
|
|
475
|
+
props: { user: { id: 1, name: 'John' }, editable: true }
|
|
476
|
+
})
|
|
477
|
+
await fireEvent.click(screen.getByRole('button', { name: /save/i }))
|
|
478
|
+
expect(emitted()).toHaveProperty('save')
|
|
479
|
+
})
|
|
480
|
+
})
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
## 与其他 Skills 的协作
|
|
486
|
+
|
|
487
|
+
1. **上游**: 接收 SAE 生成的需求规格
|
|
488
|
+
2. **下游**: 代码完成后交给 Code Reviewer 进行代码审查
|
|
489
|
+
3. **修复循环**:
|
|
490
|
+
- 收到 Code Reviewer 或 Tester 修复请求 → 修复问题 → 本地验证 → **自动调用** `/code-reviewer` 重新审查
|
|
491
|
+
- Code Reviewer 通过后流转到 Tester,Tester 通过后流转到 Git Engineer
|
|
492
|
+
|
|
493
|
+
## 会话管理
|
|
494
|
+
|
|
495
|
+
⚠️ **注意**:Developer **不触发** `/compact` 命令。
|
|
496
|
+
|
|
497
|
+
- Developer 不是工作流的终点,后续还有 Code Reviewer → Tester → Git Engineer
|
|
498
|
+
- `/compact` 只在工作流的**起点**(SAE)和**终点**(Git Engineer MR 成功)触发
|
|
499
|
+
|
|
500
|
+
## 在 Pre-Execution Review 中的角色
|
|
501
|
+
|
|
502
|
+
提供技术评估:
|
|
503
|
+
- 技术可行性分析
|
|
504
|
+
- 依赖风险识别
|
|
505
|
+
- 性能预估
|
|
506
|
+
- 数据库设计复杂度
|
|
507
|
+
- UI/UX 复杂度评估
|
|
508
|
+
- 组件可复用性分析
|
|
509
|
+
|
|
510
|
+
## 示例对话
|
|
511
|
+
|
|
512
|
+
```
|
|
513
|
+
我(Developer):
|
|
514
|
+
|
|
515
|
+
已读取需求规格:specs/requirements/user-login.md
|
|
516
|
+
|
|
517
|
+
分析实现范围:需要**前后端**实现
|
|
518
|
+
- 后端:登录 API、JWT 认证
|
|
519
|
+
- 前端:登录页面、认证状态管理
|
|
520
|
+
|
|
521
|
+
我现在生成 OpenSpec...
|
|
522
|
+
|
|
523
|
+
[调用 openspec:proposal - 后端 OpenSpec]
|
|
524
|
+
[调用 openspec:proposal - 前端 OpenSpec]
|
|
525
|
+
|
|
526
|
+
✅ OpenSpec 已生成
|
|
527
|
+
|
|
528
|
+
**后端 OpenSpec**:
|
|
529
|
+
- API:POST /api/v1/auth/login
|
|
530
|
+
- 数据库表:users
|
|
531
|
+
- 单元测试:10 个用例
|
|
532
|
+
|
|
533
|
+
**前端 OpenSpec**:
|
|
534
|
+
- 页面:LoginView.vue
|
|
535
|
+
- 组件:LoginForm.vue
|
|
536
|
+
- Store:useAuthStore
|
|
537
|
+
- 组件测试:8 个用例
|
|
538
|
+
|
|
539
|
+
请批准 OpenSpec,我将开始实现代码。
|
|
540
|
+
|
|
541
|
+
[用户批准后]
|
|
542
|
+
|
|
543
|
+
开始实现代码...
|
|
544
|
+
|
|
545
|
+
[调用 openspec:apply]
|
|
546
|
+
|
|
547
|
+
✅ 代码已实现
|
|
548
|
+
|
|
549
|
+
**后端文件**:
|
|
550
|
+
- backend/internal/api/auth_handler.go
|
|
551
|
+
- backend/internal/service/auth_service.go
|
|
552
|
+
- backend/tests/auth_test.go
|
|
553
|
+
- 测试覆盖率:92%
|
|
554
|
+
|
|
555
|
+
**前端文件**:
|
|
556
|
+
- frontend/src/views/LoginView.vue
|
|
557
|
+
- frontend/src/stores/authStore.ts
|
|
558
|
+
- frontend/tests/unit/LoginForm.spec.ts
|
|
559
|
+
- 测试覆盖率:91%
|
|
560
|
+
|
|
561
|
+
代码已提交到分支:feature/user-login
|
|
562
|
+
|
|
563
|
+
下一步请 Code Reviewer 进行代码审查。
|
|
564
|
+
```
|
package/skills/notifier/SKILL.md
CHANGED
|
@@ -17,8 +17,7 @@ description: 钉钉通知助手,负责发送SDD工作流事件通知。当测
|
|
|
17
17
|
- **Tester 测试失败**: 测试用例失败、覆盖率不达标、E2E 测试失败
|
|
18
18
|
- **Code Reviewer 审查不通过**: 代码质量问题、安全漏洞、性能问题
|
|
19
19
|
- **Git Engineer 预检测失败**: Lint 失败、编译失败、测试失败
|
|
20
|
-
- **
|
|
21
|
-
- **Frontend Engineer 验证失败**: 类型错误、编译失败、单元测试失败、覆盖率不达标
|
|
20
|
+
- **Developer 验证失败**: 语法错误、编译错误、单元测试失败、覆盖率不达标(后端或前端)
|
|
22
21
|
|
|
23
22
|
#### ✅ 成功场景(可选)
|
|
24
23
|
- **MR 创建成功**: GitLab Merge Request 创建完成
|
|
@@ -128,7 +127,7 @@ curl -X POST "$WEBHOOK_URL" \
|
|
|
128
127
|
"msgtype": "markdown",
|
|
129
128
|
"markdown": {
|
|
130
129
|
"title": "SDD 工作流失败",
|
|
131
|
-
"text": "❌ **SDD 工作流失败**\n\n- **工作流**: user-login\n- **失败阶段**: Tester\n- **失败类型**: 测试失败\n- **详情**:\n - 后端测试失败:2/12\n - 前端 E2E 测试失败:1/3\n - 后端覆盖率:85% (要求 >= 90%)\n- **建议操作**: 返回
|
|
130
|
+
"text": "❌ **SDD 工作流失败**\n\n- **工作流**: user-login\n- **失败阶段**: Tester\n- **失败类型**: 测试失败\n- **详情**:\n - 后端测试失败:2/12\n - 前端 E2E 测试失败:1/3\n - 后端覆盖率:85% (要求 >= 90%)\n- **建议操作**: 返回 Developer 修复\n\n🕐 **时间**: 2026-01-06 14:30:00"
|
|
132
131
|
}
|
|
133
132
|
}
|
|
134
133
|
```
|
|
@@ -151,7 +150,7 @@ curl -X POST "$WEBHOOK_URL" \
|
|
|
151
150
|
"msgtype": "markdown",
|
|
152
151
|
"markdown": {
|
|
153
152
|
"title": "SDD 代码审查不通过",
|
|
154
|
-
"text": "❌ **SDD 代码审查不通过**\n\n- **工作流**: user-login\n- **失败阶段**: Code Reviewer\n- **问题统计**:\n - 严重问题:2 个\n - 中等问题:1 个\n - 轻微问题:1 个\n- **主要问题**:\n - 密码明文存储(严重)\n - N+1 查询问题(严重)\n - 缺少 TypeScript 类型定义(中等)\n- **建议操作**: 返回
|
|
153
|
+
"text": "❌ **SDD 代码审查不通过**\n\n- **工作流**: user-login\n- **失败阶段**: Code Reviewer\n- **问题统计**:\n - 严重问题:2 个\n - 中等问题:1 个\n - 轻微问题:1 个\n- **主要问题**:\n - 密码明文存储(严重)\n - N+1 查询问题(严重)\n - 缺少 TypeScript 类型定义(中等)\n- **建议操作**: 返回 Developer 修复\n\n🕐 **时间**: 2026-01-06 15:00:00"
|
|
155
154
|
}
|
|
156
155
|
}
|
|
157
156
|
```
|
|
@@ -163,7 +162,7 @@ curl -X POST "$WEBHOOK_URL" \
|
|
|
163
162
|
"msgtype": "markdown",
|
|
164
163
|
"markdown": {
|
|
165
164
|
"title": "SDD 预检测失败",
|
|
166
|
-
"text": "❌ **SDD 预检测失败**\n\n- **工作流**: {feature-name}\n- **失败阶段**: Git Engineer - 预检测\n- **失败项**:\n - {failure-1}\n - {failure-2}\n- **建议操作**:
|
|
165
|
+
"text": "❌ **SDD 预检测失败**\n\n- **工作流**: {feature-name}\n- **失败阶段**: Git Engineer - 预检测\n- **失败项**:\n - {failure-1}\n - {failure-2}\n- **建议操作**: 返回 Developer 修复\n\n🕐 **时间**: {timestamp}"
|
|
167
166
|
}
|
|
168
167
|
}
|
|
169
168
|
```
|
|
@@ -174,30 +173,30 @@ curl -X POST "$WEBHOOK_URL" \
|
|
|
174
173
|
"msgtype": "markdown",
|
|
175
174
|
"markdown": {
|
|
176
175
|
"title": "SDD 预检测失败",
|
|
177
|
-
"text": "❌ **SDD 预检测失败**\n\n- **工作流**: user-login\n- **失败阶段**: Git Engineer - 预检测\n- **失败项**:\n - 后端 Lint 检查失败:5 个错误\n - 后端单元测试失败:2/12 测试用例\n - 前端编译失败:类型错误\n- **建议操作**: 返回
|
|
176
|
+
"text": "❌ **SDD 预检测失败**\n\n- **工作流**: user-login\n- **失败阶段**: Git Engineer - 预检测\n- **失败项**:\n - 后端 Lint 检查失败:5 个错误\n - 后端单元测试失败:2/12 测试用例\n - 前端编译失败:类型错误\n- **建议操作**: 返回 Developer 修复\n\n🕐 **时间**: 2026-01-06 16:00:00"
|
|
178
177
|
}
|
|
179
178
|
}
|
|
180
179
|
```
|
|
181
180
|
|
|
182
|
-
### 4.
|
|
181
|
+
### 4. Developer 验证失败
|
|
183
182
|
|
|
184
183
|
```json
|
|
185
184
|
{
|
|
186
185
|
"msgtype": "markdown",
|
|
187
186
|
"markdown": {
|
|
188
187
|
"title": "SDD 验证失败",
|
|
189
|
-
"text": "❌ **SDD
|
|
188
|
+
"text": "❌ **SDD Developer 验证失败**\n\n- **工作流**: {feature-name}\n- **失败阶段**: Developer\n- **失败项**:\n - {failure-1}\n - {failure-2}\n- **建议操作**: 修复验证问题后重新验证\n\n🕐 **时间**: {timestamp}"
|
|
190
189
|
}
|
|
191
190
|
}
|
|
192
191
|
```
|
|
193
192
|
|
|
194
|
-
|
|
193
|
+
**示例(后端验证失败)**:
|
|
195
194
|
```json
|
|
196
195
|
{
|
|
197
196
|
"msgtype": "markdown",
|
|
198
197
|
"markdown": {
|
|
199
198
|
"title": "SDD 验证失败",
|
|
200
|
-
"text": "❌ **SDD
|
|
199
|
+
"text": "❌ **SDD Developer 验证失败**\n\n- **工作流**: user-login\n- **失败阶段**: Developer (后端)\n- **失败项**:\n - 编译失败:语法错误 auth_service.go:45\n - 单元测试失败:3/10 测试用例\n - 覆盖率不达标:85% (要求 >= 90%)\n- **建议操作**: 修复语法错误、测试失败、补充测试用例\n\n🕐 **时间**: 2026-01-06 13:00:00"
|
|
201
200
|
}
|
|
202
201
|
}
|
|
203
202
|
```
|
|
@@ -232,7 +231,7 @@ curl -X POST "$WEBHOOK_URL" \
|
|
|
232
231
|
"msgtype": "markdown",
|
|
233
232
|
"markdown": {
|
|
234
233
|
"title": "SDD 工作流完成",
|
|
235
|
-
"text": "✅ **SDD 工作流完成**\n\n- **工作流**: {feature-name}\n- **完成阶段**:\n - ✅ SAE 需求规格\n - ✅
|
|
234
|
+
"text": "✅ **SDD 工作流完成**\n\n- **工作流**: {feature-name}\n- **完成阶段**:\n - ✅ SAE 需求规格\n - ✅ Developer 代码实现\n - ✅ Tester 测试验证\n - ✅ Code Reviewer 代码审查\n - ✅ Git Engineer MR 创建\n- **MR 链接**: {mr-url}\n\n🕐 **时间**: {timestamp}"
|
|
236
235
|
}
|
|
237
236
|
}
|
|
238
237
|
```
|