Skip to content

US-P08: Đọc / ghi SAPP Ops qua passthrough (auto-login, kiểm tra kết nối) ​

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.

FieldValue
US IDUS-P08
Role thực hiệnR1 - Người dùng tool (qua sub-tool sapp.010 — SAPP 26878; auto-login dùng thêm bởi sapp.011 — SAPP 26297) — Assumption (OQ về G-01), xem OQ-P-13
PhaseAs-built (đã triển khai)
PriorityN/A — as-built
StatusDraft
NFR liên quanNFR-P-01, NFR-P-03, NFR-P-04, NFR-P-05, NFR-P-08 — xem Overview §5
OQ liên quanOQ-P-01, OQ-P-02, OQ-P-08, OQ-P-15, OQ-P-19 — xem Overview §6

Nguồn inventory: A-18, A-19, A-21.

Sub-tool đang dùng dịch vụ này (Fact):

Sub-toolDùng phần nàoBằng chứng
sapp.010 — FS 26878Toàn bộ passthrough (bước ops, classcode, màn re-sync / gửi lại, kiểm tra kết nối) qua route /sapp-ops/*fe/src/data/services/sapp/sapp-ops.service.ts:26-470; importer duy nhất: fe/src/ui/components/works/sapp/sapp-26878-step-ops.tsx:31-32, fe/src/ui/components/works/sapp/sap-resync-panel.tsx:8, fe/src/ui/components/works/sapp/sapp-26878-step-sql.tsx:10
sapp.011 — FS 26297Chỉ phần tự đăng nhập Ops (A-21) cho route riêng /sapp-26297/*; không gọi route /sapp-ops/*be/libs/modules/src/lib/sapp/sapp-26297.common.service.ts:46, :62
sapp.007 — FS 24395 bulk productKhông dùng — đi bằng bộ xác thực Ops cũ SAPP_BASE_API_URL + SAPP_API_TOKEN (BR-12)be/libs/modules/src/lib/sapp/common.service.ts:278-302

1. US Statement ​

text
As a Người dùng tool (qua sub-tool 26878)  [Assumption — OQ-P-13 / G-01]
I want đọc và tạo/sửa dữ liệu SAPP Ops (lớp, lịch, học viên, đơn, giao dịch, resync SAP…) trên đúng môi trường mà không phải cầm tài khoản Ops
So that [Assumption] dựng dữ liệu test cho các flow doanh thu mà trình duyệt không bao giờ thấy credential Ops

2. Dependencies & Definition Of Ready ​

N/A — đã triển khai (Mode B).

Dependency runtime:

#Cần sẵn sàngAi cung cấpTrạng thái
D1SAPP_OPS_{API_URL,USERNAME,PASSWORD}_<ENV> (US-P04)Admin CMSTheo môi trường
D2Redis của mind_keep (giữ token)Hạ tầngĐã có
D3SAPP Ops REST API POST {baseUrl}/api/v1/auth/loginĐội SAPPNgoài hệ thống

3. Business Rules &ZeroWidthSpace;

IDRuleÁp dụng ởĐã cover bởi (AC)Nguồn code (Mode B/C)
BR-01Môi trường chọn bằng đoạn cố định trong đường dẫn (prod / staging / dev), mỗi môi trường một route; 33 thao tác × 3 môi trường (bảng §4 M1 Fields)M1AC-M1.1be/apps/api/src/sapp/sapp-ops.controller.ts:61-73, :634-2386
BR-02BE tự đăng nhập Ops thay người dùng bằng URL + username + password của môi trường trong env_systems; thiếu một trong ba → lỗi 13030 "SAPP Ops login credentials are not configured". Không có route đăng nhập nào được mở raM1AC-M1.2, EC-M1.1be/libs/modules/src/lib/sapp/sapp-auth.common.service.ts:58-84, be/apps/api/src/sapp/sapp-ops.controller.ts:68-70
BR-03Token Ops giữ trong Redis theo môi trường, tới (hạn của token − 60 giây); token không có hạn → 30 phút; tối đa 24 giờM1AC-M1.3be/libs/modules/src/lib/sapp/sapp-auth.common.service.ts:136-144, :171-202, be/libs/constants/src/lib/sapp/sapp-ops.constants.ts:66-84
BR-04Ops trả 401 → xoá token, đăng nhập lại, thử lại đúng một lần; 403 không thử lạiM1AC-M1.4, EC-M1.2be/libs/modules/src/lib/sapp/sapp-auth.common.service.ts:121-134, be/libs/constants/src/lib/sapp/sapp-ops.constants.ts:86-92
BR-05Nhiều yêu cầu cùng lúc chỉ tạo một lượt đăng nhập mỗi môi trường (trong một tiến trình API)M1AC-M1.5be/libs/modules/src/lib/sapp/sapp-auth.common.service.ts:43-49, :98-105
BR-06Đăng nhập lỗi → 13031 "Failed to login to the SAPP Ops API"; đăng nhập được mà không thấy token → 13032. Token được dò theo danh sách trường ưu tiên (có act), cố ý bỏ qua refresh token rftM1EC-M1.3be/libs/modules/src/lib/sapp/sapp-auth.common.service.ts:146-169, be/libs/constants/src/lib/sapp/sapp-ops.constants.ts:43-63
BR-07Passthrough không tự kiểm rule nghiệp vụ của Ops (ngày học tương lai, giá > 0, định dạng giờ…) — Ops quyếtM1AC-M1.6be/libs/modules/src/lib/sapp/sapp-ops.common.service.ts:73-77
BR-08Lỗi từ Ops trả về kèm câu thông báo gốc của Ops (và mã lỗi riêng nếu nhận ra được, vd đơn đã thanh toán 13053); Ops trả success=false với HTTP 200 cũng coi là lỗiM1AC-M1.6, EC-M1.4be/libs/modules/src/lib/sapp/sapp-ops.common.service.ts:37-41, :94-126
BR-09Số trang / kích thước trang không phải số nguyên dương bị bỏ qua (dùng mặc định) thay vì gửi sang OpsM1EC-M1.5be/apps/api/src/sapp/sapp-ops.controller.ts:48-59
BR-10Kiểm tra kết nối (ping) thực hiện một lời gọi Ops có xác thực rẻ nhất và chỉ trả { ok: true } — không bao giờ trả tokenM2AC-M2.1be/libs/modules/src/lib/sapp/sapp-ops.common.service.ts:280-296
BR-11Timeout: đăng nhập 30 giây; lời gọi Ops thường 10 phútM1NFR-P-05be/libs/constants/src/lib/sapp/sapp-ops.constants.ts:38-41, :69-74, be/libs/constants/src/lib/sapp/sapp.constants.ts:38
BR-12Tồn tại song song hai cách xác thực Ops: bộ cũ một token cho mọi môi trường (thay tay khi hết hạn) và bộ tự đăng nhập theo môi trường của US nàyCấu hìnhAC-M1.7be/libs/modules/src/lib/sapp/common.service.ts:278-302, be/libs/modules/src/lib/sapp/sapp-auth.common.service.ts:33-38

⚠️ Observed (không phải BR): mở đủ thao tác ghi trên prod, không chốt chặn prod ở tầng dùng chung (OQ-P-02); nhánh giữ token 30 phút khi hạn còn < 30 giây (OQ-P-08); route public (OQ-P-01).

4. Design &ZeroWidthSpace;

a. Mối liên hệ giữa các màn & User Flow &ZeroWidthSpace;

text
[Sub-tool 26878: bước ops / classcode / re-sync] ──→ M1 /api/v1/sapp/<env>/sapp-ops/<thao tác>
                                                     ├─ token Redis còn hạn → gọi Ops
                                                     ├─ chưa có token → đăng nhập Ops (1 lượt/env) → gọi Ops
                                                     └─ Ops 401 → xoá token → đăng nhập lại → thử lại 1 lần
[Sub-tool 26878: kiểm tra kết nối] ──────────────────→ M2 /sapp-ops/ping → { ok: true }
[Sub-tool 26297 (route riêng)] ── dùng chung cơ chế đăng nhập của M1

b. Chi tiết từng màn &ZeroWidthSpace;

Màn M1 - Dịch vụ passthrough SAPP Ops &ZeroWidthSpace;

FieldValue
Figma frameN/A — as-built, không có Figma
Trigger vào mànSub-tool gọi một thao tác Ops
Mô tả ngắnKhông có màn riêng ở nền tảng — dịch vụ API; UI thuộc FS 26878 (US-D03, US-D18)
UI States &ZeroWidthSpace;

N/A — dịch vụ không có màn riêng; UI thuộc sub-tool gọi (FS 26878 US-D03).

Fields &ZeroWidthSpace;

33 thao tác mỗi môi trường (route prod/…, lặp lại cho staging/…, dev/…) — Fact, be/apps/api/src/sapp/sapp-ops.controller.ts:634-2386:

NhómĐọcGhi (⚠️ có bản PROD)
Kết nốiGET ping—
Danh mục / môn / cơ sở / khoáGET course_categories, GET subjects, GET facilities, GET courses, GET courses/:courseId/sectionsPOST subjects, POST facilities, POST courses
LớpGET classes, GET classes/:classId/students, GET classes/:classId/sectionsPOST classes, PUT classes, PUT classes/:classId/class-room, POST classes/auto-update-schedule, PUT classes/:classId/students/transfer
Lịch học / giáo viênGET class-schedules/:classId/teachersPOST class-schedules, PUT class-schedules/:id, PUT class-schedules/:id/cancel, DELETE class-schedules/:id, POST teachers
User—POST users
Sản phẩm / đơn / giao dịchGET payment-products, GET product-orders/deal/:dealIdPOST payment-products, POST product-orders, POST product-orders/:orderId/transactions, POST product-orders/transactions/:id/confirm
Resync SAP—POST sap-revenue/entries/:entryId/resync, POST sap-revenue/classes/:classId/resync-failed, POST product-orders/transactions/:id/resync-sap

Tham số phân trang chung: page_index, page_size (số nguyên dương, BR-09). Body các thao tác ghi theo DTO của từng thao tác (mô tả ở shared/api-docs/sapp.md §SAPP Ops passthrough) — không đặc tả lại ở đây.

Filter / Search / Sort &ZeroWidthSpace;

N/A — dịch vụ API, không phải màn List (phân trang theo BR-09).

Actions &ZeroWidthSpace;
A1 - Gọi một thao tác Ops &ZeroWidthSpace;
ItemDescription
TriggerSub-tool gọi route /api/v1/sapp/<env>/sapp-ops/<thao tác>
BehaviorLấy token (BR-02, BR-03, BR-05), gọi Ops, xử lý 401 (BR-04), chuyển lỗi (BR-08). Đọc/ghi SAPP Ops của môi trường trong đường dẫn. ⚠️ Ghi PROD: route prod/… ghi thẳng dữ liệu Ops production (tạo user/lớp/lịch/đơn/giao dịch, xoá/huỷ lịch, chuyển học viên, xác nhận giao dịch, resync SAP); tầng dùng chung không có chốt chặn prod (OQ-P-02). Chốt chặn prod nếu có nằm ở FE sub-tool (FS 26878)
Success ResultDữ liệu Ops (lớp bọc data)

Error cases:

CaseExpected Handling
Thiếu credential13030
Đăng nhập lỗi / không có token13031 / 13032
Ops từ chối nghiệp vụMã lỗi của thao tác (vd 13043, 13044, 13045, 13046) + ": <câu gốc của Ops>"
Ops success=false HTTP 200Mã lỗi của thao tác
Acceptance Criteria của màn M1 &ZeroWidthSpace;
AC-M1.1 - Môi trường theo đường dẫn &ZeroWidthSpace;
gherkin
Given sub-tool gọi GET /api/v1/sapp/staging/sapp-ops/classes
When BE xử lý
Then lời gọi đi tới SAPP_OPS_API_URL_STAGING bằng token của staging
And không có tham số nào đổi được môi trường ngoài đoạn đường dẫn

Maps to:

  • Business Rule: BR-01
AC-M1.2 - Tự đăng nhập, không lộ credential &ZeroWidthSpace;
gherkin
Given Redis chưa có token dev
When sub-tool gọi một thao tác dev
Then BE đăng nhập Ops bằng credential dev trong env_systems rồi gọi thao tác
And trình duyệt không nhận username / password / token

Maps to:

  • Business Rule: BR-02
AC-M1.3 - Dùng lại token &ZeroWidthSpace;
gherkin
Given token prod trong Redis còn hạn
When có lời gọi prod tiếp theo
Then không đăng nhập lại

Maps to:

  • Business Rule: BR-03
AC-M1.4 - 401 → đăng nhập lại một lần &ZeroWidthSpace;
gherkin
Given token trong Redis đã bị Ops thu hồi
When Ops trả 401
Then BE xoá token, đăng nhập lại và thử lại đúng một lần
And nếu lần thử lại vẫn lỗi thì trả lỗi, không lặp tiếp

Maps to:

  • Business Rule: BR-04
AC-M1.5 - Một lượt đăng nhập cho yêu cầu đồng thời &ZeroWidthSpace;
gherkin
Given chưa có token staging
When 5 yêu cầu staging đến cùng lúc
Then chỉ một lượt đăng nhập Ops được gửi

Maps to:

  • Business Rule: BR-05
AC-M1.6 - Lỗi Ops mang câu gốc &ZeroWidthSpace;
gherkin
Given Ops từ chối tạo lịch vì ngày học ở quá khứ
When sub-tool gọi POST class-schedules
Then BE không tự chặn trước; lỗi trả về là "Failed to create SAPP Ops class schedule: <câu gốc của Ops>"

Maps to:

  • Business Rule: BR-07, BR-08
AC-M1.7 - Hai bộ xác thực tách biệt &ZeroWidthSpace;
gherkin
Given SAPP_API_TOKEN (bộ cũ) hết hạn
When sub-tool 26878 gọi passthrough
Then passthrough vẫn chạy (dùng bộ tự đăng nhập); chỉ sub-tool dùng bộ cũ (24395 bulk product) bị ảnh hưởng

Maps to:

  • Business Rule: BR-12
Negative AC / Edge Cases của màn M1 &ZeroWidthSpace;
IDTình huốngHành vi mong đợi
EC-M1.1Thiếu SAPP_OPS_PASSWORD_DEV13030
EC-M1.2Ops trả 403Không đăng nhập lại, trả lỗi (BR-04)
EC-M1.3Đăng nhập Ops trả 200 nhưng không có trường token nào13032
EC-M1.4Tạo giao dịch cho đơn đã thanh toánMã 13053 kèm câu gốc (BR-08)
EC-M1.5page_size=abcBỏ qua, dùng mặc định (BR-09)
EC-M1.6⚠️ Observed — Gọi thao tác ghi trên prod/…Thực thi trên Ops production; không đăng nhập, không chốt chặn ở tầng dùng chung (OQ-P-02, NFR-P-01)
EC-M1.7⚠️ Observed — Token nhận về còn hạn < 30 giâyVẫn được giữ 30 phút; lời gọi sau có thể dùng token đã chết và được cứu bởi nhánh 401 (be/libs/modules/src/lib/sapp/sapp-auth.common.service.ts:195-200; OQ-P-08, DR-P-04)
EC-M1.8⚠️ Observed — Mã lỗi 13058 / 13059 bị dùng cho hai lỗi khác nhau (cập nhật/xoá lịch Ops và cấu hình LMS của 26297)Người nhận không phân biệt được lỗi theo mã (be/libs/constants/src/lib/error-codes/error-codes.constants.ts:812-820, :834-845; OQ-P-19)

Màn M2 - Kiểm tra kết nối Ops (ping) &ZeroWidthSpace;

FieldValue
Figma frameN/A — as-built, không có Figma
Trigger vào mànSub-tool 26878 gọi GET /api/v1/sapp/<env>/sapp-ops/ping (bước ops ping, fe/src/ui/components/works/sapp/sapp-26878-step-ops.tsx:1018)
Mô tả ngắnChứng minh credential của môi trường dùng được
UI States &ZeroWidthSpace;

N/A — dịch vụ không có màn riêng; hiển thị do bước Ops của FS 26878.

Fields &ZeroWidthSpace;

N/A — không có tham số ngoài môi trường trong đường dẫn.

Filter / Search / Sort &ZeroWidthSpace;

N/A — không phải màn List.

Actions &ZeroWidthSpace;
A1 - Ping &ZeroWidthSpace;
ItemDescription
TriggerBước ping
BehaviorĐăng nhập (nếu cần) + một lời gọi Ops đọc rẻ nhất. Chỉ đọc
Success Result{ ok: true }

Error cases:

CaseExpected Handling
Credential sai / thiếu13031 / 13030
Acceptance Criteria của màn M2 &ZeroWidthSpace;
AC-M2.1 - Ping không trả token &ZeroWidthSpace;
gherkin
Given credential dev đúng
When gọi ping dev
Then nhận { ok: true } và không có token trong response

Maps to:

  • Business Rule: BR-10
Negative AC / Edge Cases của màn M2 &ZeroWidthSpace;
IDTình huốngHành vi mong đợi
EC-M2.1Ops tạm không phản hồiLỗi theo timeout (BR-11)

5. Cross-feature AC &ZeroWidthSpace;

AC-X.1 - Chốt chặn prod thuộc sub-tool &ZeroWidthSpace;

gherkin
Given passthrough mở route prod cho mọi thao tác ghi
When FS 26878 đặc tả bước Ops
Then FS 26878 phải ghi rõ chốt chặn prod (nếu có) nằm ở FE và BE vẫn nhận prod (⚠️ Observed)

Maps to:

  • REL-05 (Be Affected - FS 26878)

AC-X.2 - 26297 dùng chung cơ chế đăng nhập &ZeroWidthSpace;

gherkin
Given FS 26297 gọi Ops qua route riêng
When token hết hạn / 401
Then hành vi đăng nhập lại theo BR-02…BR-06 của US này

Maps to:

  • REL-06 (Be Affected - FS 26297)

AC-X.3 - 24395 bulk product dùng bộ cũ &ZeroWidthSpace;

gherkin
Given FS 24395 bulk product
When đặc tả xác thực Ops
Then FS 24395 tham chiếu BR-12 (bộ cũ), không phải cơ chế tự đăng nhập

Maps to:

  • REL-03 (Be Affected - FS 24395)