Skip to content

Feature Inventory — HubSpot tools (Clone · Snapshot · Property · Pipeline) ​

Kiểm kê tính năng đã triển khai, dựng từ code. Đầu vào cho FS as-built (Mode B). Mọi dòng có bằng chứng file:dòng; không có bằng chứng → §8 Câu hỏi.

Công thức truy vết: ba/system-profile.md §3. Mọi đường dẫn tính từ root repo mind_keep/. AI draft — chưa qua Gate R1. Không có số liệu đo từ API chạy thật; mọi hành vi suy từ đọc source.

FieldValue
Projectba/projects/2026-SAPP-Works-tools
ModeB – As-built
Ngày đọc code2026-09-30
Commite77c47a
Điểm vào BA cung cấp4 sub-tool dưới /works/sapp/tools: hs-clone-prod-to-dev (sapp.001), hs-snapshot-property (sapp.002), hs-get-property (sapp.003), hs-pipeline (sapp.004)
Thành phần chạm tớiFE · BE (api) · HubSpot CRM API ngoài (portal prod + portal dev)
StatusDraft

1. Phạm vi đã truy vết ​

  • Trong phạm vi:
    • 4 màn web: Clone property prod → dev, Property snapshot & history, Property info, Pipeline manager.
    • Các API BE mà 4 màn gọi: get property (deals/contacts/tickets × prod/dev/staging), clone property prod → dev, property-history (6 route), list/get pipeline, clone pipeline prod → dev, duplicate pipeline trong cùng portal (prod và dev).
    • Service BE HubSpotCommonService (be/libs/modules/src/lib/hubspot/common.service.ts) và HTTP client HubSpotService (be/libs/services/src/lib/hubspot/hubspot.service.ts) đến mức endpoint HubSpot được gọi.
    • Ghi chú: lời giao việc trỏ tới be/libs/modules/src/lib/sapp/common.service.ts; thực tế 4 tool không đi qua file đó — controller gọi thẳng HubSpotCommonService (be/apps/api/src/sapp/sapp.controller.ts:163).
  • Ngoài phạm vi (dừng truy vết tại đây):
    • Gate truy cập tool (ẩn / tắt / khoá secret theo code) → nền tảng (fe/src/ui/pages/works/sapp/tools/shell.tsx:427 ToolGate; bảng tools seed tại be/libs/database/migrations/1783700000000-create-tools.ts:6-9).
    • Lưu "tool dùng gần nhất" / chọn tool hạ cánh → nền tảng (fe/src/ui/pages/works/sapp/tools/registry.ts:115-122, fe/app/works/sapp/tools/page.tsx:10).
    • Đọc credential từ bảng env_systems → nền tảng (be/libs/modules/src/lib/hubspot/common.service.ts:47-58).
    • Cơ chế @Public() / guard toàn cục → nền tảng (be/apps/api/src/sapp/sapp.controller.ts:114).
    • hubspot-property-field.tsx: không được 4 tool này dùng — chỉ được import bởi sapp-24395-tool, sap-log-trace, các step của sapp-26878 (Grep hubspot-property-field trong fe/src). Chỉ ghi tên.
    • Route thêm option cho property (POST dev/hubspot/{deals|contacts}/properties/:property/options, be/apps/api/src/sapp/sapp.controller.ts:821,1101) — dùng bởi sapp-26878-step-option.tsx:86, không thuộc 4 tool.
    • Suggested trace properties + Property history timeline (trace) (sapp.controller.ts:1538-1701) — Grep property-suggestions|property-timeline trong fe/src không có kết quả → không màn nào trong 4 tool gọi. Chỉ ghi tên (xem Q-12).

2. Điểm vào (Entry points) ​

IDLoạiTên / đường dẫn người dùng thấyBằng chứng
E-01Màn web/works/sapp/tools/hs-clone-prod-to-dev — sidebar "Clone", nhóm "SAPP Common Hubspot Tools"; tiêu đề "Clone property: prod → dev"fe/app/works/sapp/tools/hs-clone-prod-to-dev/page.tsx:10; fe/src/ui/pages/works/sapp/tools/registry.ts:43-46; fe/src/ui/components/works/sapp/clone-tool.tsx:96; code sapp.001 tại fe/src/data/constants/tool-codes.ts:32
E-02Màn web/works/sapp/tools/hs-snapshot-property — sidebar "Snapshot"; tiêu đề "Property snapshot & history"fe/app/works/sapp/tools/hs-snapshot-property/page.tsx:10; registry.ts:47; fe/src/ui/components/works/sapp/snapshot-tool.tsx:134; code sapp.002 tại tool-codes.ts:33
E-03Màn web/works/sapp/tools/hs-get-property — sidebar "Property"; tiêu đề "Property info"fe/app/works/sapp/tools/hs-get-property/page.tsx:10; registry.ts:48; fe/src/ui/components/works/sapp/property-tool.tsx:115; code sapp.003 tại tool-codes.ts:34
E-04Màn web/works/sapp/tools/hs-pipeline — sidebar "Pipeline"; tiêu đề "Pipeline manager"fe/app/works/sapp/tools/hs-pipeline/page.tsx:10; registry.ts:49; fe/src/ui/components/works/sapp/pipeline-tool.tsx:223; code sapp.004 tại tool-codes.ts:35
E-05APIGET /api/v1/sapp/{prod|dev|staging}/hubspot/deals/properties/:property; GET …/{prod|dev|staging}/hubspot/contacts/properties/:property; GET …/{prod|dev}/hubspot/tickets/properties/:property (8 route; tickets không có staging)be/apps/api/src/sapp/sapp.controller.ts:550,571,592,1012,1033,1054,1128,1149; URL FE fe/src/data/constants/api.ts:179-183
E-06APIPOST /api/v1/sapp/dev/hubspot/{deals|contacts|tickets}/properties/clone-prod/:property (3 route)sapp.controller.ts:615,1077,1170; api.ts:184-187
E-07APIPOST /api/v1/sapp/{prod|dev}/hubspot/{deals|contacts|tickets}/:objectId/property-history (6 route)sapp.controller.ts:1380,1402,1424,1446,1468,1490; api.ts:196-200
E-08APIGET /api/v1/sapp/{prod|dev}/hubspot/{deals|tickets}/pipelines (4 route)sapp.controller.ts:848,867,1194,1213; api.ts:201-204
E-09APIGET /api/v1/sapp/{prod|dev}/hubspot/{deals|tickets}/pipelines/:pipelineId (4 route)sapp.controller.ts:886,907,1232,1253; api.ts:205-209
E-10APIPOST /api/v1/sapp/dev/hubspot/{deals|tickets}/pipelines/clone-prod/:pipelineId (2 route)sapp.controller.ts:928,1274; api.ts:210-213
E-11APIPOST /api/v1/sapp/dev/hubspot/{deals|tickets}/pipelines/:pipelineId/duplicate (2 route, ghi vào dev)sapp.controller.ts:984,1330; api.ts:214-219
E-12APIPOST /api/v1/sapp/prod/hubspot/{deals|tickets}/pipelines/:pipelineId/duplicate (2 route, ghi vào prod)sapp.controller.ts:956,1302; api.ts:214-219

3. Hành động người dùng / hệ thống ​

Môi trường: "prod" và "staging" dùng cùng token portal prod; "dev" dùng token portal dev (be/libs/constants/src/lib/hubspot/hubspot.constants.ts:14-31). Mọi lời gọi HubSpot đi tới cùng một host https://api.hubapi.com, phân biệt portal chỉ bằng token (be/libs/services/src/lib/hubspot/hubspot.service.ts:35, hubspot.constants.ts:4).

IDAi (role)Làm gìĐiểm vàoKết quả quan sát đượcBằng chứng
A-01Người dùng qua được gate của tool (role chưa rõ — Q-01)Mở một trong 4 tool từ sidebar hoặc link chia sẻE-01..E-04Tool hiển thị trong khung chung; ẩn/tắt/khoá do gate → nền tảngfe/app/works/sapp/tools/layout.tsx:25-26; pipeline-tool.tsx:47-50
A-02Như A-01Tra cứu định nghĩa một property: chọn môi trường (Prod/Dev), loại object (Deal/Ticket/Contact), nhập internal name, bấm "Get property"E-03 → E-05Chỉ đọc portal đã chọn. Hiện name, label, Type, Field type, Group, Description, bảng options (Label/Value/Order/Hidden) và Raw JSON có nút Copy JSONproperty-tool.tsx:25-34,95-107,170-237; fe/src/data/services/sapp/get-property.service.ts:17-31; be/libs/modules/src/lib/hubspot/common.service.ts:489-507; HubSpot GET /crm/v3/properties/{object}/{name} tại hubspot.service.ts:75-83
A-03Như A-01Clone một property từ prod sang dev: chọn loại object, nhập internal name, bấm "Clone to dev"E-01 → E-06Đọc prod, ghi dev. Nếu dev đã có property cùng tên → trả property dev hiện có, không sửa. Nếu chưa có → tạo mới ở dev. Popup "Clone completed — Property … is now available in the dev portal" và JSON property devclone-tool.tsx:23-27,62-88,141-158; fe/src/data/services/sapp/clone-property.service.ts:15-27; sapp.controller.ts:624-631; common.service.ts:820-875; HubSpot GET /crm/v3/properties/{object}/{name} (prod + dev) và POST /crm/v3/properties/{object} (dev) tại hubspot.service.ts:75-95
A-04Như A-01Xem lịch sử thay đổi của một hoặc nhiều property trên một bản ghi (deal/ticket/contact): chọn môi trường, loại object, nhập object id, danh sách property, tuỳ chọn "Target time", bấm "Check snapshot"E-02 → E-07Chỉ đọc portal đã chọn. Mỗi property: bảng Value/Timestamp/Source; nếu có target time thì hiện "value at target" và tô dòng khớp, gắn nhãn "target". Không có dữ liệu → "No history returned." / "No history entries"snapshot-tool.tsx:93-126,218-300; fe/src/data/services/sapp/property-history.service.ts:24-42; sapp.controller.ts:1358-1378; common.service.ts:105-170; HubSpot GET /crm/v3/objects/{object}/{id}?propertiesWithHistory=…&archived=false tại hubspot.service.ts:121-135
A-05Như A-01Tải danh sách pipeline: chọn môi trường (Prod/Dev), loại object (Deal/Ticket), bấm "Load pipelines"E-04 → E-08Chỉ đọc. Mỗi pipeline hiện label, "order N", "N stages", id; rỗng → "No pipelines found."pipeline-tool.tsx:82-94,257-300; fe/src/data/services/sapp/pipeline.service.ts:13-22; common.service.ts:973-986; HubSpot GET /crm/v3/pipelines/{object} tại hubspot.service.ts:226-230
A-06Như A-01Xem stage của một pipeline: bấm "View stages"E-04 → E-09Chỉ đọc. Bảng Order/Label/Metadata (deal: probability/isClosed; ticket: ticketState/isClosed), nút Copy JSONpipeline-tool.tsx:96-115,304-315,357-416; pipeline.service.ts:25-39; common.service.ts:1007-1025; HubSpot GET /crm/v3/pipelines/{object}/{id} tại hubspot.service.ts:234-242
A-07Như A-01Clone pipeline prod sang dev: khi môi trường = Prod, bấm "Clone to dev" trên một pipeline → modal "Clone pipeline to dev", sửa "New label (optional)" (điền sẵn label nguồn), bấm "Clone to dev"E-04 → E-10Đọc prod, ghi dev. Nếu dev đã có pipeline cùng label đích → trả pipeline đó, không sửa; chưa có → tạo pipeline mới ở dev cùng toàn bộ stage. Popup "Clone completed"pipeline-tool.tsx:117-146,187-198,317-335,424-507; pipeline.service.ts:52-66; sapp.controller.ts:937-948; common.service.ts:1058-1099; HubSpot GET /crm/v3/pipelines/{object}/{id} (prod), GET /crm/v3/pipelines/{object} (dev), POST /crm/v3/pipelines/{object} (dev) tại hubspot.service.ts:226-254
A-08Như A-01Nhân bản pipeline trong portal dev: môi trường = Dev, bấm "Duplicate", nhập "New label" (điền sẵn "<label> (copy)"), bấm "Duplicate"E-04 → E-11Ghi dev. Tạo pipeline mới trong dev với cùng stage; nếu label đã tồn tại → trả pipeline đó. Popup "Duplicate completed — … was created in the dev portal", tự tải lại danh sáchpipeline-tool.tsx:148-181,201-214,337-353; pipeline.service.ts:78-94; sapp.controller.ts:993-1004,1339-1350; common.service.ts:1058-1099
A-09Như A-01Nhân bản pipeline trong portal prod: môi trường = Prod, bấm "Duplicate", nhập label, bấm "Duplicate"E-04 → E-12⚠️ Observed — Ghi vào portal HubSpot prod: tạo pipeline mới cùng toàn bộ stage trong prod. Chỉ có modal nhập label, không có bước xác nhận riêng cho prod; subtitle modal ghi "into prod portal"pipeline-tool.tsx:31-34,337-353,431-433,500-502; sapp.controller.ts:956-977,1302-1323; HubSpot POST /crm/v3/pipelines/{object} với token prod tại hubspot.service.ts:246-254
A-10Bất kỳ ai gọi được API (không cần đăng nhập — R-01)Gọi trực tiếp các route E-05..E-12, kể cả biến thể staging và route ticket/contact mà UI không mởE-05..E-12Các route hoạt động độc lập với gate FE; route staging trả cùng dữ liệu như prodsapp.controller.ts:551,572,593,616,849,868,887,908,929,957,985,1381; sapp.controller.ts:596-597
A-11Hệ thốngBáo lỗi khi gọi API thất bạiE-01..E-04Popup lỗi tiêu đề theo thao tác ("Failed to clone property", "Failed to fetch property", "Failed to fetch property history", "Failed to load pipelines", "Failed to load pipeline", "Failed to clone pipeline", "Failed to duplicate pipeline"), nội dung message (code)clone-tool.tsx:46-60; property-tool.tsx:72-86; snapshot-tool.tsx:70-84; pipeline-tool.tsx:64-80,87,111,132,165

4. Dữ liệu &ZeroWidthSpace;

Không có bảng DB riêng cho 4 tool — dữ liệu là định nghĩa property / pipeline / lịch sử property sống trong HubSpot. Bảng tools (trạng thái tool) và env_systems (credential) → nền tảng.

Entity / bảngFieldTypeBắt buộcMặc định / enumBằng chứng
Tham số môi trường (path)envenumCóprod · staging · dev (UI 4 tool chỉ cho chọn Prod/Dev, mặc định Prod)be/libs/constants/src/lib/hubspot/hubspot.enum.ts:1-5; property-tool.tsx:25-28,52; snapshot-tool.tsx:26-29,45; pipeline-tool.tsx:31-34,54
Tham số loại object (path)objectenumCóProperty/History: deals · contacts · tickets (mặc định Deal). Pipeline: deals · ticketsfe/src/data/models/sapp-hubspot.interface.ts:12,50; clone-tool.tsx:23-27,32; pipeline-tool.tsx:36-39,55
Property HubSpot (response)name, label, type, fieldType, groupNamestringCó (theo DTO)—be/libs/interface/src/lib/dto/hubspot/hubspot-property.dto.ts:27-41
Property HubSpot (response)description, options[] (label, value, description, displayOrder, hidden), displayOrder, hiddenstring / array / number / booleanKhông—hubspot-property.dto.ts:10-57
Payload tạo property khi clonename, label, type, fieldType, description, groupName, options[]——groupName luôn = nhóm chuẩn theo object: deals → dealinformation, contacts → contactinformation, tickets → ticketinformation; option hidden mặc định falsebe/libs/modules/src/lib/hubspot/common.service.ts:674-700; hubspot.constants.ts:39-43
Request property-historypropertiesstring[]CóChuỗi CSV cũng được tách theo dấu phẩybe/libs/interface/src/lib/dto/hubspot/hubspot-property-history.dto.ts:10-14; be/libs/interface/src/lib/dto/decorators/dto.decorator.ts:156-185
Request property-historytargetTimeDate (ISO)KhôngBỏ trống = "hiện tại"hubspot-property-history.dto.ts:16-20; snapshot-tool.tsx:123-124
Response property-history (mỗi property)history[] (value, timestamp, sourceType, …), targetValue, targetEntrymap theo tên property—targetValue = null khi không có mốc nào trước target timehubspot-property-history.dto.ts:23-73; common.service.ts:152-170
Pipeline (response)id, label, displayOrder, stages[] (id, label, displayOrder, metadata), archived—label bắt buộc—be/libs/interface/src/lib/dto/hubspot/hubspot-pipeline.dto.ts:10-50
Request clone pipelinelabelstringKhôngBỏ trống → giữ label nguồnhubspot-pipeline.dto.ts:57-63
Request duplicate pipelinelabelstringCó (phải là string; chuỗi rỗng vẫn qua validate)—hubspot-pipeline.dto.ts:52-55; dto.decorator.ts:17-25
Payload tạo pipelinelabel, displayOrder, stages[] (label, displayOrder, metadata)——Bỏ id pipeline và id stage (HubSpot cấp mới)common.service.ts:1034-1046,1086-1087
Mã lỗi12001 HUBSPOT_ENV_NOT_CONFIGURED (400), 12002 HUBSPOT_API_ERROR (400), 12003 HUBSPOT_PROPERTY_NOT_FOUND (404), 12004 FAILED_CLONE_HUBSPOT_PROPERTY (400), 12005 HUBSPOT_OBJECT_NOT_FOUND (404), 12007 HUBSPOT_PIPELINE_NOT_FOUND (404), 12008 FAILED_CLONE_HUBSPOT_PIPELINE (400)———be/libs/constants/src/lib/error-codes/error-codes.constants.ts:466-505

5. Rule & validation tìm thấy &ZeroWidthSpace;

IDRule (ngôn ngữ nghiệp vụ)LoạiÁp dụng ởBằng chứngNghi là bug?
R-01Mọi API của 4 tool mở công khai, không cần đăng nhập, kể cả API ghi vào dev và ghi vào prodđiều kiện (quyền)A-02..A-10sapp.controller.ts:551,572,593,616,849,868,887,908,929,957,985,1013,1034,1055,1078,1129,1150,1171,1195,1214,1233,1254,1275,1303,1331,1381,1403,1425,1447,1469,1491⚠️ Observed — Q-02
R-02Phải nhập tên property (sau khi cắt khoảng trắng) mới được clone / tra cứu; thiếu → popup "Missing property name"validationA-02, A-03clone-tool.tsx:76-85; property-tool.tsx:95-104Không
R-03Clone property luôn đi một chiều prod → dev; UI không cho chọn chiều khácđiều kiệnA-03sapp.controller.ts:626-630; fe/src/data/constants/api.ts:184-187Không
R-04Clone property không ghi đè: nếu dev đã có property cùng tên thì trả nguyên property dev, không đổi label/optionstrạng tháiA-03common.service.ts:841-848 (tuỳ chọn ghi đè overrideExisting tồn tại nhưng controller không bật: sapp.controller.ts:626-631)Không
R-05Khi clone property, nhóm property (group) của nguồn bị bỏ; property mới luôn nằm ở nhóm chuẩn của objectcông thứcA-03common.service.ts:684-689; hubspot.constants.ts:39-43Không
R-06Khi clone property, chỉ chép name, label, type, fieldType, description và options (mỗi option: label, value, description, displayOrder, hidden — hidden thiếu thì = false)công thứcA-03common.service.ts:678-698Không
R-07Popup thành công của clone property luôn nói "is now available in the dev portal", không phân biệt vừa tạo mới hay đã có sẵnhiển thịA-03clone-tool.tsx:62-71; common.service.ts:848⚠️ Observed — Q-05
R-08Tra cứu property: mọi lỗi từ HubSpot (không chỉ "không tồn tại") đều trả về "HubSpot property not found" (12003, HTTP 404)điều kiệnA-02, A-03common.service.ts:500-505⚠️ Observed — Q-06
R-09Môi trường "staging" dùng cùng credential portal prod, nên đọc staging = đọc prodcông thứcA-10hubspot.constants.ts:19-26; sapp.controller.ts:596-597Không
R-10Thiếu access token của môi trường → lỗi 12001 "HubSpot access token is not configured for this environment"validationA-02..A-09common.service.ts:47-58Không
R-11Snapshot: phải có object id và ít nhất một tên property; danh sách property tách bằng dấu phẩy hoặc xuống dòng, bỏ khoảng trắng và mục rỗngvalidationA-04snapshot-tool.tsx:94-115Không
R-12Snapshot (BE): danh sách property rỗng → lỗi 12003 "HubSpot property not found"validationA-04common.service.ts:112-117Không
R-13Snapshot: object id không tồn tại (HubSpot 404) → 12005; lỗi HubSpot khác → 12002điều kiệnA-04common.service.ts:127-138Không
R-14Giá trị tại mốc thời gian = 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ị nullcông thứcA-04common.service.ts:79-94,160-166Không
R-15Không nhập mốc thời gian → "giá trị tại mốc" = bản ghi đầu tiên trong lịch sử (HubSpot trả mới nhất trước)công thứcA-04common.service.ts:160-162; hubspot.service.ts:118-119Không
R-16Mốc thời gian nhập trên UI không kèm múi giờ, được hiểu theo giờ trình duyệt rồi đổi sang ISO (UTC); cột Timestamp hiển thị nguyên chuỗi HubSpot trả về, không đổi múi giờcông thức / hiển thịA-04snapshot-tool.tsx:37-40,123-124,278⚠️ Observed — Q-08
R-17Nhãn "value at target" hiển thị theo ô Target time hiện tại trên form, không theo giá trị đã gửi; kết quả không bị xoá khi đổi/xoá ô nàyhiển thịA-04snapshot-tool.tsx:232-245⚠️ Observed — Q-09
R-18Snapshot chỉ lấy bản ghi chưa lưu trữ (archived=false)điều kiệnA-04hubspot.service.ts:131-134Không
R-19Pipeline chỉ có cho Deal và Ticket; Contact không cóđiều kiệnA-05..A-09pipeline-tool.tsx:36-39; fe/src/data/models/sapp-hubspot.interface.ts:49-50Không
R-20Nút "Clone to dev" chỉ hiện khi môi trường đang chọn là Prod; nút "Duplicate" hiện ở cả Prod và Devđiều kiệnA-07, A-08, A-09pipeline-tool.tsx:317-353⚠️ Observed (Duplicate ở Prod) — Q-03
R-21Clone / duplicate pipeline không ghi đè: pipeline đích được so khớp theo label (chính xác, sau khi cắt khoảng trắng label mới); đã có → trả nguyên pipeline đótrạng tháiA-07..A-09common.service.ts:1068,1081-1084Không
R-22Clone pipeline: label mới để trống → giữ label nguồn. UI điền sẵn label nguồn vào ôcông thứcA-07common.service.ts:1068; pipeline-tool.tsx:191-197,327Không
R-23Duplicate pipeline: UI bắt buộc nhập label (thiếu → "Missing label"); UI điền sẵn "<label> (copy)"validationA-08, A-09pipeline-tool.tsx:201-208,346Không
R-24Duplicate qua API với label rỗng/chỉ khoảng trắng vẫn qua validate; BE rơi về label nguồn, tìm thấy chính pipeline nguồn và trả nó về "thành công" mà không tạo gìđiều kiệnA-10hubspot-pipeline.dto.ts:52-55; dto.decorator.ts:17-25; common.service.ts:1068,1081-1084⚠️ Observed — Q-10
R-25Pipeline tạo mới giữ nguyên displayOrder và metadata stage của nguồn; id pipeline/stage do HubSpot cấp mớicông thứcA-07..A-09common.service.ts:1034-1046Không
R-26Trong lúc một thao tác pipeline đang chạy, mọi nút và ô chọn bị khoá; modal không đóng được khi đang clone/duplicateđiều kiệnA-05..A-09pipeline-tool.tsx:183-185,434-439,448Không
R-27Sau duplicate thành công, danh sách pipeline tự tải lại; sau clone sang dev thì không (danh sách đang xem là prod)trạng tháiA-07, A-08pipeline-tool.tsx:133-145,177-178Không
R-28Các khoá SAPP_*_HUBSPOT_API_URL được khai báo nhưng HTTP client luôn gọi host cố định https://api.hubapi.comcông thứcA-02..A-09hubspot.constants.ts:4,15,28; hubspot.service.ts:35Không (chỉ ghi nhận)

Trạng thái & chuyển trạng thái (clone / duplicate — áp dụng cho property và pipeline):

text
[CHƯA CÓ Ở ĐÍCH] --(bấm Clone/Duplicate, nguồn tồn tại)--> [ĐÃ TẠO Ở ĐÍCH]
[ĐÃ CÓ Ở ĐÍCH (cùng name / cùng label)] --(bấm Clone/Duplicate)--> [ĐÃ CÓ Ở ĐÍCH] (không đổi, trả bản hiện có)
[NGUỒN KHÔNG TỒN TẠI] --(bấm)--> lỗi 12003 (property) / 12007 (pipeline)

Ma trận môi trường đọc/ghi:

ToolĐọcGhiGhi vào prod?
hs-get-property (sapp.003)prod hoặc dev (UI); API còn có staging (= prod)—Không
hs-snapshot-property (sapp.002)prod hoặc dev—Không
hs-clone-prod-to-dev (sapp.001)prod (nguồn) + dev (kiểm tra tồn tại)dev (tạo property)Không
hs-pipeline (sapp.004)prod hoặc devdev (clone prod → dev; duplicate trong dev) và prod (duplicate trong prod)Có — A-09 / E-12

6. Quyền, tích hợp, thông báo, job &ZeroWidthSpace;

LoạiChi tiếtBằng chứng
Quyền (BE)Tất cả route E-05..E-12 gắn @Public() — không yêu cầu xác thực, không kiểm tra permission codesapp.controller.ts:114 (import) và các dòng liệt kê ở R-01
Quyền (FE)Truy cập tool do gate chung theo code (ẩn / tắt / khoá secret) → nền tảng. Comment trong pipeline-tool nói rõ không đặt gate cứng ở FEfe/src/ui/pages/works/sapp/tools/shell.tsx:427-435; pipeline-tool.tsx:47-50; seed be/libs/database/migrations/1783700000000-create-tools.ts:6-9 (mặc định isEnabled=true, isVisible=true, secretType='none' tại dòng 33)
Tích hợp ngoàiHubSpot CRM v3: GET/POST /crm/v3/properties/{object}[/{name}], GET /crm/v3/objects/{object}/{id}?propertiesWithHistory, GET/POST /crm/v3/pipelines/{object}[/{id}]. Portal prod (token SAPP_PROD_HUBSPOT_ACCESS_TOKEN, cũng dùng cho staging) và portal dev (SAPP_DEV_HUBSPOT_ACCESS_TOKEN)hubspot.service.ts:67-135,226-254; hubspot.constants.ts:10-32
CredentialĐọc từ env_systems mỗi lần gọi → nền tảngcommon.service.ts:47-58
Thông báo (mail / push / MQTT / Discord)Không tìm thấy. Chỉ popup trên UIclone-tool.tsx:65-71; pipeline-tool.tsx:137-143,170-176
LogLỗi được ghi log BE theo tên handlervd sapp.controller.ts:566,634,951,979,1375
Job / cronKhông tìm thấy—

7. Drift — tài liệu nói khác code &ZeroWidthSpace;

IDTài liệu (file + section)Tài liệu nóiCode đang làmBằng chứng
DR-01shared/api-docs/sapp.md:14 §Overview"the three routes below are currently marked @Public()"Toàn bộ route HubSpot của 4 tool (≥ 29 route, gồm cả route ghi prod) đều @Public()sapp.controller.ts các dòng ở R-01
DR-02shared/api-docs/sapp.md:12 §OverviewLàm việc với "two portals (prod / dev)"Có thêm env staging (dùng credential prod) cho get property deals/contacts; tài liệu nhắc staging ở :74-80, :119 nhưng mô tả tổng quan chưa cập nhậthubspot.enum.ts:1-5; sapp.controller.ts:592,1054
DR-03shared/api-docs/sapp.md:150 §Pipeline endpoints"There are 5 routes per object type"Bảng ngay dưới liệt kê 6 dòng; thực tế mỗi object có 7 route (list prod/dev, get prod/dev, clone, duplicate prod, duplicate dev)sapp.controller.ts:848-1010 (deals), 1194-1356 (tickets)
DR-04shared/api-docs/sapp.md:148 §Pipeline endpoints (câu mở đầu)"Clones a pipeline definition … from prod to dev"Nhóm route này còn tạo pipeline trong portal prod (duplicate prod); tài liệu chỉ nhắc ở :176 mà không cảnh báo đây là thao tác ghi prodsapp.controller.ts:956-977,1302-1323
DR-05shared/api-docs/sapp.md:177-181 §Duplicate behaviorBody label "required"DTO chỉ kiểm tra là string; chuỗi rỗng/khoảng trắng qua được và BE trả lại chính pipeline nguồn (R-24) — tài liệu không nóihubspot-pipeline.dto.ts:52-55; common.service.ts:1068,1081-1084
DR-06shared/api-docs/sapp.md:60 §Get a prod deal property — ErrorsLỗi 12003 / 1200112003 được trả cho mọi lỗi HubSpot (token hỏng, rate limit, lỗi 5xx), không chỉ property không tồn tạicommon.service.ts:500-505
DR-07shared/api-docs/sapp.md:16-25 §Required env_systems keysSAPP_*_HUBSPOT_API_URL "(reserved)"Khớp — code không dùng, host cố định. Ghi lại để FS không mô tả sai là có cấu hình host theo môi trườnghubspot.service.ts:35; hubspot.constants.ts:4
DR-08shared/api-docs/sapp.md §Contacts endpoints :121-126, §OverviewKhông có route thêm optionCó route POST dev/hubspot/{deals|contacts}/properties/:property/options chưa được mô tả trong sapp.md (ngoài 4 tool, dùng bởi sapp-26878)sapp.controller.ts:821,1101; fe/src/data/constants/api.ts:192
DR-09Swagger DTO hubspot-property-history.dto.ts:33-45,62-65Response property-history có sourceId, sourceLabel, updatedByUserId, valueLabel, targetValueLabelService property-history chỉ dựng history / targetEntry / targetValue, không gắn valueLabel / targetValueLabel (chỉ timeline làm việc đó); sapp.md:222-241 khớp code, Swagger thì khôngcommon.service.ts:140-170
DR-10be/.agents/maps/modules/hubspot.md (bảng đầu file)Module HubSpot nằm ở apps/hubspot-service, apps/event-processor-service, apps/background-job-service, apps/ops; client @hubspot/api-clientRepo này chỉ có be/apps/api, hook, schedule; 4 tool đi qua SappController + HubSpotCommonService + client REST tự viết. Map không đề cập SAPP toolsbe/apps/ (ls); hubspot.service.ts:21-35

8. Câu hỏi cho BA (code không trả lời được) &ZeroWidthSpace;

IDCâu hỏiVì sao cầnChặn bước sau?
Q-01Ai (role/nhóm người dùng) được dùng 4 tool này? Có phân biệt người chỉ được đọc (Property, Snapshot) và người được ghi (Clone, Pipeline)?Viết Actor + quyền trong FS; code chỉ có gate chung theo tool, không có roleCó
Q-02Toàn bộ API (kể cả ghi dev và ghi prod) đang @Public(), tài liệu nói "temporary". Đây là trạng thái chấp nhận được hay là rủi ro cần ghi thành OQ/defect? Có kế hoạch siết @AuthRequired không?Quyết định ghi BR quyền hay OQ bảo mậtCó
Q-03Duplicate pipeline trong prod (A-09 / E-12) là cố ý hay bug? Nếu cố ý: ai được làm, có cần bước xác nhận riêng khi ghi prod không?Tool duy nhất trong nhóm ghi vào prod; quyết định BR vs OQCó
Q-04Mục đích nghiệp vụ của từng tool là gì (vd clone prod → dev để dựng dữ liệu test cho dự án nào)?Viết mục tiêu / US Statement — không suy từ codeKhông
Q-05Khi property đã tồn tại ở dev nhưng khác định nghĩa prod (options khác), tool trả bản dev cũ và vẫn báo "Clone completed". Người dùng có cần được báo "đã có sẵn, không cập nhật" không? Có nhu cầu ghi đè (code có sẵn overrideExisting nhưng không bật)?Quyết định BR "không ghi đè" và thông báoKhông
Q-06Mọi lỗi HubSpot khi đọc property đều hiện "property not found" (12003). Cố ý hay bug?Thông báo lỗi trong FS; ảnh hưởng chẩn đoán khi token hết hạnKhông
Q-07Nhập tên property không tồn tại trong Snapshot: code không báo lỗi riêng, trả lịch sử rỗng ("No history entries") — cần xác nhận bằng chạy thật HubSpot phản hồi thế nào. Hành vi mong muốn là gì?Acceptance criteria cho SnapshotKhông
Q-08Target time hiểu theo giờ trình duyệt, còn Timestamp hiển thị nguyên chuỗi UTC từ HubSpot. Người dùng có nhầm múi giờ (VN +7) không? Cố ý hay cần đổi?Rule hiển thị thời gianKhông
Q-09Nhãn "value at target" phụ thuộc ô Target time hiện tại, không theo lần tra đã gửi (R-17). Cố ý hay bug?Quyết định ghi BR hay defectKhông
Q-10Gọi API duplicate với label rỗng trả về chính pipeline nguồn như thành công (R-24). Cố ý hay bug?Quyết định BR hay defectKhông
Q-11UI cho chọn Prod/Dev, không có Staging, trong khi API get property có staging (= prod). Có cần Staging trên 4 tool này không?Phạm vi FSKhông
Q-12Route "Suggested trace properties" và "Property history timeline (trace)" (sapp.controller.ts:1538-1701) có trong tài liệu cạnh property-history nhưng không màn nào trong fe/src gọi. Chúng thuộc tool nào / có nằm trong phạm vi tài liệu này không?Chốt phạm viKhông
Q-13So khớp pipeline theo label phân biệt hoa thường và chỉ cắt khoảng trắng ở label mới — nếu dev có "Sales Pipeline" và prod là "Sales pipeline", tool sẽ tạo thêm một pipeline. Đây là hành vi chấp nhận?Rule idempotent trong FSKhông

9. Nhật ký nguồn đã đọc &ZeroWidthSpace;

File / sectionMục đích
ba/_workflow/templates/feature-inventory/Template.mdKhung tài liệu
ba/system-profile.md §3–§5Công thức truy vết, ranh giới ghi, quy ước
fe/app/works/sapp/tools/{hs-clone-prod-to-dev,hs-snapshot-property,hs-get-property,hs-pipeline}/page.tsxRoute màn
fe/app/works/sapp/tools/layout.tsx, fe/app/works/sapp/tools/page.tsxKhung chung, index (→ nền tảng)
fe/src/ui/pages/works/sapp/tools/registry.tsNhóm sidebar, nhãn, slug
fe/src/ui/pages/works/sapp/tools/shell.tsx (Grep ToolGate)Vị trí gate (→ nền tảng)
fe/src/data/constants/tool-codes.ts:20-40Code sapp.001–004
fe/src/ui/components/works/sapp/clone-tool.tsx (đọc hết)Màn Clone
fe/src/ui/components/works/sapp/snapshot-tool.tsx (đọc hết)Màn Snapshot
fe/src/ui/components/works/sapp/property-tool.tsx (đọc hết)Màn Property
fe/src/ui/components/works/sapp/pipeline-tool.tsx (đọc hết)Màn Pipeline
fe/src/ui/components/works/sapp/hubspot-property-field.tsx (Grep export + nơi import)Xác nhận không dùng bởi 4 tool
fe/src/data/services/sapp/{clone-property,get-property,pipeline,property-history,add-property-option}.service.tsService FE
fe/src/data/constants/api.ts:170-240URL "SAPP HUBSPOT TOOLS"
fe/src/data/models/sapp-hubspot.interface.tsKiểu dữ liệu FE
be/apps/api/src/sapp/sapp.controller.ts:1-175, 545-645, 845-1015, 1296-1425 + Grep route hubspot và fromEnv/toEnv dòng 1012-1520Route, môi trường, @Public()
be/libs/modules/src/lib/hubspot/common.service.ts:1-180, 489-513, 674-724, 820-895, 973-1109Logic get/clone property, history, pipeline
be/libs/services/src/lib/hubspot/hubspot.service.ts (Grep method/path; đọc 118-142)Endpoint HubSpot thực gọi
be/libs/constants/src/lib/hubspot/hubspot.constants.ts:1-50, hubspot.enum.tsMap env → credential, nhóm property mặc định, host
be/libs/constants/src/lib/error-codes/error-codes.constants.ts:466-505Mã lỗi
be/libs/interface/src/lib/dto/hubspot/{hubspot-pipeline,hubspot-property-history,hubspot-property}.dto.tsDTO request/response
be/libs/interface/src/lib/dto/decorators/dto.decorator.ts:17-25, 156-185, 397-445Hành vi validate của decorator
be/libs/database/migrations/1783700000000-create-tools.ts:1-40Seed code tool + mặc định trạng thái
shared/api-docs/sapp.md:1-370Đối chiếu Drift
be/.agents/maps/modules/hubspot.md:1-40 + ls be/appsĐối chiếu map module
Grep property-suggestions|property-timeline trong fe/srcXác nhận không màn nào gọi (Q-12)