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.
Files changed (138) hide show
  1. package/README.md +19 -0
  2. package/bin/cli.js +38 -0
  3. package/package.json +48 -0
  4. package/src/commands/add.js +129 -0
  5. package/src/commands/init-check.js +19 -0
  6. package/src/commands/init-context.js +37 -0
  7. package/src/commands/init-rules.js +42 -0
  8. package/src/commands/init-workflow.js +36 -0
  9. package/src/commands/init.js +722 -0
  10. package/src/utils/config.js +167 -0
  11. package/src/utils/file.js +53 -0
  12. package/templates/GETTING-STARTED.md +196 -0
  13. package/templates/content/context/AGENTS.md.template +462 -0
  14. package/templates/content/rules/01-evnict-kit-general-rules.md +303 -0
  15. package/templates/content/rules/02-evnict-kit-security-rules.md +423 -0
  16. package/templates/content/rules/03-evnict-kit-backend-conventions.md +383 -0
  17. package/templates/content/rules/04-evnict-kit-frontend-conventions.md +402 -0
  18. package/templates/content/rules/05-evnict-kit-project-conventions.md +228 -0
  19. package/templates/content/skills/evnict-kit-brainstorm/SKILL.md +140 -0
  20. package/templates/content/skills/evnict-kit-bug-fix/SKILL.md +108 -0
  21. package/templates/content/skills/evnict-kit-checkpoint/SKILL.md +156 -0
  22. package/templates/content/skills/evnict-kit-code-review/SKILL.md +158 -0
  23. package/templates/content/skills/evnict-kit-coordinate/SKILL.md +274 -0
  24. package/templates/content/skills/evnict-kit-create-api/SKILL.md +281 -0
  25. package/templates/content/skills/evnict-kit-create-component/SKILL.md +263 -0
  26. package/templates/content/skills/evnict-kit-create-page/SKILL.md +247 -0
  27. package/templates/content/skills/evnict-kit-database-migration/SKILL.md +164 -0
  28. package/templates/content/skills/evnict-kit-doc-postmortem/SKILL.md +93 -0
  29. package/templates/content/skills/evnict-kit-finish-branch/SKILL.md +87 -0
  30. package/templates/content/skills/evnict-kit-fix-attt/SKILL.md +129 -0
  31. package/templates/content/skills/evnict-kit-fix-business-logic/SKILL.md +89 -0
  32. package/templates/content/skills/evnict-kit-git-worktrees/SKILL.md +104 -0
  33. package/templates/content/skills/evnict-kit-merge-checklist/SKILL.md +108 -0
  34. package/templates/content/skills/evnict-kit-onboard/SKILL.md +143 -0
  35. package/templates/content/skills/evnict-kit-prompt-standard/SKILL.md +103 -0
  36. package/templates/content/skills/evnict-kit-receiving-review/SKILL.md +89 -0
  37. package/templates/content/skills/evnict-kit-security-audit/SKILL.md +190 -0
  38. package/templates/content/skills/evnict-kit-spec/SKILL.md +237 -0
  39. package/templates/content/skills/evnict-kit-tdd/SKILL.md +413 -0
  40. package/templates/content/skills/evnict-kit-wiki/SKILL.md +412 -0
  41. package/templates/content/workflows/evnict-kit-archive-wiki.md +100 -0
  42. package/templates/content/workflows/evnict-kit-attt.md +100 -0
  43. package/templates/content/workflows/evnict-kit-bug-fix.md +107 -0
  44. package/templates/content/workflows/evnict-kit-feature-large.md +393 -0
  45. package/templates/content/workflows/evnict-kit-feature-small.md +86 -0
  46. package/templates/content/workflows/evnict-kit-handoff.md +243 -0
  47. package/templates/content/workflows/evnict-kit-implement.md +247 -0
  48. package/templates/content/workflows/evnict-kit-init-check.md +76 -0
  49. package/templates/content/workflows/evnict-kit-init-context.md +58 -0
  50. package/templates/content/workflows/evnict-kit-init-rules.md +114 -0
  51. package/templates/content/workflows/evnict-kit-init-wiki.md +80 -0
  52. package/templates/content/workflows/evnict-kit-plan.md +308 -0
  53. package/templates/content/workflows/evnict-kit-review.md +53 -0
  54. package/templates/content/workflows/evnict-kit-spec-archive.md +53 -0
  55. package/templates/content/workflows/evnict-kit-wiki-archive-feature.md +164 -0
  56. package/templates/content/workflows/evnict-kit-wiki-query.md +91 -0
  57. package/templates/content/workflows/evnict-kit-wiki-scan-project.md +272 -0
  58. package/templates/context/AGENT.md.template +9 -0
  59. package/templates/context/AGENTS.md.template +462 -0
  60. package/templates/context/CLAUDE.md.template +301 -0
  61. package/templates/context/copilot-instructions.md.template +60 -0
  62. package/templates/context/cursorrules.template +114 -0
  63. package/templates/instruct/Instruct-Agent-AI.be.md +96 -0
  64. package/templates/instruct/Instruct-Agent-AI.fe.md +79 -0
  65. package/templates/rules/antigravity/01-evnict-kit-general-rules.md +303 -0
  66. package/templates/rules/antigravity/02-evnict-kit-security-rules.md +423 -0
  67. package/templates/rules/antigravity/03-evnict-kit-backend-conventions.md +383 -0
  68. package/templates/rules/antigravity/04-evnict-kit-frontend-conventions.md +402 -0
  69. package/templates/rules/antigravity/05-evnict-kit-project-conventions.md +228 -0
  70. package/templates/rules/claude/README.md +8 -0
  71. package/templates/rules/cursor/01-evnict-kit-general-rules.mdc +46 -0
  72. package/templates/rules/cursor/02-evnict-kit-security-rules.mdc +46 -0
  73. package/templates/rules/cursor/03-evnict-kit-backend-conventions.mdc +50 -0
  74. package/templates/rules/cursor/04-evnict-kit-frontend-conventions.mdc +43 -0
  75. package/templates/rules/cursor/05-evnict-kit-project-conventions.mdc +63 -0
  76. package/templates/rules/cursor/README.md +7 -0
  77. package/templates/skills/evnict-kit-brainstorm/SKILL.md +140 -0
  78. package/templates/skills/evnict-kit-bug-fix/SKILL.md +108 -0
  79. package/templates/skills/evnict-kit-checkpoint/SKILL.md +156 -0
  80. package/templates/skills/evnict-kit-code-review/SKILL.md +158 -0
  81. package/templates/skills/evnict-kit-coordinate/SKILL.md +274 -0
  82. package/templates/skills/evnict-kit-create-api/SKILL.md +281 -0
  83. package/templates/skills/evnict-kit-create-component/SKILL.md +263 -0
  84. package/templates/skills/evnict-kit-create-page/SKILL.md +247 -0
  85. package/templates/skills/evnict-kit-database-migration/SKILL.md +164 -0
  86. package/templates/skills/evnict-kit-doc-postmortem/SKILL.md +93 -0
  87. package/templates/skills/evnict-kit-finish-branch/SKILL.md +87 -0
  88. package/templates/skills/evnict-kit-fix-attt/SKILL.md +129 -0
  89. package/templates/skills/evnict-kit-fix-business-logic/SKILL.md +89 -0
  90. package/templates/skills/evnict-kit-git-worktrees/SKILL.md +104 -0
  91. package/templates/skills/evnict-kit-merge-checklist/SKILL.md +108 -0
  92. package/templates/skills/evnict-kit-onboard/SKILL.md +143 -0
  93. package/templates/skills/evnict-kit-prompt-standard/SKILL.md +103 -0
  94. package/templates/skills/evnict-kit-receiving-review/SKILL.md +89 -0
  95. package/templates/skills/evnict-kit-security-audit/SKILL.md +190 -0
  96. package/templates/skills/evnict-kit-spec/SKILL.md +237 -0
  97. package/templates/skills/evnict-kit-tdd/SKILL.md +413 -0
  98. package/templates/skills/evnict-kit-wiki/SKILL.md +412 -0
  99. package/templates/wiki/README.md +35 -0
  100. package/templates/wiki/config.example.yaml +17 -0
  101. package/templates/wiki/package.json +17 -0
  102. package/templates/wiki/raw/notes/.gitkeep +1 -0
  103. package/templates/wiki/scripts/ingest.js +66 -0
  104. package/templates/workflows/antigravity/evnict-kit-archive-wiki.md +100 -0
  105. package/templates/workflows/antigravity/evnict-kit-attt.md +100 -0
  106. package/templates/workflows/antigravity/evnict-kit-bug-fix.md +107 -0
  107. package/templates/workflows/antigravity/evnict-kit-feature-large.md +393 -0
  108. package/templates/workflows/antigravity/evnict-kit-feature-small.md +86 -0
  109. package/templates/workflows/antigravity/evnict-kit-handoff.md +243 -0
  110. package/templates/workflows/antigravity/evnict-kit-implement.md +247 -0
  111. package/templates/workflows/antigravity/evnict-kit-init-check.md +76 -0
  112. package/templates/workflows/antigravity/evnict-kit-init-context.md +58 -0
  113. package/templates/workflows/antigravity/evnict-kit-init-rules.md +114 -0
  114. package/templates/workflows/antigravity/evnict-kit-init-wiki.md +80 -0
  115. package/templates/workflows/antigravity/evnict-kit-plan.md +308 -0
  116. package/templates/workflows/antigravity/evnict-kit-review.md +53 -0
  117. package/templates/workflows/antigravity/evnict-kit-spec-archive.md +53 -0
  118. package/templates/workflows/antigravity/evnict-kit-wiki-archive-feature.md +164 -0
  119. package/templates/workflows/antigravity/evnict-kit-wiki-query.md +91 -0
  120. package/templates/workflows/antigravity/evnict-kit-wiki-scan-project.md +272 -0
  121. package/templates/workflows/claude/README.md +6 -0
  122. package/templates/workflows/claude/evnict-kit-archive-wiki.md +98 -0
  123. package/templates/workflows/claude/evnict-kit-attt.md +98 -0
  124. package/templates/workflows/claude/evnict-kit-bug-fix.md +105 -0
  125. package/templates/workflows/claude/evnict-kit-feature-large.md +391 -0
  126. package/templates/workflows/claude/evnict-kit-feature-small.md +84 -0
  127. package/templates/workflows/claude/evnict-kit-handoff.md +240 -0
  128. package/templates/workflows/claude/evnict-kit-implement.md +245 -0
  129. package/templates/workflows/claude/evnict-kit-init-check.md +74 -0
  130. package/templates/workflows/claude/evnict-kit-init-context.md +56 -0
  131. package/templates/workflows/claude/evnict-kit-init-rules.md +112 -0
  132. package/templates/workflows/claude/evnict-kit-init-wiki.md +78 -0
  133. package/templates/workflows/claude/evnict-kit-plan.md +305 -0
  134. package/templates/workflows/claude/evnict-kit-review.md +51 -0
  135. package/templates/workflows/claude/evnict-kit-spec-archive.md +51 -0
  136. package/templates/workflows/claude/evnict-kit-wiki-archive-feature.md +162 -0
  137. package/templates/workflows/claude/evnict-kit-wiki-query.md +89 -0
  138. 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