Giao diện
US-H03: Xem lịch sử thay đổi property trên một bản ghi ​
Thuộc FS: 00-overview.md — SAPP HubSpot tools (sapp.001–004) 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. As-built tại commit
e77c47a. Nguồn: inventory A-04 (và A-11 cho popup lỗi).
| Field | Value |
|---|---|
| US ID | US-H03 |
| Role thực hiện | R1 - Người dùng tool (Assumption — OQ-H-01 về G-01) |
| Phase | As-built (đã triển khai) |
| Priority | N/A — as-built |
| Status | Draft |
| NFR liên quan | NFR-H-01, NFR-H-02, NFR-H-04, NFR-H-05 — xem Overview §5 |
| OQ liên quan | OQ-H-01, OQ-H-04, OQ-H-07, OQ-H-08, OQ-H-09 — xem Overview §6 |
1. US Statement ​
text
As a Người dùng tool [Assumption — OQ-H-01 về G-01]
I want nhập id một deal / ticket / contact và danh sách property, tuỳ chọn một mốc thời gian, để xem lịch sử giá trị từng property và giá trị tại mốc đó
So that [Assumption — OQ-H-04] tái dựng trạng thái bản ghi tại một thời điểm khi điều tra sự cố dữ liệu2. Dependencies & Definition Of Ready ​
N/A — đã triển khai (Mode B). Dependency runtime:
| # | Cần sẵn sàng | Ai cung cấp | Trạng thái |
|---|---|---|---|
| D1 | Tool sapp.002 đang bật / hiển thị / đã mở khoá — US-P02 | Admin CMS | Runtime |
| D2 | env_systems: token của portal đã chọn — US-P04 | Admin CMS | Runtime |
3. Business Rules ​
| ID | Rule | Áp dụng ở | Đã cover bởi (AC) | Nguồn code (Mode B/C) |
|---|---|---|---|---|
| BR-01 | Người dùng chọn portal Prod / Dev (mặc định Prod) và loại object Deal / Ticket / Contact (mặc định Deal); chỉ đọc, không ghi HubSpot | M1 - field Environment, Object type; action A1 | AC-M1.1 | fe/src/ui/components/works/sapp/snapshot-tool.tsx:26-35,45-46; be/libs/services/src/lib/hubspot/hubspot.service.ts:121-135 |
| BR-02 | Phải nhập object id (sau khi cắt khoảng trắng); thiếu → popup "Missing object id" | M1 - action A1 | AC-M1.2 | fe/src/ui/components/works/sapp/snapshot-tool.tsx:94,100-107 |
| BR-03 | Danh sách property tách theo dấu phẩy hoặc xuống dòng, cắt khoảng trắng, bỏ mục rỗng; cần ≥ 1 tên, thiếu → popup "Missing properties". Nếu gọi API trực tiếp với danh sách rỗng → lỗi 12003 | M1 - field Properties; action A1 | AC-M1.3 | fe/src/ui/components/works/sapp/snapshot-tool.tsx:95-98,108-115; be/libs/modules/src/lib/hubspot/common.service.ts:112-117 |
| BR-04 | Mỗi property được yêu cầu luôn có một khối kết quả: tên, bảng Value / Timestamp / Source theo thứ tự HubSpot trả (mới nhất trước); không có bản ghi lịch sử → dòng "No history entries" | M1 - state Has data | AC-M1.1, EC-M1.3 | be/libs/modules/src/lib/hubspot/common.service.ts:152-170; fe/src/ui/components/works/sapp/snapshot-tool.tsx:223-298 |
| BR-05 | Có mốc thời gian: "giá trị tại mốc" = bản ghi lịch sử có thời điểm muộn nhất nhưng không sau mốc; không có bản ghi nào trước mốc → giá trị null | M1 - action A1 | AC-M1.4, AC-M1.5 | be/libs/modules/src/lib/hubspot/common.service.ts:79-94,160-166 |
| BR-06 | Không nhập mốc: "giá trị tại mốc" = bản ghi đầu tiên (mới nhất) trong lịch sử | M1 - action A1 | AC-M1.6 | be/libs/modules/src/lib/hubspot/common.service.ts:160-162; be/libs/services/src/lib/hubspot/hubspot.service.ts:118-119 |
| BR-07 | Dòng lịch sử trùng "giá trị tại mốc" (cùng thời điểm và giá trị) được tô nền và gắn nhãn "target" | M1 - state Has data | AC-M1.4, AC-M1.6 | fe/src/ui/components/works/sapp/snapshot-tool.tsx:258-275 |
| BR-08 | Chỉ đọc bản ghi chưa lưu trữ (archived) | M1 - action A1 | EC-M1.2 | be/libs/services/src/lib/hubspot/hubspot.service.ts:131-134 |
| BR-09 | Object id không tồn tại ở portal → lỗi 12005 "HubSpot object not found"; lỗi HubSpot khác → 12002 "HubSpot API request failed" | M1 - action A1 | EC-M1.1, EC-M1.2 | be/libs/modules/src/lib/hubspot/common.service.ts:127-138 |
| BR-10 | Lỗi gọi API → popup "Failed to fetch property history", nội dung message (code) (NFR-H-04) | M1 - action A1 | EC-M1.1 | fe/src/ui/components/works/sapp/snapshot-tool.tsx:70-84 |
⚠️ Observed (không phải BR): múi giờ của mốc vs cột Timestamp (EC-M1.4, OQ-H-08); nhãn "value at target" đi theo ô Target time hiện tại (EC-M1.5, OQ-H-09); property không tồn tại không báo lỗi riêng (EC-M1.3, OQ-H-07).
4. Design ​
a. Mối liên hệ giữa các màn & User Flow ​
text
[Sidebar "SAPP Common Hubspot Tools" → "Snapshot"] (US-P01, gate US-P02)
↓
[M1: Property snapshot & history]
├─ thiếu object id / property ─→ popup "Missing object id" / "Missing properties"
├─ OK ─────────────────────────→ mỗi property 1 khối lịch sử (+ "value at target" nếu có mốc)
└─ lỗi (12001/12002/12005) ────→ popup "Failed to fetch property history"Link flow chi tiết: N/A — as-built, không có Figma.
b. Chi tiết từng màn ​
Màn M1 - Property snapshot & history ​
| Field | Value |
|---|---|
| Figma frame | N/A |
| Trigger vào màn | Mở /works/sapp/tools/hs-snapshot-property (sidebar "Snapshot") hoặc link chia sẻ |
| Mô tả ngắn | Tiêu đề "Property snapshot & history"; mô tả "Inspect the change history of selected properties for a single deal / ticket / contact. Set a target time to reconstruct the value at a point in time." (fe/src/ui/components/works/sapp/snapshot-tool.tsx:130-144) |
UI States ​
| State | Khi nào | Hiển thị | Figma frame |
|---|---|---|---|
| Default | Vừa vào màn | Environment = Prod, Object type = Deal, ô "Object id" (placeholder "e.g. 1234567890"), "Target time (optional)" (chọn ngày + giờ), ô "Properties (comma or newline separated)" (placeholder "dealstage, amount"), nút "Check snapshot" | N/A |
| Loading | Đang gọi API | Nút "Checking…"; mọi ô bị khoá (NFR-H-05) | N/A |
| Has data | API trả kết quả | Mỗi property 1 khối: tên; nhãn "value at target: <giá trị hoặc null> (<timestamp>)" nếu ô Target time đang có giá trị; bảng Value / Timestamp / Source | N/A |
| Empty | Property không có lịch sử | Trong khối của property: "No history entries". (Dòng "No history returned." chỉ hiện khi kết quả không có property nào — với BR-04 thực tế khó xảy ra từ UI) | N/A |
| Error | Thiếu input / API lỗi | Popup lỗi; vùng kết quả trống | N/A |
| Disabled | Đang gọi API | Như Loading | N/A |
Fields ​
| Field | Required | Type | Default | Format | Validation | Error Message | Visibility | Depends On |
|---|---|---|---|---|---|---|---|---|
| Environment | Yes | Dropdown: Prod / Dev | Prod | — | BR-01 | — | Always | — |
| Object type | Yes | Dropdown: Deal / Ticket / Contact | Deal | — | BR-01 | — | Always | — |
| Object id | Yes | Text | Trống | Cắt khoảng trắng | BR-02 | "Missing object id" — "Please enter the HubSpot object id." | Always | — |
| Target time | No | Date + time | Trống (= "hiện tại") | Giờ theo trình duyệt, gửi đi dạng ISO (UTC) | — | — | Always | Có giá trị → hiện nhãn "value at target" |
| Properties | Yes | Textarea (2 dòng) | Trống | Phân tách bằng dấu phẩy hoặc xuống dòng | BR-03 | "Missing properties" — "Enter at least one property internal name." | Always | — |
| Kết quả: Value / Timestamp / Source | — | Readonly table | — | Timestamp hiển thị nguyên chuỗi HubSpot trả; Source trống → "—" | — | — | Sau khi tra thành công | BR-04, BR-07 |
Filter / Search / Sort ​
N/A — không có lọc / sắp xếp trên màn; thứ tự dòng lịch sử theo HubSpot trả (BR-04).
Actions ​
A1 - Check snapshot ​
| Item | Description |
|---|---|
| Trigger | Bấm "Check snapshot" |
| Behavior | Kiểm BR-02, BR-03 → xoá kết quả cũ → gọi POST /api/v1/sapp/{prod|dev}/hubspot/{deals|tickets|contacts}/:objectId/property-history với danh sách property và mốc (nếu có). BE đọc bản ghi + lịch sử property từ HubSpot portal đã chọn, tính "giá trị tại mốc" (BR-05, BR-06). Không ghi hệ thống nào |
| Success Result | Mỗi property một khối kết quả (BR-04, BR-07) |
Error cases:
| Case | Expected Handling |
|---|---|
| Thiếu object id | Popup "Missing object id" (BR-02) |
| Không có property hợp lệ | Popup "Missing properties" (BR-03) |
| Object id không tồn tại | Popup "Failed to fetch property history" — "HubSpot object not found (12005)" (BR-09) |
| Lỗi HubSpot khác | Popup "Failed to fetch property history" — "HubSpot API request failed (12002)" (BR-09) |
| Token chưa cấu hình | Popup … "(12001)" (NFR-H-02) |
Acceptance Criteria của màn M1 ​
AC-M1.1 - Xem lịch sử nhiều property ​
gherkin
Given deal 1234567890 ở portal prod có lịch sử cho "dealstage" và "amount"
When người dùng nhập Object id = "1234567890", Properties = "dealstage,\n amount ," và bấm "Check snapshot"
Then hệ thống tra 2 property "dealstage" và "amount" (đã tách, cắt khoảng trắng, bỏ mục rỗng)
And hiện 2 khối, mỗi khối có bảng Value / Timestamp / Source, dòng mới nhất ở trên
And không có dữ liệu HubSpot nào bị thay đổiMaps to:
- Business Rule: BR-01, BR-03, BR-04
- Field/Action: Object id, Properties / A1
AC-M1.2 - Thiếu object id ​
gherkin
Given ô Object id trống
When người dùng bấm "Check snapshot"
Then hiện popup "Missing object id" — "Please enter the HubSpot object id." và không gọi APIMaps to:
- Business Rule: BR-02
AC-M1.3 - Thiếu property ​
gherkin
Given Object id có giá trị, ô Properties chỉ chứa " , \n "
When người dùng bấm "Check snapshot"
Then hiện popup "Missing properties" — "Enter at least one property internal name." và không gọi APIMaps to:
- Business Rule: BR-03
AC-M1.4 - Giá trị tại mốc thời gian ​
gherkin
Given "dealstage" có lịch sử: "closedwon" lúc 2026-09-20T03:00Z, "presentation" lúc 2026-09-10T03:00Z
When người dùng đặt Target time tương ứng 2026-09-15T00:00Z và bấm "Check snapshot"
Then khối "dealstage" hiện "value at target: presentation (2026-09-10T03:00Z…)"
And dòng "presentation" được tô nền và gắn nhãn "target"Maps to:
- Business Rule: BR-05, BR-07
AC-M1.5 - Mốc trước mọi lịch sử ​
gherkin
Given lịch sử sớm nhất của "amount" là 2026-09-10
When người dùng đặt Target time trước 2026-09-10 và bấm "Check snapshot"
Then khối "amount" hiện "value at target: null" và không dòng nào gắn nhãn "target"Maps to:
- Business Rule: BR-05
AC-M1.6 - Không nhập mốc ​
gherkin
Given ô Target time trống
When người dùng bấm "Check snapshot"
Then không hiện nhãn "value at target"
And dòng đầu tiên (mới nhất) của mỗi property vẫn được tô nền và gắn nhãn "target" (vì giá trị tại mốc = bản mới nhất)Maps to:
- Business Rule: BR-06, BR-07
Negative AC / Edge Cases của màn M1 ​
| ID | Tình huống | Hành vi mong đợi |
|---|---|---|
| EC-M1.1 | Object id không có ở portal đã chọn (vd id prod tra trên Dev) | Popup "Failed to fetch property history" — "HubSpot object not found (12005)" (BR-09) |
| EC-M1.2 | Bản ghi đã bị lưu trữ (archived) | Chỉ đọc bản ghi chưa lưu trữ (BR-08) → theo phản hồi HubSpot, dự kiến 12005 — suy từ code, chưa chạy thử |
| EC-M1.3 | Một tên property không tồn tại | ⚠️ Observed — hành vi hiện tại theo code: không báo lỗi riêng, khối của tên đó hiện "No history entries" (BR-04). Cần chạy thật để xác nhận — OQ-H-07 |
| EC-M1.4 | Người dùng ở VN (+7) đặt Target time | ⚠️ Observed — mốc được hiểu theo giờ trình duyệt rồi đổi sang ISO (UTC), còn cột Timestamp hiện nguyên chuỗi UTC HubSpot trả, không đổi múi giờ (fe/src/ui/components/works/sapp/snapshot-tool.tsx:37-40,123-124,278) → dễ lệch 7 giờ khi so bằng mắt — OQ-H-08 |
| EC-M1.5 | Sau khi có kết quả, người dùng sửa hoặc xoá ô Target time mà không bấm lại | ⚠️ Observed — kết quả không bị xoá; nhãn "value at target" hiện / ẩn theo ô hiện tại nhưng giá trị trong nhãn vẫn là của lần tra trước (fe/src/ui/components/works/sapp/snapshot-tool.tsx:232-245) — OQ-H-09 |
| EC-M1.6 | Danh sách property có tên trùng | Tên trùng được gửi nguyên; kết quả là map theo tên nên chỉ còn một khối cho tên đó — suy từ code (be/libs/modules/src/lib/hubspot/common.service.ts:157-168), chưa chạy thử |
5. Cross-feature AC ​
AC-X.1 - Tool bị gate chặn ​
gherkin
Given tool sapp.002 đang bị ẩn / tắt / khoá mã bí mật
When người dùng mở /works/sapp/tools/hs-snapshot-property
Then hành vi theo gate của nền tảng (US-P02)
And API property-history vẫn gọi trực tiếp được (NFR-P-01)Maps to:
- REL-H-01 (Affects - Hub + gate tool)
AC-X.2 - Token theo môi trường ​
gherkin
Given token của portal đã chọn chưa cấu hình (US-P04)
When người dùng bấm "Check snapshot"
Then nhận lỗi 12001Maps to:
- REL-H-02 (Affects - Cấu hình env_systems)