Giao diện
Feature Inventory — SAPP-20603 eContract (Retry · Check luồng · Thống kê lỗi) ​
Kiểm kê tính năng đã triển khai, dựng từ code. Đầu vào cho FS as-built (Mode B) và là "bức tranh hiện tại" cho Mode C. Mọi dòng phải có bằng chứng
file:dòng; không có bằng chứng → không ghi vào bảng (đưa sang §8 Câu hỏi).Công thức truy vết:
ba/system-profile.md§3.⚠️ Chỉ đọc source, chưa chạy app, chưa gọi API. Hành vi cron của hệ thống econtract (ngoài repo) chỉ được biết qua tài liệu
shared/api-docs/sapp.mdvà audit — ghi rõ ở từng dòng, không phải số đo.
| Field | Value |
|---|---|
| Project | ba/projects/2026-SAPP-Works-tools |
| Mode | B – As-built |
| Ngày đọc code | 2026-09-30 |
| Commit | e77c47a |
| Điểm vào BA cung cấp | 3 sub-tool nhóm "SAPP 20603 - EContract" dưới /works/sapp/tools: econtract (sapp.005), econtract-timeline (sapp.012), econtract-error-stats (sapp.013) |
| Thành phần chạm tới | FE · BE · hệ thống ngoài: DB MySQL econtract PRODUCTION của SAPP (repo econtract-payment) |
| Status | Draft |
1. Phạm vi đã truy vết ​
- Trong phạm vi:
- 3 màn: Retry econtract, Check luồng econtract, Thống kê lỗi econtract.
- 4 API:
GET /api/v1/sapp/prod/econtract/flow-processes/:dealId,POST …/flow-processes/:dealId/retry,GET …/deals/:dealId/timeline,GET …/error-stats. - Service BE
SappCommonService(phần econtract), DTOecontract-*.dto.ts, hằng số & mã lỗi econtract. - Liên kết chéo giữa 3 màn (deep link
?dealId=).
- Ngoài phạm vi (dừng truy vết tại đây):
- Cơ chế khoá / ẩn / seckey của tool theo
code(tool gate,tools-state-context,tool-availability) → nền tảng. - Cách
@Public()và guard xác thực hoạt động → nền tảng. - Đọc cấu hình
env_systems(EnvSystemMapCommonService) → nền tảng. - Pool kết nối DB ngoài (
ExternalDbService) → nền tảng (chỉ ghi 1 chi tiết ảnh hưởng giờ, xem ⚠️ R-09). - Lưu trạng thái tool / last-tool, shell sidebar → nền tảng.
- Cron
reTryFlow/reProcessFlowvà việc gọi EFY/FPT thật — nằm trong repoecontract-paymentcủa SAPP, không có trong repo này.
- Cơ chế khoá / ẩn / seckey của tool theo
2. Điểm vào (Entry points) ​
| ID | Loại | Tên / đường dẫn người dùng thấy | Bằng chứng |
|---|---|---|---|
| E-01 | Màn web | /works/sapp/tools/econtract — "Retry econtract" (tool code sapp.005) | fe/app/works/sapp/tools/econtract/page.tsx:5-11 · fe/src/ui/pages/works/sapp/tools/registry.ts:52-56 · fe/src/data/constants/tool-codes.ts:36 |
| E-02 | Màn web | /works/sapp/tools/econtract-timeline — "Check luồng econtract" (sapp.012) | fe/app/works/sapp/tools/econtract-timeline/page.tsx:5-11 · registry.ts:57-61 · tool-codes.ts:43 |
| E-03 | Màn web | /works/sapp/tools/econtract-error-stats — "Thống kê lỗi econtract" (sapp.013) | fe/app/works/sapp/tools/econtract-error-stats/page.tsx:5-11 · registry.ts:62-66 · tool-codes.ts:44 |
| E-04 | API | GET /api/v1/sapp/prod/econtract/flow-processes/:dealId (chỉ đọc) | be/apps/api/src/sapp/sapp.controller.ts:173-190 · fe/src/data/constants/api.ts:469-470 |
| E-05 | API | POST /api/v1/sapp/prod/econtract/flow-processes/:dealId/retry — GHI vào DB econtract PRODUCTION | sapp.controller.ts:192-210 · api.ts:471-472 |
| E-06 | API | GET /api/v1/sapp/prod/econtract/deals/:dealId/timeline (chỉ đọc) | sapp.controller.ts:212-230 · api.ts:473-474 |
| E-07 | API | GET /api/v1/sapp/prod/econtract/error-stats?from&to&bucketMin&flowName (chỉ đọc) | sapp.controller.ts:232-250 · api.ts:475 |
| E-08 | Deep link | …/econtract?dealId=X (chỉ điền sẵn ô) · …/econtract-timeline?dealId=X (điền và tự chạy) | fe/src/ui/components/works/sapp/retry-econtract-tool.tsx:403-411 · fe/src/ui/components/works/sapp/econtract-timeline-tool.tsx:636-648 |
| E-09 | Dữ liệu khởi tạo | Đăng ký 3 tool vào bảng tool (seed migration) | be/libs/database/migrations/1783700000000-create-tools.ts:10 · …/1786400000000-seed-tool-sapp-20603-econtract-timeline.ts:20 · …/1786500000000-seed-tool-sapp-20603-econtract-error-stats.ts:20 |
3. Hành động người dùng / hệ thống ​
Chuỗi gọi chung: màn → service FE (
fe/src/data/services/sapp/*.service.ts) → URLapi.ts→ controller →SappCommonService→ DB econtract prod.
| ID | Ai (role) | Làm gì | Điểm vào | Kết quả quan sát được | Bằng chứng |
|---|---|---|---|---|---|
| A-01 | Người dùng tool (role chưa rõ — Q-04) | Nhập HubSpot deal id, bấm Kiểm tra (hoặc Enter) | E-01 → E-04 | Đọc mọi flow process của deal; hiện stepper 4 bước (Kiểm tra → Retry → Chờ cron → Kết quả), danh sách flow process (tên, trạng thái, retry, reprocess, loại, cập nhật, dữ liệu thô) và kết luận: dừng / đủ điều kiện retry tay / hệ thống tự chạy | retry-econtract-tool.tsx:413-434 · :342-353 · :67-91 · :45-50 · :217-264 · fe/src/data/services/sapp/get-flow-processes.service.ts:11-19 · be/libs/modules/src/lib/sapp/common.service.ts:1707-1721 |
| A-02 | Hệ thống (FE) | Khi mọi flow FAIL đều có retry = 0: không cho bấm Retry, tự chuyển sang bước "Chờ cron", bước 2 hiện "Hệ thống tự chạy" | E-01 | Thông báo "Hệ thống sẽ tự chạy lại trong ~1 phút" + đồng hồ đếm ngược; không có lời gọi ghi | retry-econtract-tool.tsx:351 · :500 · :195 · :631-633 · :650-652 |
| A-03 | Người dùng tool | Bấm "Retry process này" → hộp xác nhận liệt kê từng dòng sẽ đặt lại (tên · FAIL · retry = N → 0) → bấm Retry (hoặc Huỷ) | E-01 → E-05 | ⚠️ GHI PRODUCTION: BE chạy UPDATE econtract_flow_processes SET retry = 0 cho mọi dòng FAIL có retry > 0 của deal trên DB econtract prod; trả lại các dòng sau cập nhật; FE vào bước "Chờ cron" | retry-econtract-tool.tsx:603-621 · :438-462 · :356-371 · fe/src/data/services/sapp/retry-flow-process.service.ts:15-26 · common.service.ts:2428-2476 |
| A-04 | Hệ thống (FE) | Đếm ngược tới giây 15 của phút kế tiếp, rồi tự đọc lại flow process | E-01 → E-04 | Badge 3 nhánh: "SUCCESS — đã chạy lại thành công" / "Vẫn FAIL — lần chạy lại vừa rồi lỗi tiếp" / "Chưa chạy — cron chưa lấy process này"; chỉ hiện các dòng đang theo dõi | retry-econtract-tool.tsx:110-117 · :386-401 · :373-384 · :98-108 · :266-290 · :656-661 |
| A-05 | Người dùng tool | Bấm "Kiểm tra lại (về bước 1)" khi kết quả không phải SUCCESS | E-01 → E-04 | Quay lại bước 1, tăng số "Lượt N" | retry-econtract-tool.tsx:669-679 · :425-426 · :575 |
| A-06 | Người dùng tool | Bấm "Copy thông tin gửi dev" | E-01 | Copy vào clipboard (không tạo file): deal, lý do, mỗi dòng tên · status · retry · reprocess · cập nhật | retry-econtract-tool.tsx:464-482 · :685-703 |
| A-07 | Người dùng tool | Bấm link "Xem chi tiết ở Check luồng econtract" khi retry SUCCESS | E-01 → E-02 | Mở màn Check luồng với ?dealId= | retry-econtract-tool.tsx:662-668 |
| A-08 | Người dùng tool | Nhập deal id, bấm Check | E-02 → E-06 | Deal id được ghi lên URL (để chia sẻ/tải lại); tải timeline | econtract-timeline-tool.tsx:650-670 · fe/src/data/services/sapp/get-econtract-deal-timeline.service.ts:11-19 · common.service.ts:1733-1895 |
| A-09 | Người dùng tool | Xem kết quả Check luồng | E-02 | Cảnh báo (nếu có); 5 ô đếm (Job trace, Flow process, Hợp đồng, Webhook, Step FAIL); múi giờ DB + job trace cũ nhất; contract id; checklist 6 mốc luồng chuẩn; bảng bước FAIL; timeline mới nhất ở trên, lọc bật/tắt theo nguồn; mở từng dòng xem chi tiết JSON (steps, error, context, payload) dạng text | econtract-timeline-tool.tsx:746-897 · :71-120 · :351-390 · :194-200 · :903-922 |
| A-10 | Người dùng tool | Chọn Từ / Đến (giờ máy), bucket, flow → Xem; hoặc bấm preset (1 giờ·1′, 6 giờ·5′, 24 giờ·15′, 7 ngày·60′, 30 ngày·60′) | E-03 → E-07 | Tải thống kê; không tự tải khi mở màn | econtract-error-stats-tool.tsx:395-399 · :410 · :217-252 · :64-70 · fe/src/data/services/sapp/get-econtract-error-stats.service.ts:14-22 · common.service.ts:1917-2176 |
| A-11 | Người dùng tool | Xem kết quả thống kê | E-03 | 5 ô tổng (Lần chạy, Lần chạy lỗi, Tổng deal, Deal bị lỗi, Tỷ lệ lỗi); 3 biểu đồ (Lỗi theo thời gian, Lần chạy lỗi theo flow, Tỷ lệ lỗi %); "Lỗi gặp nhiều nhất"; "Bước chết nhiều nhất"; vùng trước job trace cũ nhất được tô mờ | econtract-error-stats-tool.tsx:419-466 · :487-601 · :606 · :679 · :289-298 |
| A-12 | Người dùng tool | Bấm "Danh sách" ở ô Deal bị lỗi → lọc (Tất cả / Vẫn lỗi / Đã tự hồi phục, ô tìm), copy 1 hoặc N deal id, mở Check luồng của deal ở tab mới | E-03 → E-02 | Modal danh sách deal lỗi; copy chỉ deal id vào clipboard | econtract-error-stats-tool.tsx:451-461 · :711-712 · :745-946 · :948-986 · :734-743 |
4. Dữ liệu ​
Không có entity TypeORM nào trong DB mind_keep cho nhóm này — mọi bảng dưới là bảng của DB econtract production (hệ thống ngoài), đọc qua SQL thô. Bằng chứng:
common.service.ts:258-263·be/.agents/maps/modules/tool.md:64.
| Entity / bảng | Field | Type | Bắt buộc | Mặc định / enum | Bằng chứng |
|---|---|---|---|---|---|
econtract_flow_processes (ngoài) | cột được đọc: id, name, deal_id, contract_type, fpt_contract_id, efy_contract_id, status, retry, reprocess, created_at, updated_at | — | — | request_data không bao giờ đọc (chứa đường dẫn file trên server) | be/libs/constants/src/lib/sapp/sapp.constants.ts:128-150 |
econtract_flow_processes | name | string | — | Tên flow, vd CREATE_CONTRACT, EFY_CANCEL_CONTRACT — phải duy nhất trong 1 deal để retry | be/libs/interface/src/lib/dto/sapp/econtract-flow-process.dto.ts:18-21 |
econtract_flow_processes | status | string | — | NEW | SUCCESS | FAIL | econtract-flow-process.dto.ts:26-27 · sapp.constants.ts:131 |
econtract_flow_processes | retry | number | — | Số lần đã chạy lại, không phải số lượt còn lại (RETRY_MAX_NUMBER = 1 phía econtract) | econtract-flow-process.dto.ts:29-33 · be/libs/constants/src/lib/error-codes/error-codes.constants.ts:545-547 |
econtract_flow_processes | reprocess | number/boolean | — | true khi cron 5 phút đã cấp thêm 1 vòng | econtract-flow-process.dto.ts:35-39 |
econtract_job_traces (ngoài) | id, flow_name, deal_id, flow_process_id, fpt_contract_id, efy_contract_id, status, steps (JSON), context (JSON), error, created_at, updated_at | — | — | status FAIL / SUCCESS; mỗi dòng = 1 lần chạy, chỉ thêm | common.service.ts:1771-1776 · sapp.constants.ts:190-191 · be/libs/interface/src/lib/dto/sapp/econtract-deal-timeline.dto.ts:47-71 |
econtract_job_traces.steps[] | { step, status OK|FAIL, at, kind, provider?, message?, request?, response?, error? } | JSON | — | step khớp getEfyAccessToken|getFptAccessToken → request/response thay bằng [hidden] | econtract-deal-timeline.dto.ts:58-65 · sapp.constants.ts:169-177 · common.service.ts:2284-2297 |
contracts (ngoài) | id, type, deal_id, fpt_contract_id, efy_contract_id, status, created_at, updated_at | — | — | contract_info không được đọc | common.service.ts:1783-1788 · econtract-deal-timeline.dto.ts:88-97 |
econtract_webhook_logs (ngoài) | id, provider, event, contract_id, note, payload (JSON), created_at, updated_at | — | — | provider EFY | FPT; không có deal_id — nối qua contract id | common.service.ts:1806-1811 · econtract-deal-timeline.dto.ts:99-115 · sapp.constants.ts:154-155 |
| Tham số thống kê (request) | from | ISO datetime | Có | tính từ (bao gồm) | be/libs/interface/src/lib/dto/sapp/econtract-error-stats.dto.ts:20-21 |
| Tham số thống kê | to | ISO datetime | Có | tới (không bao gồm) | econtract-error-stats.dto.ts:23-24 |
| Tham số thống kê | bucketMin | number | Không | 1 | 5 | 15 | 60, mặc định BE 5 (FE mặc định 15) | econtract-error-stats.dto.ts:26-30 · sapp.constants.ts:197-198 · econtract-error-stats-tool.tsx:181 |
| Tham số thống kê | flowName | string | Không | trống = tất cả flow | econtract-error-stats.dto.ts:32-35 · common.service.ts:1962 |
env_systems (mind_keep, → nền tảng) | SAPP_PROD_ECONTRACT_DB_HOST / _PORT / _NAME / _USERNAME / _PASSWORD | string | host, name, username bắt buộc | port mặc định 3306 | sapp.constants.ts:4-14 · common.service.ts:1685-1704 |
| Redis cache (mind_keep) | sapp:econtract:job-traces:oldest | string | — | TTL 1 ngày | sapp.constants.ts:186-188 · common.service.ts:2253-2275 |
5. Rule & validation tìm thấy ​
| ID | Rule (ngôn ngữ nghiệp vụ) | Loại | Áp dụng ở | Bằng chứng | Nghi là bug? |
|---|---|---|---|---|---|
| R-01 | Phải nhập deal id (bỏ khoảng trắng đầu/cuối) mới được kiểm tra; thiếu thì báo "Thiếu deal id" | validation | A-01, A-08 | retry-econtract-tool.tsx:413-422 · econtract-timeline-tool.tsx:650-659 | Không |
| R-02 | Retry bị từ chối nếu deal không có flow process nào (mã 13002, 404) | điều kiện | A-01, A-03 | common.service.ts:2435-2440 · error-codes.constants.ts:523-527 · FE nhắc lại: retry-econtract-tool.tsx:68-70 | Không |
| R-03 | Retry bị từ chối nếu có ≥ 2 flow process cùng tên trong deal (tính cả dòng SUCCESS) — không đoán dòng nào (mã 13063, 409) | điều kiện | A-01, A-03 | common.service.ts:2442-2450 · error-codes.constants.ts:552-557 · retry-econtract-tool.tsx:71-79 | Không (chủ màn chốt D2 — audit) |
| R-04 | Retry bị từ chối nếu không có dòng nào ở trạng thái FAIL (mã 13003, 409) | điều kiện | A-01, A-03 | common.service.ts:2452-2460 · error-codes.constants.ts:528-532 · retry-econtract-tool.tsx:80-88 | Không |
| R-05 | Nếu mọi dòng FAIL đều có retry = 0 thì không retry tay — hiểu là "hệ thống sẽ tự chạy lại" (mã 13006, 409; FE không hiện nút Retry) | điều kiện | A-02 | common.service.ts:2462-2468 · error-codes.constants.ts:543-551 · retry-econtract-tool.tsx:89-90 · :351 | Không (đã sửa nghĩa theo audit T0-01) |
| R-06 | Dòng đủ điều kiện retry tay = FAIL và retry ≥ 1 (mọi giá trị reprocess). Retry đặt lại retry = 0 cho tất cả dòng như vậy của deal trong 1 lệnh, kể cả khi thuộc nhiều flow khác tên | điều kiện / trạng thái | A-03 | common.service.ts:2462 · :2470-2474 · retry-econtract-tool.tsx:89 | ⚠️ Observed — xem Q-02 |
| R-07 | Trước khi ghi prod phải qua hộp xác nhận liệt kê từng dòng sẽ bị đặt lại; Huỷ thì không ghi | điều kiện | A-03 | retry-econtract-tool.tsx:444-461 | ⚠️ Observed (nhẹ) — nếu ngữ cảnh không cung cấp hàm xác nhận, code ghi luôn không hỏi (:446); thực tế provider có cung cấp (fe/src/logic/contexts/app-status.provider.tsx:188) — Q-08 |
| R-08 | Trong lúc đang gọi hoặc đang chờ cron, ô deal id và nút Kiểm tra bị khoá | trạng thái | A-01..A-04 | retry-econtract-tool.tsx:554-563 | Không |
| R-09 | Giờ "cập nhật" ở màn Retry lấy thẳng từ cột DATETIME qua driver, không định dạng theo đồng hồ DB như màn Check luồng; pool kết nối không đặt múi giờ | công thức | A-01, A-04 | common.service.ts:2405-2415 · be/libs/services/src/lib/external-db/external-db.service.ts:35-45 · so với cách chữa ở sapp.constants.ts:179-184 · common.service.ts:2200-2207 | ⚠️ Observed — có thể lệch giờ theo múi giờ tiến trình BE, Q-05 |
| R-10 | Kết quả sau chờ cron: dòng theo dõi SUCCESS → thành công; FAIL với retry ≥ 1 → vẫn lỗi; còn lại → chưa chạy. Có 1 dòng "vẫn lỗi" thì cả lượt là vẫn lỗi | công thức | A-04 | retry-econtract-tool.tsx:98-108 | Không |
| R-11 | Thời điểm đọc lại = giây 15 của phút kế tiếp (giả định cron econtract chạy ở giây 0 mỗi phút) | giới hạn / công thức | A-04 | retry-econtract-tool.tsx:110-117 · :653 | Không rõ — giả định lịch cron, Q-06 |
| R-12 | Hiện ghi chú "liên hệ developer" khi bị dừng ở bước 1, hoặc khi đã ≥ 2 lượt liên tiếp "chưa chạy" | điều kiện | A-06 | retry-econtract-tool.tsx:520 · :382 · :145-146 | Không |
| R-13 | Retry chỉ chạy lại luồng econtract, không đổi deal stage trên HubSpot (mô tả màn) | giới hạn | A-03 | retry-econtract-tool.tsx:533-534 | Không |
| R-14 | Deep link: màn Retry chỉ điền sẵn deal id, không tự chạy; màn Check luồng điền và tự chạy 1 lần | điều kiện | E-08 | retry-econtract-tool.tsx:403-411 · econtract-timeline-tool.tsx:636-648 | Không |
| R-15 | Mỗi bảng trong timeline lấy tối đa 500 dòng mới nhất; chạm trần → cảnh báo TRUNCATED | giới hạn | A-08 | sapp.constants.ts:157-161 · common.service.ts:1750-1759 | Không |
| R-16 | Bảng thiếu (MISSING_TABLE) hoặc user DB không có quyền đọc (ACCESS_DENIED) → trả mảng rỗng + cảnh báo, không làm hỏng cả lượt | điều kiện | A-08, A-10 | common.service.ts:2209-2232 · :1761-1766 · :1982-1991 | Không |
| R-17 | Webhook được nối qua contract id FPT/EFY; deal không có contract id → cảnh báo NO_CONTRACT_ID (truy vấn webhook vẫn chạy với điều kiện rỗng) | điều kiện | A-08 | common.service.ts:1798-1822 | Không |
| R-18 | Deal không có job trace và dòng cũ nhất của deal sớm hơn job trace cũ nhất toàn bảng → cảnh báo PREDATES_TRACE (thiếu dữ liệu là bình thường) | điều kiện | A-08 | common.service.ts:1824-1841 | Không |
| R-19 | Timeline sắp mới nhất trước, chỉ theo created_at; mọi mốc giờ gắn offset đồng hồ DB | công thức | A-09 | common.service.ts:2313-2392 · :2234-2250 · :2299-2311 | Không |
| R-20 | Che request/response của step lấy access token EFY/FPT ở backend (theo tên step) | giới hạn (bảo mật) | A-09 | sapp.constants.ts:169-177 · common.service.ts:1791-1796 · :2284-2297 — nguồn yêu cầu: shared/external/sapp/sapp-20603/2026-09-25-sapp-20603-tra-loi.md:182-212 | Không |
| R-21 | Dữ liệu chi tiết (steps, payload webhook, link_file_pdf) chỉ hiển thị dạng text JSON, không có link bấm được, không có chức năng xuất file — điều kiện của SAPP | giới hạn (bảo mật) | A-09, A-12 | econtract-timeline-tool.tsx:194-200 · :351-390 · nguồn: 2026-09-25-sapp-20603-tra-loi.md:223-231 | Không |
| R-22 | Checklist 6 mốc luồng chuẩn: (1) flow process CREATE_CONTRACT (SUCCESS = đạt, NEW/không có = chưa tới, khác = lỗi); (2) job CREATE_CONTRACT có ≥ 1 lần SUCCESS; (3) có bản ghi hợp đồng; (4) webhook ký (EFY DA_KY / FPT completed) — nhận webhook huỷ (EFY HUY,TU_CHOI / FPT rejected,voided,overdue) mà chưa ký → lỗi; (5) job hoàn tất (EFY_CONTRACT_COMPLETED/CONTRACT_COMPLETED) SUCCESS; (6) hợp đồng COMPLETED | công thức / trạng thái | A-09 | econtract-timeline-tool.tsx:44-120 | Không |
| R-23 | Thống kê: to phải sau from, bucket ∈ {1,5,15,60}, số bucket ≤ 1500; sai → mã 13062 (FE chặn trước với thông báo tiếng Việt) | validation | A-10 | common.service.ts:1920-1935 · sapp.constants.ts:197-205 · error-codes.constants.ts:568-573 · econtract-error-stats-tool.tsx:217-233 | Không |
| R-24 | Thống kê đếm chỉ từ econtract_job_traces (mỗi lần chạy 1 dòng), vì flow process bị ghi đè khi retry sẽ làm mất lỗi đã hồi phục | công thức | A-11 | common.service.ts:1908-1916 · econtract-error-stats.dto.ts:10-17 | Không |
| R-25 | Tỷ lệ lỗi = 100 × lần lỗi / lần chạy, 2 chữ số thập phân; bucket không có lần chạy → trống. Mọi bucket trong khoảng đều có mặt (bucket rỗng = 0) | công thức | A-11 | common.service.ts:2067-2090 · econtract-error-stats-tool.tsx:316-318 | Không |
| R-26 | Top 20 lỗi, gom theo dòng đầu của error (cắt 300 ký tự); bước lỗi đếm trên 2000 lần chạy lỗi mới nhất; danh sách deal lỗi tối đa 500 deal lỗi gần nhất (kèm cảnh báo khi chạm trần) | giới hạn | A-11, A-12 | sapp.constants.ts:206-215 · common.service.ts:2011-2033 · :2044-2064 · :2109-2122 | Không |
| R-27 | Deal "Đã tự hồi phục" = lần chạy cuối cùng trong khoảng (mọi trạng thái) là SUCCESS; còn lại là "Vẫn lỗi" | công thức | A-12 | common.service.ts:2040-2043 · :2058 · econtract-error-stats-tool.tsx:742-743 · :837-842 | Không |
| R-28 | Khoảng bắt đầu trước job trace cũ nhất → cảnh báo PREDATES_TRACE, vùng đó tô mờ trên biểu đồ (0 vì chưa ghi, không phải vì không lỗi) | điều kiện | A-11 | common.service.ts:2123-2130 · econtract-error-stats-tool.tsx:267 · :273 · :289-298 | Không |
| R-29 | Danh sách flow trong bộ lọc = 5 flow biết trước + mọi flow đã thấy trong các lần tải | công thức | A-10 | econtract-error-stats-tool.tsx:56-62 · :183 · :211-213 · :384-389 | Không |
Trạng thái & chuyển trạng thái (nếu có):
text
# Luồng màn Retry (FE) — retry-econtract-tool.tsx:42-50, :489-508
[Kiểm tra] --(không có dòng / trùng tên / không FAIL)--> [DỪNG ở bước 1 + liên hệ dev]
[Kiểm tra] --(mọi FAIL có retry = 0)--> [Chờ cron] (bước Retry = "Hệ thống tự chạy")
[Kiểm tra] --(có FAIL retry ≥ 1)--> [Retry] --(xác nhận, POST ghi prod)--> [Chờ cron]
[Chờ cron] --(giây 15 phút kế, đọc lại)--> [Kết quả: SUCCESS | Vẫn FAIL | Chưa chạy]
[Kết quả ≠ SUCCESS] --(Kiểm tra lại)--> [Kiểm tra] (Lượt N+1)
# Dòng econtract_flow_processes phía econtract-payment — CHỈ theo tài liệu, không có trong repo này
# (shared/api-docs/sapp.md:2919-2931, đọc ở econtract-payment commit efbdb2d)
[FAIL · retry=0] --(reTryFlow, mỗi phút)--> chạy lại → [SUCCESS] | [FAIL · retry=1]
[FAIL · retry=1 · reprocess=false] --(reProcessFlow, mỗi 5 phút)--> [FAIL · retry=0 · reprocess=true]
[FAIL · retry=1 · reprocess=true] --(chỉ retry tay của tool này)--> [FAIL · retry=0]
[NEW] / [SUCCESS] : không cron nào lấy6. Quyền, tích hợp, thông báo, job ​
| Loại | Chi tiết | Bằng chứng |
|---|---|---|
| Quyền (API) | ⚠️ Cả 4 API đều @Public() — không yêu cầu đăng nhập, kể cả POST …/retry ghi DB prod. Không tìm thấy guard nào gắn code tool với route BE | sapp.controller.ts:174 · :193 · :213 · :233 · be/.agents/maps/modules/tool.md:20-22 · shared/api-docs/sapp.md:2877 |
| Quyền (màn) | Hiển thị / khoá / seckey của từng tool do BE quản lý theo code (sapp.005, sapp.012, sapp.013), FE chỉ đọc trạng thái → nền tảng | fe/src/data/constants/tool-codes.ts:1-20 · :36 · :43-44 |
| Tích hợp ngoài | DB MySQL econtract PRODUCTION của SAPP. Kết nối lấy từ env_systems lúc gọi; pool tối đa 5 kết nối. 3 API chỉ đọc (SELECT); 1 API ghi (UPDATE … SET retry = 0) | common.service.ts:1685-1704 · :2470-2474 · external-db.service.ts:31-49 · sapp.constants.ts:4-14 |
| Tích hợp ngoài (gián tiếp) | Sau khi retry, cron của econtract-payment chạy lại luồng và gọi nhà cung cấp hợp đồng điện tử EFY/FPT thật (tạo/huỷ hợp đồng). Repo này không gọi EFY/FPT trực tiếp | retry-econtract-tool.tsx:444-445 · shared/api-docs/sapp.md:2919-2931 |
| Tích hợp ngoài | Không gọi HubSpot trong nhóm này (deal id chỉ là khoá tra cứu) | common.service.ts:1707-2487 (không lời gọi hubSpotCommonService) · retry-econtract-tool.tsx:533-534 |
| Tải trên prod | Không có index trên deal_id / created_at — mọi truy vấn là quét toàn bảng; thống kê chạy 6 truy vấn song song mỗi lượt | sapp.constants.ts:157-161 · :200-205 · common.service.ts:1993-2065 |
| Bộ nhớ đệm | Mốc job trace cũ nhất cache Redis 1 ngày | common.service.ts:2252-2282 |
| Thông báo (mail / push / MQTT / Discord) | Không có trong 4 hàm service của nhóm | common.service.ts:1707-1906 · :1917-2176 · :2428-2487 |
| Nhật ký thao tác | Không tìm thấy ghi nhận ai / lúc nào bấm retry (chỉ log lỗi) | common.service.ts:2428-2487 · sapp.controller.ts:201-210 |
| Job / cron | Không có job trong mind_keep. Cron liên quan nằm ở econtract-payment (reTryFlow mỗi phút, reProcessFlow mỗi 5 phút) — theo tài liệu, chưa kiểm bản deploy prod | shared/api-docs/sapp.md:2919-2928 · retry-econtract-tool.tsx:36-40 |
7. Drift — tài liệu nói khác code ​
| ID | Tài liệu (file + section) | Tài liệu nói | Code đang làm | Bằng chứng |
|---|---|---|---|---|
| DR-01 | shared/api-docs/sapp.md §GET error-stats, warnings[].code (dòng 3142-3144) | TRUNCATED khi nhiều hơn 2000 lần chạy lỗi; DEALS_TRUNCATED khi nhiều hơn 500 deal | Cảnh báo bật khi ≥ 2000 / ≥ 500 — tức cả khi đúng bằng trần (không phân biệt được "vừa đủ" với "bị cắt") | common.service.ts:2109 · :2116 |
| DR-02 | shared/api-docs/sapp.md §GET flow-processes (dòng 2901-2917) và §timeline "Timestamps" (dòng 3056-3059) | Mẫu trả về ghi giờ ISO …Z; phần "Timestamps" (đọc qua DATE_FORMAT + offset DB, tránh bẫy mysql2) chỉ nêu cho timeline, im lặng với flow-processes | GET flow-processes (và response của retry) đọc DATETIME trực tiếp qua mysql2, pool không đặt timezone → giờ phụ thuộc múi giờ tiến trình BE. Mẫu tài liệu ghi rõ "written from source, not fetched live" | common.service.ts:2405-2415 · external-db.service.ts:35-45 |
| DR-03 | be/.agents/maps/modules/tool.md:86 | Retry chỉ chạy "khi có row FAIL còn retry" | Điều kiện là FAIL và retry > 0 = đã chạy lại ≥ 1 lần (retry đếm lần đã chạy, không phải lượt còn lại); FAIL + retry = 0 bị từ chối | common.service.ts:2462-2468 · error-codes.constants.ts:543-551 |
8. Câu hỏi cho BA (code không trả lời được) ​
Code cho biết hệ thống làm gì, không cho biết vì sao hay có đúng ý đồ không.
| ID | Câu hỏi | Vì sao cần | Chặn bước sau? |
|---|---|---|---|
| Q-01 | POST …/prod/econtract/…/retry ghi DB econtract production nhưng để @Public() (không cần đăng nhập, gọi thẳng API là bỏ qua được khoá tool ở FE). Đây là trạng thái "tạm thời" có chủ đích (tài liệu ghi "Public (temporary)") hay cần bảo vệ? Ai được phép retry? | Viết BR quyền / NFR bảo mật; quyết định ghi thành BR hay OQ rủi ro | Có |
| Q-02 | Một lần Retry đặt lại mọi dòng FAIL có retry ≥ 1 của deal, kể cả khi thuộc nhiều flow khác tên (vd CREATE_CONTRACT và EFY_CANCEL_CONTRACT cùng FAIL). Cố ý hay nên chỉ cho 1 flow / chuyển sang "liên hệ dev"? (Audit từng khuyến nghị "nhiều dòng FAIL cùng lúc → nhánh liên hệ dev"; quyết định D2 chỉ chốt trường hợp trùng tên) | Quyết định BR retry | Có |
| Q-03 | Có cần lưu vết ai / lúc nào / deal nào đã retry trên prod không? Hiện không có | NFR audit trail | Không |
| Q-04 | Người dùng mục tiêu của 3 màn là ai (đội vận hành, tester, dev)? Tài liệu SAPP nhắc "tool nội bộ, người dùng là đội vận hành" và "trước khi bật tool cho tester" — xin xác nhận role cho từng màn | Actor trong US Statement | Có |
| Q-05 | Giờ "cập nhật" ở màn Retry có thể lệch theo múi giờ của tiến trình BE (không dùng cách đọc giờ như màn Check luồng) — cố ý hay bug? | Quyết định BR hay OQ | Không |
| Q-06 | Đếm ngược tới giây 15 phút kế giả định cron reTryFlow chạy ở giây 0 mỗi phút; hành vi cron lấy từ bản local econtract-payment efbdb2d (2026-09-09), không phải bản deploy prod. SAPP xác nhận được lịch cron trên prod không? | Độ đúng của A-04 / R-11 | Không |
| Q-07 | API thống kê công khai, mỗi lượt 6 truy vấn quét toàn bảng trên DB prod, không giới hạn tần suất. Có cần giới hạn (rate limit / chỉ giờ hành chính)? SAPP đã nói "giờ hành chính ổn" ở mức ~0,11 s | NFR tải / an toàn prod | Không |
| Q-08 | Nếu ngữ cảnh không cấp hàm xác nhận, nút Retry ghi prod không hỏi lại (nhánh dự phòng). Có chấp nhận hay phải chặn cứng? | Quyết định rule R-07 | Không |
| Q-09 | Deal id không được kiểm tra định dạng (số) ở BE, và FE không mã hoá deal id trong URL của GET/POST flow-processes (timeline thì có). Cố ý hay bug? | Validation BR | Không |
| Q-10 | DR-01: cảnh báo cắt dữ liệu bật ở "≥ trần" — sửa tài liệu hay sửa code? (chỉ BE quyết) | Đồng bộ contract | Không |
| Q-11 | Việc còn mở trong audit: nút Retry ngay trong danh sách deal lỗi của màn Thống kê (T2-05 phần còn lại) — có thuộc phạm vi tài liệu as-built không? | Phạm vi FS | Không |
| Q-12 | Mục đích nghiệp vụ tổng của SAPP-20603 (ticket gốc) — vì sao cần retry tay thay vì chờ cron, và chỉ số "tỷ lệ lỗi" dùng để làm gì (báo cáo, cảnh báo)? | Viết BR/US Statement "để…" | Không |
9. Nhật ký nguồn đã đọc ​
| File / section | Mục đích |
|---|---|
ba/_workflow/templates/feature-inventory/Template.md | Khung tài liệu |
ba/system-profile.md §3–§5 | Công thức truy vết, ranh giới ghi |
fe/app/works/sapp/tools/econtract/page.tsx, econtract-timeline/page.tsx, econtract-error-stats/page.tsx | Route 3 màn |
fe/src/ui/pages/works/sapp/tools/registry.ts | Nhóm sidebar, slug, nhãn |
fe/src/ui/pages/works/sapp/tools/index-redirect.tsx (dòng 1-15), shell.tsx (grep) | Xác định tool gate → nền tảng |
fe/src/data/constants/tool-codes.ts | Tool code sapp.005/012/013 |
fe/src/data/constants/api.ts:468-475 | URL 4 API |
fe/src/data/services/sapp/get-flow-processes.service.ts, retry-flow-process.service.ts, get-econtract-deal-timeline.service.ts, get-econtract-error-stats.service.ts | Service FE |
fe/src/data/models/sapp-econtract.interface.ts (grep) | Kiểu dữ liệu FE |
fe/src/ui/components/works/sapp/retry-econtract-tool.tsx (toàn bộ) | Luồng màn Retry |
fe/src/ui/components/works/sapp/econtract-timeline-tool.tsx (36-229, 351-395, 600-922) | Màn Check luồng |
fe/src/ui/components/works/sapp/econtract-error-stats-tool.tsx (50-80, 174-343, 376-470, 734-990) | Màn Thống kê lỗi |
fe/src/logic/contexts/app-status.provider.tsx (grep showConfirm) | Kiểm R-07 |
be/apps/api/src/sapp/sapp.controller.ts:140-250 | Controller, @Public() |
be/apps/api/src/app/app.module.ts:88-102 | Tìm guard/interceptor toàn cục |
be/libs/modules/src/lib/sapp/common.service.ts:250-290, 1680-2487 | Toàn bộ logic econtract |
be/libs/constants/src/lib/sapp/sapp.constants.ts:1-20, 120-225 | Bảng, cột, giới hạn, regex che token |
be/libs/constants/src/lib/error-codes/error-codes.constants.ts:515-573 | Mã lỗi 13001-13006, 13060-13063 |
be/libs/interface/src/lib/dto/sapp/econtract-flow-process.dto.ts, econtract-deal-timeline.dto.ts:18-140, econtract-error-stats.dto.ts:1-80 (+ grep class) | DTO |
be/libs/services/src/lib/external-db/external-db.service.ts:25-94 | Pool DB ngoài, không đặt timezone |
be/libs/database/migrations/1783700000000-create-tools.ts, 1786400000000-…timeline.ts, 1786500000000-…error-stats.ts (grep) | Seed tool code |
be/.agents/maps/modules/tool.md (grep), platform.md:25 | Bản đồ module — nguồn DR-03 |
shared/api-docs/sapp.md:6, 2873-3162 | Contract API — đối chiếu Drift |
shared/external/sapp/sapp-20603/README.md | Sổ cái trao đổi với SAPP |
shared/external/sapp/sapp-20603/2026-09-25-sapp-20603-tra-loi.md §4 (164-298) | Điều kiện SAPP: che token, không export, link_file_pdf text thuần, múi giờ |
shared/external/sapp/sapp-20603/2026-09-25-mind-sapp-20603-ket-qua.md (1-80) | MIND đã áp dụng gì, số đo prod 2026-09-25 |
shared/external/sapp/sapp-20603/2026-09-25-mind-sapp-20603-cau-hoi.md (grep heading) | 5 câu hỏi gốc |
fe/audits/works-sapp-retry-econtract/audit.html (text), scripts/luong.mjs (đầu file), danh sách data/ | Audit màn Retry: T0-01 (hiểu ngược cột retry — đã sửa), quyết định chủ màn D1–D4 ngày 30/09, việc còn mở T2-05. Không chạy script |