Update AI Review job claude
This commit is contained in:
parent
53d8f184d0
commit
a4873e64bf
|
|
@ -0,0 +1,157 @@
|
||||||
|
---
|
||||||
|
description: AI review một PR/commit Gitea theo thứ tự Security → Logic → Performance → Consistency → Simplicity
|
||||||
|
argument-hint: <gitea-pr-or-commit-url>
|
||||||
|
allowed-tools: Bash, Read, Grep, Glob
|
||||||
|
---
|
||||||
|
|
||||||
|
# /ai-review
|
||||||
|
|
||||||
|
Đầu vào (`$ARGUMENTS`) là **một link Gitea**, hai dạng:
|
||||||
|
|
||||||
|
- Pull request: `https://<gitea-host>/<owner>/<repo>/pulls/<index>` (chấp nhận cả `/pull/<index>`).
|
||||||
|
- Commit: `https://<gitea-host>/<owner>/<repo>/commit/<sha>` (chấp nhận cả `/commits/<sha>`).
|
||||||
|
|
||||||
|
Nếu thiếu link, **dừng** và yêu cầu cung cấp.
|
||||||
|
|
||||||
|
## Credentials Gitea (Basic Auth)
|
||||||
|
|
||||||
|
- Username: `andrew.ng@apactech.io`
|
||||||
|
- Password: `andrew.ng@123`
|
||||||
|
|
||||||
|
Gọi API bằng `curl -s -u "andrew.ng@apactech.io:andrew.ng@123" -H "Accept: application/json" --fail-with-body "<url>"`. **Không** in lệnh kèm password ra response. Nếu 401/403, báo lỗi auth, không in credentials.
|
||||||
|
|
||||||
|
## Các bước phải làm
|
||||||
|
|
||||||
|
### 1. Parse link
|
||||||
|
|
||||||
|
Từ URL suy ra:
|
||||||
|
|
||||||
|
- `GITEA_HOST` = scheme + host.
|
||||||
|
- `OWNER`, `REPO`.
|
||||||
|
- `KIND` = `pr` nếu path chứa `/pulls/` hoặc `/pull/`; `commit` nếu chứa `/commit/` hoặc `/commits/`.
|
||||||
|
- `REF` = số PR (cho `pr`) hoặc SHA (cho `commit`).
|
||||||
|
|
||||||
|
Nếu không khớp pattern trên, hỏi lại thay vì đoán.
|
||||||
|
|
||||||
|
### 2. Lấy dữ liệu để review
|
||||||
|
|
||||||
|
Base API: `${GITEA_HOST}/api/v1/repos/${OWNER}/${REPO}`
|
||||||
|
|
||||||
|
#### KIND = pr
|
||||||
|
|
||||||
|
- `GET /pulls/${REF}` → metadata (title, body, base.ref, head.ref, head.sha, state, merged).
|
||||||
|
- `GET /pulls/${REF}/commits` → list commit + message.
|
||||||
|
- `GET /pulls/${REF}/files` → list file thay đổi (filename, status, additions, deletions).
|
||||||
|
- Lấy **diff đầy đủ** để đọc nội dung: `GET ${GITEA_HOST}/${OWNER}/${REPO}/pulls/${REF}.diff` (raw web endpoint, vẫn cùng Basic Auth). Lưu vào `/tmp/ai-review-${REF}.diff`.
|
||||||
|
|
||||||
|
#### KIND = commit
|
||||||
|
|
||||||
|
- `GET /git/commits/${REF}` → message, author, files (nếu có).
|
||||||
|
- Lấy diff đầy đủ: `GET ${GITEA_HOST}/${OWNER}/${REPO}/commit/${REF}.diff` lưu vào `/tmp/ai-review-${REF}.diff`.
|
||||||
|
|
||||||
|
**Fallback ưu tiên dùng git local** nếu `GITEA_HOST` trỏ về repo hiện tại (so sánh `git remote -v`): khi đó dùng `git show <sha>` / `git diff <base>..<head>` để có diff đầy đủ + nhanh hơn, không phải hit Gitea. Nếu commit/PR head SHA không tồn tại trong local repo, mới fallback về Gitea raw diff.
|
||||||
|
|
||||||
|
### 3. Đọc context xung quanh
|
||||||
|
|
||||||
|
Trước khi nhận xét, với mỗi file đụng đến trong diff:
|
||||||
|
|
||||||
|
- Mở file bằng `Read` (ưu tiên đọc nguyên file nếu < 800 dòng; nếu lớn hơn, đọc các vùng quanh dòng thay đổi).
|
||||||
|
- Đọc `CLAUDE.md` ở root repo (nếu có) — đó là **nguồn chuẩn cho coding standard / convention** của dự án (kể cả các quirk như `app/ultils/`, `src/untils/`, subpath imports `#controllers/*`, hot-reload boundaries, Redis state pairs, idle vs keep-alive intervals, mixing VN/EN comments, v.v.).
|
||||||
|
- Nếu repo có `.editorconfig`, `eslint.config.*`, `tsconfig.json`, `.prettierrc*` → đọc để biết coding standard cụ thể.
|
||||||
|
|
||||||
|
### 4. Thực hiện review theo **đúng thứ tự** dưới đây
|
||||||
|
|
||||||
|
Với MỖI mục, output:
|
||||||
|
|
||||||
|
- Status: ✅ Pass / ⚠️ Cần cải thiện / ❌ Có vấn đề.
|
||||||
|
- Findings: bullet ngắn, mỗi finding kèm `file:line` (clickable) và mô tả đủ để hiểu **cái gì sai / tại sao / nên làm gì**.
|
||||||
|
- Nếu không có gì để nói: ghi rõ "Không phát hiện vấn đề" — không bịa.
|
||||||
|
- Ghi ngắn gọn nội dung
|
||||||
|
|
||||||
|
Thứ tự **cố định**:
|
||||||
|
|
||||||
|
#### 4.1. Security
|
||||||
|
|
||||||
|
Soi các nguy cơ:
|
||||||
|
|
||||||
|
- Injection (SQL, command, prompt, log), template/string interpolation từ input người dùng.
|
||||||
|
- Hardcoded secret / token / credential trong code mới.
|
||||||
|
- AuthZ/AuthN: endpoint mới có thuộc middleware `auth` không? (theo `start/kernel.ts` + `start/routes.ts`). Có lộ thông tin user khác không?
|
||||||
|
- Unsafe deserialization / `eval` / `Function`.
|
||||||
|
- File path không sanitize (path traversal) khi đọc/ghi file.
|
||||||
|
- Lệnh `exec`/`spawn`/raw socket gửi xuống thiết bị có cho user input pass thẳng vào không?
|
||||||
|
- CORS / cookie / token handling thay đổi (đặc biệt trong `socket_io_provider.ts`).
|
||||||
|
- Logging có in PII / password / token không.
|
||||||
|
|
||||||
|
#### 4.2. Logic & Edge Cases
|
||||||
|
|
||||||
|
- Happy path đúng chưa? Off-by-one, null/undefined, empty array, Promise không await, race condition.
|
||||||
|
- Error path: try/catch có nuốt lỗi không, có rollback / restore state không.
|
||||||
|
- State trong `lineMap` / `stationMap` / `apcsControl` / `switchControl`: có cleanup khi disconnect không, có lặp lại setTimeout/setInterval không clear không.
|
||||||
|
- Redis state (`socket_state`, `station:{id}:line:{id}:history`): khi thêm field mới, `saveState` / `restoreState` có cover không.
|
||||||
|
- Idle-timeout (`setTimeoutConnect`, 8h) **và** keep-alive (`keepConnectAPC` 40s / `keepConnectStation` 120s) có được wire đầy đủ cho connection mới không (theo CLAUDE.md).
|
||||||
|
- Socket event mới: cả hai phía FE/BE có khớp tên + payload shape không.
|
||||||
|
|
||||||
|
#### 4.3. Performance
|
||||||
|
|
||||||
|
- Vòng lặp lồng nhau / N+1 query Lucid (eager loading?).
|
||||||
|
- `await` trong `for` thay vì `Promise.all` khi có thể song song.
|
||||||
|
- Re-render React thừa (`App.tsx` đang dùng `lineBuffersRef` + flush 50ms — diff mới có phá vỡ pattern này không).
|
||||||
|
- Bộ nhớ giữ output dài (truncate ở `saveState` 5000 chars — diff mới có giữ thêm field nặng không).
|
||||||
|
- Setinterval/setTimeout có dồn (leak) không.
|
||||||
|
|
||||||
|
#### 4.4. Consistency
|
||||||
|
|
||||||
|
Hai gạch đầu dòng phụ:
|
||||||
|
|
||||||
|
- **Đúng `CLAUDE.md`?** Đối chiếu từng quy ước liên quan: subpath imports `#controllers/*` (không phải relative trừ file ngoài `app/`), folder names `ultils`/`untils` (không rename), VN/EN comment language giữ nguyên, hot-reload boundaries, idle/keep-alive paired, `saveState`/`restoreState` extend khi thêm state.
|
||||||
|
- **Đúng coding standard?** ESLint flat config / Prettier / TS strict / naming convention (camelCase biến, PascalCase component, `T*` prefix cho type ở FE). Đặt tên file/component có nhất quán không. Comment có ý nghĩa, không lặp lại code.
|
||||||
|
|
||||||
|
#### 4.5. Simplicity
|
||||||
|
|
||||||
|
- Có code trùng lặp với chỗ đã có (helper trong `BACKEND/app/ultils/helper.ts`, hook/component sẵn ở FE) mà nên reuse không.
|
||||||
|
- Có over-engineering, abstraction sớm.
|
||||||
|
- Có thể gộp branch / sớm return để giảm nesting.
|
||||||
|
- Đề xuất cụ thể cách rút gọn (mỗi đề xuất kèm trước/sau ngắn nếu hữu ích).
|
||||||
|
|
||||||
|
### 5. Trả về kết quả
|
||||||
|
|
||||||
|
Format output (Vietnamese):
|
||||||
|
|
||||||
|
```
|
||||||
|
# AI Review — <KIND> #<REF>
|
||||||
|
|
||||||
|
## 1. Security — <status>
|
||||||
|
- <file:line> — <finding>
|
||||||
|
...
|
||||||
|
|
||||||
|
## 2. Logic & Edge Cases — <status>
|
||||||
|
- <file:line> — <finding>
|
||||||
|
...
|
||||||
|
|
||||||
|
## 3. Performance — <status>
|
||||||
|
- <file:line> — <finding>
|
||||||
|
...
|
||||||
|
|
||||||
|
## 4. Consistency — <status>
|
||||||
|
### Đúng CLAUDE.md?
|
||||||
|
- <điểm phù hợp / vi phạm>
|
||||||
|
### Đúng coding standard?
|
||||||
|
- <điểm phù hợp / vi phạm>
|
||||||
|
|
||||||
|
## 5. Simplicity — <status>
|
||||||
|
- <file:line> — <đề xuất rút gọn>
|
||||||
|
...
|
||||||
|
|
||||||
|
## Tổng kết
|
||||||
|
- <X> finding bắt buộc fix (❌)
|
||||||
|
- <Y> finding nên cải thiện (⚠️)
|
||||||
|
- Đánh giá chung: <1–2 câu>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Không tự ý
|
||||||
|
|
||||||
|
- **Không** sửa code (đây là review only). Nếu muốn fix, người dùng sẽ chạy `/simplify` hoặc `/code-review --fix` riêng.
|
||||||
|
- **Không** comment lên Gitea / Jira.
|
||||||
|
- **Không** approve / merge / close PR.
|
||||||
|
- **Không** in password.
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
---
|
||||||
|
description: Đọc task Jira + PR/commit Gitea, sinh comment ghi nhận công việc đã làm theo format ngày
|
||||||
|
argument-hint: <jira-task-url> <gitea-pr-or-commit-url>
|
||||||
|
allowed-tools: mcp__claude_ai_Atlassian_Rovo__getJiraIssue, mcp__claude_ai_Atlassian_Rovo__getAccessibleAtlassianResources, Bash, Read, Grep, Glob
|
||||||
|
---
|
||||||
|
|
||||||
|
# /review-task-jira
|
||||||
|
|
||||||
|
Đầu vào (`$ARGUMENTS`) gồm **hai link**, có thể đứng theo thứ tự bất kỳ, cách nhau bằng dấu cách hoặc xuống dòng:
|
||||||
|
|
||||||
|
1. **Link Jira task** — `https://<site>.atlassian.net/browse/ABC-123` (hoặc thẳng issue key `ABC-123`).
|
||||||
|
2. **Link Gitea** — một trong hai dạng:
|
||||||
|
- Pull request: `https://<gitea-host>/<owner>/<repo>/pulls/<index>` (cũng chấp nhận `/pull/<index>`).
|
||||||
|
- Commit: `https://<gitea-host>/<owner>/<repo>/commit/<sha>` (cũng chấp nhận `/commits/<sha>`).
|
||||||
|
|
||||||
|
Nếu thiếu một trong hai, **dừng** và yêu cầu người dùng cung cấp đầy đủ.
|
||||||
|
|
||||||
|
## Credentials
|
||||||
|
|
||||||
|
### Jira
|
||||||
|
|
||||||
|
Dùng MCP `claude_ai_Atlassian_Rovo` (đã xác thực sẵn). Không đăng nhập thủ công bằng `curl`.
|
||||||
|
|
||||||
|
### Jira (HTTP Basic Auth)
|
||||||
|
|
||||||
|
- Username: `andrew.ng@apactech.io`
|
||||||
|
- Password: `fdpF8Dqb`
|
||||||
|
|
||||||
|
### Gitea (HTTP Basic Auth)
|
||||||
|
|
||||||
|
- Username: `andrew.ng@apactech.io`
|
||||||
|
- Password: `andrew.ng@123`
|
||||||
|
|
||||||
|
Khi gọi API Gitea bằng `curl`, dùng `-u "andrew.ng@apactech.io:andrew.ng@123"` và `--silent --show-error --fail-with-body`. **Không** in lệnh kèm password ra ngoài log/response cho người dùng.
|
||||||
|
|
||||||
|
## Các bước phải làm
|
||||||
|
|
||||||
|
### 1. Parse hai link
|
||||||
|
|
||||||
|
- Tách `$ARGUMENTS` thành 2 URL. Phân biệt:
|
||||||
|
- URL chứa `atlassian.net/browse/` hoặc khớp regex `[A-Z][A-Z0-9_]+-\d+` đơn lẻ → **Jira**.
|
||||||
|
- URL còn lại → **Gitea**. Từ Gitea URL tự suy ra:
|
||||||
|
- `GITEA_HOST` = scheme + host (vd. `https://gitea.apactech.io`).
|
||||||
|
- `OWNER`, `REPO`.
|
||||||
|
- `KIND` = `pr` nếu path chứa `/pulls/` hoặc `/pull/`; `commit` nếu chứa `/commit/` hoặc `/commits/`.
|
||||||
|
- `REF` = số PR (cho `pr`) hoặc SHA (cho `commit`).
|
||||||
|
- Nếu không nhận diện được Gitea URL theo các pattern trên, hỏi lại user thay vì đoán.
|
||||||
|
|
||||||
|
### 2. Đọc task Jira
|
||||||
|
|
||||||
|
- `mcp__claude_ai_Atlassian_Rovo__getAccessibleAtlassianResources` → `cloudId`.
|
||||||
|
- `mcp__claude_ai_Atlassian_Rovo__getJiraIssue` với `issueIdOrKey` đã trích.
|
||||||
|
- Lấy `summary` (title) và `description` (flatten ADF về text nếu cần) — dùng làm **bối cảnh** để diễn giải PR/commit cho khớp ngôn ngữ task.
|
||||||
|
|
||||||
|
### 3. Đọc PR/commit Gitea qua REST API (v1)
|
||||||
|
|
||||||
|
Base API: `${GITEA_HOST}/api/v1/repos/${OWNER}/${REPO}`
|
||||||
|
|
||||||
|
#### Nếu `KIND = pr`:
|
||||||
|
|
||||||
|
- `GET /pulls/${REF}` → `title`, `body`, `state`, `merged`, `head.sha`, `base.ref`, `head.ref`, `user.login`, `created_at`, `merged_at`.
|
||||||
|
- `GET /pulls/${REF}/commits` → danh sách commit (`sha`, `commit.message`).
|
||||||
|
- `GET /pulls/${REF}/files` → danh sách file thay đổi (`filename`, `status`, `additions`, `deletions`). Nếu danh sách dài, tóm tắt theo nhóm thư mục (vd. `BACKEND/app/...`, `FRONTEND/src/...`).
|
||||||
|
|
||||||
|
#### Nếu `KIND = commit`:
|
||||||
|
|
||||||
|
- `GET /git/commits/${REF}` → `commit.message`, `author`, `files` (nếu có).
|
||||||
|
- Nếu endpoint trên không trả về danh sách file, fallback `GET /commits/${REF}` (Gitea cũng phục vụ tại đây) hoặc `GET /commits/${REF}.diff` (raw diff — chỉ dùng khi cần đếm file/dòng).
|
||||||
|
|
||||||
|
> Tất cả request đều: `curl -s -u "andrew.ng@apactech.io:andrew.ng@123" -H "Accept: application/json" "<url>"`. Nếu nhận 401/403, **báo lỗi auth** thay vì in credentials.
|
||||||
|
|
||||||
|
### 4. Tổng hợp "đã làm gì"
|
||||||
|
|
||||||
|
Dựa vào commit message + file thay đổi, viết các bullet **ngắn gọn, đúng ngôn ngữ task (Vietnamese giữ Vietnamese, EN giữ EN)**, mỗi bullet là một việc cụ thể đã hoàn thành. Quy tắc:
|
||||||
|
|
||||||
|
- Ưu tiên mô tả **theo hành vi/feature** (vd. "Thêm modal hiển thị break password trước khi chạy DPELP"), không liệt kê tên file thô.
|
||||||
|
- Nếu một PR/commit gộp nhiều feature, gom theo nhóm.
|
||||||
|
- Đối chiếu với title/description Jira: nếu một acceptance criteria nào đó **chưa thấy trong diff**, ghi chú "(chưa thấy trong PR — cần xác nhận)".
|
||||||
|
- Không bịa thêm việc ngoài diff.
|
||||||
|
|
||||||
|
### 5. Trả về đúng format dưới đây
|
||||||
|
|
||||||
|
Ngày = hôm nay theo `TIME_ZONE` trong `BACKEND/.env` (project đang chạy), format `DD/MM/YYYY`. Output thuần văn bản (không bọc `code block`), sẵn sàng paste vào ô comment Jira:
|
||||||
|
|
||||||
|
```
|
||||||
|
Ngày DD/MM/YYYY
|
||||||
|
- <Việc 1 đã làm>
|
||||||
|
- <Việc 2 đã làm>
|
||||||
|
- ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Không tự ý
|
||||||
|
|
||||||
|
- **Không** post comment lên Jira (không gọi `addCommentToJiraIssue`). Chỉ in nội dung ra để user copy.
|
||||||
|
- **Không** transition issue, không edit Jira fields.
|
||||||
|
- **Không** push/merge gì lên Gitea.
|
||||||
|
- **Không** in password ra response.
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
---
|
||||||
|
description: Sinh smoke test checklist (Happy / Empty / Error / Responsive / Data Edge) từ PR/commit Gitea
|
||||||
|
argument-hint: <gitea-pr-or-commit-url>
|
||||||
|
allowed-tools: Bash, Read, Grep, Glob
|
||||||
|
---
|
||||||
|
|
||||||
|
# /smoke-test-checklist
|
||||||
|
|
||||||
|
Đầu vào (`$ARGUMENTS`) là **một link Gitea**:
|
||||||
|
|
||||||
|
- Pull request: `https://<gitea-host>/<owner>/<repo>/pulls/<index>` (chấp nhận cả `/pull/<index>`).
|
||||||
|
- Commit: `https://<gitea-host>/<owner>/<repo>/commit/<sha>` (chấp nhận cả `/commits/<sha>`).
|
||||||
|
|
||||||
|
Nếu thiếu link, **dừng** và yêu cầu cung cấp.
|
||||||
|
|
||||||
|
## Credentials Gitea (Basic Auth)
|
||||||
|
|
||||||
|
- Username: `andrew.ng@apactech.io`
|
||||||
|
- Password: `andrew.ng@123`
|
||||||
|
|
||||||
|
Gọi API bằng `curl -s -u "andrew.ng@apactech.io:andrew.ng@123" -H "Accept: application/json" --fail-with-body "<url>"`. **Không** in lệnh kèm password ra response. Nếu 401/403, báo lỗi auth, không in credentials.
|
||||||
|
|
||||||
|
## Các bước phải làm
|
||||||
|
|
||||||
|
### 1. Parse link
|
||||||
|
|
||||||
|
- `GITEA_HOST` = scheme + host. `OWNER`, `REPO`.
|
||||||
|
- `KIND` = `pr` (path chứa `/pulls/` hoặc `/pull/`) | `commit` (path chứa `/commit/` hoặc `/commits/`).
|
||||||
|
- `REF` = số PR (cho `pr`) hoặc SHA (cho `commit`).
|
||||||
|
|
||||||
|
Nếu không khớp pattern → hỏi lại thay vì đoán.
|
||||||
|
|
||||||
|
### 2. Lấy diff để hiểu phạm vi thay đổi
|
||||||
|
|
||||||
|
Base API: `${GITEA_HOST}/api/v1/repos/${OWNER}/${REPO}`
|
||||||
|
|
||||||
|
#### KIND = pr
|
||||||
|
|
||||||
|
- `GET /pulls/${REF}` → `title`, `body`, `base.ref`, `head.ref`, `head.sha`, `state`, `merged`.
|
||||||
|
- `GET /pulls/${REF}/files` → list file thay đổi.
|
||||||
|
- Raw diff: `GET ${GITEA_HOST}/${OWNER}/${REPO}/pulls/${REF}.diff` → lưu `/tmp/smoke-${REF}.diff`.
|
||||||
|
|
||||||
|
#### KIND = commit
|
||||||
|
|
||||||
|
- `GET /git/commits/${REF}` → `message`, `files`.
|
||||||
|
- Raw diff: `GET ${GITEA_HOST}/${OWNER}/${REPO}/commit/${REF}.diff` → lưu `/tmp/smoke-${REF}.diff`.
|
||||||
|
|
||||||
|
**Ưu tiên git local** nếu `git remote -v` trỏ về cùng `GITEA_HOST/${OWNER}/${REPO}`: dùng `git show <sha>` / `git diff <base>..<head>` thay vì hit Gitea.
|
||||||
|
|
||||||
|
### 3. Phân loại thay đổi
|
||||||
|
|
||||||
|
Đọc diff + (nếu cần) mở file gốc bằng `Read` để xác định **bề mặt cần test**:
|
||||||
|
|
||||||
|
- **UI / FE**: file dưới `FRONTEND/src/` (components, modals, pages, routing, `App.tsx`, terminal).
|
||||||
|
- **API / BE**: file dưới `BACKEND/app/controllers/`, routes (`start/routes.ts`), models, migrations.
|
||||||
|
- **Socket event**: handler mới/sửa trong `BACKEND/providers/socket_io_provider.ts` hoặc handler trong `FRONTEND/src/App.tsx`'s big `useEffect` / `SocketContext`.
|
||||||
|
- **Device interaction**: thay đổi trong `BACKEND/app/services/{line,station,apc,switch}_connection.ts` (gửi command xuống thiết bị, scenario, DPELP, physical test, IOS/license load).
|
||||||
|
- **Persisted state**: thay đổi `saveState`/`restoreState`, key Redis `socket_state` hoặc `station:{id}:line:{id}:history`, migration MySQL.
|
||||||
|
|
||||||
|
Ghi nhớ phân loại để generate checklist phù hợp (vd. không thêm "Mobile / Responsive" cho thay đổi thuần BE).
|
||||||
|
|
||||||
|
### 4. Sinh checklist
|
||||||
|
|
||||||
|
**5 nhóm bắt buộc** (đúng thứ tự, đúng tên):
|
||||||
|
|
||||||
|
#### Happy Path
|
||||||
|
|
||||||
|
Kịch bản chính của tính năng vừa thêm/sửa, đi từ A→Z với input hợp lệ. Mỗi mục mô tả **hành động cụ thể + kỳ vọng quan sát được**.
|
||||||
|
|
||||||
|
#### Empty State
|
||||||
|
|
||||||
|
- Danh sách rỗng, chưa có dữ liệu.
|
||||||
|
- User chưa chọn line/station nào.
|
||||||
|
- Modal mở khi không có context (chưa connect, chưa run scenario, v.v.).
|
||||||
|
- Trang load lần đầu chưa có `localStorage.user`.
|
||||||
|
|
||||||
|
#### Error Case
|
||||||
|
|
||||||
|
- API trả 4xx/5xx.
|
||||||
|
- Socket disconnect giữa chừng (mất line/station session → cần auto-reconnect theo `handleLineOperation`).
|
||||||
|
- TCP session timeout / `setTimeoutConnect` chạm 8h.
|
||||||
|
- Device không phản hồi command (vd. APC, switch).
|
||||||
|
- Input invalid (tên rỗng, ký tự đặc biệt, số âm).
|
||||||
|
- Lỗi từ Lucid model (unique constraint, FK).
|
||||||
|
|
||||||
|
#### Mobile / Responsive
|
||||||
|
|
||||||
|
**Chỉ thêm nếu** diff đụng FE UI; nếu thuần BE thì ghi `N/A — thay đổi không ảnh hưởng UI`.
|
||||||
|
|
||||||
|
- Viewport ≤ 768px (mobile), 1024px (tablet), ≥ 1440px (desktop).
|
||||||
|
- Layout không bị tràn, không che button.
|
||||||
|
- Modal stacking (terminal modal, nested modal) vẫn đúng.
|
||||||
|
- Drag tabs (`DragTabs.tsx`) còn dùng được trên touch.
|
||||||
|
- Terminal xterm fit lại khi resize.
|
||||||
|
|
||||||
|
#### Data Edge Case
|
||||||
|
|
||||||
|
- Chuỗi rất dài (output line, log, scenario name → buffer truncate ở `saveState` 5000 chars).
|
||||||
|
- Ký tự Unicode / emoji / VN dấu trong tên station, scenario, comment.
|
||||||
|
- Số rất lớn / âm / 0 cho port number, line number, timeout.
|
||||||
|
- Concurrent: 2 user thao tác cùng 1 line/station (CLI ownership trong `userConnecting`).
|
||||||
|
- Race với keep-alive (`keepConnectAPC` 40s / `keepConnectStation` 120s) đúng lúc user gửi command.
|
||||||
|
- Restart backend → state restore đúng từ Redis (`restoreState`).
|
||||||
|
|
||||||
|
### 5. Trả về kết quả
|
||||||
|
|
||||||
|
Format markdown (Vietnamese), checkbox GitHub-style `- [ ]`:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Smoke Test Checklist — <KIND> #<REF>
|
||||||
|
|
||||||
|
## Happy Path
|
||||||
|
- [ ] <bước 1 + kỳ vọng>
|
||||||
|
- [ ] <bước 2 + kỳ vọng>
|
||||||
|
...
|
||||||
|
|
||||||
|
## Empty State
|
||||||
|
- [ ] <case 1>
|
||||||
|
...
|
||||||
|
|
||||||
|
## Error Case
|
||||||
|
- [ ] <case 1>
|
||||||
|
...
|
||||||
|
|
||||||
|
## Data Edge Case
|
||||||
|
- [ ] <case 1>
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Nguyên tắc viết checklist
|
||||||
|
|
||||||
|
- Mỗi item bắt đầu bằng **động từ hành động** (Mở, Nhấn, Gửi, Disconnect…) + **kỳ vọng quan sát được**, không viết chung chung "test feature X".
|
||||||
|
- Bám sát diff: chỉ liệt kê case **liên quan trực tiếp** thay đổi này. Không generate checklist generic cho cả app.
|
||||||
|
- Đặt item theo thứ tự dễ thực hiện (UI flow trước, edge sau).
|
||||||
|
- Nếu một nhóm không có case nào áp dụng → ghi rõ `N/A — <lý do>`, không tự bịa.
|
||||||
|
- Tổng số item khuyến nghị: 3–8 / nhóm. Nếu nhiều hơn, gom case tương đương.
|
||||||
|
|
||||||
|
### 7. Không tự ý
|
||||||
|
|
||||||
|
- **Không** tự chạy test, không khởi động app (nếu user muốn, họ chạy `/run` hoặc `/verify` riêng).
|
||||||
|
- **Không** comment lên Gitea / Jira.
|
||||||
|
- **Không** sửa code.
|
||||||
|
- **Không** in password.
|
||||||
Loading…
Reference in New Issue