Giao diện
SAPP-20603 eContract (Retry · Check luồng · Thống kê lỗi) - FS Overview ​
File tổng quan + index của FS. Mỗi User Story là 1 file riêng trong cùng thư mục (
US-XX-<slug>.md). Các phần dùng chung (tổng quan, flow tổng, related features, NFR, Open Questions, References) đặt tập trung tại đây — file US chỉ tham chiếu ID, không lặp lại.⚠️ As-built, dựng từ code tại commit
e77c47a— chưa chạy màn, chưa gọi API. Hành vi cron của hệ thống econtract (repoecontract-paymentcủa SAPP, ngoài repo này) chỉ biết qua tài liệushared/api-docs/sapp.md— mọi câu về cron đều ghi rõ "theo tài liệu".
| Field | Value |
|---|---|
| Doc ID | FS-SAPP-20603 |
| Mode | B – As-built |
| As-built tại commit | e77c47a |
| Last Updated | 2026-09-30 |
| Author | AI (lane ba/) |
| Reviewers | BA |
| Status | DRAFT |
| Figma Project | N/A — as-built, không có Figma |
| Related BRD | ../../brd/brd-as-built-v0.1-20260930.md |
| Related Impact Matrix | N/A — Mode B, không có Impact Matrix |
1. Tổng quan dự án ​
Nhóm 3 sub-tool "SAPP 20603 - EContract" trong workspace /works/sapp/tools làm việc trực tiếp trên DB econtract PRODUCTION của SAPP: kiểm tra và chạy lại (retry) luồng hợp đồng điện tử của một HubSpot deal bị lỗi (sapp.005), dựng lại timeline xử lý hợp đồng của một deal (sapp.012), và thống kê lỗi job econtract theo khoảng thời gian kèm danh sách deal lỗi (sapp.013). Chỉ duy nhất thao tác Retry là ghi (đặt lại bộ đếm retry trên prod để cron của econtract chạy lại luồng và gọi nhà cung cấp EFY/FPT thật); mọi phần còn lại chỉ đọc.
1.1 Bối cảnh ​
- Luồng hợp đồng điện tử của deal do hệ thống econtract của SAPP chạy bằng cron:
reTryFlowmỗi phút chạy lại dòng FAIL chưa retry,reProcessFlowmỗi 5 phút cấp thêm 1 vòng (theo tài liệushared/api-docs/sapp.md:2919-2931, đọc ởecontract-paymentcommitefbdb2d). Dòng đã hết vòng tự động thì chỉ retry tay mới chạy lại được. - Trước tool, việc điều tra / chạy lại cần truy cập DB econtract prod. Tool dùng 1 user DB cấu hình trong
env_systems(SAPP_PROD_ECONTRACT_DB_*). - SAPP đặt điều kiện cho phần hiển thị: che token EFY/FPT, không export,
link_file_pdfkhông bấm được (2026-09-25-sapp-20603-tra-loi.md §4.4).
1.2 Mục tiêu ​
Assumption(chưa có câu trả lời G-05 / OQ-E-12): giảm thời gian điều tra và xử lý deal có luồng hợp đồng điện tử lỗi mà không cần dev truy cập DB prod; theo dõi mức lỗi của luồng econtract theo thời gian.- Gợi ý từ nguồn SAPP (không phải KPI): tool là tool nội bộ, người dùng là đội vận hành; dữ liệu chi tiết để "đối chiếu khi điều tra" (
2026-09-25-sapp-20603-tra-loi.md:230-232). - Không có KPI / ràng buộc thời gian nào được xác nhận.
1.3 In Scope ​
- 3 màn: Retry econtract (
/works/sapp/tools/econtract, sapp.005), Check luồng econtract (…/econtract-timeline, sapp.012), Thống kê lỗi econtract (…/econtract-error-stats, sapp.013). - 4 API
/api/v1/sapp/prod/econtract/*: đọc flow process, retry (ghi prod), timeline, thống kê lỗi. - Liên kết chéo giữa 3 màn qua
?dealId=. - Các bảng ngoài được đọc:
econtract_flow_processes,econtract_job_traces,contracts,econtract_webhook_logs(DB econtract prod); cache Redis mốc job trace cũ nhất.
1.4 Out Of Scope ​
- Khoá / ẩn / mã bí mật của tool, hub sidebar → FS nền tảng US-P01, US-P02.
- Cơ chế
@Public()/ guard → FS nền tảng NFR-P-01 (xem NFR-E-01). - Cấu hình kết nối
env_systems→ FS nền tảng US-P04. - Pool kết nối DB ngoài (chỉ ghi ảnh hưởng múi giờ, OQ-E-05).
- Cron
reTryFlow/reProcessFlowvà lời gọi EFY/FPT thật — nằm ở repoecontract-paymentcủa SAPP. - Nút Retry ngay trong danh sách deal lỗi (việc còn mở T2-05 của audit — chưa có trong code, OQ-E-11).
1.5 Roles And Permissions ​
| Role ID | Role Name | Description | Permission Summary |
|---|---|---|---|
| R1 | Người dùng tool | Assumption (OQ về G-01) — nguồn SAPP gợi ý "đội vận hành" và "tester" (2026-09-25-sapp-20603-tra-loi.md:225-230), chưa được BA xác nhận | Dùng cả 3 màn khi tool đang bật / đã mở khoá ở FE (US-P02). API không đòi đăng nhập — xem NFR-E-01 |
2. Luồng tổng quan của dự án ​
text
[Hub /works/sapp/tools — US-P01, US-P02]
├─→ [Retry econtract (sapp.005)]
│ US-E01 Kiểm tra flow process
│ ├─ Dừng ─────────────→ US-E03 Copy thông tin gửi dev
│ ├─ Hệ thống tự chạy ─→ (chờ cron, đọc lại — như US-E02 M2)
│ └─ Đủ điều kiện ─────→ US-E02 Retry (⚠️ GHI PROD) → Chờ cron → Kết quả
│ ├─ SUCCESS ──→ US-E03 link → US-E04
│ └─ khác ─────→ Kiểm tra lại (US-E01, Lượt N+1)
├─→ [Check luồng econtract (sapp.012)] US-E04 Timeline (chỉ đọc)
└─→ [Thống kê lỗi econtract (sapp.013)] US-E05 Thống kê (chỉ đọc)
└─ "Danh sách" → US-E06 Deal lỗi → mở US-E04 (tab mới)Phía econtract-payment (theo tài liệu, không có trong repo này — shared/api-docs/sapp.md:2919-2931):
text
[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ấyLink flow: N/A — không có flow vẽ riêng.
3. Các tính năng liên quan ​
| Mã | Tính năng liên quan | Link tài liệu | Loại liên quan | Mục bị ảnh hưởng ở feature kia | Mục ảnh hưởng ở feature hiện tại | Mô tả ảnh hưởng |
|---|---|---|---|---|---|---|
| REL-01 | Hub & khoá tool (nền tảng) | US-P01 · US-P02 | Affects | - | Truy cập cả 3 màn (tool code sapp.005 / 012 / 013) | Tool tắt / ẩn / khoá thì FE không cho vào màn; BE không kiểm tra (NFR-E-01) |
| REL-02 | Cấu hình env_systems (nền tảng) | US-P04 | Affects | - | Mọi API của nhóm | Thiếu host / tên DB / username của SAPP_PROD_ECONTRACT_DB_* → mã 13001, không màn nào chạy được |
| REL-03 | Cron econtract-payment + EFY/FPT (hệ thống SAPP, ngoài repo) | shared/api-docs/sapp.md:2919-2931 | Be Affected | Lượt cron reTryFlow kế tiếp | US-E02 action Retry | Retry đặt retry = 0 trên prod → cron chạy lại luồng và gọi EFY/FPT thật (tạo / huỷ hợp đồng) |
| REL-04 | HubSpot deal | - | Affects | - | Ô "HubSpot deal id" của US-E01, US-E04 | Deal id chỉ là khoá tra cứu; nhóm này không gọi HubSpot và Retry không đổi deal stage |
4. User Story Index ​
| US ID | Tên User Story | File | Role | Priority | Status |
|---|---|---|---|---|---|
| US-E01 | Kiểm tra flow process eContract của một deal | US-E01-kiem-tra-flow-process.md | R1 | N/A — as-built | Draft |
| US-E02 | Retry các flow FAIL và chờ cron xử lý (⚠️ Ghi PROD) | US-E02-retry-flow-fail.md | R1 | N/A — as-built | Draft |
| US-E03 | Chia sẻ kết quả retry (copy gửi dev, mở Check luồng) | US-E03-chia-se-ket-qua.md | R1 | N/A — as-built | Draft |
| US-E04 | Xem timeline luồng eContract của một deal | US-E04-timeline-econtract.md | R1 | N/A — as-built | Draft |
| US-E05 | Thống kê lỗi eContract theo khoảng thời gian | US-E05-thong-ke-loi.md | R1 | N/A — as-built | Draft |
| US-E06 | Xem danh sách deal lỗi và trạng thái tự hồi phục | US-E06-danh-sach-deal-loi.md | R1 | N/A — as-built | Draft |
Status
Draft= as-built chờ Gate R2. Truy vết hành động inventory: A-01, A-02 → US-E01 · A-03, A-04, A-05 → US-E02 · A-06, A-07 → US-E03 · A-08, A-09 → US-E04 · A-10, A-11 → US-E05 · A-12 → US-E06.
5. Non-functional Requirements ​
| ID | Requirement | Applies To (US/màn/API) | Acceptance Criteria |
|---|---|---|---|
| NFR-E-01 | Quyền truy cập API: theo NFR-P-01 của FS nền tảng — không lặp lại ở đây. Riêng nhóm này: 4 route /api/v1/sapp/prod/econtract/* đều thuộc diện đó, kể cả route Retry ghi DB prod (be/apps/api/src/sapp/sapp.controller.ts:174 · :193 · :213 · :233) | US-E01…US-E06, 4 API | Xem NFR-P-01. Rủi ro riêng của route ghi → OQ-E-01 |
| NFR-E-02 | Bảo mật dữ liệu hiển thị (điều kiện SAPP): che request/response của step lấy access token EFY/FPT ngay ở backend; không đọc request_data (đường dẫn file trên server) và contract_info; dữ liệu chi tiết chỉ hiện dạng text JSON, link_file_pdf không bấm được; không có chức năng xuất file (chỉ copy deal id / thông tin tóm tắt vào clipboard) | US-E01, US-E03, US-E04, US-E06 | Step getEfyAccessToken/getFptAccessToken hiện [hidden] (be/libs/constants/src/lib/sapp/sapp.constants.ts:169-177 · be/libs/modules/src/lib/sapp/common.service.ts:2284-2297); không có nút export trên 3 màn. Nguồn: 2026-09-25-sapp-20603-tra-loi.md:223-231 |
| NFR-E-03 | Tải trên DB prod: không có index trên deal_id / created_at → mọi truy vấn quét toàn bảng; thống kê chạy 6 truy vấn song song mỗi lượt; pool tối đa 5 kết nối. Giới hạn: timeline 500 dòng / bảng; thống kê ≤ 1500 bucket, top 20 lỗi, bước lỗi trên 2000 lần chạy lỗi, 500 deal lỗi; mốc job trace cũ nhất cache Redis 1 ngày | US-E04, US-E05, US-E06 | Giới hạn ở sapp.constants.ts:157-161 · :197-215; pool be/libs/services/src/lib/external-db/external-db.service.ts:31-49; cache common.service.ts:2252-2282. Không có rate limit — OQ-E-07 |
| NFR-E-04 | Chịu lỗi từng bảng: bảng chưa tồn tại (MISSING_TABLE) hoặc user DB không có quyền đọc (ACCESS_DENIED) → bảng đó rỗng + cảnh báo, không làm hỏng cả lượt | US-E04, US-E05 | common.service.ts:2209-2232 · :1761-1766 · :1982-1991 |
| NFR-E-05 | Múi giờ: timeline và thống kê đọc giờ theo đồng hồ DB econtract (gắn offset), hiển thị theo giờ máy người xem, có ghi tên múi giờ DB. Màn Retry không áp dụng cách này (OQ-E-05) | US-E04, US-E05, US-E06 (US-E01/E02 ngoại lệ) | common.service.ts:2200-2207 · :2234-2250; dòng "Giờ hiển thị theo máy của bạn · đồng hồ DB econtract" fe/src/ui/components/works/sapp/econtract-timeline-tool.tsx:794 |
| NFR-E-06 | Nhật ký thao tác: hiện trạng không có ghi nhận ai / lúc nào / deal nào đã Retry trên prod — chỉ log lỗi phía BE | US-E02 | common.service.ts:2428-2487 · sapp.controller.ts:201-210. Có cần hay không → OQ-E-03 |
| NFR-E-07 | Không thông báo: không gửi mail / push / MQTT / Discord trong cả nhóm | US-E01…US-E06 | common.service.ts:1707-1906 · :1917-2176 · :2428-2487 |
6. Open Questions ​
| ID | Question | Owner | Due Date | Status | Blocks (US) |
|---|---|---|---|---|---|
| OQ-E-01 | Route Retry ghi DB econtract PROD nhưng không đòi đăng nhập (gọi thẳng API là bỏ qua được khoá tool ở FE; tài liệu ghi "Public (temporary)"). Có chủ đích tạm thời hay cần bảo vệ? Ai được phép Retry? (inventory Q-01 · G-02) | BA / BE | TBD | Open | US-E02 |
| OQ-E-02 | ⚠️ Observed — 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 bug? Nên chỉ 1 flow / chuyển sang nhánh "liên hệ dev"? (inventory Q-02, R-06 · G-03; audit từng khuyến nghị nhánh liên hệ dev, quyết định D2 chỉ chốt trường hợp trùng tên) | BA | TBD | Open | US-E02 |
| OQ-E-03 | ⚠️ Observed — không có nhật ký Retry (ai / lúc nào / deal nào). Có cần lưu vết thao tác ghi prod không? (inventory Q-03) | BA | TBD | Open | US-E02 |
| OQ-E-04 | Người dùng mục tiêu của 3 màn là ai (đội vận hành, tester, dev)? Mọi US Statement đang ghi "Người dùng tool" là Assumption. (inventory Q-04 · G-01) | BA | TBD | Open | US-E01…US-E06 |
| OQ-E-05 | ⚠️ Observed — giờ "cập nhật" ở màn Retry đọc thẳng cột DATETIME qua driver, pool không đặt múi giờ → có thể lệch theo múi giờ của tiến trình BE (khác cách màn Check luồng đọc giờ). Cố ý hay bug? (inventory Q-05, R-09) | BA / BE | TBD | Open | US-E01, US-E02, US-E03 |
| OQ-E-06 | Màn Retry đọc lại ở giây 15 của phút kế tiếp, giả định cron reTryFlow chạy giây 0 mỗi phút; lịch cron lấy từ bản local econtract-payment efbdb2d, không phải bản deploy prod. SAPP xác nhận lịch cron prod? (inventory Q-06, R-11) | BA → SAPP | TBD | Open | US-E02 |
| OQ-E-07 | API thống kê không đòi đăng nhập, mỗi lượt 6 truy vấn quét toàn bảng prod, không giới hạn tần suất. Cần rate limit / chỉ giờ hành chính? (SAPP đã nói "giờ hành chính ổn" ở ~0,11 s) (inventory Q-07) | BA / BE | TBD | Open | US-E05 |
| OQ-E-08 | ⚠️ Observed — nếu ngữ cảnh giao diện không cấp hàm hộp xác nhận, nút Retry ghi prod ngay không hỏi (nhánh dự phòng). Thực tế provider có cấp. Chấp nhận hay phải chặn cứng? Kèm: hộp xác nhận không bật kiểu "thao tác nguy hiểm". (inventory Q-08, R-07) | BA / FE | TBD | Open | US-E02 |
| OQ-E-09 | ⚠️ Observed — deal id không được kiểm tra định dạng (số) ở BE; FE không mã hoá deal id trong URL của đọc / retry flow process (timeline thì có). Cố ý hay bug? (inventory Q-09) | BA / BE / FE | TBD | Open | US-E01, US-E02 |
| OQ-E-10 | DR-E-01: cảnh báo cắt dữ liệu bật ở "≥ trần" chứ không phải "> trần" — sửa tài liệu hay sửa code? (chỉ BE quyết) (inventory Q-10) | BE | TBD | Open | US-E05, US-E06 |
| OQ-E-11 | Nút Retry ngay trong danh sách deal lỗi (audit T2-05 phần còn lại) — chưa có trong code; có thuộc phạm vi tài liệu / backlog không? (inventory Q-11) | BA | TBD | Open | US-E06 |
| OQ-E-12 | Mục đích nghiệp vụ của SAPP-20603: vì sao cần retry tay thay vì chờ cron; chỉ số "tỷ lệ lỗi" dùng để làm gì (báo cáo, cảnh báo)? Mọi "So that" và §1.2 đang là Assumption. (inventory Q-12 · G-05) | BA | TBD | Open | US-E01…US-E06 |
6b. Drift: tài liệu ↔ code (Mode B/C — Mode A ghi N/A) ​
| ID | Tài liệu nói | Code đang làm (bằng chứng file:dòng) | Ảnh hưởng | Owner quyết |
|---|---|---|---|---|
| DR-E-01 | shared/api-docs/sapp.md:3142-3144 (§GET error-stats, warnings[].code): TRUNCATED khi nhiều hơn 2000 lần chạy lỗi; DEALS_TRUNCATED khi nhiều hơn 500 deal (inventory DR-01) | Cảnh báo bật khi ≥ 2000 / ≥ 500, tức cả khi đúng bằng trần — be/libs/modules/src/lib/sapp/common.service.ts:2109 · :2116 | Không phân biệt được "vừa đủ" với "bị cắt" (US-E05 BR-10, US-E06 BR-02) | BE (OQ-E-10) |
| DR-E-02 | shared/api-docs/sapp.md:2901-2917 (mẫu GET flow-processes) ghi giờ ISO …Z; phần "Timestamps" (:3056-3059, đọc qua DATE_FORMAT + offset DB) chỉ nêu cho timeline, im lặng với flow-processes (inventory DR-02) | GET flow-processes và response Retry đọc DATETIME trực tiếp, pool không đặt timezone → giờ phụ thuộc múi giờ tiến trình BE — common.service.ts:2405-2415 · be/libs/services/src/lib/external-db/external-db.service.ts:35-45. Mẫu tài liệu ghi rõ "written from source, not fetched live" | Giờ "cập nhật" ở US-E01 / US-E02 / US-E03 có thể lệch (OQ-E-05) | BE |
| DR-E-03 | be/.agents/maps/modules/tool.md:86: Retry chỉ chạy "khi có row FAIL còn retry" (inventory DR-03) | Điều kiện là FAIL và retry > 0 = đã chạy lại ≥ 1 lần (retry đếm lần đã chạy); FAIL + retry = 0 bị từ chối 13006 — common.service.ts:2462-2468 · be/libs/constants/src/lib/error-codes/error-codes.constants.ts:543-551 | Người đọc bản đồ module hiểu ngược điều kiện Retry (US-E02 BR-03) | BE |
7. References ​
- BRD: ../../brd/brd-as-built-v0.1-20260930.md
- Impact Matrix: N/A — Mode B
- Solution Decision: N/A
- Figma: N/A — as-built, không có Figma
- API Spec:
shared/api-docs/sapp.md:2873-3162(eContract) — chỉ đọc, BE sở hữu - FS nền tảng: ../sapp-platform-as-built-v0.1-20260930/00-overview.md
- Code đã đọc (Mode B/C) — chi tiết ở feature-inventory-20603-econtract-20260930.md §9:
fe/src/ui/components/works/sapp/retry-econtract-tool.tsxfe/src/ui/components/works/sapp/econtract-timeline-tool.tsxfe/src/ui/components/works/sapp/econtract-error-stats-tool.tsxfe/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.tsbe/apps/api/src/sapp/sapp.controller.ts:170-250be/libs/modules/src/lib/sapp/common.service.ts:1680-2487be/libs/constants/src/lib/sapp/sapp.constants.ts,be/libs/constants/src/lib/error-codes/error-codes.constants.ts:515-573be/libs/interface/src/lib/dto/sapp/econtract-*.dto.ts
- Meeting Notes / Q&A (nguồn ý đồ): sổ cái shared/external/sapp/sapp-20603/README.md · câu hỏi · trả lời SAPP · kết quả
- Quyết định dự án: ../../../project-decisions.md · câu hỏi chặn G-01…G-10: gate-r1-summary-20260930.md
Template Conformance Check ​
Quét 2026-09-30, so mục lục từng file với ba/_workflow/templates/fs/User-Story.md: Metadata (US ID · Role · Phase · Priority · Status · NFR · OQ) · 1. US Statement · 2. Dependencies & DoR · 3. Business Rules (cột "Đã cover bởi (AC)" + "Nguồn code", mọi mã AC/EC được trỏ tới đều có trong file) · 4. Design (a. flow, b. mỗi màn: UI States · Fields · Filter/Search/Sort · Actions · AC G/W/T · Negative AC) · 5. Cross-feature AC. Section không áp dụng giữ heading + N/A — <lý do>.
| US file | Section thiếu | Trạng thái |
|---|---|---|
| US-E01-kiem-tra-flow-process.md | (đủ) — 1 màn; Filter = N/A có lý do; DoR = N/A + dependency runtime | ✅ |
| US-E02-retry-flow-fail.md | (đủ) — 2 màn (M1 hộp xác nhận, M2 chờ cron & kết quả), mỗi màn đủ 6 mục; Filter = N/A có lý do | ✅ |
| US-E03-chia-se-ket-qua.md | (đủ) — 1 màn; Filter, Loading / Error / Disabled = N/A có lý do | ✅ |
| US-E04-timeline-econtract.md | (đủ) — 1 màn, có Filter/Search/Sort (lọc theo nguồn) | ✅ |
| US-E05-thong-ke-loi.md | (đủ) — 1 màn, có Filter/Search/Sort | ✅ |
| US-E06-danh-sach-deal-loi.md | (đủ) — 1 màn (modal), có Filter/Search/Sort | ✅ |
Tổng: 6 file US · 67 BR · 48 AC màn + 12 Cross-feature AC · 41 EC · 7 NFR · 12 OQ · 3 DR.