Skip to content

US-S09: Đồng bộ lại qua ticket HubSpot (luồng 5) ​

Thuộc FS: 00-overview.md — SAPP-26297 Chuyển nhượng học viên (tool sapp.011) 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.

Cơ chế chạy bước, tự chấm, xác nhận GHI, ghi ngược fixture → US-S01. Câu SQL hs5, hs5s → US-S02 §4. Đồng bộ enrollment và logic hoàn tác thuộc hubspot-service của SAPP (SAPP-28978), không do mind_keep cài.

FieldValue
US IDUS-S09
Role thực hiệnR1 - Người dùng tool — Assumption (OQ về G-01 → OQ-S-01)
PhaseAs-built (đã triển khai @ e77c47a)
PriorityN/A — as-built
StatusĐã triển khai — chưa chạy được end-to-end (guard "Ticket đã được xử lý" phía SAPP chặn phần hoàn tác; pipeline/stage kích hoạt đồng bộ chờ SAPP — OQ-S-10) · Draft
NFR liên quanNFR-S-01, NFR-S-02 — xem Overview §5
OQ liên quanOQ-S-01, OQ-S-02, OQ-S-06, OQ-S-08, OQ-S-10, OQ-S-12, OQ-S-14, OQ-S-19 — xem Overview §6

1. US Statement ​

text
As a Người dùng tool  [Assumption — OQ-S-01]
I want tạo contact + ticket HubSpot test, kéo ticket sang Close success để kích hoạt đồng bộ, rồi xoá mã lớp khỏi ticket
       và đồng bộ lại, đọc lại trạng thái đồng bộ và dòng enrollment trong DB Ops
So that kiểm SAPP-28978: "CX xóa mã lớp khỏi ticket rồi đồng bộ lại → BE hoàn tác đúng những gì lần trước đã làm cho mã đó"
        (tóm tắt luồng trên màn; mục đích nghiệp vụ rộng hơn là [Assumption] — OQ-S-18)

2. Dependencies & Definition Of Ready ​

N/A — đã triển khai. Dependency runtime (đang thiếu → chưa chạy được end-to-end):

#Cần sẵn sàngAi cung cấpTrạng thái
D1Pipeline enrollment + stage "Close success" mà hubspot-service lắng nghe (dev có 21 pipeline, nhiều cái có stage tên "Close success")SAPP⏸ Chờ SAPP câu 4 — OQ-S-10
D2SAPP mở / nới guard "Ticket đã được xử lý" (hoặc có bản build bỏ guard trên dev)SAPP⏸ Chờ SAPP câu 5 — OQ-S-10
D3Ý nghĩa cột user_hubspot_enrollments (xoá mềm hay xoá hẳn; giá trị sync_status_hubspot; case 5.5 dựa vào gì)SAPP⏸ Chờ SAPP câu 6 — OQ-S-10
D4Credentials HubSpot trong env_systems của môi trường chọn (thiếu ⇒ lỗi cấu hình HubSpot)Admin CMS—

3. Business Rules ​

IDRuleÁp dụng ởĐã cover bởi (AC)Nguồn code (Mode B/C)
BR-01Bước tạo contact gửi email = {contact_email}, firstname = "Test", lastname = "SAPP-26297", lop_dang_ky (mã lớp tách bằng dấu chấm phẩy); đạt khi response có contact.id và ghi ngược contact_idM1 - bước tạo contactAC-M1.1fe/src/ui/components/works/sapp/sapp-26297-flows.ts:1530-1551
BR-02Email đã tồn tại trên HubSpot ⇒ dùng lại contact đó và ghi đè các property gửi lên; response báo reused; lỗi khác ⇒ lỗi tạo HubSpot của mind_keepM1 - bước tạo contactAC-M1.2be/libs/modules/src/lib/hubspot/common.service.ts:607-661
BR-03Bước tạo ticket gửi: tiêu đề "SAPP-26297 test <ngày hôm nay>", pipeline, stage mở, owner, phân loại yêu cầu mặc định "Bảo lưu khoá học", lớp đăng ký chính = mã lớp cũ, lớp mới = mã 1, mã 2 (tách bằng dấu phẩy), khu vực; gắn contact vào ticket; đạt khi có id và ghi ngược ticket_id; HubSpot từ chối ⇒ lỗi 12006 kèm câu từ chốiM1 - bước tạo ticketAC-M1.1sapp-26297-flows.ts:1553-1593 · be/libs/modules/src/lib/sapp/sapp-26297.common.service.ts:244-254 · be/libs/constants/src/lib/hubspot/hubspot.constants.ts:57
BR-04Bước "Kéo ticket sang Close success" sửa stage của ticket = {hs_stage_close_id}; đạt khi stage đọc lại = giá trị đó. Theo ghi chú code, đổi stage là thứ kích hoạt đồng bộ thật phía SAPPM1 - bước kéo stageAC-M1.1, AC-M1.3sapp-26297-flows.ts:1595-1613 · sapp-26297.common.service.ts:256
BR-05Bước đọc ticket chấm trạng thái đồng bộ LMS của ticket = SYNC_SUCCESS (A.1); ở case B và 5.x không có check; trạng thái trống = đồng bộ chưa xong, chờ rồi chạy lạiM1 - bước đọc ticketAC-M1.1, AC-M1.3sapp-26297-flows.ts:1615-1630
BR-06Case B (xác nhận blocker): bỏ mã lớp mới 1 khỏi lớp mới (check lớp mới = mã 2), kéo ticket ra stage mở, kéo lại Close success, đọc ticket, SQL hs5; hướng dẫn: DB không đổi + log hubspot-service có "Ticket đã được xử lý" = đã trúng guardM1 - case BAC-M1.3sapp-26297-flows.ts:1710-1751
BR-07Case 5.1–5.8 (hoàn tác khi xoá mã lớp) đều gắn cảnh báo BLOCKED; bước: [SQL hs5s dựng, ở 5.3] · hướng dẫn · sửa mã lớp (không check) · kéo lại Close success · đọc ticket (không check) · SQL hs5; kết quả DB / mail kiểm bằng mắtM1 - case 5.1 → 5.8AC-M1.4sapp-26297-flows.ts:1632-1678,1752-1815
BR-08SQL hs5 câu 1 đọc dòng enrollment của ticket và ghi ngược hs_user_id từ cột user_idM1 - SQL hs5AC-M1.1sapp-26297-flows.ts:1632-1643 · be/libs/constants/src/lib/sapp/sapp-26297-sql.constants.ts:271-294

4. Design &ZeroWidthSpace;

a. Mối liên hệ giữa các màn & User Flow &ZeroWidthSpace;

text
[Tab "5 · HubSpot đồng bộ lại"]
  5.0: [pipeline (đọc)] → [owner (đọc)] → tester chép id vào fixture → [tạo contact (GHI HubSpot)] → contact_id
  A.1: [tạo ticket (GHI)] → ticket_id → [kéo Close success (GHI) ⇒ SAPP đồng bộ] → [đọc ticket: SYNC_SUCCESS] → [SQL hs5]
  B:   [bỏ MA_LOP_MOI_1 (GHI)] → [ra stage mở (GHI)] → [vào lại Close (GHI)] → [đọc ticket] → [SQL hs5] → đọc: trúng guard
  5.1–5.8: [(SQL hs5s)] → [sửa mã lớp (GHI)] → [vào lại Close (GHI)] → [đọc ticket] → [SQL hs5]   ⏸ BLOCKED

Ticket HubSpot: [stage mở] --(sửa stage = Close success)--> đồng bộ SAPP --> trạng thái đồng bộ = SYNC_SUCCESS | SYNC_FAILURE

b. Chi tiết từng màn &ZeroWidthSpace;

Màn M1 - Tab "5 · HubSpot đồng bộ lại" &ZeroWidthSpace;

FieldValue
Figma frameN/A
Trigger vào mànBấm tab "5 · HubSpot đồng bộ lại"
Mô tả ngắnTóm tắt: "SAPP-28978. CX xóa mã lớp khỏi ticket rồi đồng bộ lại → BE hoàn tác đúng những gì lần trước đã làm cho mã đó. ⛔ Phần end-to-end đang BLOCKED bởi guard 'Ticket đã được xử lý'. Tool dựng được đồng bộ lần đầu (A.1) và xác nhận blocker (B)." 11 case
UI States &ZeroWidthSpace;
StateKhi nàoHiển thịFigma frame
DefaultVào tabTóm tắt + 11 case đóng; fixture hiện ô HubSpot của luồng 5N/A
LoadingBước đang chạyTheo US-S01N/A
Has dataBước chạy xong✓/✗ + "x/y đạt"; B và 5.1–5.8 có khung cảnh báo BLOCKEDN/A
EmptyBước pipeline / owner / sửa mã lớp / đọc ticket ở 5.x không có checkChỉ response thôN/A
ErrorHubSpot từ chối / thiếu cấu hìnhHộp đỏ "Không gọi được Ops qua API: <status> <mã> …"N/A
DisabledFixture thiếu contact_id / ticket_id / stageNút khoá "Chưa điền: …"N/A
Fields &ZeroWidthSpace;
FieldRequiredTypeDefaultFormatValidationError MessageVisibilityDepends On
email (contact)YesText{contact_email}emailUS-S01 BR-10"Chưa điền: …"Bước tạo contactFixture
firstname, lastnameNoText"Test", "SAPP-26297"—Trống ⇒ không gửi (xem EC-M1.1)—Bước tạo contact—
lop_dang_kyNoText{class_code_old}mã lớp tách ;——Bước tạo contactFixture
contact_id (gắn ticket)YesText{contact_id}id HubSpotUS-S01 BR-10"Chưa điền: …"Bước tạo ticketGhi ngược từ tạo contact
subjectNoText"SAPP-26297 test {today}"{today} = ngày giờ VN YYYY-MM-DD——Bước tạo ticket—
hs_pipeline, hs_pipeline_stage, hubspot_owner_idYesText{hs_pipeline_id}, {hs_stage_open_id}, {hs_owner_id}id HubSpotUS-S01 BR-10"Chưa điền: …"Bước tạo ticketTester chép từ 5.0
phan_loai_yeu_cau_dich_vuNoText"Bảo lưu khoá học"———Bước tạo ticket—
lop_dang_ki_chinh, lop_moiNoText{class_code_old}, {class_code_1},{class_code_2}mã lớp tách ,Trống ⇒ không gửi (xem EC-M1.1)—Bước tạo / sửa ticketFixture
khu_vucNoText{khu_vuc}từ thứ 2 là chương trình——Bước tạo ticketFixture
ticket_id (chọn bản ghi)YesText{ticket_id}id HubSpotUS-S01 BR-10"Chưa điền: …"Bước sửa / đọc ticketGhi ngược từ tạo ticket
Actions &ZeroWidthSpace;
A1 - Chạy các bước của một case &ZeroWidthSpace;
ItemDescription
TriggerMở case, chạy từng bước (US-S01)
BehaviorThao tác dùng: pipeline, owner, đọc ticket (đọc); tạo contact, tạo ticket, sửa ticket (GHI HubSpot); SQL hs5 (đọc), hs5s (GHI DB Ops). Ghi vào: HubSpot theo môi trường chọn — dev = portal HubSpot dev; staging = portal HubSpot PROD (xem cảnh báo dưới); DB Ops dev/staging (SQL). Kéo stage kích hoạt đồng bộ thật phía SAPP
Success ResultCác check đạt theo bảng case

⚠️ Ghi PROD — Hành vi hiện tại: route staging/sapp-26297/hubspot/* dùng môi trường HubSpot "staging", và cấu hình nền tảng cố ý cho "staging" dùng lại credentials portal prod (không có portal staging riêng) (be/apps/api/src/sapp/sapp-26297.controller.ts:431,498,540 · be/libs/constants/src/lib/hubspot/hubspot.constants.ts:19-26). Vì vậy ở tab staging, tạo contact (kể cả ghi đè contact thật trùng email — BR-02), tạo ticket và kéo stage ghi vào HubSpot production, trái với banner "Không có route production" — OQ-S-19.

Error cases:

CaseExpected Handling
HubSpot từ chối tạo ticketHộp đỏ mã 12006 + câu từ chối (BR-03)
Thiếu credentials HubSpot của môi trườngHộp đỏ lỗi cấu hình HubSpot (nền tảng)
Đọc ticket khi đồng bộ chưa xongCheck SYNC_SUCCESS ✗, trạng thái trống — chờ rồi chạy lại

Bảng case (11 case):

Mã caseTênBướcKỳ vọng tool chấm
5.0Chuẩn bị HubSpotpipeline · owner · tạo contact (lop_dang_ky = mã lớp cũ)Có contact.id (ghi contact_id); pipeline/owner không chấm — tester chép id
A.1Đồng bộ lần đầu (Bảo lưu)tạo ticket · kéo Close · đọc ticket · SQL hs5Có id (ghi ticket_id) · stage = close · SYNC_SUCCESS; 3 dòng enrollment (mã cũ → RESERVED, 2 mã mới → REASSIGNED) đọc SQL
BXác nhận blocker (đồng bộ lần 2)sửa lớp mới = mã 2 · ra stage mở · vào lại Close · đọc ticket · SQL hs5 · hướng dẫnlop_moi = mã 2 · stage = close; hiện tại DB không đổi + log "Ticket đã được xử lý" (đọc tay)
5.1Bỏ mã lớp cũ khỏi lớp đăng ký chínhhướng dẫn "để trống" · sửa mã lớp · vào lại Close · đọc · SQL hs5BLOCKED; kỳ vọng (văn bản): reverted, lớp cũ + Foundation về NORMAL, xoá dòng enrollment
5.2Bỏ mã mới 1 (lớp chưa khai giảng)như trênBLOCKED; (văn bản) reverted, học viên bị gỡ khỏi lớp, xoá dòng enrollment
5.3Bỏ mã mới 2 (đã khai giảng + có tiến độ)SQL hs5s (GHI) · như trênBLOCKED; (văn bản) manual, giữ học viên, mail E05, ticket vẫn SYNC_SUCCESS
5.4Học viên đã sang trạng thái khác ở lớp cũnhư trên (dựng bằng hs5s câu 2)BLOCKED; (văn bản) failed, không ghi đè, giữ dòng enrollment, mail E03, SYNC_FAILURE
5.5Mã lớp chưa từng được tạo trên LMSnhư trênBLOCKED; (văn bản) reverted, chỉ xoá dòng enrollment — cột guide dùng không có trên dev
5.6Học viên đang TRANSFERED_TO ở lớp mớinhư trên (dựng bằng hs5s câu 3)BLOCKED; (văn bản) failed, mail E03
5.7Xoá toàn bộ mã lớphướng dẫn "để trống cả hai" · như trênBLOCKED; (văn bản) tất cả hoàn tác, không báo thành công giả
5.8Xoá 2 mã, 1 thành công 1 lỗinhư trênBLOCKED; (văn bản) mã ok reverted, mã lỗi failed, không rollback mã ok, SYNC_FAILURE
Acceptance Criteria của màn M1 &ZeroWidthSpace;
AC-M1.1 - Đồng bộ lần đầu (5.0 + A.1) &ZeroWidthSpace;
gherkin
Given fixture có contact_email, class_code_old, class_code_1, class_code_2, hs_pipeline_id, hs_stage_open_id,
      hs_stage_close_id, hs_owner_id, khu_vuc
When người dùng chạy "Tạo contact học viên" và xác nhận GHI
Then response có contact.id và fixture contact_id được ghi
When người dùng chạy "Tạo ticket Bảo lưu"
Then ticket được tạo ở stage mở, gắn contact, response có id và fixture ticket_id được ghi
When người dùng chạy "Kéo ticket sang Close success"
Then properties.hs_pipeline_stage = hs_stage_close_id
When người dùng chạy "Đọc lại ticket" sau khi đồng bộ xong
Then properties.trang_thai_dong_bo_lms = "SYNC_SUCCESS"
And SQL hs5 câu 1 ghi hs_user_id vào fixture

Maps to:

  • Business Rule: BR-01, BR-03, BR-04, BR-05, BR-08
AC-M1.2 - Contact trùng email &ZeroWidthSpace;
gherkin
Given HubSpot đã có contact với email = contact_email
When người dùng chạy bước tạo contact
Then tool dùng lại contact đó (reused), ghi đè firstname, lastname, lop_dang_ky bằng giá trị gửi lên
And fixture contact_id = id contact cũ

Maps to:

  • Business Rule: BR-02
AC-M1.3 - Xác nhận blocker (case B) &ZeroWidthSpace;
gherkin
Given A.1 đã đồng bộ SYNC_SUCCESS
When người dùng chạy "Xóa MA_LOP_MOI_1 khỏi lop_moi"
Then properties.lop_moi = class_code_2
When người dùng chạy "Kéo ticket ra khỏi Close success" rồi "Kéo lại vào Close success"
Then properties.hs_pipeline_stage = hs_stage_close_id
And bước đọc ticket không có check; tester đối chiếu SQL hs5 và log hubspot-service theo hướng dẫn

Maps to:

  • Business Rule: BR-04, BR-05, BR-06
AC-M1.4 - Case hoàn tác bị chặn &ZeroWidthSpace;
gherkin
Scenario Outline: case 5.x
  When người dùng mở case <case>
  Then hiện khung cảnh báo "BLOCKED: guard 'Ticket đã được xử lý' ..."
  And các bước sửa mã lớp và đọc ticket không có check tự động
  And "Kỳ vọng" hiển thị văn bản <kỳ vọng> để tester kiểm bằng mắt

  Examples:
    | case | kỳ vọng                                                   |
    | 5.1  | reverted, lớp cũ + Foundation về NORMAL                    |
    | 5.2  | reverted, học viên bị gỡ khỏi lớp                          |
    | 5.3  | manual, giữ học viên, mail E05                             |
    | 5.4  | failed, giữ dòng enrollment, mail E03, SYNC_FAILURE        |
    | 5.5  | reverted, chỉ xoá dòng enrollment                         |
    | 5.6  | failed, mail E03                                          |
    | 5.7  | tất cả hoàn tác, không báo thành công giả                  |
    | 5.8  | mã ok reverted, mã lỗi failed, SYNC_FAILURE               |

Maps to:

  • Business Rule: BR-07
Negative AC / Edge Cases của màn M1 &ZeroWidthSpace;
IDTình huốngHành vi mong đợi
EC-M1.1⚠️ Observed — 5.1, 5.7 "để trống" lớp đăng ký chính / lớp mớiHành vi hiện tại: ô trống bị bỏ khỏi payload ⇒ request sửa ticket không chứa property đó ⇒ HubSpot giữ nguyên giá trị cũ; case không dựng được như mô tả (API mind_keep coi chuỗi rỗng là "xoá property" nhưng màn không gửi được chuỗi rỗng) (sapp-26297-step-call.tsx:110-116 · sapp-26297-flows.ts:1757-1758,1808 · hubspot/common.service.ts:947-950) — OQ-S-02
EC-M1.2⚠️ Observed — bước pipeline / ownerHành vi hiện tại: không chấm, không tự ghi fixture; tester tự tìm trong JSON (dev có 21 pipeline) và chép tay (sapp-26297-flows.ts:1512-1528) — OQ-S-08
EC-M1.3⚠️ Observed — route đọc contactHành vi hiện tại: route đọc contact có nhưng không bước nào dùng — OQ-S-08
EC-M1.4⚠️ Ghi PROD — chạy ở tab stagingHành vi hiện tại: mọi thao tác HubSpot ghi vào portal HubSpot production (xem cảnh báo ở A1) — OQ-S-19
EC-M1.5Mã lớp đăng ký chính không có trong lop_dang_ky của contactTheo ghi chú code: đồng bộ dừng với E01 (dùng có chủ đích ở US-S10 case 6.1)
EC-M1.6Chạy lại A.1 trên cùng ticketTool gửi lại; kết quả phụ thuộc guard phía SAPP (trúng guard như case B)

5. Cross-feature AC &ZeroWidthSpace;

AC-X.1 - Kích hoạt đồng bộ thật phía SAPP &ZeroWidthSpace;

gherkin
Given ticket đang ở stage mở và gắn contact
When người dùng kéo ticket sang Close success của pipeline enrollment
Then hubspot-service của SAPP nhận sự kiện và ghi trạng thái đồng bộ ngược lên ticket (theo ghi chú code; pipeline nào kích hoạt chờ SAPP câu 4)

Maps to:

  • REL-07 (Affects - Hệ thống SAPP)
  • REL-06 (Affects - Dịch vụ HubSpot dùng chung)