Skip to content

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.md và audit — ghi rõ ở từng dòng, không phải số đo.

FieldValue
Projectba/projects/2026-SAPP-Works-tools
ModeB – As-built
Ngày đọc code2026-09-30
Commite77c47a
Điểm vào BA cung cấp3 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ớiFE · BE · hệ thống ngoài: DB MySQL econtract PRODUCTION của SAPP (repo econtract-payment)
StatusDraft

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), DTO econtract-*.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 / reProcessFlow và việc gọi EFY/FPT thật — nằm trong repo econtract-payment của SAPP, không có trong repo này.

2. Điểm vào (Entry points) ​

IDLoạiTên / đường dẫn người dùng thấyBằng chứng
E-01Mà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-02Mà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-03Mà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-04APIGET /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-05APIPOST /api/v1/sapp/prod/econtract/flow-processes/:dealId/retry — GHI vào DB econtract PRODUCTIONsapp.controller.ts:192-210 · api.ts:471-472
E-06APIGET /api/v1/sapp/prod/econtract/deals/:dealId/timeline (chỉ đọc)sapp.controller.ts:212-230 · api.ts:473-474
E-07APIGET /api/v1/sapp/prod/econtract/error-stats?from&to&bucketMin&flowName (chỉ đọc)sapp.controller.ts:232-250 · api.ts:475
E-08Deep 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-09Dữ 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) → URL api.ts → controller → SappCommonService → DB econtract prod.

IDAi (role)Làm gìĐiểm vàoKết quả quan sát đượcBằng chứng
A-01Ngườ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ạyretry-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-02Hệ 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-01Thô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 ghiretry-econtract-tool.tsx:351 · :500 · :195 · :631-633 · :650-652
A-03Người dùng toolBấ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-04Hệ 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 processE-01 → E-04Badge 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õiretry-econtract-tool.tsx:110-117 · :386-401 · :373-384 · :98-108 · :266-290 · :656-661
A-05Người dùng toolBấm "Kiểm tra lại (về bước 1)" khi kết quả không phải SUCCESSE-01 → E-04Quay lại bước 1, tăng số "Lượt N"retry-econtract-tool.tsx:669-679 · :425-426 · :575
A-06Người dùng toolBấm "Copy thông tin gửi dev"E-01Copy vào clipboard (không tạo file): deal, lý do, mỗi dòng tên · status · retry · reprocess · cập nhậtretry-econtract-tool.tsx:464-482 · :685-703
A-07Người dùng toolBấm link "Xem chi tiết ở Check luồng econtract" khi retry SUCCESSE-01 → E-02Mở màn Check luồng với ?dealId=retry-econtract-tool.tsx:662-668
A-08Người dùng toolNhập deal id, bấm CheckE-02 → E-06Deal id được ghi lên URL (để chia sẻ/tải lại); tải timelineecontract-timeline-tool.tsx:650-670 · fe/src/data/services/sapp/get-econtract-deal-timeline.service.ts:11-19 · common.service.ts:1733-1895
A-09Người dùng toolXem kết quả Check luồngE-02Cả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 textecontract-timeline-tool.tsx:746-897 · :71-120 · :351-390 · :194-200 · :903-922
A-10Người dùng toolChọ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-07Tải thống kê; không tự tải khi mở mànecontract-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-11Người dùng toolXem kết quả thống kêE-035 ô 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-12Người dùng toolBấ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ớiE-03 → E-02Modal danh sách deal lỗi; copy chỉ deal id vào clipboardecontract-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ảngFieldTypeBắt buộcMặc định / enumBằ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_processesnamestring—Tên flow, vd CREATE_CONTRACT, EFY_CANCEL_CONTRACT — phải duy nhất trong 1 deal để retrybe/libs/interface/src/lib/dto/sapp/econtract-flow-process.dto.ts:18-21
econtract_flow_processesstatusstring—NEW | SUCCESS | FAILecontract-flow-process.dto.ts:26-27 · sapp.constants.ts:131
econtract_flow_processesretrynumber—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_processesreprocessnumber/boolean—true khi cron 5 phút đã cấp thêm 1 vòngecontract-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êmcommon.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 đọccommon.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 idcommon.service.ts:1806-1811 · econtract-deal-timeline.dto.ts:99-115 · sapp.constants.ts:154-155
Tham số thống kê (request)fromISO datetimeCó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êtoISO datetimeCótới (không bao gồm)econtract-error-stats.dto.ts:23-24
Tham số thống kêbucketMinnumberKhông1 | 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êflowNamestringKhôngtrống = tất cả flowecontract-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 / _PASSWORDstringhost, name, username bắt buộcport mặc định 3306sapp.constants.ts:4-14 · common.service.ts:1685-1704
Redis cache (mind_keep)sapp:econtract:job-traces:oldeststring—TTL 1 ngàysapp.constants.ts:186-188 · common.service.ts:2253-2275

5. Rule & validation tìm thấy ​

IDRule (ngôn ngữ nghiệp vụ)LoạiÁp dụng ởBằng chứngNghi là bug?
R-01Phả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"validationA-01, A-08retry-econtract-tool.tsx:413-422 · econtract-timeline-tool.tsx:650-659Không
R-02Retry bị từ chối nếu deal không có flow process nào (mã 13002, 404)điều kiệnA-01, A-03common.service.ts:2435-2440 · error-codes.constants.ts:523-527 · FE nhắc lại: retry-econtract-tool.tsx:68-70Không
R-03Retry 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ệnA-01, A-03common.service.ts:2442-2450 · error-codes.constants.ts:552-557 · retry-econtract-tool.tsx:71-79Không (chủ màn chốt D2 — audit)
R-04Retry bị từ chối nếu không có dòng nào ở trạng thái FAIL (mã 13003, 409)điều kiệnA-01, A-03common.service.ts:2452-2460 · error-codes.constants.ts:528-532 · retry-econtract-tool.tsx:80-88Không
R-05Nế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ệnA-02common.service.ts:2462-2468 · error-codes.constants.ts:543-551 · retry-econtract-tool.tsx:89-90 · :351Không (đã sửa nghĩa theo audit T0-01)
R-06Dò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áiA-03common.service.ts:2462 · :2470-2474 · retry-econtract-tool.tsx:89⚠️ Observed — xem Q-02
R-07Trướ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ệnA-03retry-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-08Trong lúc đang gọi hoặc đang chờ cron, ô deal id và nút Kiểm tra bị khoátrạng tháiA-01..A-04retry-econtract-tool.tsx:554-563Không
R-09Giờ "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ứcA-01, A-04common.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-10Kế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ỗicông thứcA-04retry-econtract-tool.tsx:98-108Không
R-11Thờ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ứcA-04retry-econtract-tool.tsx:110-117 · :653Không rõ — giả định lịch cron, Q-06
R-12Hiệ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ệnA-06retry-econtract-tool.tsx:520 · :382 · :145-146Không
R-13Retry chỉ chạy lại luồng econtract, không đổi deal stage trên HubSpot (mô tả màn)giới hạnA-03retry-econtract-tool.tsx:533-534Không
R-14Deep 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ệnE-08retry-econtract-tool.tsx:403-411 · econtract-timeline-tool.tsx:636-648Không
R-15Mỗ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 TRUNCATEDgiới hạnA-08sapp.constants.ts:157-161 · common.service.ts:1750-1759Không
R-16Bả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ệnA-08, A-10common.service.ts:2209-2232 · :1761-1766 · :1982-1991Không
R-17Webhook đượ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ệnA-08common.service.ts:1798-1822Không
R-18Deal 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ệnA-08common.service.ts:1824-1841Không
R-19Timeline sắp mới nhất trước, chỉ theo created_at; mọi mốc giờ gắn offset đồng hồ DBcông thứcA-09common.service.ts:2313-2392 · :2234-2250 · :2299-2311Không
R-20Che 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-09sapp.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-212Không
R-21Dữ 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 SAPPgiới hạn (bảo mật)A-09, A-12econtract-timeline-tool.tsx:194-200 · :351-390 · nguồn: 2026-09-25-sapp-20603-tra-loi.md:223-231Không
R-22Checklist 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 COMPLETEDcông thức / trạng tháiA-09econtract-timeline-tool.tsx:44-120Không
R-23Thố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)validationA-10common.service.ts:1920-1935 · sapp.constants.ts:197-205 · error-codes.constants.ts:568-573 · econtract-error-stats-tool.tsx:217-233Không
R-24Thố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ụccông thứcA-11common.service.ts:1908-1916 · econtract-error-stats.dto.ts:10-17Không
R-25Tỷ 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ứcA-11common.service.ts:2067-2090 · econtract-error-stats-tool.tsx:316-318Không
R-26Top 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ạnA-11, A-12sapp.constants.ts:206-215 · common.service.ts:2011-2033 · :2044-2064 · :2109-2122Không
R-27Deal "Đã 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ứcA-12common.service.ts:2040-2043 · :2058 · econtract-error-stats-tool.tsx:742-743 · :837-842Không
R-28Khoả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ệnA-11common.service.ts:2123-2130 · econtract-error-stats-tool.tsx:267 · :273 · :289-298Không
R-29Danh sách flow trong bộ lọc = 5 flow biết trước + mọi flow đã thấy trong các lần tảicông thứcA-10econtract-error-stats-tool.tsx:56-62 · :183 · :211-213 · :384-389Khô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ấy

6. Quyền, tích hợp, thông báo, job ​

LoạiChi tiếtBằ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 BEsapp.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ảngfe/src/data/constants/tool-codes.ts:1-20 · :36 · :43-44
Tích hợp ngoàiDB 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ếpretry-econtract-tool.tsx:444-445 · shared/api-docs/sapp.md:2919-2931
Tích hợp ngoàiKhô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 prodKhô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ượtsapp.constants.ts:157-161 · :200-205 · common.service.ts:1993-2065
Bộ nhớ đệmMốc job trace cũ nhất cache Redis 1 ngàycommon.service.ts:2252-2282
Thông báo (mail / push / MQTT / Discord)Không có trong 4 hàm service của nhómcommon.service.ts:1707-1906 · :1917-2176 · :2428-2487
Nhật ký thao tácKhô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 / cronKhô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 prodshared/api-docs/sapp.md:2919-2928 · retry-econtract-tool.tsx:36-40

7. Drift — tài liệu nói khác code ​

IDTài liệu (file + section)Tài liệu nóiCode đang làmBằng chứng
DR-01shared/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 dealCả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-02shared/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-processesGET 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-03be/.agents/maps/modules/tool.md:86Retry 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ốicommon.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.

IDCâu hỏiVì sao cầnChặn bước sau?
Q-01POST …/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 roCó
Q-02Mộ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 retryCó
Q-03Có 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 trailKhông
Q-04Ngườ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ànActor trong US StatementCó
Q-05Giờ "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 OQKhô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-11Không
Q-07API 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 sNFR tải / an toàn prodKhông
Q-08Nế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-07Không
Q-09Deal 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 BRKhông
Q-10DR-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ộ contractKhông
Q-11Việ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 FSKhông
Q-12Mụ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 / sectionMục đích
ba/_workflow/templates/feature-inventory/Template.mdKhung tài liệu
ba/system-profile.md §3–§5Cô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.tsxRoute 3 màn
fe/src/ui/pages/works/sapp/tools/registry.tsNhó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.tsTool code sapp.005/012/013
fe/src/data/constants/api.ts:468-475URL 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.tsService 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-250Controller, @Public()
be/apps/api/src/app/app.module.ts:88-102Tìm guard/interceptor toàn cục
be/libs/modules/src/lib/sapp/common.service.ts:250-290, 1680-2487Toàn bộ logic econtract
be/libs/constants/src/lib/sapp/sapp.constants.ts:1-20, 120-225Bảng, cột, giới hạn, regex che token
be/libs/constants/src/lib/error-codes/error-codes.constants.ts:515-573Mã 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-94Pool 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:25Bản đồ module — nguồn DR-03
shared/api-docs/sapp.md:6, 2873-3162Contract API — đối chiếu Drift
shared/external/sapp/sapp-20603/README.mdSổ 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