Giao diện
US-P09: Chạy câu SQL đã lập danh mục trên DB Ops ​
Thuộc FS: 00-overview.md — Nền tảng dùng chung của cụm tool SAPP (as-built @
e77c47a) Phần chung (tổng quan, roles, flow tổng, related features, NFR, Open Questions, References) xem ở Overview. File này chỉ chứa nội dung riêng của US.
| Field | Value |
|---|---|
| US ID | US-P09 |
| Role thực hiện | R1 - Người dùng tool (qua sub-tool sapp.010 — SAPP 26878 và sapp.011 — SAPP 26297) — Assumption (OQ về G-01), xem OQ-P-13 |
| Phase | As-built (đã triển khai) |
| Priority | N/A — as-built |
| Status | Draft |
| NFR liên quan | NFR-P-01, NFR-P-04, NFR-P-05 — xem Overview §5 |
| OQ liên quan | OQ-P-10 — xem Overview §6; Drift DR-P-11 |
Nguồn inventory: A-20.
Sub-tool đang dùng dịch vụ này (Fact):
| Sub-tool | Cách dùng | Bằng chứng |
|---|---|---|
| sapp.010 — FS 26878 | Bước loại sql trong flow (panel "SQL cho bước này"), danh mục SAPP_26878_SQL_STATEMENTS | fe/src/ui/components/works/sapp/sapp-26878-step-sql.tsx:360-445 |
| sapp.011 — FS 26297 | Bước SQL của case, dùng lại đúng panel của 26878, danh mục s26297.* (39 câu: 20 đọc, 19 ghi) | fe/src/ui/components/works/sapp/sapp-26297-tool.tsx:14, :100; inventory 26297 E-16, A-10 |
Danh mục câu lệnh (nội dung SQL) thuộc FS nhóm; US này mô tả cơ chế chạy và panel dùng chung.
1. US Statement ​
text
As a Người dùng tool (qua sub-tool 26878 / 26297) [Assumption — OQ-P-13 / G-01]
I want xem câu SQL của bước (đã điền sẵn id của lượt chạy), rồi chạy thẳng trên DB SAPP Ops dev/staging hoặc copy sang DBeaver
So that [Assumption] dựng / kiểm / dọn dữ liệu test mà không phải tự viết SQL và không thể chạy SQL tuỳ ý2. Dependencies & Definition Of Ready ​
N/A — đã triển khai (Mode B).
Dependency runtime: SAPP_OPS_DB_{HOST,NAME,USERNAME,PASSWORD}_{DEV,STAGING} (+ PORT tuỳ chọn) trong env_systems (US-P04); DB Ops cho phép kết nối từ API mind_keep.
3. Business Rules ​
| ID | Rule | Áp dụng ở | Đã cover bởi (AC) | Nguồn code (Mode B/C) |
|---|---|---|---|---|
| BR-01 | Chỉ chạy câu lệnh có trong danh mục, gọi theo id; không bao giờ nhận SQL do người gọi gửi; giá trị tham số được driver bind, không ghép chuỗi. id không có → 13055 | A2 | AC-M1.4, EC-M1.1 | be/libs/modules/src/lib/sapp/sapp-ops-sql.common.service.ts:62-73, :112-122, :52-60 |
| BR-02 | Không chạy được trên prod: không có bộ key prod và không có route prod. Trên prod panel chỉ cho copy | M1, A2 | AC-M1.5 | be/libs/constants/src/lib/sapp/sapp-26878-sql.constants.ts:272-307, be/apps/api/src/sapp/sapp-ops.controller.ts:2404-2442, fe/src/ui/components/works/sapp/sapp-26878-step-sql.tsx:434 |
| BR-03 | Hỏi trạng thái trả configured=false khi môi trường thiếu host / name / username / password — là câu trả lời bình thường, không phải lỗi; cổng mặc định 5432 | A1 | AC-M1.1, AC-M1.2 | be/libs/modules/src/lib/sapp/sapp-ops-sql.common.service.ts:83-108, be/apps/api/src/sapp/sapp-ops.controller.ts:82-90 |
| BR-04 | Tham số thiếu hoặc rỗng → dừng với 13056 (không bao giờ bind giá trị rỗng/NULL); placeholder còn sót sau khi thay → 13057 kèm tên token và hướng dẫn viết '{token}' | A2 | EC-M1.2, EC-M1.3 | be/libs/modules/src/lib/sapp/sapp-ops-sql.common.service.ts:130-163 |
| BR-05 | Một mục gồm nhiều câu chạy trong một transaction; timeout 15 giây mỗi câu; SELECT trả tối đa 200 dòng (dòng thừa bị cắt, màn ghi "(đã cắt bớt)") | A2 | AC-M1.6 | be/libs/modules/src/lib/sapp/sapp-ops-sql.common.service.ts:25-38, :165-174, be/libs/constants/src/lib/sapp/sapp-26878-sql.constants.ts:309-313, fe/src/ui/components/works/sapp/sapp-26878-step-sql.tsx:328 |
| BR-06 | Kết quả trả id, cờ đọc/ghi, từng câu lệnh dạng placeholder (không kèm giá trị đã bind), số dòng / dòng trả về, thời gian chạy | A2 | AC-M1.4 | be/libs/modules/src/lib/sapp/sapp-ops-sql.common.service.ts:17-22, :175-180 |
| BR-07 | Hai danh mục có id trùng nhau → dịch vụ API từ chối khởi động | Cấu hình | AC-M1.8 | be/libs/constants/src/lib/sapp/sapp-ops-sql.constants.ts:7-32 |
| BR-08 | Câu gắn nhãn GHI phải xác nhận trước khi chạy: "Chạy câu GHI này trên <ENV>? … Không có undo." | A2 | AC-M1.3 | fe/src/ui/components/works/sapp/sapp-26878-step-sql.tsx:200-208 |
| BR-09 | Nút "Chạy" chỉ bật khi môi trường là dev/staging, đã cấu hình và mọi tham số đã điền; thiếu tham số → "Còn tham số chưa điền" | M1 - action Chạy | AC-M1.2, AC-M1.7 | fe/src/ui/components/works/sapp/sapp-26878-step-sql.tsx:195, :278-291 |
| BR-10 | Câu ĐỌC được đánh dấu tự chạy sẽ chạy một lần khi mở bước; câu GHI không bao giờ tự chạy; lỗi của câu tự chạy chỉ hiện tại chỗ (không bật hộp lỗi) | A3 | AC-M1.9 | fe/src/ui/components/works/sapp/sapp-26878-step-sql.tsx:215-246 |
| BR-11 | Panel phân biệt ba lý do không chạy được: thiếu credential DB (nêu tên key thiếu) · 401/403 · không gọi được API | M1 - UI state | AC-M1.2, EC-M1.5 | fe/src/ui/components/works/sapp/sapp-26878-step-sql.tsx:153-159, :380-410, :434-443 |
⚠️ Observed (không phải BR): lỗi DB trả nguyên thông điệp Postgres qua route public (OQ-P-10); câu chữ FE nói route chạy SQL cần JWT trong khi BE để public (DR-P-11).
4. Design ​
a. Mối liên hệ giữa các màn & User Flow ​
text
[Bước SQL của 26878 / case SQL của 26297]
↓ mở bước → A1 hỏi trạng thái SQL của env
[M1: Panel "SQL cho bước này"]
├─ prod ──────────────→ chỉ copy (BR-02)
├─ chưa cấu hình / 401 / không gọi được → chỉ copy + câu giải thích (BR-11)
└─ sẵn sàng → mỗi câu: [Copy] [Chạy]
├─ câu ĐỌC tự chạy (BR-10)
├─ câu GHI → xác nhận (BR-08) → A2 chạy
└─ kết quả / lỗi hiện dưới câub. Chi tiết từng màn ​
Màn M1 - Panel "SQL cho bước này" ​
| Field | Value |
|---|---|
| Figma frame | N/A — as-built, không có Figma |
| Trigger vào màn | Mở một bước loại SQL trong sub-tool 26878 hoặc 26297 |
| Mô tả ngắn | "Chạy trong DBeaver. Các id của lượt chạy này đã được điền sẵn." — liệt kê các câu của bước, nhãn ĐỌC/GHI, tham số, nút Copy / Chạy |
UI States ​
| State | Khi nào | Hiển thị | Figma frame |
|---|---|---|---|
| Loading | Đang hỏi trạng thái | "Đang kiểm kết nối DB Ops…" | N/A |
| Default (sẵn sàng) | configured=true | "Câu gắn nhãn GHI sửa thẳng dữ liệu và KHÔNG có undo — nút Chạy sẽ hỏi lại một lần. Một câu gồm nhiều lệnh chạy trong MỘT transaction." | N/A |
| Disabled (prod) | Môi trường prod | "Production không có đường chạy SQL — chỉ copy sang DBeaver được. Câu gắn nhãn GHI không có undo." | N/A |
| Disabled (thiếu credential) | configured=false | "API trả lời được nhưng chưa có credential DB cho <env>: thiếu các dòng SAPP_OPS_DB_HOST_<ENV> / NAME / USERNAME / PASSWORD trong bảng env_systems…" | N/A |
| Error (401/403) | Hỏi trạng thái bị từ chối | "Chưa đăng nhập (401): route chạy SQL là route DUY NHẤT của tool này cần JWT…" (⚠️ DR-P-11) | N/A |
| Error (không gọi được) | Lỗi mạng / 404 | "Không gọi được API kiểm tra (<chi tiết>). Nếu backend chưa deploy bản có route /sapp-ops/sql/status thì đây là lý do. Chỉ copy sang DBeaver được." | N/A |
| Has data | Câu đã chạy | Số dòng / dòng trả về từng câu, "(đã cắt bớt)" nếu vượt 200, thời gian ms | N/A |
| Empty | Câu chạy không trả dòng | Kết quả 0 dòng | N/A |
Nguồn: fe/src/ui/components/works/sapp/sapp-26878-step-sql.tsx:425-445, :310-335.
Fields ​
| Field | Required | Type | Default | Format | Validation | Error Message | Visibility | Depends On |
|---|---|---|---|---|---|---|---|---|
| Câu lệnh (hiển thị) | — | Text readonly | Điền sẵn từ id của lượt chạy | SQL với '{token}' đã thay | — | — | Always | Tham số |
| Nhãn ĐỌC / GHI | — | Badge | Theo danh mục | — | — | — | Always | — |
| Tham số của bước | Yes (mọi placeholder) | Text | Mẫu mặc định của bước (nếu có) | — | Không rỗng (BR-04, BR-09) | "Còn tham số chưa điền" / 13056 | Khi câu có placeholder | Dữ liệu các bước trước |
Filter / Search / Sort ​
N/A — không phải màn List.
Actions ​
A1 - Hỏi trạng thái SQL của môi trường (hệ thống) ​
| Item | Description |
|---|---|
| Trigger | Mở panel (env dev/staging) |
| Behavior | GET /api/v1/sapp/<dev|staging>/sapp-ops/sql/status. Chỉ đọc env_systems; không kết nối DB |
| Success Result | { configured: true/false } (BR-03) |
Error cases:
| Case | Expected Handling |
|---|---|
| 401/403 | State "Chưa đăng nhập (401)…" |
| Lỗi mạng / 404 | State "Không gọi được API kiểm tra…" |
A2 - Chạy một câu ​
| Item | Description |
|---|---|
| Trigger | Bấm "Chạy" (câu GHI: xác nhận trước — BR-08) |
| Behavior | POST /api/v1/sapp/<dev|staging>/sapp-ops/sql/run với { statementId, params } (BR-01). Kết nối trực tiếp Postgres SAPP Ops dev hoặc staging; câu GHI sửa thẳng dữ liệu, không undo. Không có đường ghi PROD (BR-02) |
| Success Result | Kết quả theo BR-06; id đọc được từ kết quả được đưa ngược vào dữ liệu lượt chạy cho bước sau |
Error cases:
| Case | Expected Handling |
|---|---|
| id không có trong danh mục | 13055 |
| Môi trường chưa cấu hình | 13054 "No SAPP Ops database is configured for this environment…" |
| Thiếu tham số | 13056 |
| DB từ chối | 13057 "The SAPP Ops database refused the statement: <thông điệp Postgres>" |
A3 - Tự chạy câu đọc ​
| Item | Description |
|---|---|
| Trigger | Mở bước có câu ĐỌC đánh dấu tự chạy, môi trường sẵn sàng |
| Behavior | Chạy một lần (BR-10); chỉ đọc DB Ops dev/staging |
| Success Result | Kết quả hiện sẵn, id điền cho bước sau |
Error cases:
| Case | Expected Handling |
|---|---|
| Lỗi | Hiện tại chỗ, không bật hộp lỗi |
A4 - Copy câu lệnh ​
| Item | Description |
|---|---|
| Trigger | Bấm "Copy câu lệnh" / "Copy" |
| Behavior | Copy câu đã điền tham số vào clipboard. Không gọi API |
| Success Result | "Đã copy" |
Error cases:
| Case | Expected Handling |
|---|---|
| Còn tham số chưa điền | Nút hiện "Còn tham số chưa điền" |
Acceptance Criteria của màn M1 ​
AC-M1.1 - Sẵn sàng ​
gherkin
Given staging có đủ SAPP_OPS_DB_HOST/NAME/USERNAME/PASSWORD_STAGING
When mở bước SQL trên staging
Then panel hiện state sẵn sàng và nút "Chạy" dùng được cho câu đã đủ tham sốMaps to:
- Business Rule: BR-03, BR-09
AC-M1.2 - Chưa cấu hình không phải lỗi ​
gherkin
Given dev thiếu SAPP_OPS_DB_PASSWORD_DEV
When mở bước SQL trên dev
Then API trả configured = false (HTTP thành công); panel nêu các key còn thiếu và chỉ cho copyMaps to:
- Business Rule: BR-03, BR-09, BR-11
AC-M1.3 - Câu GHI phải xác nhận ​
gherkin
Given câu có nhãn GHI
When bấm "Chạy"
Then hiện xác nhận "Chạy câu GHI này trên STAGING? … Không có undo."
And bấm huỷ thì không gọi APIMaps to:
- Business Rule: BR-08
AC-M1.4 - Chỉ chạy theo id, kết quả không lộ giá trị ​
gherkin
Given câu "us09.sign.1" có placeholder '{class_id}'
When chạy với class_id = "abc"
Then BE lấy SQL từ danh mục, bind "abc" làm tham số
And kết quả trả câu lệnh dạng "$1" (không chứa "abc"), số dòng và thời gianMaps to:
- Business Rule: BR-01, BR-06
AC-M1.5 - Prod chỉ copy ​
gherkin
Given sub-tool đang ở prod
When mở bước SQL
Then panel hiện "Production không có đường chạy SQL — chỉ copy sang DBeaver được…"
And không có route prod để gọiMaps to:
- Business Rule: BR-02
AC-M1.6 - Nhiều câu một transaction, giới hạn ​
gherkin
Given mục dọn dữ liệu gồm 3 câu, câu thứ 3 lỗi ràng buộc
When chạy
Then cả 3 câu bị huỷ (không câu nào được giữ) và trả 13057
And một câu SELECT trả 500 dòng thì chỉ nhận 200 dòng, đánh dấu "(đã cắt bớt)"Maps to:
- Business Rule: BR-05
AC-M1.7 - Thiếu tham số ​
gherkin
Given câu còn placeholder chưa có giá trị
When xem panel
Then nút Chạy vô hiệu với nhãn "Còn tham số chưa điền"Maps to:
- Business Rule: BR-09
AC-M1.8 - Id trùng chặn khởi động ​
gherkin
Given danh mục 26878 và 26297 có cùng một id câu lệnh
When API khởi động
Then API không khởi động được (lỗi cấu hình)Maps to:
- Business Rule: BR-07
AC-M1.9 - Câu đọc tự chạy ​
gherkin
Given bước có câu ĐỌC đánh dấu tự chạy và env sẵn sàng
When mở bước
Then câu đó chạy đúng một lần; câu GHI trong cùng bước không tự chạyMaps to:
- Business Rule: BR-10
Negative AC / Edge Cases của màn M1 ​
| ID | Tình huống | Hành vi mong đợi |
|---|---|---|
| EC-M1.1 | Gọi API với id không có trong danh mục | 13055 "Unknown SQL statement id…raw SQL is never accepted." |
| EC-M1.2 | Gọi API thiếu một tham số | 13056, không chạy câu nào |
| EC-M1.3 | Placeholder viết '{code_prefix}%' (không chiếm trọn cặp nháy) | 13057 nêu token chưa được thay |
| EC-M1.4 | ⚠️ Observed — DB từ chối câu lệnh | Thông điệp Postgres gốc (tên cột, ràng buộc) trả qua route public (be/libs/modules/src/lib/sapp/sapp-ops-sql.common.service.ts:181-193; OQ-P-10) |
| EC-M1.5 | ⚠️ Observed — Panel nói route SQL "cần JWT" | BE để route public; state 401 chỉ xảy ra nếu hạ tầng chặn (DR-P-11) |
| EC-M1.6 | Câu một phần mất > 15 giây | Hết thời gian → 13057; transaction bị huỷ |
5. Cross-feature AC ​
AC-X.1 - 26878 và 26297 dùng chung panel ​
gherkin
Given FS 26878 (bước sql) và FS 26297 (case SQL)
When đặc tả bước SQL
Then cả hai tham chiếu US-P09 cho cơ chế chạy, xác nhận GHI, trạng thái; chỉ mô tả nội dung câu trong danh mục của mìnhMaps to:
- REL-05 (Be Affected - FS 26878)
- REL-06 (Be Affected - FS 26297)