evnict-kit 0.2.1
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 +19 -0
- package/bin/cli.js +38 -0
- package/package.json +48 -0
- package/src/commands/add.js +129 -0
- package/src/commands/init-check.js +19 -0
- package/src/commands/init-context.js +37 -0
- package/src/commands/init-rules.js +42 -0
- package/src/commands/init-workflow.js +36 -0
- package/src/commands/init.js +722 -0
- package/src/utils/config.js +167 -0
- package/src/utils/file.js +53 -0
- package/templates/GETTING-STARTED.md +196 -0
- package/templates/content/context/AGENTS.md.template +462 -0
- package/templates/content/rules/01-evnict-kit-general-rules.md +303 -0
- package/templates/content/rules/02-evnict-kit-security-rules.md +423 -0
- package/templates/content/rules/03-evnict-kit-backend-conventions.md +383 -0
- package/templates/content/rules/04-evnict-kit-frontend-conventions.md +402 -0
- package/templates/content/rules/05-evnict-kit-project-conventions.md +228 -0
- package/templates/content/skills/evnict-kit-brainstorm/SKILL.md +140 -0
- package/templates/content/skills/evnict-kit-bug-fix/SKILL.md +108 -0
- package/templates/content/skills/evnict-kit-checkpoint/SKILL.md +156 -0
- package/templates/content/skills/evnict-kit-code-review/SKILL.md +158 -0
- package/templates/content/skills/evnict-kit-coordinate/SKILL.md +274 -0
- package/templates/content/skills/evnict-kit-create-api/SKILL.md +281 -0
- package/templates/content/skills/evnict-kit-create-component/SKILL.md +263 -0
- package/templates/content/skills/evnict-kit-create-page/SKILL.md +247 -0
- package/templates/content/skills/evnict-kit-database-migration/SKILL.md +164 -0
- package/templates/content/skills/evnict-kit-doc-postmortem/SKILL.md +93 -0
- package/templates/content/skills/evnict-kit-finish-branch/SKILL.md +87 -0
- package/templates/content/skills/evnict-kit-fix-attt/SKILL.md +129 -0
- package/templates/content/skills/evnict-kit-fix-business-logic/SKILL.md +89 -0
- package/templates/content/skills/evnict-kit-git-worktrees/SKILL.md +104 -0
- package/templates/content/skills/evnict-kit-merge-checklist/SKILL.md +108 -0
- package/templates/content/skills/evnict-kit-onboard/SKILL.md +143 -0
- package/templates/content/skills/evnict-kit-prompt-standard/SKILL.md +103 -0
- package/templates/content/skills/evnict-kit-receiving-review/SKILL.md +89 -0
- package/templates/content/skills/evnict-kit-security-audit/SKILL.md +190 -0
- package/templates/content/skills/evnict-kit-spec/SKILL.md +237 -0
- package/templates/content/skills/evnict-kit-tdd/SKILL.md +413 -0
- package/templates/content/skills/evnict-kit-wiki/SKILL.md +412 -0
- package/templates/content/workflows/evnict-kit-archive-wiki.md +100 -0
- package/templates/content/workflows/evnict-kit-attt.md +100 -0
- package/templates/content/workflows/evnict-kit-bug-fix.md +107 -0
- package/templates/content/workflows/evnict-kit-feature-large.md +393 -0
- package/templates/content/workflows/evnict-kit-feature-small.md +86 -0
- package/templates/content/workflows/evnict-kit-handoff.md +243 -0
- package/templates/content/workflows/evnict-kit-implement.md +247 -0
- package/templates/content/workflows/evnict-kit-init-check.md +76 -0
- package/templates/content/workflows/evnict-kit-init-context.md +58 -0
- package/templates/content/workflows/evnict-kit-init-rules.md +114 -0
- package/templates/content/workflows/evnict-kit-init-wiki.md +80 -0
- package/templates/content/workflows/evnict-kit-plan.md +308 -0
- package/templates/content/workflows/evnict-kit-review.md +53 -0
- package/templates/content/workflows/evnict-kit-spec-archive.md +53 -0
- package/templates/content/workflows/evnict-kit-wiki-archive-feature.md +164 -0
- package/templates/content/workflows/evnict-kit-wiki-query.md +91 -0
- package/templates/content/workflows/evnict-kit-wiki-scan-project.md +272 -0
- package/templates/context/AGENT.md.template +9 -0
- package/templates/context/AGENTS.md.template +462 -0
- package/templates/context/CLAUDE.md.template +301 -0
- package/templates/context/copilot-instructions.md.template +60 -0
- package/templates/context/cursorrules.template +114 -0
- package/templates/instruct/Instruct-Agent-AI.be.md +96 -0
- package/templates/instruct/Instruct-Agent-AI.fe.md +79 -0
- package/templates/rules/antigravity/01-evnict-kit-general-rules.md +303 -0
- package/templates/rules/antigravity/02-evnict-kit-security-rules.md +423 -0
- package/templates/rules/antigravity/03-evnict-kit-backend-conventions.md +383 -0
- package/templates/rules/antigravity/04-evnict-kit-frontend-conventions.md +402 -0
- package/templates/rules/antigravity/05-evnict-kit-project-conventions.md +228 -0
- package/templates/rules/claude/README.md +8 -0
- package/templates/rules/cursor/01-evnict-kit-general-rules.mdc +46 -0
- package/templates/rules/cursor/02-evnict-kit-security-rules.mdc +46 -0
- package/templates/rules/cursor/03-evnict-kit-backend-conventions.mdc +50 -0
- package/templates/rules/cursor/04-evnict-kit-frontend-conventions.mdc +43 -0
- package/templates/rules/cursor/05-evnict-kit-project-conventions.mdc +63 -0
- package/templates/rules/cursor/README.md +7 -0
- package/templates/skills/evnict-kit-brainstorm/SKILL.md +140 -0
- package/templates/skills/evnict-kit-bug-fix/SKILL.md +108 -0
- package/templates/skills/evnict-kit-checkpoint/SKILL.md +156 -0
- package/templates/skills/evnict-kit-code-review/SKILL.md +158 -0
- package/templates/skills/evnict-kit-coordinate/SKILL.md +274 -0
- package/templates/skills/evnict-kit-create-api/SKILL.md +281 -0
- package/templates/skills/evnict-kit-create-component/SKILL.md +263 -0
- package/templates/skills/evnict-kit-create-page/SKILL.md +247 -0
- package/templates/skills/evnict-kit-database-migration/SKILL.md +164 -0
- package/templates/skills/evnict-kit-doc-postmortem/SKILL.md +93 -0
- package/templates/skills/evnict-kit-finish-branch/SKILL.md +87 -0
- package/templates/skills/evnict-kit-fix-attt/SKILL.md +129 -0
- package/templates/skills/evnict-kit-fix-business-logic/SKILL.md +89 -0
- package/templates/skills/evnict-kit-git-worktrees/SKILL.md +104 -0
- package/templates/skills/evnict-kit-merge-checklist/SKILL.md +108 -0
- package/templates/skills/evnict-kit-onboard/SKILL.md +143 -0
- package/templates/skills/evnict-kit-prompt-standard/SKILL.md +103 -0
- package/templates/skills/evnict-kit-receiving-review/SKILL.md +89 -0
- package/templates/skills/evnict-kit-security-audit/SKILL.md +190 -0
- package/templates/skills/evnict-kit-spec/SKILL.md +237 -0
- package/templates/skills/evnict-kit-tdd/SKILL.md +413 -0
- package/templates/skills/evnict-kit-wiki/SKILL.md +412 -0
- package/templates/wiki/README.md +35 -0
- package/templates/wiki/config.example.yaml +17 -0
- package/templates/wiki/package.json +17 -0
- package/templates/wiki/raw/notes/.gitkeep +1 -0
- package/templates/wiki/scripts/ingest.js +66 -0
- package/templates/workflows/antigravity/evnict-kit-archive-wiki.md +100 -0
- package/templates/workflows/antigravity/evnict-kit-attt.md +100 -0
- package/templates/workflows/antigravity/evnict-kit-bug-fix.md +107 -0
- package/templates/workflows/antigravity/evnict-kit-feature-large.md +393 -0
- package/templates/workflows/antigravity/evnict-kit-feature-small.md +86 -0
- package/templates/workflows/antigravity/evnict-kit-handoff.md +243 -0
- package/templates/workflows/antigravity/evnict-kit-implement.md +247 -0
- package/templates/workflows/antigravity/evnict-kit-init-check.md +76 -0
- package/templates/workflows/antigravity/evnict-kit-init-context.md +58 -0
- package/templates/workflows/antigravity/evnict-kit-init-rules.md +114 -0
- package/templates/workflows/antigravity/evnict-kit-init-wiki.md +80 -0
- package/templates/workflows/antigravity/evnict-kit-plan.md +308 -0
- package/templates/workflows/antigravity/evnict-kit-review.md +53 -0
- package/templates/workflows/antigravity/evnict-kit-spec-archive.md +53 -0
- package/templates/workflows/antigravity/evnict-kit-wiki-archive-feature.md +164 -0
- package/templates/workflows/antigravity/evnict-kit-wiki-query.md +91 -0
- package/templates/workflows/antigravity/evnict-kit-wiki-scan-project.md +272 -0
- package/templates/workflows/claude/README.md +6 -0
- package/templates/workflows/claude/evnict-kit-archive-wiki.md +98 -0
- package/templates/workflows/claude/evnict-kit-attt.md +98 -0
- package/templates/workflows/claude/evnict-kit-bug-fix.md +105 -0
- package/templates/workflows/claude/evnict-kit-feature-large.md +391 -0
- package/templates/workflows/claude/evnict-kit-feature-small.md +84 -0
- package/templates/workflows/claude/evnict-kit-handoff.md +240 -0
- package/templates/workflows/claude/evnict-kit-implement.md +245 -0
- package/templates/workflows/claude/evnict-kit-init-check.md +74 -0
- package/templates/workflows/claude/evnict-kit-init-context.md +56 -0
- package/templates/workflows/claude/evnict-kit-init-rules.md +112 -0
- package/templates/workflows/claude/evnict-kit-init-wiki.md +78 -0
- package/templates/workflows/claude/evnict-kit-plan.md +305 -0
- package/templates/workflows/claude/evnict-kit-review.md +51 -0
- package/templates/workflows/claude/evnict-kit-spec-archive.md +51 -0
- package/templates/workflows/claude/evnict-kit-wiki-archive-feature.md +162 -0
- package/templates/workflows/claude/evnict-kit-wiki-query.md +89 -0
- package/templates/workflows/claude/evnict-kit-wiki-scan-project.md +270 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: evnict-kit-spec
|
|
3
|
+
description: Tạo spec SDD (Spec-Driven Development) — specify chức năng, clarify câu hỏi, propose plan implementation. Gộp flow từ spec-kit + OpenSpec.
|
|
4
|
+
compatibility: Java Spring Boot, Angular, ASP.NET Core
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# evnict-kit-spec — Spec-Driven Development
|
|
8
|
+
|
|
9
|
+
## Khi nào dùng
|
|
10
|
+
- Feature mới cần thiết kế trước khi code
|
|
11
|
+
- Thay đổi nghiệp vụ phức tạp cần clarify
|
|
12
|
+
- User mô tả yêu cầu bằng ngôn ngữ tự nhiên → cần chuyển thành spec rõ ràng
|
|
13
|
+
|
|
14
|
+
## Input Parameters
|
|
15
|
+
- `feature_description` (bắt buộc): Mô tả chức năng bằng tiếng Việt hoặc tiếng Anh
|
|
16
|
+
- `scope` (optional): be | fe | full (default: full)
|
|
17
|
+
- `priority` (optional): high | medium | low
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Workflow Steps
|
|
22
|
+
|
|
23
|
+
### Bước 1: Thu thập Context
|
|
24
|
+
1. Đọc `.evnict/config.yaml` → lấy project name, tech stack, wiki path
|
|
25
|
+
2. Đọc `.agent/rules/05-evnict-kit-project-conventions.md` → nắm conventions dự án
|
|
26
|
+
3. Query wiki (nếu có):
|
|
27
|
+
- Đọc index từ `{wiki_path}/processed/`
|
|
28
|
+
- Tìm theo keyword/domain/tags từ mô tả feature
|
|
29
|
+
- Nếu tìm được context liên quan → đưa vào spec
|
|
30
|
+
4. Scan codebase:
|
|
31
|
+
- Tìm modules/services liên quan đến feature
|
|
32
|
+
- Xác định các dependencies hiện có
|
|
33
|
+
- Tìm patterns đang dùng (repository, service, controller)
|
|
34
|
+
|
|
35
|
+
### Bước 2: Sinh Spec Draft
|
|
36
|
+
Tạo file `.evnict/specs/{feature-slug}/spec.md` với format sau:
|
|
37
|
+
|
|
38
|
+
```markdown
|
|
39
|
+
# Spec: {Feature Name}
|
|
40
|
+
## Generated by evnict-kit-spec
|
|
41
|
+
## Date: {YYYY-MM-DD}
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 1. WHAT — Chức năng gì
|
|
46
|
+
{Mô tả chức năng, user story format}
|
|
47
|
+
- As a [role], I want to [action], so that [benefit]
|
|
48
|
+
|
|
49
|
+
## 2. WHY — Tại sao cần
|
|
50
|
+
{Mục đích nghiệp vụ, giá trị mang lại}
|
|
51
|
+
|
|
52
|
+
## 3. WHO — Ai sử dụng
|
|
53
|
+
| Vai trò | Quyền hạn |
|
|
54
|
+
|---------|-----------|
|
|
55
|
+
| {role} | {permissions} |
|
|
56
|
+
|
|
57
|
+
## 4. SCOPE — Phạm vi
|
|
58
|
+
### Bao gồm
|
|
59
|
+
- {in-scope items}
|
|
60
|
+
|
|
61
|
+
### KHÔNG bao gồm
|
|
62
|
+
- {out-of-scope items}
|
|
63
|
+
|
|
64
|
+
## 5. BUSINESS RULES
|
|
65
|
+
| Mã | Quy tắc | Ví dụ |
|
|
66
|
+
|----|---------|-------|
|
|
67
|
+
| BR01 | {rule} | {example} |
|
|
68
|
+
|
|
69
|
+
## 6. LUỒNG NGHIỆP VỤ
|
|
70
|
+
### Luồng chính (Main Flow)
|
|
71
|
+
1. {step 1}
|
|
72
|
+
2. {step 2}
|
|
73
|
+
|
|
74
|
+
### Luồng ngoại lệ (Exception Flow)
|
|
75
|
+
- Nếu {condition} → {behavior}
|
|
76
|
+
|
|
77
|
+
## 7. TECHNICAL NOTES
|
|
78
|
+
### Database Changes
|
|
79
|
+
- Tables: {new/modified tables}
|
|
80
|
+
- Columns: {new/modified columns}
|
|
81
|
+
|
|
82
|
+
### API Endpoints
|
|
83
|
+
| Method | Path | Description |
|
|
84
|
+
|--------|------|-------------|
|
|
85
|
+
| POST | /api/{module}/{action} | {desc} |
|
|
86
|
+
|
|
87
|
+
### Frontend Components
|
|
88
|
+
- Pages: {new/modified pages}
|
|
89
|
+
- Components: {new/modified components}
|
|
90
|
+
|
|
91
|
+
## 8. ACCEPTANCE CRITERIA
|
|
92
|
+
- [ ] {criterion 1}
|
|
93
|
+
- [ ] {criterion 2}
|
|
94
|
+
|
|
95
|
+
## 9. ASSUMPTIONS
|
|
96
|
+
{Các giả định Agent tự quyết định — user review}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Bước 3: Clarify Questions
|
|
100
|
+
Sau khi sinh spec draft, đặt câu hỏi clarify NGAY TRONG OUTPUT.
|
|
101
|
+
|
|
102
|
+
**Nguyên tắc clarify:**
|
|
103
|
+
- Chỉ hỏi khi choice ẢNH HƯỞNG LỚN đến scope/security/UX
|
|
104
|
+
- Có nhiều cách hiểu hợp lý nhưng kết quả khác nhau
|
|
105
|
+
- Không có default hợp lý
|
|
106
|
+
- **TỐI ĐA 3 câu hỏi** — các vấn đề nhỏ → tự quyết định, ghi vào Assumptions
|
|
107
|
+
|
|
108
|
+
Format câu hỏi:
|
|
109
|
+
```markdown
|
|
110
|
+
## ❓ Câu hỏi cần làm rõ
|
|
111
|
+
|
|
112
|
+
### Q1: {Category}
|
|
113
|
+
{Câu hỏi cụ thể}
|
|
114
|
+
Gợi ý: A) ... | B) ... | C) Custom
|
|
115
|
+
|
|
116
|
+
### Q2: {Category}
|
|
117
|
+
{Câu hỏi cụ thể}
|
|
118
|
+
|
|
119
|
+
### Q3: {Category}
|
|
120
|
+
{Câu hỏi cụ thể}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Bước 4: User Trả Lời → Update Spec
|
|
124
|
+
1. Đọc câu trả lời của user
|
|
125
|
+
2. Cập nhật spec.md với thông tin mới
|
|
126
|
+
3. Xóa section "❓ Câu hỏi cần làm rõ"
|
|
127
|
+
4. Thêm footnote: `## Clarified: {date}`
|
|
128
|
+
5. Hiển thị spec đã update cho user confirm
|
|
129
|
+
|
|
130
|
+
### Bước 5: Confirm Spec
|
|
131
|
+
Khi user confirm spec:
|
|
132
|
+
1. Đánh dấu spec as confirmed: thêm `status: confirmed` vào header
|
|
133
|
+
2. Tạo cấu trúc folders:
|
|
134
|
+
```
|
|
135
|
+
.evnict/specs/{feature-slug}/
|
|
136
|
+
├── spec.md ← Confirmed spec
|
|
137
|
+
├── plan.md ← (sẽ tạo ở plan phase)
|
|
138
|
+
├── tasks/ ← (sẽ tạo ở plan phase)
|
|
139
|
+
└── contracts/ ← (sẽ tạo ở plan phase)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Phase 2: Plan Generation
|
|
145
|
+
|
|
146
|
+
### Bước 6: Sinh Plan
|
|
147
|
+
Sau khi spec confirmed → tạo `.evnict/specs/{feature-slug}/plan.md`:
|
|
148
|
+
|
|
149
|
+
```markdown
|
|
150
|
+
# Plan: {Feature Name}
|
|
151
|
+
## Spec: .evnict/specs/{feature-slug}/spec.md
|
|
152
|
+
|
|
153
|
+
## Tổng quan
|
|
154
|
+
- Estimated: {X} subtasks
|
|
155
|
+
- BE tasks: {N}
|
|
156
|
+
- FE tasks: {M}
|
|
157
|
+
- DB tasks: {K}
|
|
158
|
+
|
|
159
|
+
## Thứ tự thực hiện
|
|
160
|
+
1. DB Migration (PHẢI xong trước)
|
|
161
|
+
2. BE: Repository → Service → Controller (tuần tự)
|
|
162
|
+
3. FE: Service → Component → Page (tuần tự, SAU KHI BE xong API)
|
|
163
|
+
|
|
164
|
+
## Dependencies
|
|
165
|
+
- FE tasks PHẢI chờ BE hoàn thành API
|
|
166
|
+
- BE tasks PHẢI chờ DB migration xong
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Bước 7: Sinh Task Files
|
|
170
|
+
Tạo từng file trong `tasks/`:
|
|
171
|
+
|
|
172
|
+
```markdown
|
|
173
|
+
# Task {NN}: {Type} — {Description}
|
|
174
|
+
## Files cần tạo/sửa
|
|
175
|
+
- {file path 1}
|
|
176
|
+
- {file path 2}
|
|
177
|
+
|
|
178
|
+
## Test Cases (TDD)
|
|
179
|
+
- [ ] {test case 1}
|
|
180
|
+
- [ ] {test case 2}
|
|
181
|
+
|
|
182
|
+
## Acceptance Criteria
|
|
183
|
+
- [ ] {criteria}
|
|
184
|
+
|
|
185
|
+
## Estimated: {X} phút
|
|
186
|
+
## Dependencies: {task-NN | none}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Bước 8: Sinh API Contract
|
|
190
|
+
Tạo `contracts/api-contract.yaml`:
|
|
191
|
+
|
|
192
|
+
```yaml
|
|
193
|
+
feature: {feature-name}
|
|
194
|
+
generated: {date}
|
|
195
|
+
endpoints:
|
|
196
|
+
- method: POST
|
|
197
|
+
path: /api/{module}/{action}
|
|
198
|
+
description: {mô tả}
|
|
199
|
+
request:
|
|
200
|
+
body:
|
|
201
|
+
fieldName: { type: string, required: true, maxLength: 100 }
|
|
202
|
+
response:
|
|
203
|
+
200:
|
|
204
|
+
schema: ResponseData
|
|
205
|
+
data:
|
|
206
|
+
id: { type: number }
|
|
207
|
+
400:
|
|
208
|
+
schema: ResponseData
|
|
209
|
+
error: { message: string }
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Bước 9: User Review Plan → Confirm
|
|
213
|
+
Hiển thị plan tổng quan cho user → chờ confirm trước khi implement.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Error Handling
|
|
218
|
+
|
|
219
|
+
### DỪNG NGAY khi:
|
|
220
|
+
- Feature description quá mơ hồ, không thể xác định scope → Yêu cầu user mô tả rõ hơn
|
|
221
|
+
- Feature yêu cầu truy cập hệ thống bên ngoài chưa có thông tin → Hỏi user
|
|
222
|
+
- Phát hiện conflict với spec/feature đang triển khai
|
|
223
|
+
|
|
224
|
+
### Escalate khi:
|
|
225
|
+
- Feature liên quan đến bảo mật (auth, encryption) → Nhắc user review bởi Tổ trưởng ANTT
|
|
226
|
+
- Feature thay đổi database schema quan trọng → Nhắc user review bởi DBA
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Tiêu chí hoàn thành
|
|
231
|
+
- [ ] spec.md đã tạo trong `.evnict/specs/{feature-slug}/`
|
|
232
|
+
- [ ] Tối đa 3 câu hỏi clarify đã được trả lời
|
|
233
|
+
- [ ] spec.md đã được user confirm
|
|
234
|
+
- [ ] plan.md đã tạo với task breakdown
|
|
235
|
+
- [ ] Task files đã tạo trong `tasks/`
|
|
236
|
+
- [ ] API contract đã tạo (nếu có API)
|
|
237
|
+
- [ ] User đã confirm plan
|
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: evnict-kit-tdd
|
|
3
|
+
description: TDD per subtask — Red→Green→Refactor→Verify→Commit. 3-strike rule. Hướng dẫn viết test cho Spring Boot + Angular.
|
|
4
|
+
compatibility: Java Spring Boot (JUnit5 + Mockito), Angular (Jasmine + Karma)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# evnict-kit-tdd — Test-Driven Development
|
|
8
|
+
|
|
9
|
+
## Khi nào dùng
|
|
10
|
+
- Implement subtask từ plan đã approve
|
|
11
|
+
- Viết test cho code mới hoặc code sửa đổi
|
|
12
|
+
- Fix bug bằng TDD (reproduce → test fail → fix → test pass)
|
|
13
|
+
|
|
14
|
+
## Input Parameters
|
|
15
|
+
- `task_file` (bắt buộc): Path đến task file (VD: `.evnict/specs/feature/tasks/01-db-migration.md`)
|
|
16
|
+
- `scope`: be | fe (xác định test framework)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Workflow Steps
|
|
21
|
+
|
|
22
|
+
### Bước 1: Pre-conditions
|
|
23
|
+
1. Đọc task file → xác định files cần tạo/sửa và test cases
|
|
24
|
+
2. Kiểm tra `git status` → working tree PHẢI clean
|
|
25
|
+
3. Nếu dirty → `git stash` hoặc `git commit` trước
|
|
26
|
+
|
|
27
|
+
### Bước 2: TDD Cycle cho MỖI task
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
┌─────────────────────────────────────────────┐
|
|
31
|
+
│ [RED] Viết test TRƯỚC → chạy → test FAIL │
|
|
32
|
+
│ ↓ │
|
|
33
|
+
│ [GREEN] Code TỐI THIỂU để test PASS │
|
|
34
|
+
│ ↓ │
|
|
35
|
+
│ Verify: lint pass + build OK │
|
|
36
|
+
│ ↓ │
|
|
37
|
+
│ [REFACTOR] Cải thiện code (test vẫn PASS) │
|
|
38
|
+
│ ↓ │
|
|
39
|
+
│ Commit: feat({module}): {task} [task-{N}] │
|
|
40
|
+
└─────────────────────────────────────────────┘
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### RED Phase — Viết Test Trước
|
|
44
|
+
|
|
45
|
+
#### Java Spring Boot (JUnit5 + Mockito)
|
|
46
|
+
```java
|
|
47
|
+
// ✅ Service test
|
|
48
|
+
@ExtendWith(MockitoExtension.class)
|
|
49
|
+
class CustomerServiceTest {
|
|
50
|
+
|
|
51
|
+
@Mock
|
|
52
|
+
private CustomerRepository customerRepository;
|
|
53
|
+
|
|
54
|
+
@InjectMocks
|
|
55
|
+
private CustomerService customerService;
|
|
56
|
+
|
|
57
|
+
@Test
|
|
58
|
+
@DisplayName("Tạo customer thành công với data hợp lệ")
|
|
59
|
+
void create_validData_shouldReturnDTO() {
|
|
60
|
+
// Arrange
|
|
61
|
+
CustomerDTO input = new CustomerDTO();
|
|
62
|
+
input.setName("Nguyễn Văn A");
|
|
63
|
+
input.setPhone("0901234567");
|
|
64
|
+
|
|
65
|
+
when(customerRepository.create(any())).thenReturn(
|
|
66
|
+
new CustomerDTO(1L, "Nguyễn Văn A", "0901234567")
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
// Act
|
|
70
|
+
CustomerDTO result = customerService.create(input);
|
|
71
|
+
|
|
72
|
+
// Assert
|
|
73
|
+
assertNotNull(result);
|
|
74
|
+
assertEquals("Nguyễn Văn A", result.getName());
|
|
75
|
+
verify(customerRepository).create(any());
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@Test
|
|
79
|
+
@DisplayName("Tạo customer với tên trống → BusinessException")
|
|
80
|
+
void create_emptyName_shouldThrowException() {
|
|
81
|
+
CustomerDTO input = new CustomerDTO();
|
|
82
|
+
input.setName("");
|
|
83
|
+
|
|
84
|
+
assertThrows(BusinessException.class, () ->
|
|
85
|
+
customerService.create(input)
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
```java
|
|
92
|
+
// ✅ Controller test (MockMvc)
|
|
93
|
+
@WebMvcTest(CustomerController.class)
|
|
94
|
+
class CustomerControllerTest {
|
|
95
|
+
|
|
96
|
+
@Autowired
|
|
97
|
+
private MockMvc mockMvc;
|
|
98
|
+
|
|
99
|
+
@MockBean
|
|
100
|
+
private CustomerService customerService;
|
|
101
|
+
|
|
102
|
+
@Test
|
|
103
|
+
void create_validRequest_shouldReturn200() throws Exception {
|
|
104
|
+
String json = """
|
|
105
|
+
{"name": "Nguyễn Văn A", "phone": "0901234567"}
|
|
106
|
+
""";
|
|
107
|
+
|
|
108
|
+
when(customerService.create(any())).thenReturn(
|
|
109
|
+
new CustomerDTO(1L, "Nguyễn Văn A", "0901234567")
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
mockMvc.perform(post("/api/customers")
|
|
113
|
+
.contentType(MediaType.APPLICATION_JSON)
|
|
114
|
+
.content(json))
|
|
115
|
+
.andExpect(status().isOk())
|
|
116
|
+
.andExpect(jsonPath("$.status").value(0))
|
|
117
|
+
.andExpect(jsonPath("$.data.name").value("Nguyễn Văn A"));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@Test
|
|
121
|
+
void create_missingName_shouldReturn400() throws Exception {
|
|
122
|
+
String json = """
|
|
123
|
+
{"name": "", "phone": "0901234567"}
|
|
124
|
+
""";
|
|
125
|
+
|
|
126
|
+
mockMvc.perform(post("/api/customers")
|
|
127
|
+
.contentType(MediaType.APPLICATION_JSON)
|
|
128
|
+
.content(json))
|
|
129
|
+
.andExpect(status().isBadRequest());
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
```java
|
|
135
|
+
// ✅ Repository test (cần DB test container hoặc H2)
|
|
136
|
+
@JooqTest
|
|
137
|
+
class CustomerRepositoryTest {
|
|
138
|
+
|
|
139
|
+
@Autowired
|
|
140
|
+
private DSLContext dsl;
|
|
141
|
+
|
|
142
|
+
private CustomerRepository repository;
|
|
143
|
+
|
|
144
|
+
@BeforeEach
|
|
145
|
+
void setUp() {
|
|
146
|
+
repository = new CustomerRepository(dsl);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
@Test
|
|
150
|
+
void search_byKeyword_shouldReturnMatching() {
|
|
151
|
+
// Arrange — insert test data
|
|
152
|
+
dsl.insertInto(CUSTOMER)
|
|
153
|
+
.set(CUSTOMER.NAME, "Nguyễn Văn A")
|
|
154
|
+
.set(CUSTOMER.STATUS, "ACTIVE")
|
|
155
|
+
.execute();
|
|
156
|
+
|
|
157
|
+
// Act
|
|
158
|
+
List<CustomerDTO> results = repository.search("Nguyễn", 0, 20);
|
|
159
|
+
|
|
160
|
+
// Assert
|
|
161
|
+
assertFalse(results.isEmpty());
|
|
162
|
+
assertTrue(results.get(0).getName().contains("Nguyễn"));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### Angular (Jasmine + Karma)
|
|
168
|
+
```typescript
|
|
169
|
+
// ✅ Service test
|
|
170
|
+
describe('CustomerService', () => {
|
|
171
|
+
let service: CustomerService;
|
|
172
|
+
let httpMock: HttpTestingController;
|
|
173
|
+
|
|
174
|
+
beforeEach(() => {
|
|
175
|
+
TestBed.configureTestingModule({
|
|
176
|
+
imports: [HttpClientTestingModule],
|
|
177
|
+
providers: [CustomerService]
|
|
178
|
+
});
|
|
179
|
+
service = TestBed.inject(CustomerService);
|
|
180
|
+
httpMock = TestBed.inject(HttpTestingController);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
afterEach(() => httpMock.verify());
|
|
184
|
+
|
|
185
|
+
it('should search customers', () => {
|
|
186
|
+
const mockResponse = { status: 0, data: [{ id: 1, name: 'Test' }] };
|
|
187
|
+
|
|
188
|
+
service.search('test', 0, 20).subscribe(res => {
|
|
189
|
+
expect(res.status).toBe(0);
|
|
190
|
+
expect(res.data.length).toBe(1);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
const req = httpMock.expectOne(r => r.url.includes('/api/customers'));
|
|
194
|
+
expect(req.request.method).toBe('GET');
|
|
195
|
+
req.flush(mockResponse);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
// ✅ Component test
|
|
202
|
+
describe('CustomerListComponent', () => {
|
|
203
|
+
let component: CustomerListComponent;
|
|
204
|
+
let fixture: ComponentFixture<CustomerListComponent>;
|
|
205
|
+
let mockService: jasmine.SpyObj<CustomerService>;
|
|
206
|
+
|
|
207
|
+
beforeEach(async () => {
|
|
208
|
+
mockService = jasmine.createSpyObj('CustomerService', ['search']);
|
|
209
|
+
mockService.search.and.returnValue(of({ status: 0, data: [], message: '' }));
|
|
210
|
+
|
|
211
|
+
await TestBed.configureTestingModule({
|
|
212
|
+
declarations: [CustomerListComponent],
|
|
213
|
+
providers: [{ provide: CustomerService, useValue: mockService }]
|
|
214
|
+
}).compileComponents();
|
|
215
|
+
|
|
216
|
+
fixture = TestBed.createComponent(CustomerListComponent);
|
|
217
|
+
component = fixture.componentInstance;
|
|
218
|
+
fixture.detectChanges();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('should load data on init', () => {
|
|
222
|
+
expect(mockService.search).toHaveBeenCalled();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should display error message when search fails', () => {
|
|
226
|
+
mockService.search.and.returnValue(of({ status: 1, data: null, message: 'Error' }));
|
|
227
|
+
component.loadData();
|
|
228
|
+
fixture.detectChanges();
|
|
229
|
+
expect(component.errorMessage).toBe('Error');
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### GREEN Phase — Code Tối Thiểu
|
|
235
|
+
1. Viết code TỐI THIỂU để test PASS — không thêm logic chưa cần
|
|
236
|
+
2. Chạy test: `./mvnw test -pl {module}` hoặc `ng test --watch=false`
|
|
237
|
+
3. Nếu PASS → chuyển sang Verify
|
|
238
|
+
4. Nếu FAIL → sửa code (KHÔNG sửa test)
|
|
239
|
+
|
|
240
|
+
### Verify Phase
|
|
241
|
+
```bash
|
|
242
|
+
# Backend
|
|
243
|
+
./mvnw test # All tests pass
|
|
244
|
+
./mvnw spotless:check # Lint/format
|
|
245
|
+
./mvnw compile # Build OK
|
|
246
|
+
|
|
247
|
+
# Frontend
|
|
248
|
+
ng test --watch=false # All tests pass
|
|
249
|
+
ng lint # Lint OK
|
|
250
|
+
ng build # Build OK
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### REFACTOR Phase (Optional)
|
|
254
|
+
1. Cải thiện code quality (naming, extract method, reduce duplication)
|
|
255
|
+
2. Chạy lại test → PHẢI vẫn PASS
|
|
256
|
+
3. KHÔNG thêm chức năng mới trong refactor
|
|
257
|
+
|
|
258
|
+
### Commit
|
|
259
|
+
```bash
|
|
260
|
+
git add .
|
|
261
|
+
git commit -m "feat({module}): {task description} [task-{N}]"
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## 3-Strike Rule (QĐ-TTPM Mục 8.7)
|
|
267
|
+
|
|
268
|
+
Nếu test FAIL > **3 lần** cho cùng 1 đoạn code:
|
|
269
|
+
1. **DỪNG** phiên AI ngay lập tức
|
|
270
|
+
2. Thông báo user: "Task {N} gặp vấn đề sau 3 lần thử, cần phân tích thủ công"
|
|
271
|
+
3. Log lại:
|
|
272
|
+
- Đoạn code gây lỗi
|
|
273
|
+
- 3 lần thử và kết quả
|
|
274
|
+
- Giả thuyết root cause
|
|
275
|
+
4. **KHÔNG tiếp tục** implement các task tiếp theo
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## Test Coverage Guidelines
|
|
280
|
+
|
|
281
|
+
### Backend
|
|
282
|
+
| Layer | Coverage Target | Focus |
|
|
283
|
+
|-------|----------------|-------|
|
|
284
|
+
| Service | ≥ 80% | Business logic, edge cases |
|
|
285
|
+
| Controller | ≥ 70% | Request/response, validation |
|
|
286
|
+
| Repository | ≥ 60% | Query correctness |
|
|
287
|
+
|
|
288
|
+
### Frontend
|
|
289
|
+
| Type | Coverage Target | Focus |
|
|
290
|
+
|------|----------------|-------|
|
|
291
|
+
| Service | ≥ 80% | HTTP calls, data transform |
|
|
292
|
+
| Component | ≥ 60% | User interactions, display logic |
|
|
293
|
+
| Pipe | ≥ 90% | Data formatting |
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Error Handling
|
|
298
|
+
|
|
299
|
+
### DỪNG khi:
|
|
300
|
+
- Test framework không available → Nhắc user cài đặt
|
|
301
|
+
- Project không build → Fix build trước
|
|
302
|
+
- Dependency conflict → Resolve trước khi viết test
|
|
303
|
+
|
|
304
|
+
### Skip test khi:
|
|
305
|
+
- Task là DB migration → Test bằng chạy migration UP/DOWN
|
|
306
|
+
- Task là config change → Test bằng verify config loaded
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## ═══════════════════════════════════════════
|
|
311
|
+
## STOP-AND-ASK — BẮT BUỘC SAU MỖI SUBTASK
|
|
312
|
+
## ═══════════════════════════════════════════
|
|
313
|
+
|
|
314
|
+
> **Cross-reference:** Xem workflow `evnict-kit-implement.md` để biết đầy đủ quy tắc STOP-AND-ASK và xử lý mỗi option.
|
|
315
|
+
|
|
316
|
+
### Sau MỖI subtask hoàn thành
|
|
317
|
+
Agent PHẢI DỪNG, hiển thị kết quả, và hỏi user:
|
|
318
|
+
|
|
319
|
+
```
|
|
320
|
+
═══════════════════════════════════════════
|
|
321
|
+
✅ Task {N}/{Total}: {task_name} — HOÀN THÀNH
|
|
322
|
+
═══════════════════════════════════════════
|
|
323
|
+
|
|
324
|
+
📁 Files tạo/sửa:
|
|
325
|
+
+ src/.../FileA.java (NEW — {X} lines)
|
|
326
|
+
~ src/.../FileB.java (MODIFIED — {Y} lines changed)
|
|
327
|
+
|
|
328
|
+
🧪 Tests: {pass}/{total} passed
|
|
329
|
+
📏 Lint: ✅ passed | ❌ {N} issues
|
|
330
|
+
🔨 Build: ✅ passed | ❌ failed
|
|
331
|
+
📝 Commit: feat({module}): {description} [task-{NN}]
|
|
332
|
+
|
|
333
|
+
───────────────────────────────────────────
|
|
334
|
+
❓ Bạn muốn làm gì tiếp?
|
|
335
|
+
|
|
336
|
+
A) ✅ Approve — chuyển sang Task {N+1}: {next_task_name}
|
|
337
|
+
B) 👀 Review code — tôi sẽ hiển thị code và chờ feedback
|
|
338
|
+
C) 🔄 Yêu cầu sửa — mô tả cần sửa gì
|
|
339
|
+
D) ⏸️ Tạm dừng — lưu progress, tiếp tục sau
|
|
340
|
+
E) ❌ Hủy task này — rollback commit
|
|
341
|
+
F) 🚀 Auto-approve — chạy hết tasks còn lại KHÔNG hỏi nữa
|
|
342
|
+
⚠️ Chỉ dùng khi đã review 2-3 tasks đầu và tin tưởng pattern
|
|
343
|
+
|
|
344
|
+
Chọn (A/B/C/D/E/F):
|
|
345
|
+
═══════════════════════════════════════════
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### TUYỆT ĐỐI KHÔNG được:
|
|
349
|
+
- ❌ Tự động chạy task tiếp mà không hỏi user
|
|
350
|
+
- ❌ Skip phần hiển thị kết quả (files, tests, lint, build, commit)
|
|
351
|
+
- ❌ Gộp nhiều tasks thành 1 lần chạy
|
|
352
|
+
- ❌ Bỏ qua test/lint/build results trong output
|
|
353
|
+
|
|
354
|
+
### Khi user chọn B (Review code)
|
|
355
|
+
Hiển thị code cho MỖI file đã tạo/sửa:
|
|
356
|
+
```
|
|
357
|
+
📄 {FileName.java} ({NEW|MODIFIED}):
|
|
358
|
+
─────────────────────────────
|
|
359
|
+
{Hiển thị toàn bộ code nếu NEW}
|
|
360
|
+
{Hiển thị diff nếu MODIFIED}
|
|
361
|
+
─────────────────────────────
|
|
362
|
+
|
|
363
|
+
Bạn có feedback gì không? (Gõ feedback hoặc "OK" để approve)
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Khi user chọn D (Tạm dừng)
|
|
367
|
+
Lưu progress vào `.evnict/specs/{feature}/progress.md`:
|
|
368
|
+
```markdown
|
|
369
|
+
# Progress: {feature}
|
|
370
|
+
## Status: PAUSED
|
|
371
|
+
## Completed: {N}/{Total}
|
|
372
|
+
## Last updated: {timestamp}
|
|
373
|
+
|
|
374
|
+
### Tasks
|
|
375
|
+
- [x] Task 01: {name} — commit: {hash}
|
|
376
|
+
- [x] Task 02: {name} — commit: {hash}
|
|
377
|
+
- [ ] Task 03: {name} ← NEXT
|
|
378
|
+
## Resume: /evnict-kit:implement (auto-detect progress)
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Khi user chọn E (Hủy + Rollback)
|
|
382
|
+
1. `git revert HEAD` — revert commit cuối
|
|
383
|
+
2. Xóa files đã tạo trong task
|
|
384
|
+
3. Hỏi: "Muốn thử lại task này hay skip?"
|
|
385
|
+
|
|
386
|
+
### Khi user chọn F (Auto-approve)
|
|
387
|
+
1. Cảnh báo: "Tất cả tasks còn lại chạy KHÔNG hỏi. DỪNG nếu test/build fail."
|
|
388
|
+
2. Nếu gặp lỗi → TỰ ĐỘNG quay lại mode STOP-AND-ASK
|
|
389
|
+
3. Cuối cùng hiển thị Final Summary
|
|
390
|
+
|
|
391
|
+
### Khi gặp vấn đề (Bug phức tạp, cấu trúc không dự tính)
|
|
392
|
+
Agent PHẢI hỏi trước khi tự quyết định:
|
|
393
|
+
```
|
|
394
|
+
⚠️ Task {N} gặp vấn đề:
|
|
395
|
+
{mô tả nguyên nhân và phân tích vấn đề}
|
|
396
|
+
|
|
397
|
+
Đề xuất:
|
|
398
|
+
A) {approach 1} — pros/cons
|
|
399
|
+
B) {approach 2} — pros/cons
|
|
400
|
+
C) Bạn quyết định thay tôi bằng cách gõ lệnh.
|
|
401
|
+
|
|
402
|
+
Chọn approach nào?
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## Tiêu chí hoàn thành
|
|
408
|
+
- [ ] Test viết TRƯỚC code (RED phase completed)
|
|
409
|
+
- [ ] Code tối thiểu để test PASS (GREEN phase completed)
|
|
410
|
+
- [ ] Lint + build OK (Verify phase completed)
|
|
411
|
+
- [ ] Code đã refactor nếu cần (REFACTOR phase completed)
|
|
412
|
+
- [ ] Commit với message chuẩn
|
|
413
|
+
- [ ] Không vi phạm 3-strike rule
|