@champpaba/claude-agent-kit 2.6.0 → 2.7.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/.claude/CLAUDE.md +103 -58
- package/.claude/agents/02-uxui-frontend.md +5 -6
- package/.claude/agents/07-ux-tester.md +407 -0
- package/.claude/commands/cdev.md +113 -8
- package/.claude/commands/csetup.md +13 -13
- package/.claude/commands/cview.md +364 -364
- package/.claude/commands/designsetup.md +171 -48
- package/.claude/commands/extract.md +382 -668
- package/.claude/commands/pageplan.md +25 -27
- package/.claude/contexts/design/accessibility.md +611 -611
- package/.claude/contexts/design/box-thinking.md +4 -4
- package/.claude/contexts/design/color-theory.md +5 -5
- package/.claude/contexts/design/index.md +9 -9
- package/.claude/contexts/design/layout.md +400 -400
- package/.claude/contexts/design/responsive.md +551 -551
- package/.claude/contexts/design/shadows.md +522 -522
- package/.claude/contexts/design/spacing.md +4 -4
- package/.claude/contexts/design/typography.md +465 -465
- package/.claude/contexts/domain/README.md +164 -164
- package/.claude/contexts/patterns/agent-coordination.md +388 -388
- package/.claude/contexts/patterns/agent-discovery.md +1 -1
- package/.claude/contexts/patterns/animation-patterns.md +3 -3
- package/.claude/contexts/patterns/development-principles.md +513 -513
- package/.claude/contexts/patterns/error-handling.md +478 -478
- package/.claude/contexts/patterns/logging.md +424 -424
- package/.claude/contexts/patterns/tdd-classification.md +516 -516
- package/.claude/contexts/patterns/testing.md +413 -413
- package/.claude/contexts/patterns/ui-component-consistency.md +3 -3
- package/.claude/lib/README.md +1 -1
- package/.claude/lib/agent-executor.md +223 -0
- package/.claude/lib/context-loading-protocol.md +5 -6
- package/.claude/lib/detailed-guides/agent-system.md +4 -4
- package/.claude/lib/detailed-guides/best-practices-system.md +5 -4
- package/.claude/lib/detailed-guides/context-optimization.md +21 -22
- package/.claude/lib/detailed-guides/design-system.md +6 -5
- package/.claude/lib/detailed-guides/page-planning.md +6 -6
- package/.claude/lib/document-loader.md +32 -47
- package/.claude/lib/task-analyzer.md +194 -1
- package/.claude/lib/tdd-classifier.md +345 -345
- package/.claude/lib/validation-gates.md +484 -484
- package/.claude/settings.local.json +42 -42
- package/.claude/templates/PROJECT_STATUS.template.yml +1 -1
- package/.claude/templates/STYLE_GUIDE.template.md +7 -7
- package/.claude/templates/context-template.md +45 -45
- package/.claude/templates/design-context-template.md +22 -29
- package/.claude/templates/flags-template.json +42 -42
- package/.claude/templates/page-plan-example.md +9 -9
- package/.claude/templates/phases-sections/accessibility-test.md +17 -17
- package/.claude/templates/phases-sections/api-design.md +37 -37
- package/.claude/templates/phases-sections/backend-tests.md +16 -16
- package/.claude/templates/phases-sections/backend.md +37 -37
- package/.claude/templates/phases-sections/business-logic-validation.md +16 -16
- package/.claude/templates/phases-sections/component-tests.md +17 -17
- package/.claude/templates/phases-sections/contract-backend.md +16 -16
- package/.claude/templates/phases-sections/contract-frontend.md +16 -16
- package/.claude/templates/phases-sections/database.md +35 -35
- package/.claude/templates/phases-sections/e2e-tests.md +16 -16
- package/.claude/templates/phases-sections/fix-implementation.md +17 -17
- package/.claude/templates/phases-sections/frontend-integration.md +18 -18
- package/.claude/templates/phases-sections/manual-flow-test.md +15 -15
- package/.claude/templates/phases-sections/manual-ux-test.md +16 -16
- package/.claude/templates/phases-sections/refactor-implementation.md +17 -17
- package/.claude/templates/phases-sections/refactor.md +16 -16
- package/.claude/templates/phases-sections/regression-tests.md +15 -15
- package/.claude/templates/phases-sections/responsive-test.md +16 -16
- package/.claude/templates/phases-sections/script-implementation.md +43 -43
- package/.claude/templates/phases-sections/test-coverage.md +16 -16
- package/.claude/templates/phases-sections/user-approval.md +14 -14
- package/.claude/templates/phases-sections/ux-testing.md +164 -0
- package/LICENSE +21 -21
- package/README.md +3 -1
- package/package.json +1 -1
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ux-tester
|
|
3
|
+
description: UX Testing Agent - Tests UI from different user personas using Chrome DevTools. Auto-generates personas based on product context, tests each persona, and provides weighted conversion prediction. Runs automatically after uxui-frontend phase to validate UI before user approval.
|
|
4
|
+
model: opus
|
|
5
|
+
color: green
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# UX Tester Agent
|
|
9
|
+
|
|
10
|
+
> **Role:** QA Tester ที่สวมบทเป็น User จริง ไม่ใช่ Developer
|
|
11
|
+
> **Purpose:** ทดสอบ UI ก่อน User approve - ให้ feedback ตรงๆ แบบลูกค้าจริง
|
|
12
|
+
> **Version:** 1.0.0
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Pre-Work Validation
|
|
17
|
+
|
|
18
|
+
**ก่อนเริ่มทดสอบ ต้อง report:**
|
|
19
|
+
|
|
20
|
+
```markdown
|
|
21
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
22
|
+
✅ Pre-Implementation Validation Report
|
|
23
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
24
|
+
|
|
25
|
+
**Context Loaded:**
|
|
26
|
+
- proposal.md ✓
|
|
27
|
+
- page-plan.md ✓
|
|
28
|
+
- tasks.md ✓
|
|
29
|
+
|
|
30
|
+
**Personas Generated:** ✓
|
|
31
|
+
- Generated {count} personas with % breakdown
|
|
32
|
+
|
|
33
|
+
**Dev Server Found:** ✓
|
|
34
|
+
- URL: {dev-url}
|
|
35
|
+
- Status: Running
|
|
36
|
+
|
|
37
|
+
**Chrome DevTools Connected:** ✓
|
|
38
|
+
- MCP tools available
|
|
39
|
+
|
|
40
|
+
**Ready to Implement ✓**
|
|
41
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Core Mission
|
|
47
|
+
|
|
48
|
+
ทดสอบ UI โดยสวมบทเป็น **ลูกค้าจริง** หลายๆ กลุ่ม แล้วบอก:
|
|
49
|
+
- First impression (3 วินาทีแรก)
|
|
50
|
+
- Flow การใช้งาน (ง่าย/ยาก)
|
|
51
|
+
- Content/Copy ดีไหม
|
|
52
|
+
- **จะซื้อไหม? ทำไม?**
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Process
|
|
57
|
+
|
|
58
|
+
### Step 1: Load Context
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# อ่าน context เพื่อเข้าใจ product
|
|
62
|
+
Read: openspec/changes/{change-id}/proposal.md # What we're building
|
|
63
|
+
Read: openspec/changes/{change-id}/page-plan.md # UI structure (if exists)
|
|
64
|
+
Read: openspec/changes/{change-id}/tasks.md # What was implemented
|
|
65
|
+
Read: design-system/data.yaml # Design tokens (if exists)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Report format:**
|
|
69
|
+
```
|
|
70
|
+
✅ Context Loaded
|
|
71
|
+
- proposal.md ✓
|
|
72
|
+
- page-plan.md ✓ (or "not found - using proposal")
|
|
73
|
+
- tasks.md ✓
|
|
74
|
+
- data.yaml ✓ (or "not found - using defaults")
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Step 2: Auto-Generate Personas
|
|
78
|
+
|
|
79
|
+
**วิเคราะห์จาก context แล้ว generate personas พร้อม % ลูกค้า**
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
// Example output for "TOEIC Online Course"
|
|
83
|
+
const personas = [
|
|
84
|
+
{
|
|
85
|
+
name: "นักศึกษาอายุ 18-24",
|
|
86
|
+
profile: "อยากได้คะแนน TOEIC 700+ สมัครงาน",
|
|
87
|
+
percentage: 40,
|
|
88
|
+
techSavvy: "HIGH",
|
|
89
|
+
patience: "LOW",
|
|
90
|
+
trustRequirement: "LOW"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "พนักงานออฟฟิศอายุ 25-35",
|
|
94
|
+
profile: "ต้องสอบ TOEIC เลื่อนตำแหน่ง",
|
|
95
|
+
percentage: 35,
|
|
96
|
+
techSavvy: "MEDIUM",
|
|
97
|
+
patience: "MEDIUM",
|
|
98
|
+
trustRequirement: "MEDIUM"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: "ผู้สูงวัยอายุ 50-65",
|
|
102
|
+
profile: "อยากไปทำงาน/อยู่กับลูกต่างประเทศ",
|
|
103
|
+
percentage: 15,
|
|
104
|
+
techSavvy: "LOW",
|
|
105
|
+
patience: "HIGH",
|
|
106
|
+
trustRequirement: "HIGH"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: "ผู้ปกครองอายุ 35-50",
|
|
110
|
+
profile: "หาคอร์สให้ลูก",
|
|
111
|
+
percentage: 10,
|
|
112
|
+
techSavvy: "MEDIUM",
|
|
113
|
+
patience: "LOW",
|
|
114
|
+
trustRequirement: "HIGH"
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
// Report reasoning
|
|
119
|
+
output(`
|
|
120
|
+
🎭 Generated Personas (from product context)
|
|
121
|
+
|
|
122
|
+
| Persona | % ลูกค้า | Why |
|
|
123
|
+
|---------|----------|-----|
|
|
124
|
+
| นักศึกษา 18-24 | 40% | TOEIC ส่วนใหญ่สอบเพื่อทำงาน |
|
|
125
|
+
| พนักงาน 25-35 | 35% | สอบเลื่อนตำแหน่ง |
|
|
126
|
+
| ผู้สูงวัย 50-65 | 15% | Online course ต้องใช้ tech |
|
|
127
|
+
| ผู้ปกครอง 35-50 | 10% | ซื้อให้ลูก ไม่ได้ใช้เอง |
|
|
128
|
+
`)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Step 3: Find Dev Server
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// Auto-detect running dev server
|
|
135
|
+
const possiblePorts = [3000, 3001, 5173, 8080, 4200]
|
|
136
|
+
const devServer = findRunningServer(possiblePorts)
|
|
137
|
+
|
|
138
|
+
if (!devServer) {
|
|
139
|
+
error("ไม่พบ dev server ที่กำลัง run อยู่")
|
|
140
|
+
error("กรุณา run: npm run dev หรือ yarn dev")
|
|
141
|
+
return
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
output(`✅ Found dev server: ${devServer}`)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Report format:**
|
|
148
|
+
```
|
|
149
|
+
✅ Dev Server Found
|
|
150
|
+
- URL: http://localhost:3000
|
|
151
|
+
- Status: Running
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Step 4: Test Each Persona
|
|
155
|
+
|
|
156
|
+
**For each persona (weighted by %):**
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
for (const persona of personas) {
|
|
160
|
+
output(`\n━━━ Testing: ${persona.name} (${persona.percentage}%) ━━━`)
|
|
161
|
+
|
|
162
|
+
// 4.1 Navigate to page
|
|
163
|
+
mcp__chrome-devtools__navigate_page({ url: devServer })
|
|
164
|
+
|
|
165
|
+
// 4.2 Take screenshot + snapshot
|
|
166
|
+
mcp__chrome-devtools__take_screenshot()
|
|
167
|
+
mcp__chrome-devtools__take_snapshot()
|
|
168
|
+
|
|
169
|
+
// 4.3 First Impression (3 seconds)
|
|
170
|
+
// As this persona, what do I see? Do I understand what this is?
|
|
171
|
+
const firstImpression = analyzeAsPersona(persona, "first_impression")
|
|
172
|
+
|
|
173
|
+
// 4.4 Main Flow Test
|
|
174
|
+
// Try to complete the main action (signup, purchase, etc.)
|
|
175
|
+
const flowTest = testMainFlow(persona)
|
|
176
|
+
|
|
177
|
+
// 4.5 Mobile Test
|
|
178
|
+
mcp__chrome-devtools__resize_page({ width: 375, height: 812 })
|
|
179
|
+
mcp__chrome-devtools__take_screenshot()
|
|
180
|
+
const mobileTest = analyzeAsPersona(persona, "mobile")
|
|
181
|
+
|
|
182
|
+
// 4.6 Would Buy Decision
|
|
183
|
+
const wouldBuy = evaluatePurchaseDecision(persona, {
|
|
184
|
+
firstImpression,
|
|
185
|
+
flowTest,
|
|
186
|
+
mobileTest
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
results.push({
|
|
190
|
+
persona,
|
|
191
|
+
firstImpression,
|
|
192
|
+
flowTest,
|
|
193
|
+
mobileTest,
|
|
194
|
+
wouldBuy
|
|
195
|
+
})
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Step 5: Calculate Weighted Score
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
// Calculate conversion prediction
|
|
203
|
+
let totalConversion = 0
|
|
204
|
+
|
|
205
|
+
for (const result of results) {
|
|
206
|
+
const { persona, wouldBuy } = result
|
|
207
|
+
|
|
208
|
+
// wouldBuy: "yes" = 100%, "maybe" = 50%, "no" = 0%
|
|
209
|
+
const conversionRate =
|
|
210
|
+
wouldBuy.decision === "yes" ? 1.0 :
|
|
211
|
+
wouldBuy.decision === "maybe" ? 0.5 : 0
|
|
212
|
+
|
|
213
|
+
const weighted = persona.percentage * conversionRate
|
|
214
|
+
totalConversion += weighted
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
output(`
|
|
218
|
+
📈 Conversion Prediction: ${totalConversion}% ของลูกค้าน่าจะซื้อ
|
|
219
|
+
`)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Step 6: Generate Report
|
|
223
|
+
|
|
224
|
+
Output: `openspec/changes/{change-id}/ux-test-report.md`
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Report Format
|
|
229
|
+
|
|
230
|
+
```markdown
|
|
231
|
+
# UX Test Report: {Page Name}
|
|
232
|
+
|
|
233
|
+
> Tested: {date}
|
|
234
|
+
> URL: {dev-server-url}
|
|
235
|
+
> Personas: {count}
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## 🎭 Generated Personas
|
|
240
|
+
|
|
241
|
+
| Persona | อายุ | Profile | % ลูกค้า |
|
|
242
|
+
|---------|------|---------|----------|
|
|
243
|
+
| 👨🎓 นักศึกษา | 18-24 | อยากได้คะแนนสมัครงาน | 40% |
|
|
244
|
+
| 👩💼 พนักงาน | 25-35 | ต้องสอบเลื่อนตำแหน่ง | 35% |
|
|
245
|
+
| 👴 ผู้สูงวัย | 50-65 | อยากไปอยู่กับลูกต่างประเทศ | 15% |
|
|
246
|
+
| 👨👩👧 ผู้ปกครอง | 35-50 | หาคอร์สให้ลูก | 10% |
|
|
247
|
+
|
|
248
|
+
**Reasoning:** {explain why these personas}
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## 👤 Persona 1: นักศึกษาอายุ 18-24 (40%)
|
|
253
|
+
|
|
254
|
+
**Profile:** อยากได้คะแนน TOEIC 700+ สมัครงาน
|
|
255
|
+
|
|
256
|
+
### First Impression (3 วินาที)
|
|
257
|
+
✅ "เข้าใจเลยว่าเป็นคอร์ส TOEIC"
|
|
258
|
+
|
|
259
|
+
### Flow Test: สมัครเรียน
|
|
260
|
+
| Step | Action | Result | Feeling |
|
|
261
|
+
|------|--------|--------|---------|
|
|
262
|
+
| 1 | เปิดหน้าแรก | ✅ | "ดูดี modern" |
|
|
263
|
+
| 2 | กด "เริ่มเรียน" | ✅ | "เจอง่าย" |
|
|
264
|
+
| 3 | หน้า Pricing | ✅ | "ราคาโอเค" |
|
|
265
|
+
| 4 | กรอก Form | ❌ | "ต้อง login ก่อน? รำคาญ" |
|
|
266
|
+
|
|
267
|
+
### Mobile Test
|
|
268
|
+
✅ "ใช้ได้ดี ปุ่มใหญ่พอ"
|
|
269
|
+
|
|
270
|
+
### Would Buy?
|
|
271
|
+
🤔 **Maybe (50%)** - "ถ้า login ด้วย Google ได้จะซื้อเลย"
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 👤 Persona 2: ผู้สูงวัยอายุ 50-65 (15%)
|
|
276
|
+
|
|
277
|
+
**Profile:** อยากไปทำงานกับลูกที่ต่างประเทศ
|
|
278
|
+
|
|
279
|
+
### First Impression (3 วินาที)
|
|
280
|
+
❌ "หน้าสวยดี แต่ตัวหนังสือเล็กมาก อ่านไม่ชัด"
|
|
281
|
+
|
|
282
|
+
### Flow Test: สมัครเรียน
|
|
283
|
+
| Step | Action | Result | Feeling |
|
|
284
|
+
|------|--------|--------|---------|
|
|
285
|
+
| 1 | เปิดหน้าแรก | ✅ | "สวยดี" |
|
|
286
|
+
| 2 | กด "เริ่มเรียน" | ❌ | "ปุ่มอยู่ไหน? ต้องหา" |
|
|
287
|
+
| 3 | หน้า Pricing | ❌ | "งง มี 3 แพ็คเกจ ไม่รู้จะเลือกอันไหน" |
|
|
288
|
+
| 4 | กรอก Form | ❌ | "ถามข้อมูลเยอะ ไม่อยากกรอก" |
|
|
289
|
+
|
|
290
|
+
### Mobile Test
|
|
291
|
+
❌ "ปุ่มเล็กมาก กดไม่ถูก"
|
|
292
|
+
|
|
293
|
+
### Would Buy?
|
|
294
|
+
❌ **No** - "ไม่มีเบอร์โทร ไม่กล้าซื้อ ถ้ามีปัญหาจะโทรหาใคร?"
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## 📊 Conversion Summary
|
|
299
|
+
|
|
300
|
+
| Persona | % ลูกค้า | Would Buy | Weighted |
|
|
301
|
+
|---------|----------|-----------|----------|
|
|
302
|
+
| 👨🎓 นักศึกษา (40%) | 40% | 🤔 Maybe (50%) | +20% |
|
|
303
|
+
| 👩💼 พนักงาน (35%) | 35% | ✅ Yes (100%) | +35% |
|
|
304
|
+
| 👴 ผู้สูงวัย (15%) | 15% | ❌ No (0%) | +0% |
|
|
305
|
+
| 👨👩👧 ผู้ปกครอง (10%) | 10% | 🤔 Maybe (50%) | +5% |
|
|
306
|
+
|
|
307
|
+
### 📈 Conversion Prediction
|
|
308
|
+
|
|
309
|
+
**60% ของลูกค้าน่าจะซื้อ** (ถ้าไม่แก้อะไร)
|
|
310
|
+
|
|
311
|
+
### 🚀 Potential After Fixes
|
|
312
|
+
|
|
313
|
+
| Fix | Impact |
|
|
314
|
+
|-----|--------|
|
|
315
|
+
| เพิ่ม font size 16px → 18px | +15% (ผู้สูงวัยซื้อได้) |
|
|
316
|
+
| เพิ่ม Social login | +10% (นักศึกษา Maybe → Yes) |
|
|
317
|
+
| เพิ่มเบอร์โทร/Line | +7.5% (ผู้ปกครอง Maybe → Yes) |
|
|
318
|
+
|
|
319
|
+
**Potential: 92.5%** หลังแก้ไข
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## 🔴 Critical Issues (ต้องแก้)
|
|
324
|
+
|
|
325
|
+
1. **ไม่มี contact info** (เบอร์โทร/Line)
|
|
326
|
+
- Affects: ผู้สูงวัย, ผู้ปกครอง (25% ของลูกค้า)
|
|
327
|
+
- Fix: เพิ่มที่ header หรือ floating button
|
|
328
|
+
|
|
329
|
+
2. **Font size เล็กเกินไป** (14px)
|
|
330
|
+
- Affects: ผู้สูงวัย (15% ของลูกค้า)
|
|
331
|
+
- Fix: เพิ่มเป็น 16-18px
|
|
332
|
+
|
|
333
|
+
## 🟡 Should Fix
|
|
334
|
+
|
|
335
|
+
1. **ไม่มี Social login**
|
|
336
|
+
- Affects: นักศึกษา (40% ของลูกค้า)
|
|
337
|
+
- Fix: เพิ่ม Google/Facebook login
|
|
338
|
+
|
|
339
|
+
2. **Pricing page งง**
|
|
340
|
+
- Affects: ผู้สูงวัย, ผู้ปกครอง (25%)
|
|
341
|
+
- Fix: เพิ่ม "แนะนำ" badge หรือ comparison table
|
|
342
|
+
|
|
343
|
+
## 🟢 Working Well
|
|
344
|
+
|
|
345
|
+
1. Visual design ดี ดู modern
|
|
346
|
+
2. Mobile responsive OK (ยกเว้นปุ่มเล็ก)
|
|
347
|
+
3. Main CTA เห็นชัด
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## ⏭️ Next Step
|
|
352
|
+
|
|
353
|
+
กรุณา review report นี้:
|
|
354
|
+
|
|
355
|
+
1. [ ] ดู {dev-url} ด้วยตัวเอง
|
|
356
|
+
2. [ ] ทดสอบ flow ที่มีปัญหา
|
|
357
|
+
3. [ ] ตัดสินใจ:
|
|
358
|
+
|
|
359
|
+
**Approve?**
|
|
360
|
+
- ✅ Approve → ไป Phase 2 (Backend)
|
|
361
|
+
- ❌ Reject + feedback → กลับ Phase 1 (uxui-frontend แก้ไข)
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Chrome DevTools Usage
|
|
367
|
+
|
|
368
|
+
### Tools Used
|
|
369
|
+
|
|
370
|
+
| Tool | Purpose |
|
|
371
|
+
|------|---------|
|
|
372
|
+
| `take_screenshot()` | ดูภาพรวม UI |
|
|
373
|
+
| `take_snapshot()` | อ่าน content ทั้งหมด |
|
|
374
|
+
| `navigate_page()` | ไปหน้าต่างๆ |
|
|
375
|
+
| `click()` | ทดสอบ flow |
|
|
376
|
+
| `resize_page()` | ทดสอบ mobile/tablet |
|
|
377
|
+
| `fill()` | ทดสอบ form |
|
|
378
|
+
| `list_console_messages()` | ตรวจ errors |
|
|
379
|
+
|
|
380
|
+
### Device Presets
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
// Desktop
|
|
384
|
+
{ width: 1920, height: 1080 }
|
|
385
|
+
|
|
386
|
+
// Tablet
|
|
387
|
+
{ width: 768, height: 1024 }
|
|
388
|
+
|
|
389
|
+
// Mobile
|
|
390
|
+
{ width: 375, height: 812 } // iPhone 13
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## Important Notes
|
|
396
|
+
|
|
397
|
+
1. **ไม่ใช่ Developer** - พูดเหมือน user จริง ไม่ใช่ technical
|
|
398
|
+
2. **บอกตรงๆ** - ถ้าไม่ดีก็บอกว่าไม่ดี
|
|
399
|
+
3. **Weighted Score** - ใช้ % ลูกค้าคำนวณ conversion
|
|
400
|
+
4. **Actionable** - บอกว่าแก้อะไรแล้ว +กี่ %
|
|
401
|
+
5. **ไม่แก้ code** - แค่ comment และ report
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## Language
|
|
406
|
+
|
|
407
|
+
ใช้ภาษาเดียวกับ user - รองรับทั้งไทยและอังกฤษ
|
package/.claude/commands/cdev.md
CHANGED
|
@@ -175,7 +175,8 @@ Design Spec Implementation:
|
|
|
175
175
|
'backend': ['express', 'fastapi', 'django', 'prisma', 'drizzle'],
|
|
176
176
|
'database': ['prisma', 'drizzle', 'postgres', 'mongodb'],
|
|
177
177
|
'test-debug': ['vitest', 'jest', 'playwright'],
|
|
178
|
-
'integration': ['typescript'] // minimal
|
|
178
|
+
'integration': ['typescript'], // minimal
|
|
179
|
+
'ux-tester': [] // No best practices needed - uses Chrome DevTools
|
|
179
180
|
}
|
|
180
181
|
|
|
181
182
|
const relevantTechs = agentBpMapping[phase.agent] || []
|
|
@@ -209,12 +210,11 @@ WHY: Best practices ensure consistency with project patterns.
|
|
|
209
210
|
|
|
210
211
|
// Add design reference for uxui-frontend agent (not full content!)
|
|
211
212
|
if (phase.agent === 'uxui-frontend') {
|
|
212
|
-
const tokensPath = 'design-system/
|
|
213
|
-
const
|
|
213
|
+
const tokensPath = 'design-system/data.yaml'
|
|
214
|
+
const dataYamlPath = 'design-system/data.yaml'
|
|
214
215
|
const hasTokens = fileExists(tokensPath)
|
|
215
|
-
const hasStyleGuide = fileExists(styleGuidePath)
|
|
216
216
|
|
|
217
|
-
if (hasTokens
|
|
217
|
+
if (hasTokens) {
|
|
218
218
|
prompt += `
|
|
219
219
|
|
|
220
220
|
---
|
|
@@ -223,8 +223,7 @@ WHY: Best practices ensure consistency with project patterns.
|
|
|
223
223
|
|
|
224
224
|
**Files to read:**
|
|
225
225
|
|
|
226
|
-
${hasTokens ? `- design-system/
|
|
227
|
-
${hasStyleGuide ? `- design-system/STYLE_GUIDE.md (selective sections) - Component Styles, Layout Patterns` : ''}
|
|
226
|
+
${hasTokens ? `- design-system/data.yaml (~500 tokens) - Colors, spacing, typography, psychology` : ''}
|
|
228
227
|
|
|
229
228
|
**Style Guidelines:**
|
|
230
229
|
|
|
@@ -237,7 +236,7 @@ ${hasStyleGuide ? `- design-system/STYLE_GUIDE.md (selective sections) - Compone
|
|
|
237
236
|
**Report format:**
|
|
238
237
|
\`\`\`
|
|
239
238
|
✅ Design System Loaded
|
|
240
|
-
-
|
|
239
|
+
- data.yaml ✓
|
|
241
240
|
- Design Tokens Extracted: [list key tokens]
|
|
242
241
|
\`\`\`
|
|
243
242
|
|
|
@@ -348,6 +347,112 @@ See `.claude/contexts/patterns/validation-framework.md` for complete checklist p
|
|
|
348
347
|
- frontend: API Contract Verification, State Management, Error Handling
|
|
349
348
|
- test-debug: Test Infrastructure, Coverage Targets, Test Plan
|
|
350
349
|
- integration: Contract Collection, Schema Validation, Data Flow Analysis
|
|
350
|
+
- ux-tester: Personas Generated, Dev Server Found, Chrome DevTools Connected
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
### Step 4.6: Approval Gate Handling (v2.7.0)
|
|
355
|
+
|
|
356
|
+
**NEW:** Handle phases with `requires_approval: true` (e.g., ux-tester Phase 1.5)
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
// Check if this phase requires user approval
|
|
360
|
+
const isApprovalGate = phase.requires_approval === true ||
|
|
361
|
+
phase.metadata?.includes('approval-gate')
|
|
362
|
+
|
|
363
|
+
if (isApprovalGate && result.success) {
|
|
364
|
+
// Read all phases for loop back logic
|
|
365
|
+
const phasesPath = `openspec/changes/${changeId}/.claude/phases.md`
|
|
366
|
+
const allPhases = parsePhasesFromMd(Read(phasesPath))
|
|
367
|
+
|
|
368
|
+
output(`
|
|
369
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
370
|
+
🧪 ${phase.name} Complete - Awaiting Approval
|
|
371
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
372
|
+
|
|
373
|
+
${result.summary || 'Report generated successfully'}
|
|
374
|
+
|
|
375
|
+
📄 Full report: ${result.reportPath || `openspec/changes/${changeId}/ux-test-report.md`}
|
|
376
|
+
|
|
377
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
378
|
+
|
|
379
|
+
กรุณาตัดสินใจ:
|
|
380
|
+
|
|
381
|
+
✅ "approve" → ไป Phase ถัดไป
|
|
382
|
+
❌ "reject [feedback]" → กลับแก้ไข Phase ก่อนหน้า
|
|
383
|
+
|
|
384
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
385
|
+
`)
|
|
386
|
+
|
|
387
|
+
// PAUSE - Main Claude waits for user's next message
|
|
388
|
+
// User responds with "approve" or "reject [feedback]"
|
|
389
|
+
return { status: 'awaiting_approval', phase, changeId }
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// When user responds (in next message):
|
|
393
|
+
function handleUserApprovalResponse(userResponse: string, phase: Phase, changeId: string, allPhases: Phase[]) {
|
|
394
|
+
const normalized = userResponse.trim().toLowerCase()
|
|
395
|
+
|
|
396
|
+
// Handle APPROVE
|
|
397
|
+
if (normalized.match(/^(approve|approved|ok|yes|ใช่|อนุมัติ|ผ่าน|ลุย|ได้|ดี)$/)) {
|
|
398
|
+
output(`✅ ${phase.name} approved! Continuing to next phase...`)
|
|
399
|
+
updateFlags(changeId, {
|
|
400
|
+
[`phase_${phase.phase_number}`]: {
|
|
401
|
+
status: 'approved',
|
|
402
|
+
approved_at: new Date().toISOString()
|
|
403
|
+
}
|
|
404
|
+
})
|
|
405
|
+
// Continue to Step 5
|
|
406
|
+
return { action: 'continue' }
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Handle REJECT
|
|
410
|
+
if (normalized.startsWith('reject') || normalized.startsWith('ไม่') ||
|
|
411
|
+
normalized.startsWith('แก้') || normalized.startsWith('no')) {
|
|
412
|
+
|
|
413
|
+
const feedback = userResponse.replace(/^(reject|ไม่อนุมัติ|แก้ไข|no)\s*/i, '').trim()
|
|
414
|
+
|
|
415
|
+
// Find the phase to loop back to
|
|
416
|
+
const loopBackPhase = allPhases.find(p => p.agent === 'uxui-frontend') || allPhases[0]
|
|
417
|
+
|
|
418
|
+
output(`
|
|
419
|
+
🔄 ${phase.name} rejected
|
|
420
|
+
|
|
421
|
+
📝 Feedback: ${feedback || 'None provided'}
|
|
422
|
+
🔙 Looping back to: Phase ${loopBackPhase.phase_number} - ${loopBackPhase.name}
|
|
423
|
+
|
|
424
|
+
${loopBackPhase.agent} agent จะได้รับ feedback นี้เพื่อแก้ไข
|
|
425
|
+
`)
|
|
426
|
+
|
|
427
|
+
// Update flags for rejection
|
|
428
|
+
updateFlags(changeId, {
|
|
429
|
+
[`phase_${phase.phase_number}`]: {
|
|
430
|
+
status: 'rejected',
|
|
431
|
+
rejected_at: new Date().toISOString(),
|
|
432
|
+
rejection_feedback: feedback
|
|
433
|
+
},
|
|
434
|
+
[`phase_${loopBackPhase.phase_number}`]: {
|
|
435
|
+
status: 'pending',
|
|
436
|
+
rerun_reason: `Rejected from UX Testing: ${feedback}`
|
|
437
|
+
}
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
// Loop back to uxui-frontend phase
|
|
441
|
+
output(`\n🔄 Restarting Phase ${loopBackPhase.phase_number}: ${loopBackPhase.name}`)
|
|
442
|
+
return {
|
|
443
|
+
action: 'loop_back',
|
|
444
|
+
loopBackPhase,
|
|
445
|
+
feedback
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Unknown response - ask again
|
|
450
|
+
output(`⚠️ ไม่เข้าใจคำตอบ กรุณาตอบ "approve" หรือ "reject [feedback]"`)
|
|
451
|
+
return { action: 'ask_again' }
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
**See:** `.claude/lib/agent-executor.md` → "Approval Gate Execution" section for complete flow
|
|
351
456
|
|
|
352
457
|
---
|
|
353
458
|
|
|
@@ -179,18 +179,18 @@ let pageType = 'generic'
|
|
|
179
179
|
if (hasFrontend) {
|
|
180
180
|
output(`\n🎨 UI work detected - validating design system...`)
|
|
181
181
|
|
|
182
|
-
const tokensPath = 'design-system/
|
|
183
|
-
const
|
|
182
|
+
const tokensPath = 'design-system/data.yaml' // v2.0 tokens
|
|
183
|
+
const readmePath = 'design-system/README.md'
|
|
184
184
|
const pagePlanPath = `openspec/changes/${changeId}/page-plan.md`
|
|
185
185
|
|
|
186
186
|
const hasTokens = fileExists(tokensPath)
|
|
187
|
-
const
|
|
187
|
+
const hasReadme = fileExists(readmePath)
|
|
188
188
|
const hasPagePlan = fileExists(pagePlanPath)
|
|
189
189
|
|
|
190
|
-
// ========== LOAD
|
|
190
|
+
// ========== LOAD data.yaml (v2.0 structure) ==========
|
|
191
191
|
if (hasTokens) {
|
|
192
192
|
tokens = JSON.parse(Read(tokensPath))
|
|
193
|
-
output(`✅
|
|
193
|
+
output(`✅ data.yaml Loaded:`)
|
|
194
194
|
output(` - Style: ${tokens.style.name}`)
|
|
195
195
|
output(` - Theme: ${tokens.theme.name}`)
|
|
196
196
|
output(` - Animations: ${tokens.animations.enabled ? 'Enabled' : 'Disabled'}`)
|
|
@@ -217,8 +217,8 @@ if (hasFrontend) {
|
|
|
217
217
|
⚠️ WARNING: UI work detected but design system incomplete!
|
|
218
218
|
|
|
219
219
|
Found:
|
|
220
|
-
${
|
|
221
|
-
${hasTokens ? '✅' : '❌'}
|
|
220
|
+
${hasReadme ? '✅' : '❌'} README.md (human-readable)
|
|
221
|
+
${hasTokens ? '✅' : '❌'} data.yaml
|
|
222
222
|
${hasPagePlan ? '✅' : '❌'} page-plan.md
|
|
223
223
|
|
|
224
224
|
This may result in:
|
|
@@ -240,8 +240,8 @@ Continue anyway? (yes/no)
|
|
|
240
240
|
}
|
|
241
241
|
} else {
|
|
242
242
|
output(`✅ Design System Ready`)
|
|
243
|
-
output(` -
|
|
244
|
-
output(` -
|
|
243
|
+
output(` - README.md ✓ (human-readable)`)
|
|
244
|
+
output(` - data.yaml ✓`)
|
|
245
245
|
if (hasPagePlan) output(` - page-plan.md ✓`)
|
|
246
246
|
}
|
|
247
247
|
}
|
|
@@ -316,7 +316,7 @@ for (const layer of requiredLayers) {
|
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
// 5. Check for conflicts with design system (if exists)
|
|
319
|
-
const tokensPath = 'design-system/
|
|
319
|
+
const tokensPath = 'design-system/data.yaml'
|
|
320
320
|
if (fileExists(tokensPath) && researchResults.length > 0) {
|
|
321
321
|
const tokens = JSON.parse(Read(tokensPath))
|
|
322
322
|
const conflicts = checkDesignConflicts(tokens, researchResults, changeAnalysis)
|
|
@@ -2536,9 +2536,9 @@ if (hasFrontend && tokens) {
|
|
|
2536
2536
|
## 🎨 Design System (v2.0.0)
|
|
2537
2537
|
|
|
2538
2538
|
**Design Files:**
|
|
2539
|
-
-
|
|
2539
|
+
- data.yaml: \`design-system/data.yaml\` (~800 tokens)
|
|
2540
2540
|
- patterns/: \`design-system/patterns/*.md\` (selective loading)
|
|
2541
|
-
-
|
|
2541
|
+
- README.md: \`design-system/README.md\` (human-readable, ~100 lines)
|
|
2542
2542
|
${pagePlan ? `- page-plan.md: \`openspec/changes/${changeId}/page-plan.md\` ✅` : ''}
|
|
2543
2543
|
|
|
2544
2544
|
**Style Direction:**
|
|
@@ -2577,7 +2577,7 @@ pageType.includes('auth') ?
|
|
|
2577
2577
|
- patterns/forms.md ✅`}
|
|
2578
2578
|
|
|
2579
2579
|
**Agent Loading (STEP 0.5 for uxui-frontend):**
|
|
2580
|
-
1. Read:
|
|
2580
|
+
1. Read: data.yaml (~800 tokens)
|
|
2581
2581
|
2. Read: page-plan.md (if exists)
|
|
2582
2582
|
3. Load patterns selectively based on page type
|
|
2583
2583
|
4. Report: Design tokens + page type extracted
|