Skip to content

US-I02: Tạo contact test (trùng email → cập nhật contact cũ) ​

Thuộc FS: 00-overview.md — SAPP-24395 Contact / Deal instances & Bulk product creation 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 — suy từ code, chưa chạy thử.

FieldValue
US IDUS-I02
Role thực hiệnR1 - Người dùng tool (Assumption — OQ-I-16 về G-01)
PhaseAs-built (đã triển khai)
PriorityN/A — as-built
StatusDraft
NFR liên quanNFR-I-01, NFR-I-04, NFR-I-05, NFR-I-06, NFR-I-07 — xem Overview §5
OQ liên quanOQ-I-02, OQ-I-05, OQ-I-16, OQ-I-18 — xem Overview §6

Nguồn inventory: A-03, A-04. Ghi: HubSpot dev · HubSpot PROD (qua tab "Staging").

1. US Statement ​

text
As a Người dùng tool (Assumption — OQ-I-16)
I want nhập thông tin một contact (Họ tên bắt buộc, các trường khác tuỳ chọn) và tạo nó trên HubSpot của môi trường đang chọn
So that [Assumption] tôi có contact để gắn vào deal test theo case (US-I03)

2. Dependencies & Definition Of Ready ​

N/A — đã triển khai (Mode B). Dependency runtime:

#Cần sẵn sàngAi cung cấpTrạng thái
D1Token HubSpot SAPP_DEV_HUBSPOT_ACCESS_TOKEN / SAPP_PROD_HUBSPOT_ACCESS_TOKEN trong env_systems (US-P04)Admin CMSN/A — runtime
D2Route đọc định nghĩa property HubSpot (dựng widget) — US-H01BEN/A — runtime

3. Business Rules ​

IDRuleÁp dụng ởĐã cover bởi (AC)Nguồn code (Mode B/C)
BR-01Họ tên là bắt buộc: trống (sau khi bỏ khoảng trắng) thì chặn ngay trên màn với "Thiếu thông tin" / "Họ tên là bắt buộc."; API cũng từ chối nếu thiếuM1 - field Họ tên; A1AC-M1.2fe/src/ui/components/works/sapp/sapp-24395-tool.tsx:277-281; be/libs/interface/src/lib/dto/sapp/sapp-instance.dto.ts:13-14
BR-02Chỉ các trường có giá trị (sau khi bỏ khoảng trắng đầu cuối) mới được gửi sang HubSpot; trường bỏ trống không ghi gìM1 - A1AC-M1.1fe/src/ui/components/works/sapp/sapp-24395-tool.tsx:283-288; be/apps/api/src/sapp/sapp.controller.ts:2094-2108
BR-03Mỗi trường trên form ghi vào đúng một thuộc tính contact HubSpot: Họ tên → "[TVTS] Họ tên"; Email → email; Số điện thoại → SĐT marketing; Địa chỉ → địa chỉ; Tỉnh/Thành phố → khu vực sinh sống; Ngày sinh → D.O.B (tên nội bộ ở bảng Fields)M1 - FieldsAC-M1.1be/apps/api/src/sapp/sapp.controller.ts:2094-2108, :1731-1732; fe/src/ui/components/works/sapp/sapp-24395-tool.tsx:64-93
BR-04Kiểu ô nhập (text / chọn / ngày …) và danh sách lựa chọn của mỗi trường được dựng theo định nghĩa property trên HubSpot của môi trường đang chọnM1 - FieldsAC-M1.4fe/src/ui/components/works/sapp/sapp-24395-tool.tsx:322-334; fe/src/ui/components/works/sapp/hubspot-property-field.tsx:246-400
BR-05Môi trường ghi theo tab: Dev → portal HubSpot dev; Staging → portal HubSpot production (dùng đúng credential prod; code ghi chú là chủ đích vì không có portal staging riêng); Prod → portal production (chỉ qua API, tab bị tắt)M1 - A1AC-M1.3be/libs/constants/src/lib/hubspot/hubspot.constants.ts:19-26; be/libs/modules/src/lib/hubspot/common.service.ts:47-58
BR-06Tạo thành công: contact (id + tên) được thêm vào cuối danh sách của môi trường; tên hiển thị lấy từ Họ tên HubSpot trả về, không có thì lấy Họ tên đã nhập; form được xoá trắng; popup "Đã tạo contact instance" — "Contact "<tên>" (id: <id>) đã được tạo trong portal <env>."M1 - A1AC-M1.1be/libs/modules/src/lib/sapp/common.service.ts:1547-1582; fe/src/ui/components/works/sapp/sapp-24395-tool.tsx:257-272
BR-07HubSpot từ chối vì lý do khác email trùng → lỗi 12006 "Failed to create HubSpot object"; lỗi khác → 13007 "Failed to create SAPP contact instance"; màn hiện popup "Tạo contact instance thất bại"M1 - A1AC-M1.5be/libs/modules/src/lib/hubspot/common.service.ts:639-651; be/libs/modules/src/lib/sapp/common.service.ts:1572-1581; fe/src/ui/components/works/sapp/sapp-24395-tool.tsx:260

Không phải BR (⚠️ Observed → OQ): email trùng → cập nhật đè contact có sẵn (inventory R-04 → OQ-I-05); contact dùng lại bị thêm lặp vào danh sách và popup vẫn nói "đã được tạo" (OQ-I-18); tab Staging ghi vào prod (OQ-I-02).

4. Design &ZeroWidthSpace;

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

text
[M1: mục "1. Tạo HubSpot contact instance" (trong màn US-I01)]
  ↓ nhập form, bấm "Tạo contact"
  ├─ Họ tên trống ─────────────→ popup "Thiếu thông tin", ở lại M1
  ├─ HubSpot tạo mới OK ────────→ popup "Đã tạo contact instance", contact vào danh sách
  ├─ HubSpot báo email trùng ───→ ⚠️ cập nhật contact cũ → popup như tạo mới (OQ-I-05, OQ-I-18)
  └─ lỗi khác ──────────────────→ popup "Tạo contact instance thất bại"

Link flow chi tiết: N/A.

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

Màn M1 - Form "1. Tạo HubSpot contact instance" &ZeroWidthSpace;

FieldValue
Figma frameN/A
Trigger vào mànMở màn Contact / Deal instances (US-I01), chọn tab môi trường
Mô tả ngắnForm 6 trường (lưới 2 cột), mô tả "Nhập thông tin contact rồi tạo trong portal <env>. Chỉ Họ tên là bắt buộc — các trường khác tùy chọn. Chỉ id & name được lưu lại (không lưu email/phone)." Nút "Tạo contact" + "Tải lại"
UI States &ZeroWidthSpace;
StateKhi nàoHiển thịFigma frame
DefaultVừa vào6 ô trống; "Họ tên *" có dấu saoN/A
LoadingĐang tạoNút đổi "Đang tạo…"; các ô và nút bị khoáN/A
Has dataTạo xongPopup thành công; form trắng; contact mới ở cuối danh sáchN/A
Empty—N/A — form luôn hiệnN/A
ErrorThiếu Họ tên / API lỗiPopup lỗi (BR-01 / BR-07); dữ liệu đã nhập được giữN/A
DisabledĐang tạoNhư LoadingN/A
Fields &ZeroWidthSpace;
FieldRequiredTypeDefaultFormatValidationError MessageVisibilityDepends On
Họ tên * (HubSpot leadin_h_tnipa7107b_39faf8acbcd97440649d6d3d99a5b929)YesTheo định nghĩa HubSpot (BR-04)RỗngPlaceholder "Nguyễn Văn A"BR-01"Họ tên là bắt buộc."AlwaysTab môi trường
Email (email)NoTheo HubSpotRỗngPlaceholder "a@example.com"Không validate định dạng ở tool; HubSpot tự kiểmLỗi HubSpot → BR-07Always—
Số điện thoại (mkt__phone_number)NoTheo HubSpotRỗngPlaceholder "0356020000"Không validate ở tool—Always—
Địa chỉ (dia_chi)NoTheo HubSpotRỗngPlaceholder "123 Đường ABC"——Always—
Tỉnh / Thành phố (khuvucsinhsong)NoTheo HubSpot (có thể là danh sách chọn)RỗngPlaceholder "Hà Nội"——Always—
Ngày sinh (d_o_b)NoTheo HubSpotRỗng———Always—

CCCD / Hộ chiếu không nằm trên contact — được ghi lên deal (US-I03 BR-06).

Filter / Search / Sort (chỉ màn List/Report — xóa nếu không phải) &ZeroWidthSpace;

N/A — màn form, không phải List.

Actions &ZeroWidthSpace;
A1 - Tạo contact &ZeroWidthSpace;
ItemDescription
TriggerBấm "Tạo contact"
BehaviorKiểm BR-01 → gửi các trường có giá trị (BR-02, BR-03) → HubSpot tạo contact trên portal theo tab (BR-05). Nếu HubSpot báo email đã tồn tại: ⚠️ Observed — lấy contact cũ và cập nhật đè bằng dữ liệu vừa nhập (OQ-I-05). Sau đó ghi mục {id, tên} vào danh sách Redis của môi trường (BR-06). Ghi vào: HubSpot (dev hoặc production) + Redis mind_keep. ⚠️ Ghi PROD (qua Staging): ở tab Staging, contact được tạo / cập nhật trên portal HubSpot production
Success ResultPopup "Đã tạo contact instance"; form trắng; contact thêm vào danh sách

Error cases:

CaseExpected Handling
Họ tên trốngPopup "Thiếu thông tin" — "Họ tên là bắt buộc."; không gọi API
HubSpot từ chối (không phải trùng email)Popup "Tạo contact instance thất bại" — "Failed to create HubSpot object (12006)"
Lỗi khác (Redis, mạng…)Popup "Tạo contact instance thất bại" — "Failed to create SAPP contact instance (13007)" hoặc "Đã có lỗi xảy ra."
Acceptance Criteria của màn M1 &ZeroWidthSpace;
AC-M1.1 - Tạo contact mới ở Dev &ZeroWidthSpace;
gherkin
Given đang ở tab Dev
And nhập Họ tên "Nguyễn Văn A", Email "a+new@example.com", để trống các trường khác
When bấm "Tạo contact"
Then HubSpot dev có contact mới với "[TVTS] Họ tên" = "Nguyễn Văn A", email = "a+new@example.com", các thuộc tính khác không được ghi
And popup "Đã tạo contact instance" hiện "Contact "Nguyễn Văn A" (id: <id>) đã được tạo trong portal dev."
And form trở về trắng và contact nằm cuối danh sách "Contact đã tạo"

Maps to:

  • Business Rule: BR-02, BR-03, BR-06
  • Field/Action: A1
AC-M1.2 - Thiếu Họ tên &ZeroWidthSpace;
gherkin
Given Họ tên chỉ gồm khoảng trắng
When bấm "Tạo contact"
Then hiện popup "Thiếu thông tin" — "Họ tên là bắt buộc."
And không có request nào gửi tới BE

Maps to:

  • Business Rule: BR-01
AC-M1.3 - ⚠️ Ghi PROD qua tab Staging &ZeroWidthSpace;
gherkin
Given đang ở tab Staging
When tạo contact "Test Staging"
Then contact được tạo trên portal HubSpot **production** (credential prod)
And contact chỉ xuất hiện trong danh sách của tab Staging, không có trong danh sách tab Prod

Maps to:

  • Business Rule: BR-05; US-I01 BR-03
  • Field/Action: A1 — OQ-I-02
AC-M1.4 - Widget theo định nghĩa HubSpot &ZeroWidthSpace;
gherkin
Given property "khuvucsinhsong" trên HubSpot của môi trường là kiểu danh sách chọn
When mở form
Then ô "Tỉnh / Thành phố" hiện dạng chọn với các lựa chọn của HubSpot

Maps to:

  • Business Rule: BR-04
AC-M1.5 - HubSpot từ chối &ZeroWidthSpace;
gherkin
Given HubSpot trả lỗi không phải trùng email (ví dụ giá trị không hợp lệ)
When bấm "Tạo contact"
Then popup "Tạo contact instance thất bại" — "Failed to create HubSpot object (12006)"
And form giữ nguyên dữ liệu đã nhập

Maps to:

  • Business Rule: BR-07
AC-M1.6 - ⚠️ Observed: email trùng cập nhật đè contact cũ &ZeroWidthSpace;
gherkin
Given trên portal đã có contact X với email "hv@example.com" (có thể là học viên thật nếu đang ở tab Staging = production)
When tạo contact Họ tên "Test", email "hv@example.com"
Then (hành vi hiện tại) không báo lỗi; contact X bị cập nhật "[TVTS] Họ tên" = "Test" và các trường khác vừa nhập
And API trả contact X kèm cờ dùng lại = true
And popup vẫn hiện "đã được tạo" (không phân biệt tạo mới / dùng lại)
And contact X được thêm thêm một dòng vào danh sách tool (có thể lặp — OQ-I-18)

Maps to:

  • Business Rule: N/A — ⚠️ Observed (inventory R-04) → OQ-I-05, OQ-I-18
Negative AC / Edge Cases của màn M1 &ZeroWidthSpace;
IDTình huốngHành vi mong đợi
EC-M1.1Mất mạng giữa lúc tạoPopup "Tạo contact instance thất bại" với thông báo lỗi chung; form giữ dữ liệu
EC-M1.2Bấm "Tạo contact" hai lần liên tiếpNút bị khoá trong lúc đang tạo, lần hai không gửi
EC-M1.3Họ tên có ký tự đặc biệt / emojiGửi nguyên văn sang HubSpot; HubSpot quyết định chấp nhận hay lỗi (BR-07)
EC-M1.4Đổi tab khi đang nhập dởForm bị xoá (US-I01 BR-02)
EC-M1.5Gọi API prod trực tiếp (tab Prod tắt)⚠️ Observed — vẫn tạo / cập nhật contact trên production, không cần đăng nhập (NFR-I-01 → OQ-I-02)
EC-M1.6Email trùng một contact học viên thật trên production (tab Staging)⚠️ Observed — contact thật bị ghi đè (AC-M1.6, OQ-I-05)

5. Cross-feature AC &ZeroWidthSpace;

AC-X.1 - Dữ liệu contact production bị ảnh hưởng &ZeroWidthSpace;

gherkin
Given tab Staging
When tạo contact với email của một học viên đang có trên HubSpot production
Then contact của học viên đó bị cập nhật các trường vừa nhập (hành vi hiện tại — ⚠️ Observed)

Maps to:

  • REL-05 (Be Affected - Dữ liệu HubSpot portal production)

AC-X.2 - Logic tạo contact dùng chung với SAPP-26878 &ZeroWidthSpace;

gherkin
Given tool SAPP-26878 chạy bước tạo contact
When logic "tạo hoặc dùng lại contact" của 24395 thay đổi
Then hành vi bước đó ở 26878 thay đổi theo

Maps to:

  • REL-04 (Be Affected - SAPP-26878 US-D03)