Giao diện
US-E04: Xem timeline luồng eContract của một deal ​
Thuộc FS: 00-overview.md — SAPP-20603 eContract (Retry · Check luồng · Thống kê lỗi) 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.
Chỉ đọc. Màn này chỉ chạy truy vấn đọc (SELECT) trên DB econtract PRODUCTION — không ghi hệ thống nào, ngoài cache Redis của mind_keep cho mốc job trace cũ nhất.
| Field | Value |
|---|---|
| US ID | US-E04 |
| Role thực hiện | R1 - Người dùng tool (Assumption (OQ về G-01) — OQ-E-04) |
| Phase | Đã triển khai (as-built @ e77c47a) — sub-tool sapp.012 Check luồng econtract |
| Priority | N/A — as-built |
| Status | Draft |
| NFR liên quan | NFR-E-01, NFR-E-02, NFR-E-03, NFR-E-04, NFR-E-05, NFR-E-07 — xem Overview §5 |
| OQ liên quan | OQ-E-04, OQ-E-12 — xem Overview §6 |
1. US Statement ​
text
As a Người dùng tool [Assumption (OQ về G-01)]
I want nhập HubSpot deal id để xem lại toàn bộ dòng thời gian xử lý hợp đồng điện tử của deal
(job trace, flow process, hợp đồng, webhook EFY/FPT), checklist các mốc luồng chuẩn và các bước FAIL
So that tôi đối chiếu được thứ tự sự kiện (kể cả với log app) khi điều tra một deal lỗi
— nguồn: "tester đối chiếu với log app" (2026-09-25-mind-sapp-20603-cau-hoi.md:81-82),
"cần để đối chiếu khi điều tra" (2026-09-25-sapp-20603-tra-loi.md:230-232)2. Dependencies & Definition Of Ready ​
N/A — đã triển khai. Dependency runtime:
| # | Cần sẵn sàng | Ai cung cấp | Trạng thái |
|---|---|---|---|
| D1 | Khoá SAPP_PROD_ECONTRACT_DB_* trong env_systems — US-P04 | Admin CMS | Runtime |
| D2 | User DB có quyền đọc 4 bảng (thiếu bảng / thiếu quyền → cảnh báo, NFR-E-04). Đo 2026-09-25: đọc được cả 4 (2026-09-25-mind-sapp-20603-ket-qua.md) | SAPP | Runtime |
| D3 | Tool sapp.012 truy cập được — US-P02 | Admin CMS | Runtime |
3. Business Rules ​
| ID | Rule | Áp dụng ở | Đã cover bởi (AC) | Nguồn code (Mode B/C) |
|---|---|---|---|---|
| BR-01 | Phải nhập deal id (bỏ khoảng trắng); trống → "Thiếu deal id" / "Nhập HubSpot deal id cần kiểm tra." | M1 - action A1 | AC-M1.2 | fe/src/ui/components/works/sapp/econtract-timeline-tool.tsx:650-659 |
| BR-02 | Bấm Check ghi deal id lên URL (?dealId=) để tải lại / gửi người khác nguyên trạng | M1 - action A1 | AC-M1.3 | econtract-timeline-tool.tsx:660-664 |
| BR-03 | Mở màn với ?dealId= → điền ô và tự tra cứu 1 lần | M1 - trigger | AC-M1.3 | econtract-timeline-tool.tsx:636-648 |
| BR-04 | Tra cứu chỉ đọc, gộp 4 nguồn của DB econtract PROD: job trace, flow process, hợp đồng (theo deal id) và webhook EFY/FPT (nối qua contract id FPT/EFY lấy từ 3 nguồn trên); không đọc thông tin hợp đồng chi tiết | M1 - action A1 | AC-M1.1 | be/libs/modules/src/lib/sapp/common.service.ts:1733-1895 · :1783-1788 · be/apps/api/src/sapp/sapp.controller.ts:212-230 |
| BR-05 | Mỗi nguồn lấy tối đa 500 dòng mới nhất; chạm trần → cảnh báo "Chạm giới hạn 500 dòng — chỉ hiện các dòng mới nhất" | M1 - cảnh báo | AC-M1.5 | be/libs/constants/src/lib/sapp/sapp.constants.ts:157-161 · common.service.ts:1750-1759 · econtract-timeline-tool.tsx:179-188 |
| BR-06 | Bảng chưa tồn tại / user DB không có quyền đọc → nguồn đó rỗng + cảnh báo, các nguồn khác vẫn hiện | M1 - cảnh báo | AC-M1.5 | common.service.ts:2209-2232 · :1761-1766 |
| BR-07 | Deal không có contract id FPT/EFY → cảnh báo NO_CONTRACT_ID ("Deal chưa có fpt/efy contract id nên không kéo được webhook…"); truy vấn webhook vẫn chạy | M1 - cảnh báo | AC-M1.6 | common.service.ts:1798-1822 |
| BR-08 | 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 ("…không có JOB_TRACE / WEBHOOK là bình thường, không phải mất dữ liệu.") | M1 - cảnh báo | AC-M1.6 | common.service.ts:1824-1841 · nguồn ý đồ: 2026-09-25-mind-sapp-20603-cau-hoi.md:39-41 |
| BR-09 | Timeline sắp mới nhất trước, chỉ theo thời điểm tạo; mọi mốc giờ gắn offset đồng hồ DB; hiển thị theo giờ máy người xem, kèm tên múi giờ DB và mốc job trace cũ nhất | M1 - timeline | AC-M1.4 | common.service.ts:2313-2392 · :2234-2250 · econtract-timeline-tool.tsx:794-805 |
| BR-10 | request/response của step lấy access token EFY/FPT bị che thành [hidden] ngay ở backend (theo tên step) | M1 - chi tiết JOB_TRACE | AC-M1.7 | sapp.constants.ts:169-177 · common.service.ts:2284-2297 · nguồn: 2026-09-25-sapp-20603-tra-loi.md:182-212 |
| BR-11 | Dữ liệu chi tiết (steps, error, context, payload webhook, link_file_pdf) chỉ hiện dạng text JSON, không link bấm được, không có chức năng xuất file | M1 - chi tiết | AC-M1.7 | econtract-timeline-tool.tsx:194-200 · :351-390 · nguồn: 2026-09-25-sapp-20603-tra-loi.md:223-231 |
| BR-12 | Checklist "Các mốc của luồng chuẩn" 6 mốc: (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 (có job nhưng chưa SUCCESS = Lỗi); (3) có bản ghi hợp đồng; (4) webhook ký (EFY DA_KY / FPT completed) — có 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) có SUCCESS; (6) hợp đồng COMPLETED | M1 - checklist | AC-M1.8 | econtract-timeline-tool.tsx:44-120 |
| BR-13 | Deal có job huỷ hợp đồng (CANCEL_CONTRACT / EFY_CANCEL_CONTRACT) → dòng nhắc "Deal này có job huỷ hợp đồng — xem timeline bên dưới." | M1 - checklist | AC-M1.8 | econtract-timeline-tool.tsx:45 · :853-856 |
| BR-14 | Cả 4 nguồn đều rỗng → "Không tìm thấy dữ liệu econtract nào cho deal <id>." (cảnh báo nếu có vẫn hiện) | M1 - empty | AC-M1.9 | econtract-timeline-tool.tsx:689-694 · :752-759 |
| BR-15 | Tóm tắt 5 ô đếm: Job trace, Flow process, Hợp đồng, Webhook, Step FAIL (Step FAIL > 0 tô đỏ); dòng contract id nếu có | M1 - tóm tắt | AC-M1.1 | econtract-timeline-tool.tsx:763-790 · :808-821 |
| BR-16 | Bảng "Step FAIL (N)" liệt kê mọi step FAIL: job lúc, flow, step, provider, error | M1 - bảng Step FAIL | AC-M1.8 | econtract-timeline-tool.tsx:394-430 · :858 |
| BR-17 | Timeline lọc bật / tắt theo từng nguồn (JOB_TRACE, FLOW_PROCESS, CONTRACT, WEBHOOK_EFY / WEBHOOK_FPT); tiêu đề hiện số dòng đang hiện / tổng | M1 - bộ lọc | AC-M1.4 | econtract-timeline-tool.tsx:670-684 · :862-884 · common.service.ts:2333-2382 |
4. Design ​
a. Mối liên hệ giữa các màn & User Flow ​
text
[Hub → Check luồng econtract] · [US-E03 link, US-E06 tab mới, link chia sẻ: ?dealId= → tự tra cứu]
↓ nhập deal id, bấm Check / Enter
[M1: Check luồng econtract]
├─ có dữ liệu → cảnh báo (nếu có) · tóm tắt · checklist 6 mốc · Step FAIL · Timeline (lọc theo nguồn, mở chi tiết)
├─ 4 nguồn rỗng → "Không tìm thấy dữ liệu econtract nào cho deal …"
└─ lỗi API → hộp lỗi "Không tải được timeline econtract"b. Chi tiết từng màn ​
Màn M1 - Check luồng econtract ​
| Field | Value |
|---|---|
| Figma frame | N/A |
| Trigger vào màn | Hub → "Check luồng econtract" (/works/sapp/tools/econtract-timeline), hoặc link ?dealId= |
| Mô tả ngắn | "Dựng lại dòng thời gian xử lý hợp đồng của một deal: job trace, flow process, hợp đồng và webhook EFY/FPT, sắp từ mới đến cũ. Chỉ đọc, không thay đổi dữ liệu." |
UI States ​
| State | Khi nào | Hiển thị | Figma frame |
|---|---|---|---|
| Default | Vừa vào màn (không có ?dealId=) | Ô "HubSpot deal id" + nút "Check" | N/A |
| Loading | Đang tra cứu | Nút "Đang kiểm tra…", ô nhập bị khoá; kết quả cũ bị xoá | N/A |
| Has data | Có ≥ 1 dòng ở 1 nguồn | Cảnh báo (nếu có) → 5 ô đếm → dòng múi giờ / job trace cũ nhất → contract id → checklist 6 mốc → Step FAIL (nếu có) → Timeline | N/A |
| Empty | 4 nguồn rỗng | "Không tìm thấy dữ liệu econtract nào cho deal <id>." | N/A |
| Error | API lỗi | Hộp lỗi "Không tải được timeline econtract" + thông điệp (mã) (vd 13060, 13001) | N/A |
| Disabled | Đang tra cứu | Ô nhập và nút Check bị khoá | N/A |
Fields ​
| Field | Required | Type | Default | Format | Validation | Error Message | Visibility | Depends On |
|---|---|---|---|---|---|---|---|---|
| HubSpot deal id | Yes | Text (bàn phím số trên mobile) | Trống, hoặc ?dealId= | Tự do | Bỏ khoảng trắng, không rỗng (BR-01); BE cũng bỏ khoảng trắng | "Thiếu deal id" / "Nhập HubSpot deal id cần kiểm tra." | Always; khoá khi đang tra cứu | - |
| (hiển thị) Timeline — at | - | Datetime | - | YYYY-MM-DD HH:mm:ss giờ máy | - | - | Mỗi dòng | BR-09 |
| (hiển thị) source · event · status · detail | - | Text | - | source: JOB_TRACE / FLOW_PROCESS / CONTRACT / WEBHOOK_<provider> | - | - | Mỗi dòng | - |
| (hiển thị) Chi tiết dòng | - | JSON text | Đóng | JOB_TRACE: steps (at, kind, provider, step, status, message / error, request / response), error, context; webhook: payload | - | - | Khi mở dòng | BR-10, BR-11 |
Filter / Search / Sort (chỉ màn List/Report — xóa nếu không phải) ​
| Loại | Theo field | Kiểu | Default | Notes |
|---|---|---|---|---|
| Filter | source | Nút bật / tắt từng nguồn (multi) | Tất cả bật | Tắt nguồn → nút gạch ngang; đặt lại khi Check deal mới (BR-17) |
| Search | - | - | - | N/A — không có ô tìm |
| Sort | created_at | Cố định | Mới nhất trước | Không đổi được (BR-09) |
| Pagination | - | - | - | N/A — tối đa 500 dòng / nguồn (BR-05) |
Actions ​
A1 - Check ​
| Item | Description |
|---|---|
| Trigger | Bấm "Check", Enter, hoặc mở link ?dealId= |
| Behavior | Kiểm tra BR-01 → ghi deal id lên URL (BR-02) → gọi GET /api/v1/sapp/prod/econtract/deals/<dealId>/timeline. Chỉ đọc DB econtract PRODUCTION (4 SELECT, BR-04); ghi duy nhất là cache Redis mind_keep cho mốc job trace cũ nhất (TTL 1 ngày, NFR-E-03) |
| Success Result | Hiển thị theo UI State Has data / Empty |
Error cases:
| Case | Expected Handling |
|---|---|
| Ô trống | Hộp lỗi "Thiếu deal id", không gọi API |
| Thiếu cấu hình DB | Hộp lỗi "Không tải được timeline econtract" … (13001) |
| Lỗi dựng timeline | Hộp lỗi Failed to build econtract timeline for this deal (13060) |
| Một bảng thiếu / không quyền | Không lỗi — cảnh báo theo bảng (BR-06) |
A2 - Lọc theo nguồn ​
| Item | Description |
|---|---|
| Trigger | Bấm nút nguồn cạnh tiêu đề Timeline |
| Behavior | Ẩn / hiện dòng của nguồn đó (FE, không gọi API) |
| Success Result | Tiêu đề "Timeline (hiện/tổng) — mới nhất ở trên" cập nhật |
Error cases:
| Case | Expected Handling |
|---|---|
| N/A | - |
A3 - Mở chi tiết dòng / step ​
| Item | Description |
|---|---|
| Trigger | Bấm một dòng timeline; trong JOB_TRACE bấm "Xem request/response" của step |
| Behavior | Mở / đóng khối JSON text (FE, không gọi API); step token hiện [hidden] |
| Success Result | Chi tiết hiện ngay dưới dòng |
Error cases:
| Case | Expected Handling |
|---|---|
| Step không có request / response | Không có nút mở chi tiết cho step đó |
Acceptance Criteria của màn M1 ​
AC-M1.1 - Tra cứu chỉ đọc và tóm tắt ​
gherkin
Given deal D có dữ liệu ở job trace, flow process và hợp đồng trên DB econtract prod
When người dùng nhập D và bấm "Check"
Then hệ thống chỉ chạy truy vấn đọc, không đổi dữ liệu prod
And hiện 5 ô đếm Job trace, Flow process, Hợp đồng, Webhook, Step FAIL đúng số dòng mỗi nguồn
And hiện contract id của deal nếu cóMaps to:
- Business Rule: BR-04, BR-15
- Field/Action: A1
AC-M1.2 - Thiếu deal id ​
gherkin
Given ô deal id trống
When người dùng bấm "Check"
Then hiện hộp lỗi "Thiếu deal id" — "Nhập HubSpot deal id cần kiểm tra."
And không có lời gọi APIMaps to:
- Business Rule: BR-01
AC-M1.3 - Deal id trên URL ​
gherkin
Given người dùng tra cứu deal 123 bằng nút "Check"
When lượt tra cứu bắt đầu
Then URL có ?dealId=123
And mở lại / gửi URL đó cho người khác thì màn tự điền 123 và tự tra cứu một lầnMaps to:
- Business Rule: BR-02, BR-03
AC-M1.4 - Thứ tự, múi giờ và lọc nguồn ​
gherkin
Given timeline của deal D có dòng ở nhiều nguồn
When kết quả hiện ra
Then dòng mới nhất ở trên, theo thời điểm tạo
And giờ hiển thị theo máy người xem, kèm "đồng hồ DB econtract: <múi giờ>" và mốc job trace cũ nhất
When người dùng tắt nguồn FLOW_PROCESS
Then các dòng FLOW_PROCESS bị ẩn và tiêu đề đổi thành "Timeline (hiện/tổng)"Maps to:
- Business Rule: BR-09, BR-17
- Field/Action: A2
AC-M1.5 - Cảnh báo giới hạn và bảng thiếu ​
gherkin
Given bảng econtract_webhook_logs không đọc được do thiếu quyền, và job trace của deal có đủ 500 dòng
When người dùng tra cứu
Then hiện cảnh báo "econtract_webhook_logs — User DB không có quyền SELECT trên bảng này"
And cảnh báo "econtract_job_traces — Chạm giới hạn 500 dòng — chỉ hiện các dòng mới nhất"
And các nguồn còn lại vẫn hiển thị bình thườngMaps to:
- Business Rule: BR-05, BR-06
AC-M1.6 - Cảnh báo thiếu contract id / deal cũ hơn trace ​
gherkin
Given deal D chưa có contract id FPT/EFY và không có job trace, dòng cũ nhất của D sớm hơn job trace cũ nhất toàn bảng
When người dùng tra cứu D
Then hiện cảnh báo NO_CONTRACT_ID và PREDATES_TRACE với câu tiếng Việt tương ứngMaps to:
- Business Rule: BR-07, BR-08
AC-M1.7 - Che token và không xuất file ​
gherkin
Given job trace CREATE_CONTRACT có step "STEP 2 - getEfyAccessToken"
When người dùng mở chi tiết step đó
Then request và response hiện "[hidden]"
And mọi payload / steps chỉ hiện dạng text JSON, link_file_pdf không bấm được
And trên màn không có nút xuất fileMaps to:
- Business Rule: BR-10, BR-11
- Field/Action: A3
AC-M1.8 - Checklist mốc và Step FAIL ​
gherkin
Given deal D có flow process CREATE_CONTRACT SUCCESS, job CREATE_CONTRACT SUCCESS, 1 hợp đồng NEW, webhook EFY HUY và chưa có webhook DA_KY
When kết quả hiện ra
Then mốc 1, 2, 3 là Đạt; mốc 4 "Webhook ký hợp đồng" là Lỗi với ghi chú "Nhận EFY HUY"; mốc 5, 6 là Chưa tới
And nếu D có job CANCEL_CONTRACT / EFY_CANCEL_CONTRACT thì hiện "Deal này có job huỷ hợp đồng — xem timeline bên dưới."
And nếu có step FAIL thì hiện bảng "Step FAIL (N)" với job lúc, flow, step, provider, errorMaps to:
- Business Rule: BR-12, BR-13, BR-16
AC-M1.9 - Không có dữ liệu ​
gherkin
Given deal D không có dòng nào ở cả 4 nguồn
When người dùng tra cứu D
Then hiện "Không tìm thấy dữ liệu econtract nào cho deal D."Maps to:
- Business Rule: BR-14
Negative AC / Edge Cases của màn M1 ​
| ID | Tình huống | Hành vi mong đợi |
|---|---|---|
| EC-M1.1 | Mất kết nối DB / lỗi truy vấn không phải thiếu bảng / thiếu quyền | Hộp lỗi 13060; kết quả cũ đã bị xoá |
| EC-M1.2 | Deal có > 500 job trace | Chỉ 500 dòng mới nhất + cảnh báo TRUNCATED (BR-05); cảnh báo bật cả khi đúng 500 dòng |
| EC-M1.3 | Deal id có ký tự đặc biệt | FE mã hoá deal id trong URL API; BE bỏ khoảng trắng; không kiểm tra định dạng — truy vấn thường ra rỗng (BR-14) |
| EC-M1.4 | Mở 2 tab / nhiều người cùng tra cứu | Mỗi lượt quét toàn bảng trên prod (NFR-E-03); không giới hạn tần suất |
| EC-M1.5 | Refresh trang sau khi Check | Deal id còn trên URL → màn tự tra cứu lại (BR-03) |
| EC-M1.6 | Deal có nhiều hợp đồng / cả webhook EFY và FPT | Mọi contract id được gom; webhook nối theo cả hai loại id |
5. Cross-feature AC ​
AC-X.1 - Thấy kết quả của lần Retry ​
gherkin
Given US-E02 vừa Retry deal D và cron econtract đã chạy lại
When người dùng tra cứu D ở Check luồng
Then timeline có thêm dòng JOB_TRACE mới nhất ở trên cho lần chạy lại đóMaps to:
- REL-03 (Be Affected - Cron econtract-payment + EFY/FPT)
AC-X.2 - Thiếu cấu hình env_systems ​
gherkin
Given env_systems thiếu khoá bắt buộc SAPP_PROD_ECONTRACT_DB_*
When người dùng tra cứu
Then hộp lỗi mã 13001Maps to:
- REL-02 (Affects - Cấu hình env_systems)