QnA Init Docs — UC_4.6.1–4.6.4: Settings
Câu hỏi và giả định phát sinh trong Init Flow (Agent 1 Auditor + Agent 2 Challenger) cho module Settings — mỗi vòng Init Flow một section
Các vòng Init Flow đã chạy trên file này:
| Vòng | UC | Ngày | Trạng thái |
|---|---|---|---|
| 1 | UC_4.6.2 — Profile & Preferences | 2026-08-11 | ✅ BA đã chốt — SRS đã viết |
| 2 | UC_4.6.1 — Connections & Credentials | 2026-08-11 | ✅ BA đã chốt 7 mục 🔴 — SRS đã viết · ⚠️ một phần đã lỗi thời từ 2026-08-17 — xem note ngay dưới |
| 3 | UC_4.6.4 — Controls (AI chat & Reduce motion) | 2026-08-12 | ✅ BA đã chốt 4 mục 🔴 — SRS đã viết |
| 4 | UC_4.6.3 — Billing | 2026-08-12 | ✅ BA đã chốt 6 mục 🔴 — SRS đã viết · ⚠️ D-06 / D-07 đã bị đảo ngày 2026-08-21 |
| — | Vòng trả lời tổng hợp — 9 câu, 3 UC | 2026-08-21 | ✅ Đã trả lời & đã apply vào UC_4.6.1 (v1.6), UC_4.6.3 (v1.1), UC_4.6.4 (v3) |
| — | Bổ sung đợt 2 — MT5 4 password · chuẩn mã hoá · Connection Guide URLs · 6 câu chốt | 2026-08-21(Mục 3 sửa 2026-08-22) | ✅ Đã trả lời & đã apply vào UC_4.6.1 (v1.7), list-toast-popup (v3.12) |
| — | Bổ sung 2026-08-24 — Controls: Reduce Motion bỏ hẳn backend API | 2026-08-24 | ✅ Đã trả lời & đã apply vào UC_4.6.4 (v4), UC_4.6.1 (2 cross-ref) — đóng CTRL-EP-01 |
| — | Bổ sung 2026-08-27 — UC_4.6.1: reset model · guide URL hardcode · Path B · B-08 | 2026-08-27 | ✅ Đã trả lời & đã apply vào UC_4.6.1 (v1.12) — đóng B-08, [CC-TRIG-01], BR_4.6.1.15 điểm 1, storage guide URL |
| — | Bổ sung 2026-08-27 (Phần II) — UC_4.6.2: PATCH contract · phone launch scope · avatar precedence | 2026-08-27 | ✅ Đã trả lời & đã apply vào UC_4.6.2 (v11) — đóng [PP-EP-01], A-16, A-17, A-20 |
| — | Bổ sung 2026-08-27 (Phần III) — UC_4.6.4: Reduce Motion default ĐẢO ON→OFF · contract chốt | 2026-08-27 | ✅ Đã trả lời & đã apply vào UC_4.6.4 (v5), UC_4.6.2 (v11) — đóng C-07, local key, ui_preferences |
| — | Bổ sung 2026-08-28 — 10 câu, 4 UC: modal copy · placeholder · Billing · ai_enabled · user_id | 2026-08-28 | ✅ Đã trả lời & đã apply vào UC_4.6.1 (v1.13), UC_4.6.3 (v1.2), UC_4.6.4 (v6), UC_4.6.2 (v11) — đóng [CC-UI-02], D-06, D-07, D-11, D-20(a), C-04 |
| — | Bổ sung 2026-09-03 — ui_preferences là placeholder future-proofing · Desk Manager giữ endpoint riêng | 2026-09-03 | ✅ Đã trả lời & đã apply vào UC_4.6.4 (v7), UC_4.6.2 (v14) — đóng [CTRL-EP-03], [CTRL-EP-04] và câu treo cuối của Phần II |
Sau vòng 4, cả 4 UC của dải UC_4.6.1 – UC_4.6.4 đã có QnA init.
🔴 Cập nhật 2026-08-17 — Vòng 2 (UC_4.6.1) có một số quyết định đã bị khách override, đọc file này phải kèm cảnh báo sau: Khách đã đảo chiều mô hình credential (QnA STAGE 2 Settings —
Confirmed answers 2026-08-17, áp vào UC_4.6.1 v1.4):
- B-17 (không hiển thị / không copy password) → sai từ 2026-08-17: password được hiển thị (mask mặc định + icon con mắt) và có nút Copy (
[CC-DEF-05]).- B-19 / B-20 (shape response để mở cho BE quyết) → đã chốt: nested
Credentials {Username, Password, License_Key}, bỏLogin,Connection_Stringnullable ([CC-BIZ-04]).- B-04 / B-05 (nhánh + audit trail của Request Password Reset) → B-04 đã đóng: reset là ghi đè một chiều qua
POST /reset-platform-password+ modal xác nhận nội bộ (CF-02), không link ra ngoài ([CC-BIZ-06]). B-05 (audit trail) vẫn treo →[CC-BIZ-09].POST /request-credential-reset(nêu ở bảng endpoint bên dưới) không còn tồn tại.- Hướng zero-knowledge (không lưu password) đã bị rút lại — password và license key vẫn lưu dạng KMS ciphertext, middleware decrypt on-the-fly (
[CC-DEF-06]). Các mục còn lại của Vòng 2 (B-01, B-02, B-08, B-11, B-12…) vẫn có hiệu lực.
⚠️ Cập nhật 2026-08-11 (remap theo WBS): dòng trên ban đầu ghi
UC_4.6.4= Account Actions - Resign vàUC_4.6.5= Controls. WBS hiện tại chỉ cấpUC_4.6.1–UC_4.6.4cho Settings common,UC_4.6.4là Controls, và không cònUC_4.6.5. TabAccount Actionsđã ra khỏi dải common:Reset Associate Track→ UC_4.11.1 (SIM),Resign & Close Account→ UC_4.11.2 (SIM) /UC_4.17.2(LIVE). Các mục A-01 và A-19 bên dưới giữ nguyên nguyên trạng làm hồ sơ vòng cũ.
✅ Trả lời QnA — 2026-09-03 (UC_4.6.2 / UC_4.6.4: ui_preferences dùng để làm gì?)
Nguồn: khách trả lời trực tiếp, 2026-09-03. Ghi vào QnA from clients dưới ID [CTRL-EP-05] (QnA_STAGE2_SETTINGS_CAREER_VIRAL_EN.md §9 Controls & Concierge, v16).
Câu hỏi BA đã gửi khách
"Both the Get User Profile and Update User Profile APIs in the Prop Tech V7 file contain the
ui_preferencesfield. Could you explain what this field is intended for? Currently, ifui_preferencesis used to cover the side toggles like "The Desk Manager" and "Reduce Motion", I see those already have their own dedicated APIs (and "Reduce Motion" doesn't require an API at all). Because of this, I'm not clear on whatui_preferencesshould actually define here."
Câu trả lời của khách (nguyên văn)
"'Reduce Motion' does not require an API and should be using local storage.
The AI Preference Toggle has a dedicated backend endpoint because it controls core operational logic and costs, explicitly telling the Node.js middleware to stop pinging the Gemini API.
Regarding the
ui_preferencesfield: There are currently no active parameters to parse for this field today. It is intentionally included in the schema strictly as a future-proofing measure. Please maintain this column as an optional JSON object. This ensures the frontend team can easily save arbitrary cross-device layout preferences in future updates without requiring structural database schema changes later."
Chốt
| # | Hạng mục | Chốt | Áp vào |
|---|---|---|---|
| 1 | Desk Manager — endpoint [CTRL-EP-03] | ✅ ĐÓNG. Endpoint riêng POST /ai-preference. Đề xuất gộp PUT /profile của BA không được nhận — lý do khách nêu: toggle này "controls core operational logic and costs". Không mở lại nếu không có quyết định mới. | UC_4.6.4 BR_4.6.4.2 (blockquote mới) — contract không đổi so với v6 |
| 2 | Desk Manager — field [CTRL-EP-04] | ✅ ĐÓNG. Cột boolean phẳng users.ai_enabled, KHÔNG phải ui_preferences.desk_manager_enabled. → Worker Gemini query cột, không đọc JSONB. Không cần đổi schema DB. | UC_4.6.4 BR_4.6.4.2 — không đổi; note về response shape siết lại: chỉ top-level ai_enabled |
| 3 | Reduce Motion | ✅ Tái xác nhận FE-only, localStorage, không API. Không đổi so với 2026-08-24. | Không đổi |
| 4 | ui_preferences — mục đích [CTRL-EP-05] | ✅ Cột ngủ CÓ CHỦ ĐÍCH. Build: users.ui_preferences = JSONB, nullable/optional; GET /profile trả nguyên si; endpoint ghi profile nhận dạng optional pass-through, không validate cấu trúc bên trong; không backend logic nào parse, không màn hình nào đọc trong release này. | UC_4.6.2 BR_4.6.2.15; UC_4.6.4 bảng "Reduce Motion — three things are withdrawn" |
| 5 | Ranh giới A-18 | ✅ Không đổi. UC_4.6.2 vẫn không đọc/ghi ui_preferences; payload PATCH /profile vẫn là {user_id, phone_number}. | UC_4.6.2 BR_4.6.2.11 — thêm câu tái xác nhận |
✅ Đóng câu treo cuối cùng của Phần II (2026-08-27)
Phần II để lại câu hỏi: "Cần anh xác nhận: giữ payload {user_id, phone_number}, hay có preference mới sắp thêm khiến ui_preferences sống lại?"
→ Trả lời: giữ payload hiện tại. Khách nói rõ "There are currently no active parameters to parse for this field today" — không có preference nào sắp thêm. Cột được giữ lại thuần tuý để future-proof.
🔴 Một ghi chú cũ của SRS bị supersede
BR_4.6.2.15 (v11–v13) từng ghi: "Muốn dùng lại ui_preferences thì raise CR." → Nay không còn đúng hoàn toàn. Khách đã cho phép trước:
- Thêm key layout thuần frontend, cross-device (thứ tự widget, cột ẩn/hiện, tab mặc định…) → không cần CR, không migrate DB. Đây chính là lý do cột tồn tại.
- Thêm key mang logic backend hoặc chi phí (thứ mà worker / Zapier flow phải đọc) → vẫn cần CR, vì nó biến cột ngủ thành cột sống.
Việc BA cần làm tiếp (phát sinh 2026-09-03)
| # | Việc | Liên quan |
|---|---|---|
| 1 | ✅ Đã làm — cập nhật QnA_STAGE2_SETTINGS_CAREER_VIRAL.md + _EN.md lên v16: thêm [CTRL-EP-05], đóng [CTRL-EP-03] / [CTRL-EP-04], thêm Open Item #43. Dọn kèm: [CTRL-EP-01], [CTRL-TRIG-01], [PP-EP-01] bỏ trạng thái ⏳ (phản ánh câu trả lời 2026-08-24 / 2026-08-27). | [CTRL-EP-05] |
| 2 | ⏳ Chưa xong — dependency BE, không đổi: GET /profile phải bổ sung ai_enabled top-level vào response. Đây vẫn là mục backend duy nhất còn treo của UC_4.6.4. | C-04, UC_4.6.4 BR_4.6.4.2 |
| 3 | ⏳ Chưa xong — WBS: dòng 174 vẫn ghi PUT /profile (phải là PATCH /profile); dòng 176 vẫn liệt kê POST /accessibility-preference (đã bỏ). | [PP-EP-01], [CTRL-EP-01] |
| 4 | ⏳ Còn treo với khách: [CTRL-BIZ-02] — default của Reduce Motion trên thiết bị hoàn toàn mới. Câu trả lời này không đụng tới. | [CTRL-BIZ-02] |
✅ Trả lời QnA — 2026-08-28 (10 câu · UC_4.6.1 / 4.6.2 / 4.6.3 / 4.6.4)
Trạng thái apply: UC_4.6.1_v1.md v1.13 · UC_4.6.3_v1.md v1.2 · UC_4.6.4_v1.md v6 · UC_4.6.2_v1.md v11.
UC_4.6.1 — Connections & Credentials
| Q | Điểm | Kết luận | Đã apply vào |
|---|---|---|---|
| 2 | URL reset của 3 gateway | 🔄 Re-classify: blocker là BÊN THỨ 3, không phải dev team. 2026-08-24 xếp đây là output của dev khi làm xong platform integration; nay đính chính — "Phía bên thứ 3 (gateways) hiện chưa cung cấp link reset password chính thức". Dùng placeholder URL, thay link thật khi gateway cấp. ⚠️ Hệ quả: không tracking được như dev task, cửa sổ dùng placeholder không có deadline nội bộ nào. | BR_4.6.1.5 open item 1 |
| 3 | Wording modal CF-02 | ✅ [CC-UI-02] ĐÓNG — dùng chuỗi gốc của khách, sau 3 lần được duyệt: "This will instantly overwrite your current platform password and generate a new one. You will be logged out of active sessions." Bản BA draft bị rút. Đọc như cảnh báo về trạng thái cuối cho trader, không phải mô tả kỹ thuật của nút Confirm. | BR_4.6.1.5 · §9.1 row 12 |
| 4 | Deep link Sierra Chart | 🟡 Bỏ link cũ, chờ link mới. Trang index tổng của Rithmic đã gỡ và không được dùng lại. Sierra Chart dùng chung placeholder với 2 platform kia. | BR_4.6.1.11 |
| 5 | Giá trị placeholder | ✅ Dùng link giữ chỗ của hệ thống. 🔴 Phương án "để trống" nêu trong cùng câu trả lời bị loại: nút không bao giờ ẩn, nên URL rỗng ⇒ bấm vào mở tab trắng ở 3/7 platform. Mới: guide thật cho 3 platform này sẽ là PDF do BA tự soạn, không phải trang vendor → chốt luôn câu hỏi web-page-vs-PDF treo từ 2026-08-24 cho 3 platform này; 4 link Futures vẫn là trang vendor. ⚠️ Kéo theo: yêu cầu Content-Disposition: inline giờ là thật, không còn giả định. | BR_4.6.1.11 |
⚠️ Một chữ trong wording đã duyệt lệch với flow — cố ý chấp nhận, đã ghi vào SRS. Chữ "instantly" không đúng dưới model redirect: lúc bấm Confirm không có gì xảy ra — việc ghi đè và ngắt session diễn ra ở bên thứ 3, và chỉ khi trader thực sự hoàn tất reset bên đó. Trader bấm Confirm rồi đóng tab vendor thì giữ nguyên password cũ và vẫn đang đăng nhập. SRS ghi rõ: QC không được raise đây là defect, dev không được tự sửa chữ trong lúc build.
UC_4.6.3 — Billing
| Q | Điểm | Kết luận | Đã apply vào |
|---|---|---|---|
| 6 | fee_type cho Time Extension | ✅ Không tồn tại. "Đấy là dummy data ghi trên figma thôi. Không có Time Extension." → toàn bộ cảnh báo 🚨 treo từ 2026-08-21 (trader không phân biệt được reset vs extension) tự tiêu vì mất tiền đề. Bảng map 5 giá trị là đầy đủ. 🔴 Dòng Time Extension trong design không được build — nó là sample data bịa, không phải label chờ sửa. | BR_4.6.3.5 |
| 7 | Payout trong Invoice History | ✅ Không. Tab Billing chỉ theo dõi inflow — Challenge, Reset, Market Data. Toàn bộ lịch sử + quản lý Payout dời sang sub-tab riêng ở Day 2 → có đích đến rõ ràng, không còn là khoảng trống chưa ai nhận. Loại trừ là vĩnh viễn với UC này, không phải defer trong UC. | BR_4.6.3.12 |
| 8 | Path endpoint | ✅ GET /billing-history — xác nhận đúng convention kebab-case. Get Billing History là tên nghiệp vụ, không phải path. Đóng D-20(a). | BR_4.6.3.3 |
| 9 | subscription_id | 🔄 BỎ HẲN khỏi signature. Đây là bước thứ 3 và cuối: 2026-08-12 khoá cứng user_id, subscription_id → 2026-08-21 thành "optional, ignored" → 2026-08-28 xoá luôn. Signature chỉ còn user_id. Cho phép cũ "BE cứ nhận rồi bỏ qua cho khớp docx" bị rút — field tồn tại mà không làm gì là cái bẫy, mời gọi implement filter về sau. | BR_4.6.3.3 |
UC_4.6.4 — Controls
| Q | Điểm | Kết luận | Đã apply vào |
|---|---|---|---|
| 11 | ai_enabled trong GET /profile | ✅ Bắt buộc. SRS nay có bảng tách rõ 2 việc khác nhau: GET /profile đọc vị trí đã lưu 1 lần lúc load màn; POST /ai-preference ghi mỗi lần gạt. Chưa có field này thì toggle không build đúng được. Đây là mục backend duy nhất còn lại của UC. | BR_4.6.4.2 |
2 lựa chọn trong câu trả lời, SRS chốt 1: (a) field để top-level
ai_enabled, KHÔNG nhét trongui_preferences— vì phía ghi đã nhắm cột riêngusers.ai_enabled, nhét read vào JSON blob sẽ tách 1 giá trị ra 2 shape. (b) tên endpoint giữGET /profile, không dùngGET /user-profile— đây là tên mọi UC khác trong cụm đang đọc.
UC_4.6.2 — Profile & Preferences
| Q | Điểm | Kết luận | Đã apply vào |
|---|---|---|---|
| 12 | user_id trong payload | ✅ Giữ user_id ở cả 3 endpoint (PATCH /profile, PATCH /profile-photo, POST /ai-preference) cho nhất quán với RFQ gốc. Việc omit trong ví dụ payload hôm 27 là viết tắt, không phải đổi contract. | BR_4.6.2.15 |
⚠️ Ghi thêm vào SRS: đây là quyết định nhất quán, không phải phân quyền.
user_idtrong body không bao giờ được coi là nguồn quyết định ghi vào record của ai — BE resolve trader từ session và reject nếu lệch. Payload manguser_idkhác trader đang đăng nhập là lỗi, không phải lệnh ghi hộ người khác.
Chưa trả lời
| # | Câu hỏi | UC |
|---|---|---|
| 10 | Design sửa typo heading Invoices History → Invoice History, và đồng bộ dummy data (15 dòng render vs 14 trang) | UC_4.6.3 |
✅ Trả lời QnA — 2026-08-27 (Phần III · UC_4.6.4: Controls)
Trạng thái apply: UC_4.6.4_v1.md v5 · UC_4.6.2_v1.md v11 (đóng nốt câu treo ui_preferences).
Chốt
| # | Điểm | Kết luận | Đã apply vào |
|---|---|---|---|
| 1 | Desk Manager — endpoint | ✅ Xác nhận POST /ai-preference, payload {user_id, ai_enabled} → 200 OK, lưu users.ai_enabled. Không gộp vào profile. SRS nay ghi payload nguyên văn dạng code block. | BR_4.6.4.2 |
| 2 | Reduce Motion — không API | ✅ Xác nhận FE-only, không endpoint, không request. | BR_4.6.4.2 — không đổi |
| 3 | Reduce Motion — local key | ✅ stacktrading.reduce_motion (Boolean, localStorage) — nay là contract chính thức. Caveat cũ "BA-proposed, chưa phải contract khách chốt" bị rút. Không có key ⇒ resolve về default. | BR_4.6.4.2 |
| 4 | Reduce Motion — DEFAULT | 🔴 ĐẢO NGƯỢC: ON → OFF. C-07 (BA instruction 2026-08-12) bị supersede. Trader mới trên máy mới thấy đầy đủ motion — Level-Up Cinematic + nhấp nháy đỏ CRITICAL — không phải chạm setting nào. Đây chính là điểm SRS đã cảnh báo suốt v3–v4 là "inverts the motion-first presentation" → nay được giải quyết, không phải chấp nhận. | BR_4.6.4.5 — bảng default + blockquote viết lại · §9.1 row 7 |
✅ Default và scope per-device nay cùng chiều. Dưới default ON cũ, trader dùng 3 máy phải tắt 3 lần để có trải nghiệm mà sản phẩm được thiết kế quanh nó. Dưới OFF, đúng người cần giảm motion — case "weak travel laptop" vốn là lý do khiến preference này thành device-local — bật lên ở đúng máy đó, desktop mạnh không bị đụng.
⚠️ QC phải re-baseline. Test path mặc định giờ là full-motion; rule set reduced-motion (
BR_4.6.4.7) chỉ chạm tới sau khi trader chủ động bật. Mọi test viết theo v1–v4 giả định browser sạch = motion bị suppress đều sai với v5.
✅ Đóng câu treo ui_preferences của Phần II
Phần II mô tả PATCH /profile cập nhật cả ui_preferences; Phần III chốt ngược lại: vì Desk Manager giữ endpoint riêng, PATCH /profile "chỉ dùng để cập nhật số điện thoại", payload {"phone_number": "+84901234567"}.
→ ui_preferences giờ không có reader lẫn writer nào trong toàn module Settings — là cột ngủ, không phải field sống. Blockquote trong BR_4.6.2.15 đổi từ 🔴 sang ✅.
⚠️ 1 chi tiết contract cho BE: payload Phần III viết không có
user_id({"phone_number": …},{"profile_photo_url": …}) trong khiPOST /ai-preferencecó. SRS tạm giữuser_idở cả 2 endpoint profile cho nhất quán với RFQ signature. BE xác nhận: có định danh trader qua auth token không? Nếu có thì bỏuser_idkhỏi payload, không đổi gì khác.
✅ Trả lời QnA — 2026-08-27 (Phần II · UC_4.6.2: Profile & Preferences)
Nguồn: BA/khách trả lời trực tiếp trên file này (hợp nhất với đề xuất BE).
Trạng thái apply: đã ghi vào UC_4.6.2_v1.md v11.
Chốt
| # | Điểm | Kết luận | Đã apply vào |
|---|---|---|---|
| 1 | Tên endpoint [PP-EP-01] | ✅ Đóng. Chốt PATCH /profile theo chuẩn RESTful — đề xuất BE được nhận nguyên vẹn. PUT /profile (WBS) và POST Update User Profile (RFQ) chính thức bị supersede, không được cite làm contract nữa. Email + Full Name read-only. ⚠️ WBS dòng 174 vẫn ghi PUT /profile — cần sửa. | BR_4.6.2.15 — thay blockquote ❓ bằng ✅ |
| 2 | Tách 2 endpoint | ✅ Xác nhận PATCH /profile-photo (chỉ URL ảnh) và PATCH /profile (phone). Đúng như SRS v8 đã viết — không đổi gì. | BR_4.6.2.15 |
| 3 | Gộp crop → S3 → PATCH | ✅ Xác nhận: [Done] trên modal crop → xin signed URL → upload thẳng S3 → tự động PATCH /profile-photo → Sidebar User Chip + My POD cập nhật ngay. Phone chỉ gửi khi bấm [Save Changes] tổng. Đúng SRS v8. | BR_4.6.2.6, BR_4.6.2.14 |
| 4 | Rate limit đổi phone (A-16) | ✅ Không có, cho bản launch. Trader đổi tự do. ⚠️ Ghi rõ trong SRS: đây là quyết định build khi khách chưa nêu giới hạn, không phải khách đã bác giới hạn — QnA row vẫn STILL OPEN. Khách chốt sau thì rơi đúng vào chỗ này. | BR_4.6.2.12 |
| 5 | Bảo mật đổi phone (A-17) | ✅ Không có ràng buộc nào. Qua đúng 2 cổng: regex format của checkout + uniqueness toàn hệ thống → ghi thẳng PostgreSQL. Không OTP, không email cảnh báo, không audit log. | BR_4.6.2.12 — bullet mới |
| 6 | Avatar Dashboard vs Discord (A-20) | ✅ Đóng — bằng cách xoá bỏ tranh chấp. Dashboard thắng và độc lập hoàn toàn: StackTrading không bao giờ đọc avatar hay tên từ Discord API — không làm primary, không làm fallback, trên mọi surface. Lý do khách nêu: vỡ ảnh / link CDN Discord hết hạn. Dashboard dùng ảnh upload hoặc initials; Discord dùng ảnh riêng của trader. Trader có 2 ảnh khác nhau là đúng ý đồ, không phải sync gap. | BR_4.6.2.13 — thay blockquote defer bằng bảng + rationale |
✅ Hệ quả cho UC_4.14.2 (Pod Mentorship — LIVE): data contract của widget
My PODgiờ bị ràng buộc, không còn để ngỏ. Nhánh "Discord-sourced avatar làm fallback thứ 2" bị loại, không cần thiết kế nữa. Mục A-20 trong danh sách "Việc BA cần làm tiếp" của Vòng 1 (#9, #10) đóng.
🔴 Một điểm trong câu trả lời không được áp
Câu 2 mô tả PATCH /profile cập nhật "số điện thoại (phone_number) và cấu hình giao diện (ui_preferences)". SRS giữ payload chỉ {user_id, phone_number}, vì 2 lý do đều mới hơn lần cuối field này còn sống:
- A-18 (2026-08-11) đã vạch ranh giới: UC_4.6.2 không đọc/ghi
ui_preferences— nó thuộc UC_4.6.4. - Câu trả lời khách 2026-08-24 làm cột này mất sạch consumer:
Reduce Motionlưu local per device, không server-side;Desk Managerdùng cột boolean riêngusers.ai_enabledquaPOST /ai-preference. → UC_4.6.4 cũng không ghiui_preferences.
Ghi từ màn này sẽ hồi sinh một field chết — cho nó một writer nhưng vẫn không có reader nào. Cột vẫn nằm trong Zapier Users schema và trong response của GET /profile (shape không đổi). ✅ Cập nhật 2026-09-03: khách xác nhận cột này ngủ có chủ đích — "no active parameters to parse… today… strictly as a future-proofing measure". Về sau thêm key layout thuần frontend thì không cần CR; chỉ key mang logic backend/chi phí mới cần CR. Xem Trả lời QnA 2026-09-03.
→ Cần anh xác nhận: giữ payload {user_id, phone_number} (mặc định hiện tại), hay có preference mới sắp thêm khiến ui_preferences sống lại?
✅ ĐÃ TRẢ LỜI 2026-09-03 — giữ payload {user_id, phone_number}. Khách: "There are currently no active parameters to parse for this field today" → không có preference nào sắp thêm; cột giữ lại thuần tuý để future-proof. Xem Trả lời QnA 2026-09-03.
✅ Trả lời QnA — 2026-08-27 (UC_4.6.1: 9 câu — Module II)
Nguồn: BA/khách trả lời trực tiếp trên file này.
Trạng thái apply: đã ghi vào UC_4.6.1_v1.md v1.12.
⚠️ Đọc kèm: phần này đè lên mọi kết luận cũ của Vòng 2 và các vòng 2026-08-21 / 2026-08-24 ở phía dưới file.
Chốt
| # | Điểm | Kết luận | Đã apply vào |
|---|---|---|---|
| 1 | Cơ chế Password Reset | 🔴 Câu trả lời chứa 2 model ngược nhau — vừa "Dashboard sử dụng URL bên thứ ba để người dùng tự reset" (redirect), vừa "API này sẽ gọi đến Admin API của từng ISV… ép ghi đè mật khẩu cưỡng bức" (overwrite) — nhưng lại chốt "không cập nhật/lưu trữ/đồng bộ bất cứ update password nào… Chỉ lưu trữ và hiển thị assign password". BA chốt 2026-08-27: giữ model REDIRECT. Lý do overwrite bị loại: ghi đè mà không lưu và không trả về ⇒ password cũ bị huỷ, password mới không có kênh nào đến tay trader ([CC-DEF-08]: không gateway nào gửi email) ⇒ trader mất quyền vào terminal. | BR_4.6.1.5 — thêm block ✅ re-tested; mechanism không đổi |
| 2 | Wording modal CF-02 | 🔴 Không áp. Chuỗi "This will instantly overwrite your current platform password and generate a new one…" được duyệt trên tiền đề Confirm thực hiện overwrite. Theo model redirect, Confirm không overwrite, không generate, không ngắt session — bên thứ 3 làm cả 3, và chỉ khi trader thực sự hoàn tất reset ở đó. → chuỗi cũ giữ nguyên trạng thái withdrawn, bản BA draft đứng, vẫn chờ khách duyệt. | BR_4.6.1.5 Behaviour step 2 · [CC-UI-02] vẫn treo |
| 3 | Mapping License Key | ✅ Đúng — Rithmic only. MT5 / TraderEvolution: ẩn hoàn toàn dòng License Key + nút Copy, không để trống, không disable. Lý do bổ sung vào SRS: dòng trống hoặc disable sẽ nói với trader MT5 rằng có license key nhưng bị giữ lại — sai sự thật. | BR_4.6.1.3 — thêm câu re-confirm |
| 4 | Sierra Chart guide | ✅ Chấp nhận index tổng chỉ như placeholder, 🔴 vẫn phải tìm deep link đúng bài. → Sierra Chart khác TradingView / MT5: ở đây bài viết đúng có tồn tại, chỉ là chưa tìm ra. Là task content, không phải câu hỏi behaviour. | BR_4.6.1.11 — bullet mới |
| 5 | Nơi lưu Connection_Guide_URL | 🔴 Câu 15 và câu 20 mâu thuẫn (hardcode vs Table I). BA chốt: HARDCODE trong code BE. Cột Connection_Guide_URL trên Table I bị rút, không tạo. Contract GET /credentials không đổi — chỉ đổi nguồn phía sau. ⚠️ Hệ quả phải chấp nhận: mọi lần đổi link (dummy → real, deep link Sierra Chart, vá link vendor chết) đều là dev ticket + deploy; Ops sở hữu giá trị nhưng không tự apply được — thu hẹp kỳ vọng "để Ops có thể cập nhật sau". Muốn Ops tự sửa thì raise CR chuyển sang Table I. | BR_4.6.1.11 — block storage mới + RACI viết lại + đoạn null-branch |
| 6 | Placeholder guide | ✅ Mỗi platform 1 placeholder độc lập (link mới hoặc link PDF tạm). Dùng chung 1 placeholder cho cả 3 bị bác — sẽ làm 3 lần swap dính vào nhau và che mất platform nào còn treo. Nút không ẩn trong bất kỳ trường hợp nào (lần thứ 3 khách nhắc lại). | BR_4.6.1.11 |
| 7 | Gateway tự rotate credential | ✅ Để im tuyệt đối — không email, không notification, không banner, không badge stale. Đóng B-08 và [CC-TRIG-01]. Lý do ghi vào SRS: DB là master record của assigned password và chỉ của nó, nên không tồn tại "giá trị đúng" nào để đi báo. | BR_4.6.1.7 — viết lại đoạn cuối |
| 8 | Design frame Settings | ✅ Đóng — không theo dõi nữa. "Khi nào có BA sẽ tự bổ sung. Bạn đừng có để làm pending question hay push nữa." → note trong SRS đổi thành internal housekeeping, gỡ khỏi mọi danh sách open item, không hỏi khách, không nhắc lại. | Header design-asset note |
| 9 | Contract GET /credentials + path sinh password | ✅ Contract confirm đúng bản đang có (nested Credentials, bỏ Login phẳng, License_Key null trừ Rithmic, password plaintext chỉ ở endpoint này, DB chỉ lưu ciphertext). Mới: đóng BR_4.6.1.15 điểm 1 — Path B cho cả 3 gateway: Flow 1 Step 3 gọi POST /provision-sim-user → ISV tạo account và sinh credential, trả về → middleware mã hoá, ghi ciphertext → không email nào mang credential. Path A không build cho gateway nào. | BR_4.6.1.15 điểm 1 — bảng sequence mới |
Còn treo sau vòng này
| # | Việc | Chặn |
|---|---|---|
| 1 | URL màn reset của 3 gateway — vẫn chưa có. Đã re-classify 2026-08-24 là dev-sequenced, không phải content khách nợ. BE cần nói rõ gateway nào thực sự sẽ có trang reset cho trader. | BR_4.6.1.5 open item 1 (🟡) |
| 2 | Wording modal CF-02 — bản BA draft chờ khách duyệt. Bản overwrite không dùng được dưới model redirect. | [CC-UI-02] |
| 3 | Deep link Sierra Chart — phải sourcing bài đúng, không dùng index tổng khi ship. | BR_4.6.1.11 |
| 4 | Giá trị placeholder cụ thể cho 3 platform chưa có guide — BE/FE chốt. | BR_4.6.1.11 |
✅ Trả lời QnA — 2026-08-24 (UC_4.6.4: Controls — Reduce Motion vs. Desk Manager)
Đóng
CTRL-EP-01— câu treo từ 2026-08-10, đi qua Vòng 3 (C-04/C-05/C-06 phải "Applied by default") và vòng 2026-08-21 mà vẫn chưa có lời.
Câu hỏi BA đã gửi khách
BA nêu lại đề xuất gộp endpoint mà phía BA từng đưa ra — dùng một PUT /profile duy nhất, không build POST /ai-preference / POST /accessibility-preference, cả 2 toggle đẩy state boolean vào chung object ui_preferences ({"ui_preferences": {"desk_manager_enabled": true, "reduce_motion": true}}) — rồi chỉ ra 2 điểm lệch với nguồn: RFQ_ Stack Trading Prop Tech V7.pdf có sẵn API cho Desk Manager (AI Preference Toggle), còn Reduce Motion thì không có API nào. Hỏi khách chốt hướng cuối cùng.
Câu trả lời của khách (nguyên văn)
Reduce Motion: There is no backend API for this. UI animation performance depends entirely on the specific hardware the trader is currently using. A user may need to reduce motion on a weak travel laptop but keep the animations active on their powerful home desktop.
AI Desk Manager Toggle This must be a backend call. The Desk Manager commentary is generated asynchronously by our Node.js backend pinging the Gemini API. If the user turns this off, the backend must know immediately so we halt the background worker and stop spending API tokens to generate unused text.
Chốt
| # | Điểm | Kết luận | Đã apply vào |
|---|---|---|---|
| 1 | Reduce Motion — endpoint | Không có backend API. POST /accessibility-preference rút hẳn, không build. FE xử lý trọn vẹn toggle này. | BR_4.6.4.2 — viết lại; §6 — viết lại, bỏ toàn bộ network step |
| 2 | Reduce Motion — nơi lưu | Lưu local trên trình duyệt của thiết bị đang dùng. Field users.ui_preferences.reduce_motion rút — không ghi, không đọc. | BR_4.6.4.2; §4 Post-conditions |
| 3 | Reduce Motion — scope | Per device + per browser profile, KHÔNG per user. Lý do khách nêu là phần cứng: "a weak travel laptop" vs "their powerful home desktop" — nên đồng bộ theo account là sai nghiệp vụ, không phải chỉ là khác cách lưu. | BR_4.6.4.5 — viết lại, tách scope 2 toggle |
| 4 | Reduce Motion — error path | Không còn. Không gửi request thì không có HTTP 5xx, không revert vị trí toggle, không TE-SYS-01, không in-flight guard. | §7 rows 3–4; BR_4.6.4.4 |
| 5 | Desk Manager — endpoint | Vẫn là backend call, giữ POST /ai-preference + users.ai_enabled theo RFQ_ Stack Trading Prop Tech V7.pdf §API table. Đề xuất gộp vào PUT /profile + ui_preferences.desk_manager_enabled mà BA nêu trong câu hỏi không được khách chọn → rút, không đưa vào SRS. | Không đổi so với v3 — BR_4.6.4.2 giữ nguyên contract |
| 6 | Desk Manager — lý do bắt buộc backend | Flag chạy một background worker tốn tiền. Suy ra 2 ràng buộc: (a) BE phải biết ngay khi gạt, không được giữ client-side rồi reconcile sau; (b) worker phải dừng hẳn, không phải mute — "halt the background worker and stop spending API tokens". Implementation kiểu vẫn gọi Gemini rồi ẩn ở FE là FAIL rule này. | BR_4.6.4.6 — thêm note re-confirm, củng cố C-10 |
⚠️
ui_preferencesgiờ không còn consumer nào trong UC_4.6.4. Cột JSON vẫn nằm trong Zapier Users schema, nhưng cả 2 toggle đều không dùng: Desk Manager dùng cột boolean riêngusers.ai_enabled, Reduce Motion không lưu server. Ranh giới A-18 không đổi — UC_4.6.2 vẫn không đọc/ghiui_preferences; nó chỉ đơn giản là mất consumer. ✅ 2026-09-03 khách xác nhận đây là trạng thái mong muốn, không phải thiếu sót: cột giữ "strictly as a future-proofing measure", BE "maintain this column as an optional JSON object". Xem Trả lời QnA 2026-09-03.
⚠️ Hệ quả mới của scope per-device (chưa hỏi khách).
Reduce Motiondefault ON (C-07) giờ áp mỗi thiết bị mới, không phải một lần cho mỗi account. Trader dùng 3 máy phải tự tắt 3 lần. Điểm này gộp chung vào câu hỏi đang treo ở việc BA cần làm tiếp Vòng 3, mục 4.
Việc BA cần làm tiếp (phát sinh 2026-08-24)
| # | Việc | Liên quan |
|---|---|---|
| 1 | Sửa WBS dòng 176 — cột endpoint vẫn liệt kê POST /accessibility-preference, endpoint này không còn tồn tại | References/WBS/[BA Internal] Stacktrading.csv |
| 2 | Cập nhật QnA from clients (QnA_STAGE2_SETTINGS_CAREER_VIRAL.md VI + EN + CSV): row Controls & Concierge / Endpoints [CTRL-EP-01] đang là ⏳ CHƯA TRẢ LỜI, và row Trigger [CTRL-TRIG-01] vẫn mô tả Reduce Motion "giả định hoạt động tương tự → POST /accessibility-preference" | [CTRL-EP-01], [CTRL-TRIG-01] |
| 3 | ✅ ĐÃ ĐÓNG 2026-08-27 — stacktrading.reduce_motion (Boolean, localStorage) nay là contract chính thức, caveat BA-proposed bị rút | BR_4.6.4.2 |
| 4 | 🔄 ĐÃ ĐÓNG 2026-08-27 — không giữ. Default đảo thành OFF, nên vấn đề lặp-lại-trên-từng-thiết-bị tự tiêu. Reduce Motion = ON giờ lặp lại trên từng thiết bị | C-07 |
✅ Bổ sung 2026-08-21 (đợt 2) — UC_4.6.1: MT5 multi-password · chuẩn mã hoá · Connection Guide URLs
Nguồn: BA/khách trả lời trực tiếp (3 mục bổ sung + 6 câu chốt các điểm treo của v1.6).
Trạng thái apply: đã ghi vào UC_4.6.1_v1.md v1.7 và docs/BA/Common_rule/list-toast-popup.md v3.12 (CF-02).
⚠️ Đọc kèm: phần này đè lên vòng trả lời 2026-08-21 (đợt 1) ngay bên dưới ở các điểm:
Connection_Stringnullable, copy modal Password Reset, empty state chưa-provisioned.
Mục 1 — MT5 có 4 password, chỉ lưu 1
Hỏi: MT5 cấp tới 4 password cho một tài khoản — Main/Master (toàn quyền), Investor (read-only, không trade được), Trader (trade được nhưng không quản lý tiền/password), Money (quản lý tiền nhưng không trade, không đổi password). (1) Dashboard có lưu cả 4 không? (2) Nếu lưu cả 4 thì [Password Reset] dẫn tới reset password nào?
Trả lời: (1) "No, just the main and the initial." — (2) "Main."
| Hệ quả | Áp vào |
|---|---|
platform_password_ciphertext trên tài khoản MT5 chỉ chứa password Main, và là bản cấp lúc provisioning. Investor / Trader / Money không provision, không lưu, không hiển thị. | BR_4.6.1.16 (mới) · BR_4.6.1.7 |
Credentials.Password của MT5 = password Main. Dòng Assigned Password vẫn là 1 dòng duy nhất trên mọi gateway — không có biến thể UI riêng cho MT5, không có selector chọn loại password. | BR_4.6.1.16 · BR_4.6.1.2 · §9.1 row 9 |
| [Password Reset] trên MT5 nhắm vào password Main. Modal không cần biến thể MT5 vì trader không được chọn. | BR_4.6.1.5 · §9.1 row 11 |
| Rithmic và TraderEvolution mỗi bên chỉ 1 password → không ảnh hưởng. | BR_4.6.1.3 |
❓ BA nêu (khách chưa đề cập): password Investor (read-only) là thứ trader đưa cho dịch vụ analytics / copy-trading / verification bên thứ ba. Sản phẩm hiện không có chỗ nào lấy được nó. Ngoài scope cho tới khi khách hỏi — thêm vào sẽ là CR, không phải defect.
Mục 2 — Sinh password ban đầu, cipher và quản lý key
Hỏi (dev team đề xuất siết bảo mật): (1) hệ thống tự sinh password ngẫu nhiên gửi sang broker để tạo account; (2) mã hoá 2 chiều AES-256-GCM bằng secret key chia sẻ với api-core; (3) gửi ciphertext cho api-core để decrypt và trả về cho khách — worker-lifecycle không lưu plaintext. Ý khách thế nào?
Trả lời:
- "Depends if supported, the ISV may generate the initial password."
- "Your team's intuition on security is correct, but this is not a new proposal. This exact workflow is already a mandate in the V7 specification."
- "Please ensure that the 'secret key' you mentioned is securely generated and managed via AWS KMS (Key Management Service) or AWS Secrets Manager as defined in our infrastructure spec, rather than simply hardcoding a shared secret string into the application environment variables."
- "Yes, I'm supportive!"
| Hệ quả | Áp vào |
|---|---|
| Không phải requirement mới — đây là mandate đã có sẵn trong V7 spec. Không mở CR. | BR_4.6.1.15 (mới) |
| Ai sinh password ban đầu là tuỳ gateway: (A) StackTrading sinh random rồi gửi sang gateway, hoặc (B) ISV/gateway tự sinh và trả về. ❓ BE confirm từng gateway (Rithmic / MT5 / TraderEvolution). Không chặn màn hình — mọi thứ phía sau nhánh này giống hệt nhau. | BR_4.6.1.15 điểm 1 |
| Cipher = AES-256-GCM, 2 chiều (bắt buộc 2 chiều vì phải decrypt để hiển thị — không hash được). | BR_4.6.1.15 điểm 2 |
Secret key phải sinh & quản lý qua AWS KMS hoặc AWS Secrets Manager. Hardcode chuỗi secret vào env var là non-conformance rõ ràng, không phải giải pháp tạm. cipher_version ghi thế hệ key để rotate không mồ côi record cũ. | BR_4.6.1.15 điểm 3 |
Phân tách component: worker-lifecycle không bao giờ persist plaintext; chỉ api-core giữ quyền decrypt, và chỉ trả plaintext cho trader đã authenticate qua GET /credentials. Zapier và SES: không bao giờ thấy plaintext. | BR_4.6.1.15 điểm 4 · BR_4.6.1.14 |
| RACI: Sotatek build (sinh / mã hoá / lưu / decrypt) · Stack Trading ops (AWS account, KMS key policy, Secrets Manager config) · third party (bản thân credential sau khi cấp). | BR_4.6.1.15 |
Mục 3 — Connection Guide URLs (5 platform Futures)
Trả lời: khách cung cấp URL thật cho từng platform. Click [Connection Guide] dẫn thẳng tới tab tương ứng của platform đó.
⚠️ Sửa 2026-08-22 (BA): 2 link Forex — TradingView và MetaTrader 5 — đã bị bỏ trước khi publish. Chỉ còn 5 platform Futures có guide. Hai platform Forex hiện không có guide nào → nút [Connection Guide] không render cho trader dùng 2 platform đó.
| Asset class | Platform | Gateway | URL |
|---|---|---|---|
| Futures | TradeSea | Rithmic | https://help.tradesea.ai/en/articles/13669808-connect-account |
| Futures | ATAS | Rithmic | https://help.atas.net/en/support/solutions/articles/72000602593-connecting-to-rithmic |
| Futures | Quantower | Rithmic | https://help.quantower.com/quantower/connections/connection-to-rithmic |
| Futures | MotiveWave | Rithmic | https://docs.motivewave.com/knowledge-base/connection/connect-motivewave-to-r-trader-pro-gateway |
| Futures | Sierra Chart | Rithmic | https://www.rithmic.com/platforms/guides |
| Forex | TradingView | TraderEvolution | ❌ chưa có → ẩn nút |
| Forex | MetaTrader 5 | MetaTrader 5 | ❌ chưa có → ẩn nút |
| Hệ quả | Áp vào |
|---|---|
🔴 Guide resolve theo platform_selection, KHÔNG theo Gateway_Router. Đây là chỗ duy nhất trong UC mà platform và gateway tách nhau trên UI: header card ghi gateway, nút guide resolve theo platform. 5 platform Futures đều hiện header Rithmic nhưng mở 5 guide khác nhau — resolve theo gateway sẽ đưa 4/5 trader tới sai tài liệu. | BR_4.6.1.11 (viết lại + đổi tiêu đề) · §9.1 row 5 |
| Kế hoạch "placeholder guides, khách tự sửa sau" (2026-08-17) bị rút — đây là 7 URL vendor thật, StackTrading không sửa được nội dung. Vendor đổi/gỡ trang → link chết âm thầm, không có cơ chế phát hiện in-app. | BR_4.6.1.11 |
RACI: Sotatek build phần resolve + lưu mapping dạng config (đề xuất: thêm cột Connection_Guide_URL vào Table I — Platforms and Gateway Registry để sửa URL không cần deploy, ❓ BE confirm chỗ lưu) · Stack Trading ops cung cấp & bảo trì giá trị URL · third party sở hữu nội dung trang. | BR_4.6.1.11 |
🔴 Connection_Guide_URL = null là case thật, không phải nhánh phòng thủ — TradingView và MetaTrader 5 đang null, nên nhánh "ẩn hẳn nút" là trạng thái mặc định của toàn bộ nhánh Forex và phải build + test ngay từ đầu, không được coi là edge case. Khi khách gửi link thì chỉ là đổi config, không đổi code. | BR_4.6.1.11 · §9.1 row 5 · §5 step 8 |
| ⚠️ Bất đối xứng cần khách biết: trader Futures có guide, trader Forex thì không — cùng một màn hình, cùng một nút. | BR_4.6.1.11 |
❓ 2 điểm BA nêu, khách chưa xác nhận:
- Sierra Chart trỏ tới trang index tổng các guide của Rithmic (
rithmic.com/platforms/guides), không phải deep link tới bài Sierra Chart → trader phải tự tìm trong danh sách. Chấp nhận, hay cần sourcing deep link?- 2 platform Forex chưa có guide. Xin khách gửi guide cho TradingView và MetaTrader 5, hoặc xác nhận là cố ý không có. (Ứng viên vòng 2026-08-21 đã bị bỏ: bài TradingView nói về giao dịch FOREX.com trong khi UC map TradingView → TraderEvolution; bài MetaTrader 5 là trang authorization của terminal.)
6 câu chốt các điểm treo của v1.6
| # | Điểm treo | Câu trả lời | Trạng thái | Áp vào |
|---|---|---|---|---|
| 1 | POST /reset-platform-password "dẫn" trader kiểu gì, và 3 gateway có màn reset thật không? | "Hiện tại link chưa có, khách chưa gửi, sẽ add vào sau khi có link từ phía khách." → cơ chế đã chốt (trả URL đích, FE mở tab mới), nội dung còn thiếu. | 🟡 Vẫn treo — re-classify 2026-08-28: blocker là BÊN THỨ 3, gateway chưa cấp link chính thức; dùng placeholder, không có deadline nội bộ | BR_4.6.1.5 bảng open item 1 · §5 step 10 · §9.1 row 11 |
| 2 | Copy modal mâu thuẫn với flow mới | "Đúng rồi, giờ confirm chỉ dẫn sang tab mới để trader reset password thôi. Không overwrite vào assigned password nữa." | ✅ Hành vi đóng · ⚠️ wording cuối còn chờ khách duyệt | BR_4.6.1.5 step 2 · §9.1 row 12 · CF-02 |
| 3 | Empty state "Please check your email" mâu thuẫn với zero vendor email | "Ừ, nên giờ không có empty state này nữa, không còn 'Please check your email' nữa." → bỏ hẳn trạng thái, không chỉ đổi copy (BA xác nhận 2026-08-21). | ✅ Đóng | BR_4.6.1.8 rút (giữ ID, không tái sử dụng) · §6 rút · §7 thêm nhánh null → TE-SYS-01 · §9.1 xoá row 17 |
| 4 | Connection_String có thể null → header card mất nguồn | "Thường thì không bao giờ null được, vì sẽ dựa vào platform thì sẽ luôn có connection_string." → field luôn có trong payload; chỉ dòng hiển thị mới có điều kiện. Rule tạm "null thì fallback về Platform" bị rút. | ✅ Đóng | BR_4.6.1.3 block [CC-EP-02] + contract điểm 5 · §9.1 rows 6, 16 |
| 5 | Không có audit trail / rate limit cho [Password Reset] | "Đúng" — bên thứ 3 tự xử lý. StackTrading không log gì về cú hand-off. | ✅ Đóng (xác nhận lại v1.6) | BR_4.6.1.5 |
| 6 | Design frame chưa commit vào References/Wireframe/Stage 2/Settings/ | "Oke tôi bổ sung sau." → đóng 2026-08-27: "Khi nào có BA sẽ tự bổ sung. Bạn đừng có để làm pending question hay push nữa." | ✅ Đóng — internal housekeeping, không theo dõi, không push | Note ở đầu UC_4.6.1_v1.md đổi thành non-open-item, vẫn cite Figma node 7878-116828 |
Việc BA cần làm tiếp (đợt 2)
| # | Việc | Liên quan |
|---|---|---|
| 1 | 🟡 Vẫn treo, nhưng đã re-classify. URL của 3 gateway là output của dev team khi làm xong platform integration, không phải content khách nợ (2026-08-24). Nửa sau của việc này — "gateway nào không có → ẩn nút" — đã bị rút: nút không bao giờ ẩn (2026-08-24, nhắc lại 2026-08-27). | BR_4.6.1.5 open item 1 |
| 2 | ✅ ĐÃ ĐÓNG 2026-08-28 — dùng chuỗi gốc của khách, bản BA draft bị rút. | [CC-UI-02] |
| 3 | 🟡 Một phần đóng 2026-08-27. (b) đóng — nút không bao giờ ẩn, mỗi platform 1 placeholder độc lập. (a) vẫn treo — index tổng chỉ là placeholder, vẫn phải sourcing deep link đúng bài cho Sierra Chart | BR_4.6.1.11 |
| 4 | ✅ ĐÃ ĐÓNG 2026-08-27 — Path B cho cả 3 gateway (ISV sinh password, trả về qua POST /provision-sim-user). | BR_4.6.1.15 điểm 1 |
| 5 | 🔄 ĐÃ ĐÓNG 2026-08-27 — ĐẢO NGƯỢC đề xuất. Hardcode trong code BE, cột Table I bị rút. ⚠️ Hệ quả: mọi lần đổi link = deploy, Ops không tự sửa được. | BR_4.6.1.11 RACI |
| 6 | Cập nhật QnA from clients (QnA_STAGE2_SETTINGS_CAREER_VIRAL.md VI + EN + CSV): [CC-BIZ-06] và [CC-UI-02] vẫn đang mô tả mô hình overwrite cũ | Kế thừa từ đợt 1 (mục 7) |
✅ Trả lời QnA — 2026-08-21 (9 câu · UC_4.6.1 / 4.6.3 / 4.6.4)
Nguồn: BA/khách trả lời trực tiếp trên file QnA Init Docs này.
Trạng thái apply: đã ghi vào SRS — UC_4.6.1_v1.md v1.6, UC_4.6.3_v1.md v1.1, UC_4.6.4_v1.md v3.
⚠️ Đọc kèm: phần này đè lên mọi kết luận cũ của Vòng 2 (UC_4.6.1), Vòng 3 (C-13) và Vòng 4 (D-06, D-07) ở phía dưới file. Khi 2 chỗ mâu thuẫn, lấy phần này.
UC_4.6.1 — Connections & Credentials
| Q | Item | Câu trả lời | Đã apply vào |
|---|---|---|---|
| Q1 | [CC-EP-02] 🔴 — ai resolve Gateway_Router cho card header? | Gateway_Router được trả về thông qua Connection_string của API Platform Credentials. → Platform vẫn là Platform_Name và không dùng cho header; FE không tra Table I; middleware không thêm field mới. | BR_4.6.1.3 — block [CC-EP-02] chuyển ✅ closed |
| Q2 | [CC-BIZ-08] 🔴 — Rithmic / TraderEvolution có admin-API overwrite password không? | Không — và không còn liên quan, "vì giờ không overwrite password ở bên dashboard". | BR_4.6.1.5 — bảng "Closed 2026-08-21"; MT5 Manager API bị gỡ khỏi dependency set của UC |
| Q3 | [CC-BIZ-09] 🟡 — rate limit / cool-down / audit trail / có rotate License_Key không? | "Việc thay password bên 3rd party thì bên 3rd party sẽ tự xử lý, không rotate License_Key". | BR_4.6.1.5 — StackTrading không rate-limit, không log; License_Key không stale theo password |
| Q4 | 🟡 — partial failure (gateway đã overwrite nhưng DB write fail)? | "Đề xuất: không overwrite password nữa" — xác nhận đúng mô hình v1.5, không phải thay đổi mới. | §7 Exceptional Flow — item đã đóng từ v1.5, nay ghi nhận confirm |
| Q5 | [CC-DEF-08] 🟡 — Rithmic / MT5 có gửi email credential không? | "Không Gateway Router nào gửi." → xác nhận đủ cho cả 3 vendor. | BR_4.6.1.13 — bỏ caveat "believed / chưa confirm"; §1 3rd Party |
Còn treo sau vòng này (2 mục, đều là contract với BE):
| # | Việc | Chặn |
|---|---|---|
| 1 | POST /reset-platform-password trả về cái gì (URL để FE mở tab mới — giả định BA hiện tại — hay chỉ ack?) và mỗi gateway có màn reset cho trader thật không? Q2 mới trả lời nửa "admin API", nửa "đích đến" vẫn trống. | Toàn bộ flow Password Reset |
| 2 | Copy trong modal ("instantly overwrite… and generate a new one") mô tả việc bên thứ 3 làm, không phải việc bấm Confirm làm — cần khách confirm lại wording. | §9.1 row 12 |
⚠️ Lưu ý về Q1: câu trả lời ở dạng hồi tưởng ("Tôi nhớ Gateway_Router được trả về thông qua Connection_string…") và không được
RFQ_ Stack Trading Prop Tech V7.pdf§Page 18 xác nhận — tài liệu chỉ mô tảConnection_Stringlà địa chỉ server của terminal. Thêm nữa,BR_4.6.1.3điểm 5 cho phépConnection_String = null. → Cần BE confirm 1 dòng:Connection_Stringluôn có trong payload (chỉ dòng hiển thị mới optional), hay header cần fallback. Rule tạm của BA: đọc header từConnection_String,nullthì fallback vềPlatform.
UC_4.6.3 — Billing
| Q | Item | Câu trả lời | Đã apply vào |
|---|---|---|---|
| Q11 | D-06 🔴 — subscription_id của GET /billing-history xử lý thế nào? | subscription_id optional, bỏ qua — luôn trả toàn bộ history theo user_id. | BR_4.6.3.3 — đảo ngược quyết định BA 2026-08-12; Input = user_id (required) + subscription_id (optional, ignored) |
| Q12 | D-07 🟡 — thêm EXTENSION_FEE vào ENUM fee_type? | "Bỏ, chỉ sử dụng 5 giá trị đang có thôi." → không đổi schema. | BR_4.6.3.5 — gỡ dòng EXTENSION_FEE khỏi bảng mapping |
🚨 Hệ quả của Q12 phải chốt với BE. Khách đã confirm 2026-08-10 là SIM trader "execute transactions for challenge resets and time extensions", và ảnh design có dòng
Time Extension. BỏEXTENSION_FEEthì khoản extension phải đi dưới 1 trong 5 giá trị còn lại — nhiều khả năng làRESET_FEE— khi đó cộtDescriptioninChallenge Resetcho cả 2 sản phẩm và trader không phân biệt được 2 khoản chi của chính mình. → (a) BE confirmfee_typenào mang khoản extension; (b) nếu làRESET_FEEthì design phải sửa dòngTime Extensionvì nó không render được.
UC_4.6.4 — Controls
| Q | Item | Câu trả lời | Đã apply vào |
|---|---|---|---|
| Q15 | C-10 🔴 — ai_enabled = false thì worker làm gì? | "Skip call hoàn toàn — không gọi Gemini, không trừ token bucket, không push GEKKO_CHATTER." → đúng y nguyên nhánh BA đề xuất. | BR_4.6.4.6 — gỡ note "Pending client confirmation", chuyển ✅ confirmed, ràng buộc check flag trong worker, trước khi gọi LLM |
| Q17 | C-13 🟡 — Level-Up Cinematic khi reduce_motion = true? | "Cũng hiện motion, nhưng hiện motion chạy từ Certificate modal trực tiếp." → KHÔNG skip cinematic nữa. | BR_4.6.4.8 — viết lại; BR_4.6.4.7 — cinematic thành exception của rule set; BR_4.6.4.5 — nhẹ bớt cảnh báo default ON |
🔴 Q17 đảo ngược C-13 của Vòng 3. Vòng 3 chốt "skip cinematic, vào thẳng Certificate modal" (không load WebM/Lottie, không chạy text reveal/QR). Nay: motion vẫn chạy, chỉ khác điểm bắt đầu — trader vào thẳng Certificate modal và motion chạy từ modal đó. Nguồn mới đọc cho vòng này:
Level Up Cinematic Scene Handling.pdf(client supply thêm 2026-08-18) — xác nhận Certificate là trạng thái kết thúc của animation ("At the conclusion of the animation (the final certificate state), the UI will present an expanded share menu"), nên bắt đầu từ đó không mất gì về mặt narrative.4 câu còn treo, chuyển sang UC Level-Up & Certificate (không giải ở UC_4.6.4): (1) motion render trong khung modal hay full-screen phía sau? (2) layer nào chạy trong 5 layer (WebM background / Lottie / Framer Motion / QR / audio) — nếu WebM vẫn load thì budget
< 300 KBkhông còn đúng; (3) audio có chạy không? (4) nếu cả 2 trạng thái toggle đều có motion thì toggle còn đổi gì trên màn này, có cần build biến thể riêng không?
Việc BA cần làm tiếp (phát sinh từ vòng này)
| # | Việc | Liên quan |
|---|---|---|
| 1 | 🚨 Chốt với BE: POST /reset-platform-password trả về gì + mỗi gateway có màn reset cho trader không | UC_4.6.1 Q2 |
| 2 | Chốt với BE: Connection_String có luôn populated không (case null → header mất nguồn) | UC_4.6.1 Q1 |
| 3 | ✅ ĐÃ ĐÓNG 2026-08-28 — chuỗi gốc được duyệt lần 3, chốt dùng. | UC_4.6.1 [CC-UI-02] |
| 4 | ✅ ĐÃ ĐÓNG 2026-08-28 — không có Time Extension, đó là dummy data trên Figma. Câu hỏi mất tiền đề. fee_type nào mang khoản Time Extension | UC_4.6.3 Q12 |
| 5 | 🔄 ĐÃ ĐÓNG 2026-08-28 — mạnh hơn: subscription_id bỏ hẳn khỏi signature, không còn field để mà filter. subscription_id thật sự không filter | UC_4.6.3 Q11 |
| 6 | Đăng ký Level Up Cinematic Scene Handling.pdf + User journey - Certificate and Left Box.docx vào _SOURCE_MANIFEST.yaml (2 file client supply thêm 2026-08-18, chưa có trong manifest) | UC_4.6.4 Q17 |
| 7 | Cập nhật QnA from clients (QnA_STAGE2_SETTINGS_CAREER_VIRAL.md VI + EN + CSV): [CC-BIZ-06] vẫn đang mô tả mô hình overwrite cũ của 2026-08-17 | UC_4.6.1 (CR 2026-08-20) |
Vòng 1 — UC_4.6.2: Profile & Preferences
Phạm vi vòng này: chỉ UC_4.6.2 — Profile & Preferences (WBS category STAGE 2: DASHBOARD - COMMON, module Settings).
Ngày tạo: 2026-08-11
BA in Charge: QuynhAnh12 (git username không khớp BA Roster trong project_context.md — xem A-19)
Ngày BA review: 2026-08-11
Trạng thái tổng: ✅ BA đã chốt 4 nhóm chặn cứng (A-01, A-04, A-09/A-10/A-12, A-18) — Agent 3 được phép viết SRS. Các item còn lại BA không phản hồi cụ thể → áp dụng đúng đề xuất trong bảng (theo thoả thuận ở § "Hướng dẫn cho BA").
Nguồn đã đọc (theo MANDATORY FIRST-READ PROTOCOL)
| Bước | Nguồn | Kết quả |
|---|---|---|
| 0 | References/Customer supplies/_SOURCE_MANIFEST.yaml | ✅ Đã đọc |
| 1 | References/CR/_CR_INDEX.md | ✅ Không có CR nào liên quan Settings/Profile/Avatar/Phone-in-dashboard |
| 1 | References/QnA from clients/.../Stage 2 - Dashboard & Fomula (Settings).csv → hàng Profile & Preferences (dòng 303–330) | ✅ Nguồn chính của UC này |
| 2 | RFQ_ Stack Trading Prop Tech V7.pdf (§Trang 36 — Get User Profile / Update User Profile) | ✅ |
| 2 | RFQ_ Website and Dashboard Implementation V7.pdf (§Part C — Settings & Profile Module) | ✅ |
| 2 | Zapier Integration V7.pdf (§Users table schema — profile_photo_url, phone_number, ui_preferences) | ✅ |
| — | WBS References/WBS/[BA Internal] Stacktrading.csv (parse qua script/parse_wbs.js) | ⚠️ Xem A-18 (WBS lệch cột) |
| — | Design: BA gửi 7 ảnh màn hình trực tiếp trong chat (2026-08-11) + Figma node 7878-116947 | ⚠️ Xem A-19 |
Đã confirm sẵn — KHÔNG cần hỏi lại (ghi ra đây để Agent 3 dùng trực tiếp):
| # | Nội dung | Nguồn |
|---|---|---|
| 1 | Email = Read-only, không sửa được (là unique identity key, gắn với Rithmic/blacklist) | QnA Settings CSV dòng 305 + 322 (Adrian confirm) + BA instruction 2026-08-11 |
| 2 | Full Name = Read-only | QnA Settings CSV dòng 309 + 322 |
| 3 | Phone = Editable, dùng lại nguyên block validation của checkout, không geo-block theo region | QnA Settings CSV dòng 307 + 320–323 (Adrian confirm) |
| 4 | Phone phải unique — dùng lại logic duplicate-check của checkout | QnA Settings CSV dòng 317–320 (Adrian: "Yes") |
| 5 | Entry point màn hình = chip "SD / Lvl 5" ở góc dưới bên trái sidebar | QnA Settings CSV dòng 325 (Adrian - Figma comment) + BA instruction 2026-08-11 |
| 6 | Photo upload dùng S3 signed URL 2 bước: (1) FE xin signed URL → (2) upload thẳng lên S3 → (3) gửi URL kết quả vào profile_photo_url | RFQ_ Stack Trading Prop Tech V7.pdf §Trang 36 + QnA CSV dòng 316 |
| 7 | Profile là global per user — không tách SIM/LIVE | QnA Settings CSV dòng 309 (cột LIVE) |
| 8 | Remove Photo → avatar fallback về chữ cái đầu tên user (vd "Taylor Swift" → "TS") | BA instruction 2026-08-11 |
Bảng QnA & Assumption
| ID | Câu hỏi / Vấn đề | Giả định (Agent đề xuất) | BA chốt | Trạng thái |
|---|---|---|---|---|
| A-01 | [CROSS_UC_CONFLICT] Entry point mâu thuẫn với UC_4.1.2. UC_4.1.2 §2 dòng 6 đang ghi: click icon user ở footer sidebar → mở dropdown 2 item {Settings, Logout}. Nhưng QnA Settings (dòng 325, Adrian) + BA instruction 2026-08-11 + 7 ảnh design đều cho thấy: click chip "SD / Lvl 5" → vào thẳng màn Account, không có dropdown. Chốt cái nào? | Đề xuất: bỏ dropdown — click chip "SD / Lvl 5" điều hướng thẳng sang màn Account (Settings). Hệ quả: UC_4.1.2 §2 dòng 6 phải sửa, và Logout mất chỗ đứng → cần BA chỉ định Logout nằm ở đâu (đề xuất: đưa vào tab Account Actions = UC_4.6.4, cạnh Resign Account). | BA bác đề xuất — giữ nguyên UC_4.1.2. Click chip "SD / Lvl 5" ở footer sidebar → mở dropdown 2 item {Settings, Logout} → chọn Settings → mới vào màn Account. Không sửa UC_4.1.2, không di dời Logout. | ❌ Rejected (đề xuất "bỏ dropdown" sai) — UC_4.1.2 §2 dòng 6 giữ nguyên, không thay đổi. Trigger của UC_4.6.2 = user chọn item Settings trong dropdown đó. Logout vẫn thuộc UC_4.1.2 (dangling CR link ở Ghi chú Phase 2.2 là việc riêng, không thuộc UC_4.6.2). |
| A-02 | Tab mặc định khi mở màn Account. Tab list theo design: Connections & Credentials · Market Data Management · Profile & Preferences · Billing · Account Actions. Khi user click chip "SD / Lvl 5", tab nào active mặc định? | Đề xuất: tab đầu tiên — Connections & Credentials. (Design screenshot đang highlight Profile & Preferences chỉ vì đó là màn đang được document, không phải default state.) | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| A-03 | Full Name có hiển thị trên màn này không? Nguồn QnA ghi rõ "Full Name is also Read-only" (dòng 309) — hàm ý field này có tồn tại trên màn. Nhưng cả 7 ảnh design đều không có field Full Name; section General chỉ có Profile photo / Email / Phone. | Đề xuất: không render field Full Name (theo design — design là nguồn mới nhất, 2026-08-11). Câu "Full Name is also Read-only" chỉ nhằm khẳng định user không được đổi tên, không phải yêu cầu hiển thị. ⚠️ Nhưng nếu bỏ Full Name khỏi màn thì quy tắc initials ở A-06 lấy tên từ đâu cần nói rõ (lấy từ Users table, không hiển thị). | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| A-04 | [CONFLICT với design] Remove Photo → fallback là gì? BA instruction 2026-08-11: fallback về initials ("Taylor Swift" → "TS"). Nhưng ảnh design số 7 (sau khi Remove Photo) hiển thị icon người dùng generic (silhouette), không phải initials. | Đề xuất: theo BA instruction (initials "TS") — BA instruction trực tiếp thắng design mockup. Design cần update lại frame đó. Xin BA confirm để không ghi sai vào SRS. | Confirm đúng đề xuất: fallback = initials ("Taylor Swift" → "TS"). BA instruction thắng design mockup. | ✅ Confirmed — ⚠️ ảnh design số 7 (silhouette generic) cần được design update lại cho khớp SRS. |
| A-05 | Quy tắc sinh initials. "Taylor Swift" → "TS" là case 2 từ. Còn: tên 1 từ ("Madonna")? Tên 3+ từ ("Nguyen Thi Quynh Anh")? Tên non-Latin? Tên rỗng/null? | Đề xuất: lấy chữ cái đầu của từ đầu + chữ cái đầu của từ cuối, viết HOA (3+ từ → vẫn 2 ký tự, vd "Nguyen Thi Quynh Anh" → "NA"); tên 1 từ → 1 ký tự ("Madonna" → "M"); nếu Full Name rỗng/null → dùng 1 ký tự đầu của email. Nguồn tên = cột full name trong Users table (thu ở checkout Step 5). | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| A-06 | [GAP — CR-07 bắt buộc UC phải chỉ định] Định dạng file ảnh cho phép. Design chỉ ghi "Pick a photo up to 4MB." → đã có max size = 4 MB, nhưng không có danh sách extension. CR-07 §7.1 quy định UC bắt buộc phải liệt kê chính xác extension, không được hardcode default. | Đề xuất: .jpg, .jpeg, .png, .webp — max 1 file, max 4 MB. Error message dùng lại nguyên CR-07 §7.2 (sai format / quá dung lượng / lỗi server). | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| A-07 | Modal "Crop Image" (ảnh design số 6). Chưa xác định: (a) tỷ lệ crop cố định 1:1 hay tự do? (b) có zoom / pan / rotate không? (c) bấm [Done] là upload luôn lên S3 hay chỉ set preview, chờ [Save Changes] mới thật sự lưu? (d) [Cancel] → quay lại state nào? | Đề xuất: (a) khung crop cố định 1:1 (avatar tròn); (b) chỉ pan + zoom, không rotate; (c) [Done] chỉ set ảnh preview vào khối Profile photo → chỉ khi bấm [Save Changes] mới chạy S3 signed URL upload + POST /profile; (d) [Cancel] đóng modal, giữ nguyên ảnh cũ, không đánh dấu form dirty. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| A-08 | [IMPACT] Remove Photo — có confirm popup không, và commit lúc nào? Đây là hành động xoá dữ liệu, theo global-rules.md → Impact Analysis bắt buộc phải mô tả reversibility + confirmation. | Đề xuất: không cần confirm popup (vì chưa commit ngay và có [Cancel] để hoàn tác) — click [Remove Photo] chỉ đổi preview về initials + đánh dấu form dirty; chỉ khi [Save Changes] mới gọi API set profile_photo_url = null. Nút [Remove Photo] ẩn hoàn toàn khi user chưa có ảnh (khớp ảnh design số 7). Ảnh cũ trên S3: xoá hẳn hay giữ orphan? — cần BE xác nhận. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| A-09 | [CONFLICT nội dung error] Lỗi phone sai format. Design ghi "Invalid phone number format. Please check and try again." Nhưng CR-09 §9.2 đang quy định chuỗi chuẩn toàn hệ thống là "Please enter a valid phone number". Cùng 1 lỗi, 2 chuỗi khác nhau → vi phạm Single Source of Truth. | Đề xuất: giữ CR-09 ("Please enter a valid phone number") để đồng nhất với checkout — vì chính khách đã chốt "reuse the checkout phone validation" (QnA dòng 323). Design copy sẽ được align theo. ⚠️ Nếu BA muốn giữ copy của design → phải sửa CR-09 (ảnh hưởng ngược lại UC_2.8.3 checkout), không được để 2 chuỗi song song. | BA bác đề xuất "giữ CR-09 dùng chung". Chốt hướng tạo chuỗi riêng cho màn Settings: giữ nguyên CR-09 §9.2 cho checkout, cấp ID inline error mới riêng cho Settings với đúng copy trong design. | ❌ Rejected (đề xuất "dùng chung CR-09" sai) — cấp ID mới IN-08 trong list-toast-popup.md: "Invalid phone number format. Please check and try again" (bỏ dấu chấm cuối theo global-rules.md → Error Handling). CR-09 §9.2 giữ nguyên, UC_2.8.3 không đổi. |
| A-10 | [CONFLICT nội dung error] Lỗi phone trùng. Design ghi "This phone number is already registered with another account." IN-06 hiện có là "This phone number is already registered to another account." (đang được UC_2.8.3 dùng). Khác 1 giới từ. | Đề xuất: tái sử dụng IN-06 nguyên văn (to), không tạo ID mới, không tạo chuỗi thứ 2. Chỉ mở rộng phần Trigger của IN-06 để cover thêm case "Settings → Profile & Preferences → Phone onBlur/submit". | BA bác đề xuất "reuse IN-06". Cùng hướng với A-09: tạo chuỗi riêng cho Settings, giữ IN-06 nguyên vẹn cho checkout. | ❌ Rejected (đề xuất "reuse IN-06" sai) — cấp ID mới IN-09: "This phone number is already registered with another account" (giới từ with theo design, bỏ dấu chấm cuối). IN-06 giữ nguyên cho UC_2.8.3. |
| A-11 | [RULE MỚI — không có trong bất kỳ nguồn nào] "The new phone number cannot be the same as your current one." Chuỗi này chỉ xuất hiện trong design (ảnh số 4), không có trong RFQ / QnA / CR. Cần BA xác nhận đây là rule thật. Kèm theo: (a) validate ở FE hay BE? (b) so sánh cả dial code + số hay chỉ phần số? (c) nếu user chỉ đổi dial code (+1 → +44) mà giữ nguyên số thì có tính là "khác" không? | Đề xuất: rule thật, validate client-side on-blur / on-submit (không cần round-trip BE); so sánh trên chuỗi E.164 đầy đủ (dial code + số, sau khi normalize bỏ ký tự format) → đổi dial code = hợp lệ. Cần cấp ID inline error mới trong list-toast-popup.md. | Nằm trong nhóm "tạo chuỗi riêng cho Settings" mà BA đã chốt ở A-09/A-10 → rule được xác nhận là rule thật, giữ nguyên đề xuất về cơ chế validate. | ✅ Confirmed (theo quyết định gộp A-09/A-10) — cấp ID mới IN-10: "The new phone number cannot be the same as your current one" (bỏ dấu chấm cuối). Validate client-side on-blur/on-submit, so sánh trên chuỗi E.164 đầy đủ → chỉ đổi dial code vẫn hợp lệ. |
| A-12 | [GAP] Toast "Changes saved successfully." chưa có ID. Ảnh design số 2 có toast success này nhưng list-toast-popup.md không có entry nào tương ứng. Ngoài ra chuỗi trong design có dấu chấm cuối câu — vi phạm global-rules.md → Error Handling: "Error messages: no trailing period". | Đề xuất: thêm entry mới TS-DASH-01 vào list-toast-popup.md §1, nội dung "Changes saved successfully" (bỏ dấu chấm), Type = Success, dùng chung cho mọi màn Settings có nút Save. | Confirm đúng đề xuất (nằm trong nhóm A-09/A-10/A-12 BA đã chốt). | ✅ Confirmed — thêm TS-DASH-01 vào list-toast-popup.md §1: "Changes saved successfully" (Success, bỏ dấu chấm cuối). |
| A-13 | [GAP] Save thất bại thì hiện gì? Design không có frame cho case POST /profile trả 500 / mất mạng / S3 upload fail. | Đề xuất: lỗi mạng hoặc 5xx → dùng lại toast TE-SYS-01 ("Unable to connect. Please check your network and try again"); riêng S3 upload fail → dùng error toast của CR-07 §7.2 ("Failed to upload file. Please try again later"). Form giữ nguyên giá trị user đã nhập, không reset. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| A-14 | Hành vi [Save Changes] / [Cancel]. So sánh ảnh 1 (đang edit) và ảnh 2 (sau khi save thành công): ảnh 2 không còn nút [Cancel] và [Save Changes] bị dim. Suy ra 2 nút này phụ thuộc trạng thái dirty. Cần chốt chính xác. | Đề xuất: (a) form clean (chưa sửa gì) → [Cancel] ẩn, [Save Changes] Disabled; (b) form dirty → [Cancel] hiện, [Save Changes] Enabled; (c) form dirty nhưng đang có inline error → [Save Changes] Disabled; (d) click [Cancel] → revert toàn bộ (kể cả ảnh preview & remove-photo) về giá trị đã lưu gần nhất, form về clean, không cần confirm popup. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| A-15 | [IMPACT] Cảnh báo rời trang khi còn thay đổi chưa lưu. CR-05 + CF-01 có áp dụng khi user đang dirty mà: (a) chuyển sang tab Settings khác? (b) click tab khác ở sidebar chính? (c) đóng/refresh browser? | Đề xuất: áp dụng CF-01 cho cả (a) và (b); (c) dùng native beforeunload của browser (không phải CF-01, vì browser không cho custom copy). | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| A-16 | [STILL OPEN từ chính QnA khách] Rate limit / cool-down cho việc đổi phone. QnA Settings dòng 324 ghi rõ: "STILL OPEN: no rate limit / cool-down was specified for how many times the phone number can be changed. (Adrian - Figma comment)" — khách chưa trả lời. | Đề xuất: không giới hạn ở bản launch (không rate limit, không cool-down). Nếu BA muốn có, cần khách chốt con số cụ thể (vd tối đa N lần/30 ngày) trước khi viết BR. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| A-17 | [IMPACT — bắt buộc theo global-rules] Đổi phone kéo theo gì? Theo UC_2.8.3 §7 dòng 6, phone được thu ở checkout với mục đích "enable Two-Factor Authentication (2FA) and coordinate emergency Drawdown Defense protocols". Vậy khi user đổi phone trong Settings: (a) có phải verify OTP số mới trước khi commit không? (b) có ghi audit log không? (c) có gửi email thông báo tới email cũ (security notification) không? (d) có đồng bộ ngược sang Auth0 / Rithmic / MT5 không? | Đề xuất (tối thiểu cho launch): (a) không OTP — vì dashboard login là Auth0 passwordless qua email, phone chưa thực sự dùng làm factor đăng nhập; (b) có ghi updated_at trên Users table; (c) không gửi email cảnh báo ở launch; (d) không sync sang Auth0/Rithmic/MT5 — phone chỉ nằm ở Users table của StackTrading. ⚠️ Đây là điểm rủi ro bảo mật nếu sau này phone thành factor 2FA thật — đề nghị BA cân nhắc hỏi khách. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| A-18 | [BOUNDARY] ui_preferences thuộc UC nào? RFQ_ Stack Trading Prop Tech V7.pdf §Trang 36 gộp ui_preferences (Optional JSON) vào chung endpoint Update User Profile. Nhưng WBS lại tách UC_4.6.5 Controls (AI chat & Reduce motion) thành UC riêng với 2 endpoint riêng (POST /ai-preference, POST /accessibility-preference). Panel Controls (AI Chat / Reduce Motion) hiện trong mọi ảnh design của màn Account. Vậy UC_4.6.2 có sở hữu ui_preferences không? | Đề xuất: UC_4.6.2 KHÔNG sở hữu ui_preferences. Panel Controls là persistent panel dùng chung mọi tab Settings, thuộc UC_4.6.5 với 2 endpoint riêng, và 2 toggle đó lưu tức thì khi gạt (không đi qua nút [Save Changes] của section General). UC_4.6.2 chỉ ghi 1 dòng cross-ref sang UC_4.6.5. | Confirm đúng đề xuất: UC_4.6.5 sở hữu ui_preferences, 2 toggle lưu tức thì khi gạt qua endpoint riêng, không đi qua nút [Save Changes] của section General. | ✅ Confirmed — UC_4.6.2 không đọc/ghi ui_preferences; chỉ cross-ref sang UC_4.6.5 (nay là UC_4.6.4). ⚠️ Note 2026-08-24: ranh giới này không đổi, nhưng ui_preferences giờ không còn consumer nào — Reduce Motion bỏ hẳn backend API, Desk Manager dùng cột riêng users.ai_enabled. Cột JSON vẫn nằm trong Zapier Users schema nhưng UC_4.6.4 không ghi vào nữa. Xem Trả lời QnA 2026-08-24. ✅ Note 2026-09-03: khách xác nhận cột ngủ có chủ đích ("strictly as a future-proofing measure") — A-18 vẫn đúng nguyên vẹn. Xem Trả lời QnA 2026-09-03. |
| A-19 | [GAP nguồn] Tên endpoint chưa được khách xác nhận + thiếu asset trong repo. (a) QnA Settings dòng 330 hỏi khách "Could you pls check if the endpoints I listed here is correct?" → khách chưa trả lời. Đang có 2 cách gọi song song: PUT /profile (theo WBS) vs POST Update User Profile (theo RFQ V7). (b) WBS reference của UC_4.6.5 trỏ tới Wireframe Stage 2/Settings/Account (*).png nhưng folder References/Wireframe/Stage 2/Settings/ không tồn tại trong repo — 7 ảnh design hiện chỉ nằm trong chat. (c) WBS dòng 173–175 (UC_4.6.1/4.6.2/4.6.3) bị lệch cột: ô Use case description đang chứa UC_4.6.3, UC_4.6.4... thay vì mô tả. (d) git config user.name = QuynhAnh12, không có trong BA Roster của project_context.md. | Đề xuất: (a) dùng GET /profile + POST /profile theo đúng naming RFQ V7, đánh dấu [ASSUMPTION] cho tới khi khách confirm; (b) BA commit 7 ảnh design vào References/Wireframe/Stage 2/Settings/ để SRS trỏ được đường dẫn thật; (c) BA sửa lại WBS cho 3 dòng lệch cột; (d) BA bổ sung QuynhAnh12 → tên hiển thị vào BA Roster, tạm thời SRS ghi [Điền tên BA]. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| A-20 | [BA bổ sung 2026-08-11 — đóng câu hỏi khách bỏ ngỏ] Avatar dùng ở những màn nào? Câu hỏi này BA đã hỏi khách trong QnA Settings dòng 310–311 ("Which screens will this avatar be used on? … what happens if it conflicts with the avatar fetched from Discord?") và khách chưa trả lời. Nay BA trả lời trực tiếp, kèm 3 frame tham chiếu. | (không phải đề xuất của Agent — BA cung cấp trực tiếp) | BA chốt: ảnh avatar user đổi ở Settings sẽ hiển thị ở 3 nơi: (1) nút Settings ở góc dưới trái sidebar — state collapsed (avatar + Lvl 5) và state expanded (avatar + Full Name + Level 15); (2) POD system; (3) POD system trong màn Community của LIVE account. Frame tham chiếu: chip collapsed SD/Lvl 5; chip expanded photo · Sam Smith · Level 15; widget My POD với leader Marcus Chen (có ảnh) + member rows hiển thị initials MC. | ✅ Confirmed — viết thành BR_4.6.2.13: Avatar Propagation — Consumer Surfaces (SRS v3). Cơ chế: read-through, mỗi surface tự đọc profile_photo_url của user nó hiển thị; UC_4.6.2 chỉ ghi 1 cột, không push/sync. Fallback initials áp dụng theo từng user được hiển thị → member không có ảnh vẫn ra initials riêng của họ. ⚠️ Nửa còn lại của câu hỏi khách — Dashboard avatar vs Discord avatar cái nào thắng — vẫn chưa được trả lời, defer sang UC_4.14.2. |
Ghi chú Phase 2.2 — WBS Cross-UC Consistency Check
- UC_ID hợp lệ:
UC_4.6.2tồn tại trong WBS,category = STAGE 2: DASHBOARD - COMMON,module = Settings,function = Profile & Preferences→ folder đíchdashboard_common/là đúng theoglobal-rules.md → WBS Category → Folder Mapping. - Orphan-UC check: không phát hiện UC nào được tham chiếu mà thiếu trong WBS.
- Dangling reference (ngoài phạm vi UC này, cần BA xử lý riêng): UC_4.1.2 §2 dòng 6 đang link tới
References/CR/2026-08-06_CR39_dashboard-logout-action/CR_summary.md— file/folder này không tồn tại trên disk. Liên quan trực tiếp tới A-01 (Logout đi đâu). - Tab "Market Data Management": xuất hiện trong tab list của design nhưng không có UC_ID nào trong dải UC_4.6.x của WBS (dải này chỉ có Connections & Credentials, Profile & Preferences, Billing, Account Actions, Controls). Theo QnA Settings dòng 265, khách chỉ đạo tab này ẩn hoặc read-only cho SIM, chỉ dành cho LIVE → nhiều khả năng thuộc dải UC LIVE. UC_4.6.2 chỉ liệt kê tab này trong tab list, không mô tả nội dung.
Ghi chú Phase 2.5 — Impact Analysis (mandatory, state-changing actions trong phạm vi UC_4.6.2)
| Action | Uniqueness | Cascade | Reversibility | Concurrency |
|---|---|---|---|---|
Đổi Phone (POST /profile) | Có — unique toàn hệ thống, dùng lại duplicate-check của checkout (QnA dòng 320) | Chưa xác định: 2FA / Drawdown Defense / audit log / email cảnh báo → A-17 | Reversible (đổi lại được), chưa chốt rate limit → A-16 | Race: 2 user cùng submit 1 số phone → BE phải là trọng tài cuối, FE check on-blur chỉ là lớp phòng đầu tiên. IN-06 phải hiện lại cả khi BE reject lúc submit |
Upload Photo (S3 signed URL → POST /profile) | Không | Avatar hiển thị ở đâu khác (POD / Discord)? → khách chưa trả lời câu hỏi này trong QnA dòng 310–311 | Reversible qua Remove Photo | Signed URL hết hạn giữa chừng → cần xin URL mới, không được fail thầm lặng |
Remove Photo (profile_photo_url = null) | Không | Avatar fallback về initials (A-04/A-05); file cũ trên S3 xoá hay giữ orphan → A-08 | Reversible bằng cách upload lại (nhưng ảnh cũ mất, không có undo) | Không phát hiện race |
Kết quả BA review (2026-08-11)
| Nhóm | Kết quả |
|---|---|
| A-01 Entry point | ❌ Đề xuất bị bác — giữ nguyên dropdown của UC_4.1.2 {Settings, Logout}. UC_4.1.2 không bị sửa. |
| A-04 Avatar fallback | ✅ Confirmed — initials ("Taylor Swift" → "TS"). Design frame số 7 cần update. |
| A-09 / A-10 / A-12 Copy | IN-08, IN-09, IN-10, TS-DASH-01. CR-09 §9.2 và IN-06 giữ nguyên cho checkout.IN-08 và IN-09 bị retire; chuỗi "Invalid phone number format. Please check and try again" không còn dùng ở đâu nữa. IN-10 giữ lại (checkout không có case này). TS-DASH-01 không đổi. CR-09 §9.2 không bị sửa — Settings conform theo nó. Ref: UC_4.6.2 v10 BR_4.6.2.3 · list-toast-popup v3.13. |
| A-11 Rule "same as current" | ✅ Confirmed là rule thật → IN-10. |
A-18 ui_preferences | ✅ Confirmed — thuộc UC_4.6.5, lưu tức thì khi gạt. UC_4.6.2 không đụng tới. ⚠️ 2026-08-24: cột mất hết consumer (2 toggle đều không dùng). ✅ 2026-09-03: khách xác nhận đó là chủ đích — cột giữ để future-proof, không parse gì hôm nay. |
| A-02, A-03, A-05 → A-08, A-13 → A-17, A-19 | ✅ Applied by default — BA không phản hồi riêng, Agent 3 viết SRS theo đúng đề xuất trong bảng. |
| A-20 Avatar propagation (BA bổ sung sau vòng review) | ✅ Confirmed — avatar hiển thị ở sidebar chip (collapsed + expanded) và POD system (màn Community LIVE) → BR_4.6.2.13, SRS v3. Đóng được nửa câu hỏi khách bỏ ngỏ ở QnA CSV dòng 310–311. |
Việc BA cần làm tiếp (ngoài phạm vi SRS UC_4.6.2)
| # | Việc | Liên quan |
|---|---|---|
| 1 | Update design frame số 7 (Remove Photo) từ icon silhouette → initials | A-04 |
| 2 | ✅ ĐÃ ĐÓNG 2026-08-27 — không theo dõi nữa. BA tự bổ sung khi có; không để làm pending question, không push lại. References/Wireframe/Stage 2/Settings/ | A-19 (b) |
| 3 | Sửa WBS dòng 173–175 (UC_4.6.1 / UC_4.6.2 / UC_4.6.3) đang lệch cột — ô Use case description chứa UC_ID thay vì mô tả. ⚠️ Gộp luôn 2 lỗi endpoint đã chết: dòng 174 ghi PUT /profile (nay là PATCH /profile), dòng 176 ghi POST /accessibility-preference (nay không build) | A-19 (c) |
| 4 | ✅ ĐÃ ĐÓNG 2026-08-27 — chốt PATCH /profile; PUT/POST đều bị supersede. ⚠️ Còn lại: sửa WBS dòng 174 đang ghi PUT /profile | A-19 (a) |
| 5 | 🟡 Chốt cho launch 2026-08-27 — không cool-down. Nhưng QnA CSV dòng 324 vẫn STILL OPEN: đây là quyết định build khi khách chưa nêu giới hạn, không phải khách đã bác | A-16 |
| 6 | ✅ ĐÃ ĐÓNG 2026-08-27 — không ràng buộc bảo mật nào. Chỉ regex checkout + uniqueness → ghi thẳng DB | A-17 |
| 7 | Xử lý dangling CR link trong UC_4.1.2 (References/CR/2026-08-06_CR39_dashboard-logout-action/ không tồn tại) | Ghi chú Phase 2.2 |
| 8 | Bổ sung QuynhAnh12 vào BA Roster trong project_context.md | A-19 (d) |
| 9 | ✅ ĐÃ ĐÓNG 2026-08-27 — Dashboard thắng, không bao giờ đọc Discord API. Nhánh Discord-fallback bị loại khỏi UC_4.14.2. | A-20 |
| 10 | Khi viết UC_4.9.2 / UC_4.14.2: đối chiếu lại BR_4.6.2.13 để bảng consumer surfaces không lệch với data contract thật của widget My POD | A-20 |
Vòng 2 — UC_4.6.1: Connections & Credentials
Phạm vi vòng này: chỉ UC_4.6.1 — Connections & Credentials (WBS category = STAGE 2: DASHBOARD - COMMON, module = Settings, function = Connections & Credentials, BA PiC = anh.hoang12).
Ngày tạo: 2026-08-11 · Ngày BA review: 2026-08-11
Trạng thái tổng: ✅ BA đã chốt 7 mục chặn cứng (B-01, B-02, B-03, B-04, B-07, B-11, B-12, B-17). Các mục 🟡 BA không phản hồi riêng → Agent 3 áp dụng đúng cột Giả định. 2 mục còn ⛔ BLOCKED chờ khách (B-04, B-05) được viết vào SRS ở mức hành vi tối thiểu, chi tiết để trống.
Quy ước ID: vòng này dùng tiền tố
B-để không đụng dảiA-01 → A-19của vòng 1.
Nguồn đã đọc (theo MANDATORY FIRST-READ PROTOCOL)
| Bước | Nguồn | Kết quả |
|---|---|---|
| 0 | References/Customer supplies/_SOURCE_MANIFEST.yaml | ✅ Đã đọc |
| 1 | References/CR/_CR_INDEX.md (30 CR) | ⚠️ 3 CR liên quan: CR-20260720-001 (TradeSea thay NinjaTrader → Table I), CR-20260727-005 (Data-Feed Lock Banner — Rithmic Signature Gate, đang To be authored), CR-20260726-001 (email provisioning split — confirm email credential không chứa password) |
| 1 | References/QnA from clients/.../Stage 2 - Dashboard & Fomula (Settings).csv → hàng Settings: Connections & Credentials (dòng 9–16) | ✅ Nguồn chính của UC này |
| 1 | References/QnA from clients/.../QnA_STAGE2_SETTINGS_CAREER_VIRAL.md §2 (bản bóc tách, ID [CC-xxx-nn]) + §Open Items #5–#9 | ✅ |
| 2 | RFQ_ Stack Trading Prop Tech V7.pdf (§Platform Credentials endpoint; §Provision Simulation User / Provision Live User) | ✅ |
| 2 | Zapier Integration V7.pdf (§3.1 Users table; §3.6 Table I; Flow 1 Step 3–4; Flow 3 Database Write-Back Credentials) | ✅ |
| 2 | RFQ_ Website and Dashboard Implementation V7.pdf (§Part C — Settings & Profile Module) | ✅ |
| — | docs/BA/Common_rule/common_rules.md + list-toast-popup.md | ⚠️ Chưa có rule sẵn cho Copy-to-clipboard / masked credential — xem B-09 |
| — | WBS qua script/parse_wbs.js --compact | ✅ UC_4.6.1 hợp lệ, category STAGE 2: DASHBOARD - COMMON → folder dashboard_common/ đúng |
| — | Design: 2 screenshot BA gửi trực tiếp trong chat (2026-08-11) + Figma node 7878-116828 | ⚠️ Chưa commit vào References/Wireframe/Stage 2/Settings/ |
Đã confirm sẵn — KHÔNG cần hỏi lại (Agent 3 dùng trực tiếp):
| # | Nội dung | Nguồn |
|---|---|---|
| 1 | Kiến trúc mục tiêu = zero-knowledge credential cho execution platform bên ngoài (định hướng Adam Culver) | [CC-DEF-01..04] header |
| 2 | 2 cơ chế auth tách biệt: Dashboard = Auth0 Passwordless (không password); trading platform = tài khoản do Rithmic / MT5 / TraderEvolution cấp. Áp dụng cho cả SIM lẫn LIVE | [CC-DEF-01] |
| 3 | Password trading ban đầu do chính gateway provider email thẳng cho trader. Email AWS SES của StackTrading KHÔNG chứa password trading platform | [CC-DEF-01] ✅ |
| 4 | Password KHÔNG BAO GIỜ hiển thị, KHÔNG có icon con mắt để reveal — chỉ mask tĩnh | [CC-DEF-02] + row Business logic |
| 5 | Dashboard hiển thị platform_username, connection string, license key. Mất password → nút "Request Password Reset" | [CC-DEF-02] ✅ |
| 6 | License key phụ thuộc từng platform — chỉ hiển thị biến kết nối mà platform được chọn yêu cầu | [CC-DEF-03] ✅ |
| 7 | Username hiển thị plain text kèm nút Copy (để paste sang desktop software: Quantower / ATAS / Sierra Chart) | row Business logic |
| 8 | Nguyên tắc copyable: field key nào StackTrading tự lấy được từ provisioning API → phải copy được | [CC-BIZ-02] ✅ |
| 9 | "Request Password Reset" KHÔNG phải form đổi password nội bộ. StackTrading không build màn Reset Password riêng | row Business logic |
| 10 | Password được reset là của Rithmic / TraderEvolution / MT5, KHÔNG phải login dashboard. User phải đã authenticated | [CC-BIZ-03] ✅ |
| 11 | Connection Guide riêng từng platform, dùng placeholder — "Mỗi platform một cái, sau này sửa sau" | [CC-UI-01] ✅ |
| 12 | Endpoints: GET /credentials → {Platform, Login, Connection_String (masked), Connection_Guide_URL}; POST /request-credential-reset | row Endpoints + RFQ V7 §Platform Credentials |
| 13 | Flow 3 Database Write-Back (Credentials): ghi platform_username, platform_password_ciphertext, license_key_ciphertext, cipher_version, credentials_last_rotated_at | Zapier V7 Flow 3 |
| 14 | Table I: Platform_Name, Asset_Class, Gateway_Router, Is_Active, Risk_Group_Template | row Zapier table |
| 15 | NinjaTrader ngoài scope (khớp CR-20260720-001) | [CC-BIZ-02] ✅ |
| 16 | Ciphertext là KMS-envelope encrypted, chỉ Middleware giải mã, không bao giờ email, không expose qua general user profile endpoint | Zapier V7 §3.1 + Flow 1 Step 4 |
| 17 | Toàn bộ 8 Criteria cột LIVE = "(same as SIM)" → UC viết chung, không branch theo account type | CSV dòng 9–16 |
Bảng QnA & Assumption — UC_4.6.1
| ID | Câu hỏi / Vấn đề | Giả định (Agent đề xuất) | BA chốt | Trạng thái |
|---|---|---|---|---|
| B-01 | [CROSS_UC_CONFLICT] Điểm vào màn Settings. BA mô tả màn này mở bằng click button viết tắt tên user + Level ở góc dưới trái sidebar (SD / Lvl 5). Nhưng UC_4.1.2 §2 dòng 6 spec dropdown 2 item {Settings, Logout}. Click thẳng hay qua dropdown? | Giữ dropdown theo UC_4.1.2; UC_4.6.1 chỉ ghi entry point, không mô tả lại dropdown (Single Source of Truth). | ✅ Giữ dropdown. Click chip SD / Lvl 5 → dropdown {Settings, Logout} → chọn Settings → vào màn Account. UC_4.1.2 không sửa. | ✅ Đã chốt (BA, 2026-08-11) — nhất quán với A-01 vòng 1 |
| B-02 | [INTRA_RULE_CONTRADICTION] Nhãn credential card = Platform hay Gateway? Design ghi "Rithmic" — đó là Gateway_Router (Table I), không phải Platform_Name (Quantower / ATAS / MotiveWave / Sierra Chart / TradeSea / MetaTrader 5 / TradingView). Endpoint trả field tên Platform. | Hiển thị Gateway_Router làm tiêu đề card (5 platform Futures dùng chung 1 bộ credential Rithmic — ghi tên platform sẽ gây hiểu nhầm), platform_selection ở dòng phụ. | ✅ Đúng — là Gateway_Router. Hiện design mới chỉ có Rithmic, nhưng sẽ có cả MT5 và TraderEvolution. | ✅ Đã chốt (BA, 2026-08-11) |
| B-03 | Mapping field API ⇄ UI chưa khớp — chỉ ở tầng response, KHÔNG phải thiếu dữ liệu. License key đã có đủ ở 3 tầng: DB (Zapier Integration V7.pdf §3.1.6 Table: Users → license_key_ciphertext, KMS-envelope, "never emailed"), provisioning return (RFQ_ Stack Trading Prop Tech V7.pdf §Page 29 → "Return: Credentials (username, password, license_key)"), và Zapier write-back (Flow 1 Step 3–4 + Flow 3 → SET license_key_ciphertext). Chỗ hụt duy nhất: output của endpoint Platform Credentials (RFQ §Page 18) chỉ kê {Platform, Login, Connection_String (masked), Connection_Guide_URL}, không kê license_key. Design lại hiện Password và License Key là 2 dòng riêng → Connection_String không thể vừa là mask password vừa là license key. | Connection_String (masked) = dòng Password. GET /credentials phải trả thêm 1 field cho license key. → Đây là thiếu sót mô tả spec cho BE, KHÔNG phải Change Request nghiệp vụ — không cần hỏi khách, dữ liệu đã tồn tại end-to-end. | ✅ Chỉ Rithmic mới có License Key. MT5 và TraderEvolution KHÔNG có License Key.⚠️ BA chưa chắc chắn 100% — sẽ chốt thêm với khách. | 🟡 Đã chốt tạm (BA, 2026-08-11) — SRS viết data-driven (BR_4.6.1.3) + ghi rõ mapping hiện tại theo BA, đánh dấu chờ khách confirm |
| B-04 | [BLOCKED] Hành vi nút "Request Password Reset". Khách đưa 2 nhánh chưa chốt: "đưa họ tới trang reset password của integration tương ứng nếu có, hoặc thực hiện reset mật khẩu thay cho user"; đích đến là tab thứ 3 hay màn StackTrading tự build cũng chưa chốt. (Adrian đẩy cho Adam — Figma comment, chưa trả lời.) | ⚠️ No safe default cho phần "nhánh nào theo platform". Phần chốt được ngay: (a) không build màn Reset Password riêng; (b) mở tab mới (design có icon external-link). | ⛔ Để trống — BA sẽ hỏi thêm khách. | ⛔ BLOCKED — chờ khách. SRS chỉ viết mức tối thiểu đã được khách confirm (Ref: BR_4.6.1.5), chi tiết per-platform để trống |
| B-05 | [BLOCKED] Audit trail cho sự kiện reset password. Khách đẩy ngược câu hỏi ("Tài liệu Rithmic nói gì?") [CC-BIZ-01]. Static link → không log được; API call → cần audit trail. | Ghi log tại thời điểm gửi request (không phải kết quả reset) — đúng cho cả 2 nhánh của B-04. | — (phụ thuộc B-04) | ⛔ BLOCKED — hoãn cùng B-04, không viết vào SRS |
| B-06 | [BLOCKED — DB schema] Zero-knowledge có điều kiện [CC-DEF-04]: "khi nào confirm được với TraderEvolution / Rithmic / MT5 thì KHÔNG lưu password platform vào DB" — chưa confirm được với ISV, Zapier spec vẫn ghi SET platform_password_ciphertext. | SRS viết theo hành vi UI, không phụ thuộc DB: dù có lưu ciphertext hay không, UI luôn mask tĩnh và không có đường dẫn nào để reveal. UC_4.6.1 không bị block; chỉ ghi 1 dòng note. | — (BA không phản hồi riêng) | ✅ Applied by default — Ref: BR_4.6.1.2 |
| B-07 | [BLOCKED] Bảng mapping Platform → field hiển thị. Khách chốt nguyên tắc "chỉ hiện biến kết nối platform đó yêu cầu" nhưng chưa có bảng; TradeSea có cần license key → "cần hỏi Rithmic" [CC-BIZ-02]. | Không hardcode bảng vào SRS. Viết data-driven: BE trả đúng tập field platform yêu cầu; field null/vắng trong response → ẩn hẳn cả dòng. | ✅ Đã trả lời ở B-03 — Rithmic có License Key, MT5 / TraderEvolution không có. | ✅ Đã chốt (BA, 2026-08-11) — gộp vào B-03, SRS giữ cơ chế data-driven làm rule chính |
| B-08 | [BLOCKED] Credential rotation [CC-TRIG-01] — khách chưa trả lời. Rithmic/MT5 rotate credential (credentials_last_rotated_at đổi) thì trader có nhận email mới không, hay Dashboard chỉ âm thầm refresh Username? | Dashboard luôn hiển thị giá trị mới nhất từ GET /credentials mỗi lần vào tab (không cache) → UI tự đúng, không cần rule riêng. Không spec notification/email cho rotation (không có nguồn). Muốn có thông báo → mở CR mới. | — (BA không phản hồi riêng) | ✅ Applied by default — Ref: BR_4.6.1.7 |
| B-09 | [PATTERN] Hành vi nút Copy. Design: click → nút Copy đổi thành Copied ✓. Chưa spec: bao lâu revert? Có toast không? Clipboard API bị chặn thì sao? Copy field thứ 2 thì field thứ 1 có reset? | Đổi label tại chỗ thành Copied trong 3 giây rồi tự revert; không dùng toast (tránh spam khi copy liên tiếp). Chỉ 1 field ở trạng thái Copied tại 1 thời điểm. Clipboard fail → giữ label Copy + Toast TE-SYS-01.⚠️ Đề xuất chuẩn hoá CR-14: Copy-to-Clipboard Control — pattern lặp ở Billing, Discord Linking, Certificate (polygon_tx_hash), Payout portal. | — (BA không phản hồi riêng) | ✅ Applied by default — Ref: BR_4.6.1.4. Không tạo ID toast mới (đổi label inline, không phải toast) |
| B-10 | Empty / chưa provision. User đã thanh toán nhưng provisioning chưa xong hoặc fail (Ref: BN-06) → platform_username = null. Tab hiển thị gì? | Empty state trong khung card: Your platform credentials are being provisioned. Please check your email — ẩn cả 3 nút (Copy / Request Password Reset / Connection Guide). Không auto-poll. | — (BA không phản hồi riêng) | ✅ Applied by default — Ref: BR_4.6.1.8 |
| B-11 | Gating theo account status. Soft Breach / Hard Breach / Failed / Terminated / Resigned có còn xem được tab này không? Không nguồn nào nhắc tới. | Không gate với Soft/Hard Breach và Failed (nhất quán "Frosted Glass": account đóng vẫn login được, chỉ disable thao tác). Riêng Resigned cần BA chốt. | ✅ Soft Breach và Hard Breach vẫn giữ (vẫn xem được). Resigned thì tài khoản đã bị khoá nên KHÔNG view được nữa. | ✅ Đã chốt (BA, 2026-08-11) — Ref: BR_4.6.1.9 |
| B-12 | Multi-platform / multi-account. Design chỉ vẽ 1 card. Trader có thể vừa có SIM vừa có LIVE (sau Go-Live), hoặc mua thêm track khác → 1 card hay danh sách nhiều card? | 1 card duy nhất. GET /credentials nhận user_id (không nhận account_id) → API chỉ trả 1 bộ. Go-Live thì Flow 3 ghi đè cùng bản ghi Users → card tự hiển thị credential LIVE. Không có lịch sử credential cũ. | ✅ Chỉ 1 card. User SIM là 1; lên LIVE thì restart lại từ đầu nên cũng chỉ 1. | ✅ Đã chốt (BA, 2026-08-11) — Ref: BR_4.6.1.6 |
| B-13 | [CR_CONFLICT] Rithmic Signature Gate banner — CR-20260727-005 đánh dấu "Dashboard UC (chưa viết): 🔴 To be authored". Banner thuộc UC_4.6.1 hay tab Market Data Management? | Thuộc Market Data Management — CR nói về price feed / data feed status, và design có tab riêng với Data Feed Status badge. UC_4.6.1 chỉ ghi 1 dòng cross-ref, không mô tả banner. | — (BA không phản hồi riêng) | ✅ Applied by default — Ref: BR_4.6.1.10. ⚠️ Tab Market Data Management vẫn chưa có UC_ID trong WBS (trùng ghi chú vòng 1) |
| B-14 | Overflow các field credential. platform_username (trader_0x4F_mc), license_key (RTH-2024-A1B2C3D4) — dài tối đa bao nhiêu? Màn hẹp xử lý sao? | Cả 2 field: Truncate with tooltip; giá trị copy vẫn là giá trị đầy đủ, không phải bản đã truncate. Không wrap (tránh vỡ chiều cao card). Không giới hạn ký tự phía FE — giá trị do gateway sinh. | — (BA không phản hồi riêng) | ✅ Applied by default — Ref: BR_4.6.1.4 + §9 |
| B-15 | Nút "Connection Guide" (góc trên phải). Mở tab mới hay modal? Connection_Guide_URL = null (placeholder chưa có) thì ẩn hay disabled? | Mở tab mới (target="_blank") — nhất quán UC_4.1.5 và Support icon. null → ẩn hẳn nút (nhất quán nguyên tắc field null → ẩn container). | — (BA không phản hồi riêng) | ✅ Applied by default — Ref: BR_4.6.1.11 |
| B-16 | GET /credentials lỗi (5xx / timeout / mất mạng). Không nguồn nào spec. | Toast TE-SYS-01 + giữ khung card ở skeleton, không auto-retry. User reload trang để gọi lại. | — (BA không phản hồi riêng) | ✅ Applied by default — Ref: §7 Exceptional Flow |
| B-17 | Chuỗi mask của Password. Design hiện chuỗi dấu chấm cố định (~12 ký tự) — hằng số tĩnh hay phản ánh độ dài password thật? (Phản ánh độ dài thật = rò rỉ thông tin, phá zero-knowledge.) | Hằng số tĩnh, luôn cùng số ký tự bất kể password thật, và không copy được (design không có nút Copy trên dòng Password). | ✅ Chỉ view thôi, không copy được. | ✅ Đã chốt (BA, 2026-08-11) — Ref: BR_4.6.1.2 |
| B-19 | Response shape của GET /credentials — dev đề xuất nhét username/password/license key vào field Login. Dev xác nhận: POST provisioning đã lưu username + password + license key vào DB; GET Platform Credentials đọc từ DB ra. Dev phỏng đoán các giá trị đó "có thể nằm trong field Login" của {Platform, Login, Connection_String, Connection_Guide_URL}. RFQ §Page 18 không nói Login là scalar hay nested object → nhiều shape đều thoả. Nhưng nếu Login gánh hết thì Connection_String còn dùng làm gì? | UC không chốt shape — BR_4.6.1.3 cố ý viết data-driven nên sống được với cả 2 phương án. Chỉ ràng buộc 2 điều lên bất kỳ shape nào BE chọn:(1) Username và License Key phải là 2 giá trị lấy ra được riêng biệt — vì là 2 dòng riêng, 2 nút Copy riêng. Không được gộp thành 1 chuỗi bắt FE tự parse.(2) Password phải được mask sẵn từ BE. ⚠️ Đây là điểm rủi ro của đề xuất dev: nếu Login gánh cả password thì rất dễ trả plaintext ra. Zapier Integration V7.pdf §3.1.6 + Flow 1 Step 4 ghi rõ platform_password_ciphertext "decryptable only by Middleware" và "must not be exposed via general user profile endpoints". FE render dấu chấm mà payload chứa plaintext là KHÔNG đạt — giá trị vẫn lộ ở Network tab / devtools.→ Đề nghị BE ghi lại contract cuối cùng để QA assert được. | — | 🟡 Chờ BE chốt contract — không block SRS |
| B-20 | Dev nói "mình có lưu password rồi" — đúng với spec hiện tại nhưng ngược hướng khách muốn. Zapier Integration V7.pdf hiện đúng là bắt lưu platform_password_ciphertext. Nhưng [CC-DEF-04] khách chỉ đạo: "Một khi đã confirm được với TraderEvolution / Rithmic / MT5 — KHÔNG lưu password platform vào database. Middleware phải gọi provisioning và huỷ bỏ mọi password trả về." | Nhắc BE: việc lưu password là trạng thái tạm, chờ ISV confirm rồi sẽ bỏ. Đừng build phụ thuộc cứng vào việc password luôn có trong DB (vd: đừng thiết kế Login object với password là field bắt buộc). UI của UC_4.6.1 không đổi dù bỏ hay giữ — xem B-06. | — | 🟡 Nhắc BE — trùng Open Item #5, không block SRS |
| B-18 | [Ghi nhận sai lệch đánh số UC] File QnA_STAGE2_SETTINGS_CAREER_VIRAL.md đánh số Settings là UC_4.8.1–UC_4.8.8 (bản cũ); WBS hiện tại là UC_4.6.1–UC_4.6.5 và gộp còn 5 function. | SRS dùng UC_4.6.1 theo WBS (WBS là single source of truth cho UC indexing). Đề xuất BA cập nhật header WBS Range trong file QnA cho khớp. | — (BA không phản hồi riêng) | ✅ Applied by default — SRS dùng UC_4.6.1 |
Ghi chú Phase 2.2 — WBS Cross-UC Consistency Check (vòng 2)
- UC_ID hợp lệ:
UC_4.6.1tồn tại trong WBS,category = STAGE 2: DASHBOARD - COMMON→ folderdashboard_common/đúng theoglobal-rules.md → WBS Category → Folder Mapping. [CR_CONFLICT]CR-20260720-001: Table I (Zapier Integration V7.pdf§3.6) vẫn liệt kêNinjaTrader 8, nhưng CR đã thay bằng TradeSea và khách xác nhận NinjaTrader ngoài scope[CC-BIZ-02]. → SRS không liệt kê NinjaTrader.[CR_CONFLICT]CR-20260727-005: xem B-13 — CR vẫn ở trạng tháiTo be authored, chưa có UC nhận.[MISSING_DEPENDENCY]:UC_4.6.3(Billing),UC_4.6.4(Account Actions - Resign),UC_4.6.5(Controls) chưa có SRS → UC_4.6.1 tham chiếu plain text kèm "not yet documented in this repo".- Cross-UC nhất quán: tab list và entry point trong UC_4.6.1 phải khớp BR_4.6.2.1 của vòng 1 — đã đối chiếu, khớp.
Ghi chú Phase 2.5 — Impact Analysis (state-changing actions trong phạm vi UC_4.6.1)
| Action | Uniqueness | Cascade | Reversibility | Concurrency |
|---|---|---|---|---|
| Copy Username / License Key | Không | Không — thao tác client-side thuần, không gọi API, không ghi DB | N/A | Copy field thứ 2 khi field thứ 1 đang Copied → field cũ revert ngay (B-09) |
POST /request-credential-reset | Không | Gateway (Rithmic/MT5/TE) gửi email reset cho trader → password cũ có thể bị vô hiệu ngay ở phía gateway, trader đang kết nối terminal có thể bị disconnect | Không reversible — StackTrading không rollback được thao tác của gateway | Bấm 2 lần liên tiếp / 2 tab → cần chặn double-submit. ⛔ Chi tiết phụ thuộc B-04 (chưa chốt nhánh) |
⚠️ Tác động của
POST /request-credential-resetkhông được viết đầy đủ vào SRS vì phụ thuộc B-04 (chưa chốt gọi API hay redirect). Khi khách trả lời B-04 → phải bổ sung Impact + Confirmation popup nếu cần.
Kết quả BA review vòng 2 (2026-08-11)
| Nhóm | Kết quả |
|---|---|
| B-01 Entry point | ✅ Giữ dropdown UC_4.1.2 — không sửa UC_4.1.2 |
| B-02 Nhãn card | ✅ Gateway_Router — hiện có Rithmic, sẽ có thêm MT5 và TraderEvolution |
| B-03 / B-07 License Key theo platform | 🟡 Rithmic có; MT5 + TraderEvolution không có. BA chưa chắc chắn → sẽ chốt thêm với khách. SRS giữ rule data-driven làm rule chính |
| B-04 Reset Password | ⛔ Để trống — BA sẽ hỏi khách |
| B-11 Account status gating | ✅ Soft/Hard Breach vẫn xem được; Resigned không xem được |
| B-12 Số lượng card | ✅ Đúng 1 card (SIM 1, lên LIVE restart từ đầu nên cũng 1) |
| B-17 Mask password | ✅ View-only, không copy được |
| B-05, B-06, B-08, B-09, B-10, B-13 → B-16, B-18 | ✅ Applied by default — BA không phản hồi riêng, Agent 3 viết SRS theo đúng đề xuất trong bảng |
Việc BA cần làm tiếp (ngoài phạm vi SRS UC_4.6.1)
| # | Việc | Liên quan |
|---|---|---|
| 1 | ✅ ĐÃ ĐÓNG 2026-08-27 — đúng: Rithmic only. MT5/TE ẩn hoàn toàn dòng License Key + nút Copy (không để trống, không disable). Gateway → field credential | B-03 / B-07 |
| 2 | ✅ ĐÃ ĐÓNG — 2026-08-17 chốt "reset hộ", rồi 2026-08-20 đảo lại thành redirect ra bên thứ 3. | B-04 |
| 3 | ✅ ĐÃ ĐÓNG 2026-08-21 — bên thứ 3 tự xử lý; StackTrading không log gì. Muốn có audit trail thì phải raise CR. | B-05 |
| 4 | Theo dõi ISV confirm để loại platform_password_ciphertext khỏi Zapier Database Write-Back | B-06 / Open Item #5 |
| 5 | ✅ ĐÃ ĐÓNG 2026-08-27 — để im tuyệt đối, không notification nào. | B-08 / Open Item #9 |
| 6b | Chốt contract GET /credentials với BE (shape của Login, vị trí license key) và kiểm tra payload thật không chứa plaintext password — kể cả khi FE đã render mask | B-19 |
| 6c | Nhắc BE: việc lưu platform_password_ciphertext là trạng thái tạm, khách muốn bỏ khi ISV confirm — đừng thiết kế response phụ thuộc cứng vào password | B-20 |
| 6 | Note cho BE: GET /credentials phải trả thêm field license key. Dữ liệu đã có sẵn ở DB (§3.1.6 license_key_ciphertext) và ở provisioning return (§Page 29); chỉ danh sách output của endpoint Platform Credentials (§Page 18) không kê ra. Không cần CR, không cần hỏi khách — chỉ là spec BE chưa đầy đủ | B-03 |
| 7 | Gán UC_ID cho tab Market Data Management + chốt UC nhận banner của CR-20260727-005 | B-13 |
| 8 | ✅ ĐÃ ĐÓNG 2026-08-27 — không theo dõi nữa. BA tự bổ sung khi có; không để làm pending question, không push lại. References/Wireframe/Stage 2/Settings/ | Nguồn design |
| 9 | Cập nhật header WBS Range trong QnA_STAGE2_SETTINGS_CAREER_VIRAL.md từ UC_4.8.x → UC_4.6.x | B-18 |
| 10 | Cân nhắc chuẩn hoá CR-14: Copy-to-Clipboard Control vào common_rules.md | B-09 |
Vòng 3 — UC_4.6.4: Settings — Controls (AI chat & Reduce motion)
Phạm vi vòng này: chỉ UC_4.6.4 — Controls (AI chat & Reduce motion) (WBS dòng 176, category STAGE 2: DASHBOARD - COMMON, module Settings, assignee anh.hoang12).
Ngày tạo: 2026-08-12
BA in Charge: Anh Hoang (theo assignee của WBS dòng 176; git config user.name = QuynhAnh12 vẫn chưa có trong BA Roster — xem A-19(d) vòng 1)
Ngày BA review: 2026-08-12
Trạng thái tổng: ✅ BA đã chốt 4 item chặn cứng (C-01, C-02, C-03, C-13) — Agent 3 được phép viết SRS. Các item còn lại BA không phản hồi riêng → áp dụng đúng đề xuất trong bảng.
Nguồn đã đọc (theo MANDATORY FIRST-READ PROTOCOL)
| Bước | Nguồn | Kết quả |
|---|---|---|
| 0 | References/Customer supplies/_SOURCE_MANIFEST.yaml | ✅ Đã đọc |
| 1 | References/CR/_CR_INDEX.md (31 CR) | ✅ Không có CR nào liên quan tới Settings/Controls/AI toggle/Reduce Motion. CR gần nhất về Dashboard là CR-20260806-001 (Logout) — không đụng UC này. |
| 1 | References/QnA from clients/.../Stage 2 - Dashboard & Fomula (Settings).csv dòng 423–447 (Settings: Controls & Concierge) | ✅ Nguồn chính — có 2 câu khách đã trả lời ngày 2026-08-10 (scope Reduce Motion + tooltip/label), 2 câu chưa trả lời (trigger, endpoint) |
| 2 | RFQ_ Stack Trading Prop Tech V7.pdf §3.2 (kênh GEKKO_CHATTER), §3.2.1 (The Desk Manager — engine, 15 event, rate limit, master prompt), §API table (AI Preference Toggle), §4.3 mục 21 (non-blocking delivery) | ✅ |
| 2 | RFQ_ Website and Dashboard Implementation V7.pdf §Part C — Settings & Profile Module ("Must include a 'Reduce Motion' accessibility toggle"), §The Desk Manager (stacked cards) | ✅ |
| 2 | Zapier Integration V7.pdf | ✅ Không có Flow/Table nào liên quan UC này |
| — | WBS dòng 176 (đọc trực tiếp CSV — ⚠️ script/parse_wbs.js đang lỗi: Cannot find module './lib_xlsx_min.js') | ⚠️ Xem C-18(c) |
| — | Cross-UC: UC_4.6.2_v1.md, UC_4.8.3_v1.md (The Desk Manager SIM), UC_4.1.1-4.1.5_v1.md, docs/BA/Common_rule/common_rules.md (CR-10 Tooltip), list-toast-popup.md | ✅ |
| — | Design: 2 ảnh BA gửi trực tiếp trong chat (2026-08-12) + Figma node 7878-116828 | ⚠️ Xem C-18(b) |
Đã confirm sẵn — KHÔNG cần hỏi lại (ghi ra đây để Agent 3 dùng trực tiếp):
| # | Nội dung | Nguồn |
|---|---|---|
| 1 | Đổi label: toggle trong Settings > Controls đổi tên từ AI Chat → Desk Manager. Data contract không đổi — vẫn users.ai_enabled qua POST /ai-preference | QnA Settings CSV dòng 443–447 (Adrian Stack, 2026-08-10) |
| 2 | Tooltip Desk Manager: "Enable or disable the AI Desk Manager assistant." | QnA Settings CSV dòng 445 (Adrian, 2026-08-10) |
| 3 | Tooltip Reduce Motion: "Disable non-essential animations and transitions." | QnA Settings CSV dòng 446 (Adrian, 2026-08-10) |
| 4 | Scope Reduce Motion (3 nhóm): (a) tắt continuous motion — infinite loop, background movement, pulsing; (b) tắt parallax / depth effect gắn với scroll; (c) đơn giản hoá heavy positional animation (slide, wipe, bounce) → opacity fade nhanh hoặc render state tức thì | QnA Settings CSV dòng 427–432 + 442 (Adrian, 2026-08-10) |
| 5 | KHÔNG có popup xác nhận khi gạt Reduce Motion — không dùng blocking modal kiểu breach/reset | QnA Settings CSV dòng 426 |
| 6 | Lưu tức thì khi gạt (real-time, không cần reload), không đi qua nút [Save Changes] của section General | QnA Settings CSV dòng 433–435 + vòng 1 A-18 (BA confirmed) |
| 7 | Panel Controls là persistent panel hiển thị ở MỌI tab Settings | WBS dòng 176 ("from a persistent panel shown across all Settings tabs") + vòng 1 A-18 + 2 ảnh design (panel hiện ở cả tab Profile & Preferences và Billing) |
| 8 | POST /ai-preference input {user_id, ai_enabled (Boolean)} → HTTP 200 OK → update ai_enabled flag | RFQ_ Stack Trading Prop Tech V7.pdf §API table ("AI Preference Toggle") |
| 9 | Giống hệt nhau giữa SIM và LIVE — không phân nhánh môi trường | QnA Settings CSV dòng 424 (cột LIVE: "Same as SIM for all 3 controls") |
| 10 | Entry point màn Account = chip "SD / Lvl 5" ở footer sidebar → dropdown → chọn Settings | Vòng 1 A-01 (BA đã chốt — giữ nguyên dropdown của UC_4.1.2) |
Bảng QnA & Assumption — Vòng 3
| ID | Câu hỏi / Vấn đề | Giả định (Agent đề xuất) | BA chốt | Trạng thái |
|---|---|---|---|---|
| C-01 | [CROSS_UC_CONFLICT — chặn cứng] UC_ID của Controls đang có 3 giá trị khác nhau trong repo. WBS dòng 176 = UC_4.6.4 (khớp chỉ thị BA 2026-08-12). Nhưng UC_4.6.2 BR_4.6.2.11 + §9.1 row 3 + BR_4.6.2.1 ghi UC_4.6.5; UC_4.8.3 BR_4.8.3.5 + BR_4.8.3.3 ghi UC_4.6.6. Ngoài ra BR_4.6.2.1 còn map UC_4.6.4 = Account Actions — Resign Account, trong khi WBS đã chuyển Account Actions sang UC_4.11.1/UC_4.11.2 (SIM) và UC_4.17.2 (LIVE). | Đề xuất: chốt UC_4.6.4 theo WBS (WBS là single source of truth về UC indexing theo CLAUDE.md). Hệ quả bắt buộc phải sửa kèm (ID-only remap, không đổi logic): (a) UC_4.6.2_v1.md — BR_4.6.2.11, §9.1 row 3, BR_4.6.2.1 (bảng tab → owning UC: UC_4.6.5 → UC_4.6.4, và row Account Actions → UC_4.11.1/UC_4.11.2 thay vì UC_4.6.4); (b) UC_4.8.3_v1.md — BR_4.8.3.3 + BR_4.8.3.5 (UC_4.6.6 → UC_4.6.4). | Confirm đúng đề xuất: chốt UC_4.6.4 theo WBS, được phép sửa kèm 2 file stale. | ✅ Confirmed — đã áp dụng: UC_4.6.2_v1.md → v2 (BR_4.6.2.1 tab table, BR_4.6.2.11, §1 Description, §9.1 row 3); UC_4.8.3_v1.md → v2 (BR_4.8.3.3, BR_4.8.3.5). Tab Account Actions remap → UC_4.11.1/UC_4.11.2 (SIM), UC_4.17.2 (LIVE). |
| C-02 | [FOLDER] Tên folder đích. BA chỉ định UC_4.6.1 - 4.6.4, nhưng folder đang tồn tại trên disk là UC_4.6.1-4.6.5 (chứa UC_4.6.2_v1.md + index.md + file QnA này). Theo WBS, dải Settings common giờ chỉ còn UC_4.6.1 → UC_4.6.4 → tên folder cũ đã sai. Nhưng đổi tên folder sẽ phá 5 inbound link đang trỏ tới UC_4.6.1-4.6.5/UC_4.6.2_v1.md: list-toast-popup.md (TS-DASH-01, IN-08, IN-09, IN-10) và chính file QnA này. | Đề xuất Phương án A (khuyến nghị): đổi tên folder UC_4.6.1-4.6.5 → UC_4.6.1-4.6.4 và sửa đồng thời 5 inbound link nêu trên (thao tác cơ học, không đổi nội dung). Phương án B: giữ nguyên tên folder cũ vòng này, xử lý rename thành 1 task cleanup riêng. ⚠️ KHÔNG tạo folder UC_4.6.1-4.6.4 mới song song với folder cũ — sẽ tách đôi cụm docs Settings. | Confirm Phương án A: đổi tên folder. | ✅ Confirmed — đã git mv UC_4.6.1-4.6.5 → UC_4.6.1-4.6.4 và sửa 5 inbound link (list-toast-popup.md: TS-DASH-01/IN-08/IN-09/IN-10; dashboard_common/index.md; UC_4.6.2_v1.md; chính file này). |
| C-03 | [SCOPE — chặn cứng] "Controls" có mấy toggle: 2 hay 3? Tên category khách dùng là "Controls & Concierge", và cột LIVE ghi "Same as SIM for all 3 controls… same Concierge ambiguity" (CSV dòng 424) → hàm ý có control thứ 3 tên Concierge. WBS dòng 176 (cột UI note) cũng ghi "Persistent Controls block (2 toggles) + Concierge entry point". Nhưng: (a) tên function trong WBS chỉ là "Controls (AI chat & Reduce motion)"; (b) cả 2 ảnh design chỉ có 2 toggle (Desk Manager, Reduce Motion); (c) không có bất kỳ mô tả nào về Concierge trong RFQ V7 / Dashboard V7 / Zapier V7 — riêng "Digital Concierge" chỉ xuất hiện ở Flow 38 (Discord bot monitor #the-pit), hoàn toàn khác nghiệp vụ và thuộc UC_4.5.2. | Đề xuất: UC_4.6.4 chỉ gồm 2 toggle (Desk Manager, Reduce Motion). Concierge entry point = OUT OF SCOPE của UC này — không đủ nguồn để viết một dòng requirement nào (không có định nghĩa, không có endpoint, không có wireframe, khách chưa trả lời). Ghi 1 dòng nêu rõ loại trừ trong §1 Overview. Nếu khách sau này định nghĩa Concierge → mở CR riêng. | Confirm đúng đề xuất: Concierge out of scope. | ✅ Confirmed — UC_4.6.4 chỉ gồm 2 toggle. §1 Overview ghi 1 dòng loại trừ Concierge kèm lý do (không đủ nguồn). Nếu khách định nghĩa sau → mở CR riêng. |
| C-04 | [GAP nguồn — chặn cứng] Toggle được nạp giá trị ban đầu từ endpoint nào? Khách chỉ confirm 2 endpoint ghi (POST /ai-preference, POST /accessibility-preference). Không nguồn nào nói endpoint đọc. GET /profile (RFQ V7 §Trang 36) trả {profile_photo_url, email, phone_number, ui_preferences} — không có ai_enabled. Vậy khi mở màn Settings, FE lấy ai_enabled và reduce_motion ở đâu? | Đề xuất: dùng GET /profile làm nguồn đọc duy nhất cho cả 2 toggle, và yêu cầu BE bổ sung ai_enabled vào response của endpoint này (hiện đang thiếu). reduce_motion đọc từ ui_preferences. Ghi rõ đây là [ASSUMPTION] cần khách/BE confirm — trong SRS sẽ ghi là điểm phụ thuộc BE, không ghi như fact đã chốt. | (BA không phản hồi riêng — áp dụng đề xuất) | 🔴 Đúng một nửa — sửa 2026-08-24. ai_enabled đọc từ GET /profile ✅ giữ, và yêu cầu BE bổ sung ai_enabled vào response vẫn là dependency đang treo. Nhưng reduce_motion KHÔNG đọc từ GET /profile nữa — không có backend API cho toggle này, FE đọc từ local store của thiết bị. Xem Trả lời QnA 2026-08-24. |
| C-05 | [GAP nguồn] Giá trị 2 toggle lưu ở cột nào trong DB? ai_enabled có cột riêng (users.ai_enabled — RFQ V7 xác nhận). Còn reduce_motion lưu ở đâu thì không nguồn nào nói. Vòng 1 A-18 đã chốt: ui_preferences (JSON) thuộc quyền sở hữu của UC Controls chứ không phải UC_4.6.2. | Đề xuất: reduce_motion lưu trong users.ui_preferences (JSON object) — khớp với A-18 và với schema ui_preferences (JSON Object) trong Zapier V7 Users table. ai_enabled giữ nguyên cột boolean riêng. | (BA không phản hồi riêng — áp dụng đề xuất) | 🔴 ĐÃ BỊ ĐẢO 2026-08-24. reduce_motion không lưu server-side ở đâu cả — không phải ui_preferences, không phải cột nào khác. Lưu local trên trình duyệt của từng thiết bị. ai_enabled giữ nguyên cột boolean ✅. Hệ quả: ui_preferences mất consumer duy nhất trong UC_4.6.4. Xem Trả lời QnA 2026-08-24. |
| C-06 | [GAP nguồn] Schema của POST /accessibility-preference. Tên endpoint chỉ có trong WBS; RFQ V7 không mô tả input/output. Khách được hỏi (CTRL-EP-01, CSV dòng 290 tương đương) → chưa trả lời. | Đề xuất (đối xứng với /ai-preference): input {user_id, reduce_motion: Boolean} → HTTP 200 OK → update users.ui_preferences.reduce_motion. Đánh dấu [ASSUMPTION] cho tới khi khách confirm. | (BA không phản hồi riêng — áp dụng đề xuất) | 🔴 ĐÃ ĐÓNG & BÁC 2026-08-24 — CTRL-EP-01 closed. Khách trả lời nguyên văn: "There is no backend API for this." Endpoint POST /accessibility-preference rút hẳn, không build. Giả định đối xứng 2 endpoint là sai — 2 toggle không đối xứng. Xem Trả lời QnA 2026-08-24. |
| C-07 | [GAP — bắt buộc theo global-rules "No Filler Text"] Giá trị mặc định của 2 toggle với account mới. Không nguồn nào nói. Ảnh design thể hiện cả 2 đang ON, nhưng đó là ảnh mô tả UI, không phải default state. | Đề xuất: Desk Manager mặc định ON (RFQ V7 mô tả đây là feature "optional" nhưng là phần cốt lõi của trải nghiệm dashboard, và widget Desk Manager là 1 trong 3 widget chính của Command tab — nếu default OFF thì user mới sẽ thấy placeholder "Disabled in settings" ngay lần đầu đăng nhập, phản trực giác); Reduce Motion mặc định OFF. | BA chốt trực tiếp 2026-08-12: cả 2 toggle default ON. Reduce Motion ON = animation bị tắt mặc định. Sau khi trader tự chỉnh, hệ thống lưu lựa chọn đó cho mọi lần login sau. | ✅ Confirmed (override đề xuất) — đề xuất cũ Reduce Motion = OFF bị bác. Đã ghi vào BR_4.6.4.5. ⚠️ Hệ quả đã note trong SRS: mọi trader mới mặc định không thấy Level-Up Cinematic (rơi vào BR_4.6.4.8) và không thấy blinking CRITICAL của Market Status, cho tới khi tự tắt toggle. Nên hỏi khách confirm vì ngược với chủ đích motion-first của RFQ. |
| C-08 | [GAP accessibility] Có seed Reduce Motion theo thiết lập OS của user không? Trình duyệt cung cấp media query prefers-reduced-motion (thiết lập hệ điều hành). Không nguồn nào nhắc tới. | Đề xuất: khi user chưa từng set giá trị (ui_preferences.reduce_motion chưa tồn tại), lần render đầu tiên FE khởi tạo toggle theo prefers-reduced-motion của OS. Sau khi user tự gạt 1 lần → giá trị trong DB là authoritative, không bị OS ghi đè nữa. ⚠️ Nếu BA thấy phức tạp hoá → bỏ, luôn default OFF (C-07). | BA bác đề xuất 2026-08-12: bỏ hẳn rule seed theo OS. | ❌ Rejected — không đọc prefers-reduced-motion ở bất kỳ đâu. Default cứng theo C-07 (ON) là nguồn duy nhất cho lần load đầu. Lý do: giữ cả 2 rule sẽ mâu thuẫn trực tiếp với default cứng BA vừa chốt. |
| C-09 | [GAP — bắt buộc theo global-rules "Impact Analysis"] Gạt toggle mà API fail thì sao? Design không có frame lỗi. Vì toggle lưu tức thì (không có nút Save), phải định nghĩa rõ hành vi khi POST trả 5xx / mất mạng. | Đề xuất: optimistic UI — toggle lật ngay khi click (đúng tinh thần "applied immediately, no reload"), gọi API nền. Nếu API fail → toggle tự lật ngược về giá trị cũ + toast lỗi Ref: TE-SYS-01. Trong lúc request đang bay, toggle đó tạm Disabled để chặn double-click gây race. Nếu 401 → Ref: TE-AUTH-01 → redirect Auth0. Không có toast success khi thành công (khớp "NO confirmation popup", và TS-DASH-01 chỉ dành cho nút [Save Changes]). | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| C-10 | [IMPACT — khách bỏ ngỏ, ảnh hưởng CHI PHÍ] ai_enabled = false là dừng hẳn gọi Gemini API hay chỉ ẩn output? CSV dòng 440 ghi thẳng: "The exact mechanism of the ai_enabled toggle… not specified in source, needs confirmation". QnA_STAGE2_SETTINGS_CAREER_VIRAL.md mục 17 cũng flag: "Cost implication (Gemini calls) if the toggle only hides output". | Đề xuất: ai_enabled = false → BE dừng hẳn: worker check flag trước khi gọi Gemini, không gọi API, không tốn token, không push GEKKO_CHATTER. FE hiển thị placeholder "Disabled in settings" trong widget (đã có sẵn ở UC_4.8.3 BR_4.8.3.3). ⚠️ Đề nghị BA hỏi khách chốt — đây là quyết định kiến trúc BE, không phải suy đoán của BA. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| C-11 | [IMPACT] Bật lại Desk Manager sau khi tắt — có backfill commentary đã bỏ lỡ không? Và Token Bucket (10 critique/giờ/user) có bị tiêu hao trong lúc toggle OFF không? | Đề xuất: không backfill — engine là stateless (RFQ V7 §3.2.1), commentary bỏ lỡ là mất vĩnh viễn. Token Bucket không bị tiêu hao khi OFF (hệ quả trực tiếp của C-10: không gọi API thì không tiêu token). Bật lại → card stack hiển thị lại các card đã sinh trước đó (nếu FE còn giữ), commentary mới bắt đầu từ event kế tiếp. | BA chốt trực tiếp 2026-08-12: tắt Desk Manager → toàn bộ lịch sử card cũ mất hết, bật lại là chạy comment mới lại từ đầu. | ⚠️ Partially rejected — phần "không backfill" và "không tiêu Token Bucket" giữ nguyên; nhưng phần "card đã sinh trước đó hiển thị lại" bị bác. Đã sửa BR_4.6.4.6: lịch sử bị xoá khi tắt, bật lại widget về empty state "No data available", không khôi phục được. Đồng bộ sang UC_4.8.3_v1.md v3 (BR_4.8.3.3 + §6). |
| C-12 | [IMPACT — bắt buộc] Reduce Motion = ON ảnh hưởng cụ thể tới những UC nào đã viết? Khách chỉ đưa scope directive theo nhóm (continuous motion / parallax / positional animation), không đưa danh sách component. BA note trong chính CSV dòng 432 yêu cầu: "cross-check it against the Level-Up cinematic reduced-motion guard so both use the same rule set". Rà repo, các animation đã được document: (a) BR_4.1.3.4 — Market Status widget state CRITICAL = blinking (nhấp nháy liên tục → thuộc nhóm (a) continuous motion); (b) UC_4.7.4 — Days Remaining counter pulse/glow khi còn <10 ngày (→ nhóm (a)); (c) Level-Up cinematic (xem C-13). | Đề xuất: UC_4.6.4 định nghĩa rule set theo 3 nhóm (đúng chỉ đạo khách), không liệt kê component — vì đây là rule ngang (cross-cutting), mỗi UC sở hữu animation tự chịu trách nhiệm tuân thủ. Kèm 1 bảng "downstream UC bị ảnh hưởng đã biết" liệt kê (a)(b)(c) ở trên để trace được, và nói rõ danh sách này không exhaustive. Fallback khi ON: blinking → đổi state tĩnh; pulse/glow → bỏ hẳn hiệu ứng, giữ nguyên giá trị số. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| C-13 | [IMPACT — RỦI RO CAO] Reduce Motion = ON thì Level-Up Cinematic có chạy không? Cinematic là chuỗi full-screen 4 lớp (WebM/HEVC background + Lottie + Framer Motion staggered text + QR animation), bắt buộc redirect user về tab Command khi LEVEL_PROMOTION fire (CSV dòng 91, Adrian). RFQ có ghi "Reduced-motion guards" trong performance budget nhưng không định nghĩa guard đó làm gì. | Đề xuất: khi reduce_motion = true → bỏ qua toàn bộ chuỗi cinematic (không load WebM/HEVC + Lottie — cũng đúng luôn mục tiêu performance budget <300 KB), vẫn redirect về tab Command, và hiển thị thẳng Certificate modal ở state cuối. Nghĩa là: user không mất milestone, chỉ mất phần animation. Nút Share / Download Certificate giữ nguyên. ⚠️ Đây là suy luận của BA, cần khách confirm vì ảnh hưởng tới một trong những trải nghiệm marketing quan trọng nhất của sản phẩm. | Confirm đúng đề xuất: skip cinematic → vào thẳng Certificate modal. | ✅ Confirmed — viết thành BR riêng trong UC_4.6.4. Vẫn redirect về tab Command, không load WebM/HEVC + Lottie, hiển thị ngay Certificate modal state cuối; Share/Download giữ nguyên. ⚠️ Vẫn nên hỏi khách confirm lại khi viết UC Level-Up & Certificate. |
| C-14 | [SCOPE] Reduce Motion áp dụng phạm vi nào — chỉ Dashboard hay cả Marketing site? Preference lưu theo user đã đăng nhập; marketing site là public, chưa có user context. | Đề xuất: chỉ áp dụng trong Dashboard đã đăng nhập (UC_4.x). Marketing site (UC_1.x) nằm ngoài phạm vi UC này — nếu cần thì dùng prefers-reduced-motion của OS ở tầng CSS, không liên quan tới toggle này. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| C-15 | [GAP] Preference là per-user hay per-device? Ảnh hưởng: user đổi máy/trình duyệt thì giữ hay mất setting. | Đề xuất: per-user, lưu server-side (cả 2 đều ghi vào bảng users) → đồng bộ trên mọi thiết bị và mọi session. Không lưu localStorage như nguồn sự thật. Hệ quả cần ghi rõ: nếu user mở nhiều tab cùng lúc, tab kia không tự cập nhật toggle cho tới khi refresh — SRS sẽ ghi nhận đây là hành vi chấp nhận được (không dùng WebSocket sync cho preference). | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| C-16 | [INTRA_RULE / CROSS_UC] Panel Controls tương tác thế nào với dirty-state của tab đang mở? BR_4.6.2.8 đã ghi: gạt toggle không làm form dirty. Nhưng chưa có ai định nghĩa chiều ngược lại: nếu form Profile & Preferences đang dirty mà user gạt toggle → có bung CF-01 không? (Gạt toggle không phải là "rời trang".) | Đề xuất: không bung CF-01. Gạt toggle là hành động độc lập, ghi qua endpoint riêng, không điều hướng, không đụng tới dữ liệu đang staging của form → dữ liệu chưa lưu của form vẫn giữ nguyên, [Save Changes] vẫn Enabled. Hai luồng hoàn toàn tách biệt. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| C-17 | [GAP] Toggle có bị Disabled trong trạng thái tài khoản đặc biệt không? Vd: Hard Breach / Frosted Glass (UC_4.10.2), account ReadOnly sau khi Resign (Flow 20), hoặc account đang Promoting. BR_4.8.3.3 có nói widget Desk Manager ngừng hiển thị khi account bị khoá — nhưng đó là widget, không phải toggle. | Đề xuất: 2 toggle luôn Enabled miễn là user còn đăng nhập được vào dashboard — đây là preference cá nhân/accessibility, không phải hành động giao dịch, không nên bị khoá theo trạng thái tài khoản. Trường hợp account bị khoá thì widget Desk Manager tự ẩn theo BR_4.8.3.3 (luật của UC kia), toggle vẫn gạt được và vẫn lưu được. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| C-18 | [GAP nguồn / asset] (a) Khách chưa trả lời 2 câu: xác nhận trigger (CTRL-TRIG-01) và xác nhận endpoint (CTRL-EP-01) — CSV dòng 435 + 290. (b) WBS trỏ reference tới Wireframe Stage 2/Settings/Account (*).png nhưng folder References/Wireframe/Stage 2/Settings/ vẫn chưa tồn tại (đã nêu ở A-19(b) vòng 1, chưa xử lý) — 2 ảnh design vòng này cũng chỉ nằm trong chat. (c) node script/parse_wbs.js --compact đang lỗi: Cannot find module './lib_xlsx_min.js' → mọi skill docs auto-chain với wbs-reader sẽ fail; vòng này phải đọc CSV thô thay thế. | Đề xuất: (a) SRS ghi endpoint theo tên WBS/RFQ + đánh dấu [ASSUMPTION], đồng thời BA nhắc khách trả lời 2 câu còn treo; (b) BA commit ảnh design vào References/Wireframe/Stage 2/Settings/, tạm thời SRS cite Figma node 7878-116828; (c) BA/dev bổ sung file script/lib_xlsx_min.js bị thiếu hoặc sửa parse_wbs.js. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
Ghi chú Phase 2.2 — WBS Cross-UC Consistency Check (vòng 3)
- UC_ID hợp lệ:
UC_4.6.4tồn tại trong WBS dòng 176,category = STAGE 2: DASHBOARD - COMMON,module = Settings,function = Controls (AI chat & Reduce motion)→ folder đíchdashboard_common/là đúng theoglobal-rules.md → WBS Category → Folder Mapping. - Cross-UC conflict: 3 UC_ID khác nhau cho cùng 1 function (
UC_4.6.4/UC_4.6.5/UC_4.6.6) → C-01. Đây là conflict chặn cứng, phải chốt trước khi Agent 3 viết SRS. - Orphan-UC check:
UC_4.6.5vàUC_4.6.6được tham chiếu trong 2 file docs nhưng không tồn tại trong WBS → orphan reference, sẽ hết sau khi áp C-01. - Stale mapping: BR_4.6.2.1 map tab
Account Actions→UC_4.6.4, nhưng WBS đã chuyển sangUC_4.11.1/UC_4.11.2(SIM) vàUC_4.17.2(LIVE). Nằm trong phạm vi sửa của C-01. - Không có CR liên quan: rà toàn bộ 31 CR trong
_CR_INDEX.md→ không CR nào chạm Settings/Controls/AI toggle/Reduce Motion.
Ghi chú Phase 2.5 — Impact Analysis (mandatory — state-changing actions trong phạm vi UC_4.6.4)
| Action | Uniqueness | Cascade (downstream) | Reversibility | Concurrency |
|---|---|---|---|---|
Gạt Desk Manager OFF (POST /ai-preference {ai_enabled: false}) | Không | Cao: widget The Desk Manager (SIM UC_4.8.3, LIVE UC_4.12.3) → placeholder "Disabled in settings"; BE có dừng gọi Gemini hay không → C-10 (ảnh hưởng chi phí); Token Bucket → C-11 | Reversible ngay (gạt lại ON), nhưng commentary bỏ lỡ trong lúc OFF mất vĩnh viễn, không backfill → C-11 | Nhiều tab mở cùng lúc → tab khác không tự sync → C-15. Double-click trong lúc request đang bay → C-09 (Disabled tạm thời) |
Gạt Desk Manager ON | Không | Commentary hoạt động lại từ event kế tiếp; không backfill → C-11 | Reversible | Như trên |
Gạt Reduce Motion ON (POST /accessibility-preference | Không | Rất cao, cross-cutting: áp lên mọi animation của dashboard — Market Status blinking (BR_4.1.3.4), Days Remaining pulse/glow (UC_4.7.4), Level-Up Cinematic (C-13 — rủi ro cao), và mọi animation chưa được document → C-12 | Reversible ngay | Như trên. Áp dụng ngay không cần reload → cần định nghĩa rõ animation đang chạy dở bị cắt thế nào (đề xuất: dừng ở state cuối, không rewind) |
Gạt Reduce Motion OFF | Không | Animation hoạt động lại; không replay lại animation đã bị bỏ qua trước đó | Reversible | Như trên |
Không có Zapier Flow / Zapier Table nào liên quan UC này (đã rà
Zapier Integration V7.pdf). Không có 3rd party trực tiếp trên UI — Google Gemini là dependency của UC_4.8.3/UC_4.12.3, UC_4.6.4 chỉ bật/tắt cờ.
✅ Kết quả BA review — Vòng 3 (2026-08-12)
| Nhóm | Kết quả |
|---|---|
| C-01 UC_ID | ✅ Confirmed — chốt UC_4.6.4 theo WBS. Đã sửa kèm UC_4.6.2_v1.md (v1 → v2) và UC_4.8.3_v1.md (v1 → v2). |
| C-02 Folder | ✅ Confirmed Phương án A — đã rename UC_4.6.1-4.6.5 → UC_4.6.1-4.6.4 + sửa 5 inbound link. |
| C-03 Concierge | ✅ Confirmed — out of scope, UC_4.6.4 chỉ gồm 2 toggle. |
| C-13 Cinematic | |
| C-07 Default 2 toggle | ✅ Confirmed (BA bổ sung 2026-08-12, override đề xuất) — cả 2 default ON; Reduce Motion ON = animation bị tắt. Lựa chọn của trader được lưu cho mọi lần login sau. |
| C-08 Seed theo OS | ❌ Rejected (BA bổ sung 2026-08-12) — bỏ hẳn, không đọc prefers-reduced-motion. |
| C-11 Lịch sử commentary | ⚠️ Partially rejected (BA bổ sung 2026-08-12) — tắt Desk Manager thì lịch sử card mất hết, bật lại chạy từ đầu. Phần "không backfill" giữ nguyên. |
| C-04 → C-06, C-09, C-10, C-12, C-14 → C-18 | ✅ Applied by default — BA không phản hồi riêng, Agent 3 viết SRS theo đúng cột "Giả định (Agent đề xuất)". |
| C-04 / C-05 / C-06 Endpoint & storage của Reduce Motion | 🔴 ĐÃ BỊ ĐẢO 2026-08-24 — CTRL-EP-01 closed. POST /accessibility-preference rút hẳn; users.ui_preferences.reduce_motion rút hẳn; toggle này không có backend API, FE lưu local per device. ai_enabled + POST /ai-preference giữ nguyên, và khách xác nhận đây bắt buộc phải là backend call. Xem Trả lời QnA 2026-08-24. |
| C-15 Per-user hay per-device | 🔴 ĐÃ BỊ SỬA MỘT NỬA 2026-08-24. Desk Manager per user, server-side ✅ giữ. Reduce Motion per device + per browser profile — local store là source of truth, ngược hẳn với kết luận cũ "localStorage không bao giờ là source of truth". |
Việc BA cần làm tiếp (ngoài phạm vi SRS UC_4.6.4)
| # | Việc | Liên quan |
|---|---|---|
| 1 | ✅ ĐÃ ĐÓNG 2026-08-24 — CTRL-EP-01 (và bác giả định cũ): Reduce Motion không có backend API, POST /accessibility-preference không build. POST /accessibility-preferenceCTRL-EP-03 + CTRL-EP-04 — endpoint riêng POST /ai-preference, cột phẳng users.ai_enabled; CTRL-TRIG-01 cũng đã được tái xác nhận. ⏳ Còn treo duy nhất: dependency BE bổ sung ai_enabled vào response GET /profile — mục backend cuối cùng của UC này. | C-04, C-06, C-18(a) |
| 2 | ✅ ĐÃ ĐÓNG 2026-08-21 — "skip call hoàn toàn". ai_enabled = false | C-10 |
| 3 | ✅ ĐÃ ĐÓNG 2026-08-21 (nhưng đảo ngược kết luận cũ) — motion vẫn chạy, từ Certificate modal. | C-13 |
| 4 | 🔄 ĐÃ ĐÓNG 2026-08-27 — ĐẢO NGƯỢC. Default chuyển ON → OFF; trader mới thấy đầy đủ motion. C-07 bị supersede. Reduce Motion = ON | C-07, C-13 |
| 5 | ✅ ĐÃ ĐÓNG 2026-08-27 — không theo dõi nữa. References/Wireframe/Stage 2/Settings/ | C-18(b) |
| 6 | Sửa script/parse_wbs.js — lỗi Cannot find module './lib_xlsx_min.js', làm hỏng auto-chain wbs-reader của mọi skill docs | C-18(c) |
| 7 | Khi viết UC Level-Up & Certificate: đồng bộ rule set reduced-motion với BR_4.6.4.7 của UC này | C-12, C-13 |
Vòng 4 — UC_4.6.3: Billing
Phạm vi vòng này: chỉ UC_4.6.3 — Billing (WBS dòng 175: category = STAGE 2: DASHBOARD - COMMON, module = Settings, function = Billing, BA PiC = anh.hoang12).
Ngày tạo: 2026-08-12 · Ngày BA review: 2026-08-12 Trạng thái tổng: ✅ BA đã chốt đủ 6 mục 🔴 chặn cứng (D-01, D-03, D-04, D-06, D-08, D-10) — Agent 3 được phép viết SRS. Các mục 🟡 BA không phản hồi riêng → áp dụng đúng cột Giả định (theo thoả thuận đã dùng ở cả 3 vòng trước).
Chỉ thị phạm vi đọc nguồn (BA, 2026-08-12): trong
Broadcast, Settings_Market Data.docx, chỉ đọc từ headingSettings - Billingđổ xuống. Toàn bộ phầnSettings - Market Data management(§1.0, §2.1, §2.2) bypass hoàn toàn — không thuộc UC_4.6.3.
Quy ước ID: vòng này dùng tiền tố
D-để không đụng dảiA-(vòng 1),B-(vòng 2),C-(vòng 3).
Nguồn đã đọc (theo MANDATORY FIRST-READ PROTOCOL)
| Bước | Nguồn | Kết quả |
|---|---|---|
| 0 | References/Customer supplies/_SOURCE_MANIFEST.yaml | ✅ Đã đọc |
| 1 | References/CR/_CR_INDEX.md (30 CR) | ⚠️ 1 CR liên quan gián tiếp: CR-20260810-001 (Triple-A pending removal → ảnh hưởng câu hỏi đa tiền tệ, xem D-08). Không CR nào chạm trực tiếp tab Billing |
| 1 | References/Customer supplies/(Stage 2) Community & Settings/Broadcast, Settings_Market Data.docx §Settings - Billing / §2.3 Invoice History + block Manage Billing | ✅ Nguồn chính của UC này (Adrian gửi 2026-08-10) |
| 1 | References/QnA from clients/.../MarketData_Billing_Wireframe_Brief.md §PHẦN 5 (BIL-0, BIL-7, BIL-7b, BIL-8, BIL-11 → BIL-15) + §Open Items O-4/O-6/O-9/O-10/O-11/O-12 | ✅ Bản bóc tách docx + 2 câu trả lời khách 2026-08-10 (xoá nút Manage Billing; Invoice History cho cả SIM lẫn LIVE) |
| 1 | References/QnA from clients/.../Stage 2 - Dashboard & Fomula (Settings).csv dòng 333 + QnA_STAGE2_SETTINGS_CAREER_VIRAL.md §6 | ⚠️ Cả 2 file vẫn ghi Billing = BLOCKED, chờ docx — đã lỗi thời so với docx 2026-08-10. Xem D-18 |
| 2 | RFQ_ Stack Trading Prop Tech V7.pdf (§Trang 36 — Get Billing History; §Trang 37 — Get Active Subscriptions / Get Saved Cards / Delete Saved Card; §Trang 38–39 — Generate Data Invoices; §3.7 Payment, Tax and Billing Architecture) | ✅ |
| 2 | Zapier Integration V7.pdf (§3.1.2 Table invoices; Flow 22 Monthly Data Fee Billing; Table D — Monthly_Data_Invoice_Available, Urgent_Data_Payment_Required, Data_Feed_Downgraded) | ✅ |
| 2 | RFQ_ Website and Dashboard Implementation V7.pdf (§Part C — Settings & Profile Module: "Billing Portal Link") | ⚠️ Mâu thuẫn với docx mới — xem D-01 |
| — | WBS dòng 175 (đọc trực tiếp CSV — ⚠️ script/parse_wbs.js vẫn lỗi: Cannot find module './lib_xlsx_min.js', đã nêu ở C-18(c) vòng 3, chưa xử lý) | ⚠️ Xem D-20(c) |
| — | Cross-UC: UC_4.6.1_v1.md, UC_4.6.2_v1.md, UC_4.6.4_v1.md, UC_4.1.1-4.1.5_v1.md, docs/BA/Common_rule/common_rules.md (CR-06 Pagination, CR-08 Timestamp, CR-11 Monetary Display), list-toast-popup.md | ✅ |
| — | Design: 3 ảnh BA gửi trực tiếp trong chat 2026-08-12 (bảng có data / empty state / error state) + Figma node 1-15026 (WBS dòng 175) | ⚠️ Xem D-20(b) |
Đã confirm sẵn — KHÔNG cần hỏi lại (ghi ra đây để Agent 3 dùng trực tiếp):
| # | Nội dung | Nguồn |
|---|---|---|
| 1 | Tab Billing CHỈ có bảng Invoice History. Không có section thứ hai. Toàn bộ Payment Methods / Subscription Funding Source / Active Subscriptions thuộc tab Market Data Management, không thuộc UC này | Broadcast, Settings_Market Data.docx §1.0 + §2.1–2.2 (nằm dưới heading Settings - Market Data management) vs §2.3 (dưới heading Settings - Billing) |
| 2 | Xoá nút Manage Billing và toàn bộ khái niệm "billing portal". Không có 3rd party, invoice nằm trong PostgreSQL của chính hệ thống | Khách trả lời 2026-08-10: "I want to delete that 'Manage Billing' button and create the page in the dashboard instead as described. It is a button to nowhere. There is no 3rd party involved, we already store the invoices." |
| 3 | Bảng hiển thị cho MỌI user, không gate theo SIM/LIVE. SIM có invoice của evaluation purchase / challenge reset / time extension | Khách trả lời 2026-08-10: "The Invoice History section must be visible to all users, regardless of whether they are SIM or LIVE, so they can view the receipts for these payments." |
| 4 | Không có PDF. Invoice là bản ghi giao dịch thô trong PostgreSQL, endpoint trả JSON array. "There is no PDF rendering required for this phase." | docx §2.3 mục 1 Storage Format |
| 5 | Không filter phía backend. API trả toàn bộ lịch sử của user trong 1 lần gọi. Chỉ cho phép sort client-side theo Date hoặc Amount | docx §2.3 mục 2 Filtering |
| 6 | Đúng 5 cột: Invoice ID · Date · Amount & Currency · Status · Description → map lần lượt tới id, created_at, amount, currency, status, fee_type | docx §2.3 mục 3 Display Layout |
| 7 | Endpoint: Get Billing History (GET) → JSON Array of Objects (invoice_id, amount, currency, status, created_at, fee_type) | RFQ_ Stack Trading Prop Tech V7.pdf §Trang 36 + docx §2.3 |
| 8 | Schema bảng invoices: id (UUID, PK), user_id (FK), amount (Float), currency (String, default "USD"), status (String: 'paid','void','refunded'), created_at (Timestamp), fee_type (ENUM: MARKET_DATA_BASE, MARKET_DATA_ADDON, PLATFORM_FEE, CHALLENGE_FEE, RESET_FEE) | Zapier Integration V7.pdf §3.1.2 |
| 9 | Không cần in hoá đơn giấy trong dashboard — user cần receipt thì tra email do payment gateway gửi | docx §2.3 mục 3 ("they can reference the email receipts sent by the payment gateway") |
| 10 | Entry point màn Account = chip SD / Lvl 5 ở footer sidebar → dropdown → chọn Settings → chọn tab Billing | Vòng 1 A-01 + vòng 2 B-01 (BA đã chốt 2 lần — giữ nguyên dropdown của UC_4.1.2) |
| 11 | Panel Controls (Desk Manager / Reduce Motion) hiển thị cả trên tab Billing nhưng không thuộc UC này — thuộc UC_4.6.4 | Vòng 3 C-03 + ảnh design vòng 3 (panel hiện trên chính tab Billing) |
| 12 | Màn này read-only hoàn toàn — không có nút Save, không có form, không có state-changing action nào ngoài sort/paginate/retry (thuần client-side) | Suy trực tiếp từ #1 + #2 + #4 |
Bảng QnA & Assumption — Vòng 4
| ID | Câu hỏi / Vấn đề | Giả định (Agent đề xuất) | BA chốt | Trạng thái |
|---|---|---|---|---|
| D-01 | 🔴 [CONFLICT design ⇄ khách — chặn cứng] Dòng subtitle "billing portal" vẫn còn nguyên trong cả 3 ảnh design. Cả 3 frame BA gửi 2026-08-12 đều hiển thị: "View invoices, update payment method, and manage your subscription through our secure billing portal." Nhưng khách đã chốt thẳng ngày 2026-08-10 rằng không có billing portal nào cả và nút Manage Billing phải bị xoá. Design đã bỏ nút nhưng giữ lại câu mô tả — câu này giờ nói dối user 3 lần: (a) "update payment method" — chức năng đó nằm ở tab Market Data Management, không phải tab này; (b) "manage your subscription" — cũng ở tab kia; (c) "through our secure billing portal" — không tồn tại. RFQ_ Website and Dashboard Implementation V7.pdf §Part C cũng vẫn ghi "Billing Portal Link" — nhưng đó là bản cũ, docx 2026-08-10 thắng. | Đề xuất: xoá hẳn dòng subtitle, không thay bằng câu khác. Heading Invoice History + bảng là đủ; docx mô tả màn này là "a clean ledger of past payments", không cần dẫn nhập. ⚠️ Nếu BA muốn giữ 1 dòng mô tả → phải viết lại hoàn toàn, đề xuất copy thay thế: "A record of every payment on your account" — nhưng phải là chuỗi mới, không được giữ bản cũ. | BA bác đề xuất: "Vẫn để, khách thấy oke." Giữ nguyên dòng subtitle của design, không xoá, không viết lại. | ❌ Rejected (đề xuất "xoá subtitle" sai) — giữ nguyên văn chuỗi design: "View invoices, update payment method, and manage your subscription through our secure billing portal" (bỏ dấu chấm cuối theo global-rules.md). Khách đã xem và chấp nhận. Nút Manage Billing vẫn bị xoá — chỉ chuỗi mô tả được giữ. |
| D-02 | 🟡 [COPY] Heading của màn: Invoices History (design) hay Invoice History (docx)? Design ghi Invoices History — sai ngữ pháp tiếng Anh. Docx và RFQ đều dùng Invoice History. | Đề xuất: Invoice History theo docx. Đây là lỗi typo trong design, không phải quyết định nghiệp vụ. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| D-03 | 🔴 [CONFLICT nội tại trong chính design + lệch CR-06 — chặn cứng] Số dòng mỗi trang là 10 hay 15? Ảnh design ghi "Showing 1–15 of 137 invoices" và render đúng 15 dòng → hàm ý 15 dòng/trang. Nhưng chính thanh phân trang bên phải trong cùng ảnh đó lại ghi 1 2 3 … 14 — 14 trang. 137 ÷ 15 = 10 trang, còn 137 ÷ 10 = 14 trang. Vậy chính con số trang trong design lại khớp với 10 dòng/trang, không khớp với 15. Thêm nữa CR-06 quy định default toàn hệ thống là 10 bản ghi/trang. | Đề xuất: 10 dòng/trang theo CR-06 — được chính con số 14 trong design corroborate. Phần "Showing 1–15" + 15 dòng render là dummy data dựng tay không đồng bộ với widget phân trang, không phải quyết định thiết kế. ⚠️ Kèm theo: CR-06 còn quy định có dropdown chọn page size (10/20/50/100) — design không có dropdown này, và khách đã chốt "No backend filtering is required" nên thêm control là vẽ thừa. Đề xuất deviation có chủ đích khỏi CR-06: giữ page size cố định 10, không render dropdown. | BA chốt (override đề xuất): "Chỉ là dummy data thôi, pagination bao nhiêu chả được, nó có bao nhiêu nó hiển thị bấy nhiêu. Miễn cứ max 15 invoices 1 pagination là được. Invoices mới nhất để lên đầu. Date và Amount sort được." | ⚠️ Partially rejected — chốt 15 dòng/trang (không phải 10). Số trang và dòng "Showing…" render theo tổng số bản ghi thật trả về, không theo con số trong ảnh dummy. Deviation có chủ đích khỏi CR-06 ở 2 điểm: page size = 15 thay vì 10, và không render dropdown chọn page size (khách đã chốt "No backend filtering is required"). Phần "sort mặc định mới nhất lên đầu" + "chỉ Date/Amount sort được" → khớp nguyên đề xuất D-12. |
| D-04 | 🔴 [CONFLICT nguồn ⇄ design — chặn cứng, Open Item O-9] Endpoint chỉ trả bản ghi đã thanh toán, vậy cột Status để làm gì? Cả 2 nguồn text đều ghi endpoint chỉ lấy record đã trả tiền: RFQ tr.36 "Fetches paid records from the invoices table", docx §2.3 "The API returns the complete array of paid invoices". Nếu đúng vậy → cột Status luôn = Paid ở mọi dòng, thành cột chết. Nhưng ảnh design lại hiển thị đủ 3 badge: Paid (xanh) / Void (đỏ) / Refunded (xám) — đúng bằng 3 giá trị của schema status ('paid','void','refunded'). Và Flow 7 thật sự có sinh refund market data (POST /issue-refund type=MARKET_DATA). | Đề xuất: design thắng — endpoint trả mọi status, chữ "paid" trong RFQ/docx là cách viết lỏng nghĩa "các giao dịch đã phát sinh", không phải bộ lọc WHERE status='paid'. Giữ đủ 5 cột, cột Status render 3 badge theo đúng enum. Lý do nghiệp vụ: màn này tự nhận là "clean ledger of past payments" / bảng invoices là "Financial Audit Trail" — nếu giấu khoản refund của chính user thì phá vỡ mục đích của màn. ⚠️ Vẫn phải hỏi khách confirm, vì đây là hợp đồng dữ liệu của BE, không phải suy đoán của BA được phép chốt một mình. | Confirm đúng đề xuất: "khách bảo lấy status 3 badge này rồi." | ✅ Confirmed — khách đã chốt trực tiếp, không còn là suy đoán. Endpoint trả mọi status; giữ đủ 5 cột; cột Status render 3 badge Paid / Void / Refunded theo đúng enum status ('paid','void','refunded'). |
| D-05 | 🟡 [COPY badge] Void hay Failed? Schema ghi status có giá trị 'void'. Ảnh design hiển thị badge Void. Nhưng bản bóc tách docx (MarketData_Billing_Wireframe_Brief.md BIL-7) lại ghi badge là Failed. | Đề xuất: Void — khớp cả schema lẫn design. Failed là cách diễn giải sai của bản brief (thanh toán thất bại ≠ hoá đơn bị huỷ hiệu lực). Map cứng: paid → Paid, void → Void, refunded → Refunded. | (BA không phản hồi riêng — áp dụng đề xuất; nhất quán với "3 badge này" khách chốt ở D-04) | ✅ Applied by default |
| D-06 | 🔴 [CONFLICT giữa 2 nguồn của chính khách — chặn cứng, Open Item O-6] Get Billing History nhận user_id hay user_id + subscription_id? docx §2.3 ghi input = user_id, subscription_id → invoice bị scope theo 1 subscription. Nhưng RFQ_ Stack Trading Prop Tech V7.pdf tr.36 định nghĩa endpoint này chỉ nhận user_id. Và chính khách vừa chốt 2026-08-10 rằng bảng phải hiện cho cả user SIM — mà user SIM không có subscription nào (subscription chỉ tồn tại cho market data add-on của LIVE), invoice của họ là challenge fee / reset fee / time extension, không gắn với subscription nào cả. → Nếu subscription_id là tham số bắt buộc thì bảng của mọi user SIM sẽ luôn rỗng, mâu thuẫn trực tiếp với chính câu trả lời của khách. | Đề xuất: user_id là tham số bắt buộc duy nhất; subscription_id là optional filter (mặc định vắng = trả toàn bộ invoice của user). Tab Billing của UC này không bao giờ truyền subscription_id — nó luôn gọi ở dạng "toàn bộ lịch sử". Tham số optional đó để dành cho tab Market Data Management nếu sau này cần xem invoice theo từng feed. | BA bác đề xuất: "lấy theo docx đi, docx là bản update mới nhất." | ❌ Rejected (đề xuất "optional filter" sai) — SRS ghi signature endpoint đúng theo docx: Get Billing History (GET) nhận user_id, subscription_id. Docx 2026-08-10 là bản mới nhất, thắng RFQ_ Stack Trading Prop Tech V7.pdf tr.36.⚠️ Rủi ro đã nêu vẫn còn nguyên và được ghi lại làm điểm phụ thuộc BE trong SRS: user SIM không có subscription_id nào; nếu BE hiện thực subscription_id là bắt buộc thì bảng của mọi user SIM sẽ rỗng, mâu thuẫn với chính câu khách chốt 2026-08-10 ("visible to all users, regardless of whether they are SIM or LIVE"). → chuyển thành việc BA cần xác nhận với BE (mục 1 bảng dưới), không chặn việc viết SRS. |
| D-07 | 🟡 [GAP nguồn, Open Item O-4] fee_type không có giá trị nào cho "Time Extension". ENUM trong Zapier Integration V7.pdf §3.1.2 chỉ có 5 giá trị: MARKET_DATA_BASE, MARKET_DATA_ADDON, PLATFORM_FEE, CHALLENGE_FEE, RESET_FEE. Nhưng khách nói rõ SIM có giao dịch time extension, và ảnh design hiển thị đúng dòng Time Extension với giá $49.00 USD. Không có fee_type nào map ra được chuỗi đó. | Đề xuất: bổ sung giá trị ENUM mới EXTENSION_FEE vào bảng invoices. Không gộp chung vào RESET_FEE — reset (mua lại lượt challenge, $99 theo design) và extension (mua thêm ngày, $49 theo design) là 2 sản phẩm khác giá, gộp lại thì user không phân biệt được 2 khoản chi của chính mình. ⚠️ Đây là thay đổi schema BE, cần khách/BE confirm. SRS sẽ ghi bảng map đầy đủ 6 giá trị và đánh dấu EXTENSION_FEE là điểm phụ thuộc BE. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| D-08 | 🔴 [GAP — chặn cứng, Open Item O-11] currency là field riêng — sort theo Amount khi có nhiều loại tiền thì tính sao? Schema có currency (String, default "USD") tách khỏi amount (Float), và design hiển thị $49.00 USD (có hậu tố currency) → hàm ý hệ thống lường trước nhiều loại tiền. Nếu bảng thật sự có cả USD lẫn USDT thì sort Amount bằng số thô là sai nghĩa ($99 USD vs 99 USDT không so sánh được). | Đề xuất: mọi invoice đều là USD, do đó sort Amount = sort số thuần, không cần group theo currency. Căn cứ: RFQ_ Stack Trading Prop Tech V7.pdf §3.7 nói rõ về Triple-A — "This is for customers paying via Crypto (we only receive Fiat)", tức khách trả bằng crypto nhưng hệ thống ghi nhận doanh thu bằng fiat; thêm nữa CR-20260810-001 đang đặt Triple-A ở trạng thái pending removal. Vẫn giữ hiển thị hậu tố USD theo design ($49.00 USD) vì nó khớp field currency trả về, format số theo CR-11. ⚠️ Nếu sau này thật sự phát sinh currency ≠ USD → cần rule hiển thị/sort riêng, mở CR. | BA chốt: "ở docx khách đang gộp là Amount & Currency. Dù sao cũng chỉ USD thôi thì sort amount là đúng rồi, chỉ USD thì đa tiền tệ chỗ nào vậy?" | ✅ Confirmed — không có đa tiền tệ, câu hỏi này không cần đặt ra. Chốt: 1 cột duy nhất Amount & Currency đúng như docx §2.3 mục 3 (không tách 2 cột), giá trị luôn USD, hiển thị $49.00 USD theo CR-11, sort là so sánh số thuần trên amount. Không viết rule dự phòng đa tiền tệ vào SRS. |
| D-09 | 🟡 [GAP, Open Item O-12] created_at hiển thị theo múi giờ nào? CR-08 bắt buộc lưu/truyền UTC ISO 8601, nhưng không nói render ra màn hình theo timezone nào. Nếu FE render theo timezone trình duyệt, trader ở châu Á sẽ thấy invoice lệch 1 ngày so với email receipt của payment gateway → user tưởng là 2 giao dịch khác nhau khi mở ticket support. | Đề xuất: hiển thị theo UTC, format DD MMM YYYY đúng như design (12 Aug 2026). Không hiển thị giờ/phút — bảng này là sổ cái theo ngày, không phải log. Không convert theo timezone trình duyệt. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| D-10 | 🔴 [GAP hợp đồng dữ liệu — chặn cứng] Cột Invoice ID hiển thị cái gì? Schema ghi id (UUID, Primary Key). Endpoint output đặt tên field là invoice_id. Nhưng design hiển thị INV-004822 — mã ngắn, dễ đọc, dạng chuỗi có prefix, hoàn toàn không phải UUID. Không nguồn nào định nghĩa cách sinh mã này. Nếu FE in thẳng UUID ra bảng thì cột đầu tiên sẽ là chuỗi 36 ký tự vô nghĩa, phá layout và vô dụng khi user đọc cho support qua điện thoại. | Đề xuất: BE phải trả mã hiển thị dạng INV- + số thứ tự tăng dần, zero-pad 6 chữ số (vd INV-004822) trong field invoice_id; UUID id giữ nguyên làm khoá nội bộ và không bao giờ hiển thị. Đây là yêu cầu bổ sung cho BE, cần khách/BE confirm quy tắc sinh mã (đặc biệt: đánh số toàn hệ thống hay theo từng user). | BA bác đề xuất: "BE trả về ID như nào thì hiển thị như thế, đã bảo design là dummy data mà." | ❌ Rejected (đề xuất "ép BE sinh mã INV-XXXXXX" sai) — SRS không áp đặt format mã. Cột Invoice ID hiển thị nguyên văn giá trị invoice_id mà endpoint trả về, không transform, không thêm prefix. Chuỗi INV-004822 trong design chỉ là dummy minh hoạ. Hệ quả duy nhất phải xử lý: giá trị có thể dài (UUID 36 ký tự) → cột này bắt buộc truncate + tooltip (đã có ở D-16). |
| D-11 | 🟡 [Open Item O-10] Bảng invoices chứa cả Payout — Invoice History có hiện payout không? Zapier Integration V7.pdf §3.1.2 mô tả bảng này "Stores every financial transaction (Fees, Refunds, Payouts) for the Level 3 Audit." Nhưng fee_type ENUM chỉ có 5 giá trị toàn là phí, không có giá trị nào cho payout. Nếu payout lọt vào response → cột Description sẽ rỗng và Amount là tiền chuyển ra cho trader, ngược chiều mọi dòng khác trong bảng. | Đề xuất: KHÔNG hiển thị payout ở tab này. Tab Billing chỉ hiện các khoản user đã trả cho Stack Trading; payout là dòng tiền ngược chiều và thuộc phân hệ Payout & Withdrawal (UC_5.x, chưa viết). Cơ chế: BE lọc theo fee_type IN (5 giá trị phí + EXTENSION_FEE); bản ghi nào không có fee_type hợp lệ thì không trả về. Nếu khách muốn hiện payout ở đây → phải thiết kế lại bảng (cần cột phân biệt tiền vào/tiền ra), là CR riêng. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| D-12 | 🟡 [GAP] Sort mặc định là cột nào? docx cho phép sort Date hoặc Amount nhưng không nói cột nào sort mặc định, cũng không nói hướng. Design có icon ⇅ ở đúng 2 cột Date và Amount, không có icon ở 3 cột còn lại. | Đề xuất: mặc định Date giảm dần (mới nhất lên đầu) — sổ cái tài chính luôn đọc từ mới về cũ. Chỉ Date và Amount sort được; Invoice ID / Status / Description không sort được và không render icon. Icon có 3 state: chưa sort (⇅ mờ) · tăng dần (↑) · giảm dần (↓). Sort là client-side thuần trên toàn bộ payload đã tải, không gọi lại API. Đổi sort → quay về trang 1. | BA confirm trực tiếp trong câu trả lời D-03: "Invoices mới nhất để lên đầu. Date và Amount sort được." | ✅ Confirmed — BA chốt thẳng, không còn là giả định. Mặc định Date giảm dần; chỉ Date và Amount sort được. |
| D-13 | 🟡 [COPY — lệch giữa design và bản brief] Empty state hiển thị gì? Ảnh design (frame 2) chỉ có: icon đồng hồ lịch sử + 1 dòng "Your payment history will appear here after your first charge." — không có dòng tiêu đề. Bản MarketData_Billing_Wireframe_Brief.md BIL-8 lại đề xuất có thêm title No invoices yet. Ngoài ra design cho thấy ở empty state: heading màn vẫn hiện, còn thanh phân trang và dòng footer note đều bị ẩn. | Đề xuất: theo design — chỉ icon + 1 dòng "Your payment history will appear here after your first charge" (bỏ dấu chấm cuối theo global-rules.md → Error Handling). Không thêm title. Ẩn thanh phân trang + footer note. Header bảng (5 cột) cũng ẩn — design không render header ở state này. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| D-14 | 🟡 [COPY — lệch giữa design và bản brief] Error state hiển thị gì? Ảnh design (frame 3): icon ⚠ + title "Couldn't load your invoices" + dòng phụ "Something went wrong loading your invoices. Your history is safe." + nút Try again. Bản brief BIL-14 ghi dòng phụ khác: "Something went wrong on our end. Your payment history is safe." | Đề xuất: theo design (bản mới nhất, BA gửi 2026-08-12), bỏ dấu chấm cuối cả 2 chuỗi. Nút Try again gọi lại đúng GET /billing-history, không reload cả trang. Không cấp ID mới trong list-toast-popup.md — đây là empty/error state trong khung panel, không thuộc nhóm Toast/Banner/Overlay/Full-page; viết trực tiếp trong SRS như cách BR_4.6.1.8 đã làm cho empty state của Connections & Credentials. ⚠️ Lưu ý: error state này thay thế toast TE-SYS-01 cho trường hợp load hỏng — không bắn cả 2 cùng lúc. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| D-15 | 🟡 [GAP] Loading state. Design không có frame loading. Nhưng khách bắt BE trả toàn bộ lịch sử trong 1 lần gọi ("the full historical payload") → user nhiều invoice sẽ thấy rõ thời gian chờ. Không định nghĩa thì user tưởng bảng rỗng và nhầm với empty state D-13. | Đề xuất: header bảng hiện bình thường, thân bảng render 5 dòng skeleton theo đúng độ rộng từng cột, thanh phân trang và footer note ẩn. Không dùng spinner giữa màn (spinner làm nhảy layout khi data về). | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| D-16 | 🟡 [GAP — bắt buộc theo global-rules.md → Overflow & Text Display] Hành vi tràn nội dung của từng cột. Quy tắc bắt buộc: mọi cột text phải khai báo overflow, không được khai một phần. Không nguồn nào nói. | Đề xuất: Invoice ID → truncate + tooltip (an toàn nếu BE trả UUID thay vì mã ngắn, xem D-10); Date → không xuống dòng, không truncate (độ dài cố định); Amount → không xuống dòng, tooltip hiện giá trị đầy đủ theo CR-11; Status → badge, không truncate (tập giá trị đóng, 3 giá trị); Description → truncate + tooltip. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| D-17 | 🟡 [GAP] Dữ liệu được nạp lúc nào, có cache / auto-refresh không? Invoice mới phát sinh khi user mua reset/extension ở màn khác, hoặc khi Flow 22 sinh hoá đơn hằng tháng (Monthly_Data_Invoice_Available email). Nếu user đang mở tab Billing lúc đó thì bảng có tự cập nhật không? | Đề xuất: gọi GET /billing-history mỗi lần user vào tab Billing, không cache. Không auto-poll, không WebSocket, không tự refresh khi đang ở trên màn — user thấy invoice mới ở lần vào tab kế tiếp. Lý do: sổ cái lịch sử không phải dữ liệu real-time, và không nguồn nào yêu cầu push. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| D-18 | 🟡 [CROSS_UC + nguồn lỗi thời] 4 file cần sửa kèm sau khi UC_4.6.3 được publish. (a) BR_4.6.2.1 bảng tab → owning UC đang ghi Billing → UC_4.6.3 (not yet documented in this repo); (b) UC_4.1.2 §2 dòng 6 cũng ghi UC_4.6.3 Billing (not yet documented in this repo); (c) index.md của folder này đang liệt kê UC_4.6.3 trong mục "Chưa có tài liệu"; (d) QnA_STAGE2_SETTINGS_CAREER_VIRAL.md §6 + bản EN + Stage 2 - Dashboard & Fomula (Settings).csv dòng 333 vẫn ghi Billing = BLOCKED, chờ docx từ Adrian — đã lỗi thời từ 2026-08-10 khi docx về. | Đề xuất: (a)(b)(c) là ID/link-only remap, không đổi logic — xin BA cho phép sửa kèm trong cùng vòng này, mỗi file bump 1 version và ghi changelog. (d) là việc cập nhật nguồn QnA, đề xuất tách thành task riêng chạy qua skill source-of-truth (không nằm trong phạm vi SRS). | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| D-19 | 🟡 [SCOPE] Tab Billing có ẩn/read-only theo trạng thái tài khoản không? Các trạng thái đã có trong repo: Hard Breach / Frosted Glass (UC_4.10.2), account ReadOnly sau khi Resign (Flow 20), account bị Zombie pause (Flow 12). Không nguồn nào nói tab Billing bị ảnh hưởng. | Đề xuất: tab Billing luôn truy cập được miễn user còn đăng nhập được — đây là sổ cái lịch sử, read-only, không phải hành động giao dịch. User vừa resign hoặc vừa breach càng cần tra lại lịch sử thanh toán của mình. Nhất quán với lập luận đã dùng ở C-17 cho 2 toggle của UC_4.6.4. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| D-20 | 🟡 [GAP nguồn / asset] (a) Không nguồn nào cho biết path thật của endpoint — RFQ và docx chỉ đặt tên nghiệp vụ Get Billing History, WBS dòng 175 để trống ô endpoint. (b) 3 ảnh design vòng này vẫn chỉ nằm trong chat, folder References/Wireframe/Stage 2/Settings/ vẫn chưa tồn tại (treo từ A-19(b) vòng 1 → C-18(b) vòng 3, chưa xử lý); WBS dòng 175 trỏ tới Figma node 1-15026 thuộc file Stack-Trading-Designs---Shared-File--2-, khác file Figma mà UC_4.6.1/4.6.2/4.6.4 đang cite (-BA-Wireframe--Stack-Trading-Design). (c) node script/parse_wbs.js --compact vẫn lỗi Cannot find module './lib_xlsx_min.js' (treo từ C-18(c), chưa xử lý) → vòng này lại phải đọc CSV thô. | Đề xuất: (a) SRS ghi GET /billing-history theo convention kebab-case của các endpoint đã có trong dự án (/market-data-status, /ai-preference, /toggle-market-data), đánh dấu là điểm chờ BE/khách confirm; (b) BA commit 3 ảnh vào References/Wireframe/Stage 2/Settings/, đồng thời xác nhận file Figma nào là bản chuẩn cho cụm Settings — hiện đang có 2 file song song; (c) BA/dev sửa parse_wbs.js. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| D-21 | 🟡 [GAP] Hành vi thanh phân trang khi ít dữ liệu + sau khi đổi sort. Design chỉ có 1 frame nhiều dữ liệu. | Đề xuất: ≤ 15 dòng (đúng bằng page size BA chốt ở D-03) → ẩn hoàn toàn thanh phân trang (không hiện "Showing 1–3 of 3"). ‹ Prev Disabled ở trang 1, Next › Disabled ở trang cuối. Dải số trang rút gọn dạng 1 2 3 … N theo design, với N = tổng số trang tính từ dữ liệu thật (ceil(tổng invoice ÷ 15)) — con số 14 trong ảnh là dummy. Đổi sort → về trang 1 (nhất quán với D-12). Phân trang client-side thuần, không gọi lại API — hợp lệ vì docx cho phép xử lý client-side để cải thiện UX. | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| D-22 | 🟡 [COPY] Bảng map fee_type → chuỗi hiển thị ở cột Description. Bắt buộc phải có, nếu không FE sẽ in raw ENUM (MARKET_DATA_ADDON) ra UI. Design chỉ show 3 giá trị của SIM, dùng Title Case. | Đề xuất (Title Case theo design): CHALLENGE_FEE → Evaluation Purchase · RESET_FEE → Challenge Reset · EXTENSION_FEE → Time Extension (phụ thuộc D-07) · MARKET_DATA_BASE → Market Data — Base Feed · MARKET_DATA_ADDON → Market Data — Add-on · PLATFORM_FEE → Platform Fee. Giá trị fee_type lạ/không map được → hiển thị nguyên chuỗi fee_type (fail-safe, để QA phát hiện được ENUM mới thay vì thấy ô rỗng). | (BA không phản hồi riêng — áp dụng đề xuất) | ✅ Applied by default |
| D-23 | 🟡 [Dummy data — BA đã lưu ý sẵn] 3 ảnh design dùng data giả không nhất quán: INV-004822 lặp lại 8 lần với cùng ngày và cùng số tiền; INV-004821 lặp 3 lần; số dòng render (15) không khớp số trang (14 ⇒ 10 dòng/trang, xem D-03). | Không phải câu hỏi — ghi lại để Agent 3 không lấy giá trị trong ảnh làm business rule. Invoice ID là duy nhất, không có 2 dòng cùng mã. Mọi giá trị số/ngày trong SRS lấy từ schema và endpoint, chỉ dùng ảnh để xác định cấu trúc cột, badge, copy và layout. | ✅ Ghi nhận (không cần BA trả lời) |
Ghi chú Phase 2.2 — WBS Cross-UC Consistency Check (vòng 4)
- UC_ID hợp lệ:
UC_4.6.3tồn tại ở WBS dòng 175,category = STAGE 2: DASHBOARD - COMMON,module = Settings,function = Billing→ folder đíchdashboard_common/UC_4.6.1-4.6.4/là đúng theoglobal-rules.md → WBS Category → Folder Mapping. - ⚠️ Orphan-UC / stale ID:
MarketData_Billing_Wireframe_Brief.mdvàQnA_STAGE2_SETTINGS_CAREER_VIRAL.mdđang gọi Billing làUC_4.8.5và Market Data Management làUC_4.8.3— đây là dải UC cũ trước lần BA re-break WBS.UC_4.8.5không tồn tại trong WBS hiện tại. Chốt theo WBS: Billing =UC_4.6.3(đúng như BA chỉ định). 2 file QnA cần được remap — nằm trong D-18(d). - Ranh giới UC — điểm dễ viết nhầm nhất của vòng này:
Broadcast, Settings_Market Data.docxđặt §1.0 (Card Payment Methods,Subscription Funding Source) và §2.1–2.2 (Get Saved Cards,Delete Saved Card,Add Saved Card,Update Subscription Payment,Get Active Subscriptions,Cancel Subscription) dưới headingSettings - Market Data management, không phải dướiSettings - Billing. → UC_4.6.3 KHÔNG sở hữu quản lý thẻ, không sở hữu subscription, không sở hữu 6 endpoint đó. Toàn bộ thuộc tab Market Data Management (WBS gánUC_4.17.1, LIVE-only, chưa viết). - Không có CR liên quan trực tiếp: rà toàn bộ 30 CR trong
_CR_INDEX.md→ không CR nào chạm tab Billing.CR-20260810-001(Triple-A pending removal) chỉ liên quan gián tiếp qua câu hỏi đa tiền tệ (D-08). - Cross-UC cần sửa kèm sau khi publish:
UC_4.6.2_v1.md(BR_4.6.2.1),UC_4.1.1-4.1.5_v1.md(UC_4.1.2 §2 dòng 6),index.md— xem D-18.
Ghi chú Phase 2.5 — Impact Analysis (mandatory)
Đặc thù vòng này: UC_4.6.3 là màn read-only tuyệt đối — không tạo, không sửa, không xoá, không đổi trạng thái bất kỳ dữ liệu nào. Mọi tương tác của user (sort, chuyển trang, retry) đều là client-side thuần. Do đó bảng Impact bên dưới không có dòng nào thuộc nhóm "state-changing action"; thay vào đó liệt kê rủi ro đọc dữ liệu — vốn là rủi ro thật của một màn tự nhận là financial audit trail.
| Hành động / Sự kiện | Uniqueness | Cascade (downstream) | Reversibility | Concurrency |
|---|---|---|---|---|
Load bảng (GET /billing-history) | invoice_id phải unique — design đang lặp mã là dummy (D-23) | Không ghi gì. Rủi ro: nếu endpoint lọc status='paid' thì user không bao giờ thấy khoản refund của mình → D-04; nếu payout lọt vào response thì Description rỗng và Amount ngược chiều → D-11 | N/A (read-only) | Invoice mới sinh trong lúc user đang mở tab (mua reset/extension ở màn khác, hoặc Flow 22 sinh hoá đơn tháng) → bảng không tự cập nhật, user thấy ở lần vào tab kế tiếp → D-17 |
Sort theo Date / Amount | Không | Không gọi lại API. Rủi ro: sort Amount sai nghĩa nếu tồn tại nhiều currency → D-08 | Reversible (đổi lại sort) | Không có race — sort trên payload đã tải |
| Chuyển trang | Không | Không gọi lại API (phân trang client-side) | Reversible | Không có race |
Nút Try again ở error state | Không | Gọi lại đúng GET /billing-history, không reload trang | Reversible | Nhiều lần bấm liên tiếp → nút nên Disabled trong lúc request đang bay (nhất quán với cơ chế đã dùng ở C-09) |
Hiển thị created_at | Không | Lệch timezone → user đọc ngày khác với email receipt của gateway khi mở ticket support → D-09 | N/A | N/A |
Không có Zapier Flow nào chạy trong UC này. Flow 22 (Monthly Data Fee Billing) là producer sinh ra bản ghi mà màn này đọc, không phải một bước trong luồng của UC. Không có Zapier Table nào. Không có 3rd party trên UI — khách đã chốt "There is no 3rd party involved, we already store the invoices" (đã confirm sẵn #2); NMI/Quaderno chỉ là hệ thống sinh dữ liệu ở tầng backend, user không chạm tới từ màn này.
✅ Kết quả BA review — Vòng 4 (2026-08-12)
| Nhóm | Kết quả |
|---|---|
| D-01 Subtitle "billing portal" | ❌ Đề xuất "xoá subtitle" bị bác — "Vẫn để, khách thấy oke." Giữ nguyên văn chuỗi design. Nút Manage Billing vẫn bị xoá. |
| D-03 Page size | ⚠️ Partially rejected — chốt 15 dòng/trang (đề xuất 10 bị override). Số trang render theo dữ liệu thật, không theo ảnh dummy. Deviation có chủ đích khỏi CR-06. |
D-04 Cột Status | ✅ Confirmed — khách đã chốt 3 badge Paid / Void / Refunded. Endpoint trả mọi status, giữ đủ 5 cột. |
| D-06 Input endpoint | 🔴 ĐÃ BỊ ĐẢO 2026-08-21 — subscription_id là optional và bị bỏ qua, luôn trả full history theo user_id. Xem Trả lời QnA 2026-08-21. subscription_id optional" bị bác — lấy đúng theo docx: user_id, subscription_id. Docx 2026-08-10 thắng RFQ tr.36. Rủi ro "bảng SIM rỗng" chuyển thành việc xác nhận với BE. |
| D-08 Đa tiền tệ | ✅ Confirmed — không có đa tiền tệ, chỉ USD. Chốt 1 cột gộp Amount & Currency đúng docx, sort số thuần. Không viết rule dự phòng. |
D-10 Invoice ID | ❌ Đề xuất "ép BE sinh mã INV-XXXXXX" bị bác — BE trả gì hiển thị nấy, không transform. INV-004822 chỉ là dummy. |
| D-12 Sort mặc định | ✅ Confirmed (qua câu trả lời D-03) — Date giảm dần, chỉ Date/Amount sort được. |
| D-02, D-05, D-07, D-09, D-11, D-13 → D-21, D-22 | ✅ Applied by default — BA không phản hồi riêng, Agent 3 viết SRS theo đúng cột Giả định. |
| D-23 Dummy data | ✅ Ghi nhận — BA nhắc lại 2 lần rằng mọi giá trị trong 3 ảnh design là dummy. SRS chỉ lấy cấu trúc cột, badge, copy, layout từ ảnh. |
Chỉ thị phạm vi bổ sung (BA, 2026-08-12)
Trong Broadcast, Settings_Market Data.docx: chỉ đọc từ heading Settings - Billing đổ xuống. Phần Settings - Market Data management (§1.0 Card Payment Methods / Subscription Funding Source, §2.1 Get Saved Cards / Delete Saved Card / Add Saved Card / Update Subscription Payment, §2.2 Get Active Subscriptions / Cancel Subscription) — bypass hoàn toàn, thuộc tab Market Data Management (UC_4.17.1, chưa viết).
Việc BA cần làm tiếp (ngoài phạm vi SRS UC_4.6.3)
| # | Việc | Liên quan |
|---|---|---|
| 1 | ✅ ĐÃ TRẢ LỜI 2026-08-21 — optional, bỏ qua. Còn lại: xác nhận BE cài đặt đúng là không filter. subscription_id trong Get Billing History là optional hay bắt buộc. | D-06 |
| 2 | ✅ ĐÃ TRẢ LỜI 2026-08-21 — bỏ EXTENSION_FEE, chỉ dùng 5 giá trị. Còn lại: chốt fee_type nào mang khoản extension + sửa design dòng Time Extension. EXTENSION_FEE vào bảng invoices (hoặc xác nhận extension dùng chung RESET_FEE)Time Extension mà chính design hiển thị | D-07 |
| 3 | ✅ ĐÃ ĐÓNG 2026-08-28 — không. Billing chỉ inflow; Payout dời sang sub-tab riêng ở Day 2. Payout có hiện trong Invoice History không | D-11 |
| 4 | ✅ ĐÃ ĐÓNG 2026-08-28 — GET /billing-history xác nhận đúng. | D-20(a) |
| 5 | Yêu cầu design sửa typo heading Invoices History → Invoice History, và đồng bộ lại dummy data (15 dòng render vs 14 trang) | D-02, D-23 |
| 6 | Cập nhật QnA_STAGE2_SETTINGS_CAREER_VIRAL.md (VI + EN) + Stage 2 - Dashboard & Fomula (Settings).csv dòng 333: gỡ trạng thái BLOCKED cho Billing, remap UC_4.8.5 → UC_4.6.3 — chạy qua skill source-of-truth | D-18(d) |
| 7 | 🟡 Một phần đóng 2026-08-27. Việc commit ảnh không theo dõi nữa (BA tự làm). Còn lại: xác nhận file Figma chuẩn cho cụm Settings — đang có 2 file song song (-BA-Wireframe--Stack-Trading-Design vs Stack-Trading-Designs---Shared-File--2-) | D-20(b) |
| 8 | Sửa script/parse_wbs.js (Cannot find module './lib_xlsx_min.js') — treo từ vòng 3 C-18(c) | D-20(c) |
| 9 | Khi viết UC_4.17.1 (Market Data Management): 6 endpoint quản lý thẻ/subscription trong docx §2.1–2.2 thuộc UC đó, không thuộc UC_4.6.3. Kèm Open Items O-1/O-2/O-3/O-7 của MarketData_Billing_Wireframe_Brief.md | Ghi chú Phase 2.2 |