FibreTrace QC Test Script — Phân tích
Bản tiếng Việt của
analysis.md. Hai bản sống song song, giữ nguyên thứ tự phần và mọi citation để đối chiếu được; bản tiếng Anh là bản gốc. Đường dẫn, route, tên bảng/cột, tên hàm/component, mã test case (A-01, R-13, X-02…), citationpath:linevà thuật ngữ nghiệp vụ được giữ nguyên tiếng Anh có chủ đích.
Nguồn: .local/qc-test-script/fibretrace-qc-test-script.docx (v1.0, từ Malcolm, 2026-08-19). Các case đã rút gọn: test-cases.md (cùng thư mục). Tham chiếu dạng X:<n> trỏ tới extracted.txt.
Quy ước citation. L:<path>:<line> = clone Lovable fibre-trace-studio-8b5c03d8 đọc tại ref origin/main = ffab85ca, 2026-08-19 (working tree đang checkout của clone lệch 4.264 commit so với ref đó — mọi citation Lovable bên dưới đều được kiểm đối chiếu với ref bằng git show/git grep, không đọc file cũ trên đĩa). M:<path>:<line> = fibretrace-monet/apps/dashboard. Citation tới memory/business-logic dùng đường dẫn đầy đủ.
TL;DR
- Kịch bản nhắm vào bản Lovable MVP đang chạy, không phải monet: 30 trên 31 route riêng biệt tồn tại ở Lovable
origin/main; monet thiếu hẳn 10 route và stub tầng dữ liệu ở 14 route nữa. Đem script này chạy lên monet sẽ đẻ ra bug report sai ở gần như mọi case. - Route duy nhất không tồn tại ở đâu cả (Lovable, monet, hay canvas) là
/insights(R-13), và cái toggle module Insights (A-08) cũng không có — registry module của admin có đúng 5 module, không cái nào tên Insights (L:src/pages/admin/AdminCompanies.tsx:81). - Tài liệu không chốt được hai câu hỏi treo đã biết: bản thân nó dùng cả hai nhãn CU (“Claim Unit / credit unit”, X:6, X:276), và nó yêu cầu dùng chữ “Nominations (not Purchase Order)” (X:276) trong khi vẫn đặt tiêu đề R-01 là “Create a nomination (PO)” và route mọi thứ qua
/purchase-orders— câu hỏi đổi tên bảng vẫn treo. - Yêu cầu tài khoản mới của Malcolm là làm tự phục vụ được với user/company (luồng signup thật cộng admin duyệt có tồn tại ở HEAD), nhưng 7 trong 11 loại object của checklist môi trường bị khóa sau quyền FT Admin (programme, programme registration, reservation, license, scanner, SDU, product categories). Cái tab QC account-switcher sẽ bỏ được ma sát đăng nhập, nhưng không bỏ được việc tạo object bị gate bởi admin — đó mới là nút thắt thật.
a) App nào đang được test
Kết luận: bản Lovable MVP đang chạy (fibre-trace-studio), không kèm điều kiện gì. Không phải apps/dashboard của monet, và cũng không phải “một phần cả hai”.
Bằng chứng:
- Kiểm kê route. Trong 31 route riêng biệt mà 50 case tham chiếu tới, 30 cái tồn tại ở Lovable
origin/main(ma trận đầy đủ ở mục b). Cái duy nhất trượt là/insights(R-13), và nó không tồn tại trong bất kỳ codebase nào ta soi được: tại Lovableorigin/mainchữ “insight” chỉ khớp đúng một hằng số cục bộ không liên quan (L:src/components/EmptyProgrammeHealthCard.tsx:51); monet không có route lẫn page; quét không phân biệt hoa thường trênfrontend-canvas(.local/frontend-canvas/repo/src/) trả về 0 kết quả. R-13 đang test một tính năng chưa được xây ở đâu cả (chưa kiểm được liệu nó có đang làm dở bên trong Lovable hôm nay hay không). - Độ mới của các route admin. Script tham chiếu
/admin/programs(không phảiprogrammes),/admin/reservation-requests,/admin/overrides,/admin/claim-verifications,/admin/settings— tất cả chỉ mới ra đời trong cửa sổ Lovable gần đây (.local/lovable/sync-20260819/port-plan.md:176ghi lại việc thêmAdminOverrides/AdminReservationRequestsvà vụ đổi tênadmin/programmesthànhadmin/programs). Tạiorigin/main,/admin/programslà tên canonical còn/admin/programmescũ chỉ là redirect (L:src/App.tsx:215-216). Monet thì vẫn chỉ route tên CŨ (M:src/App.tsx:168-169) và hoàn toàn không có route reservation-requests, signup-requests, overrides, claim-verifications hay admin-settings. Ai viết script này đã nhìn vào bản Lovable đang chạy trong tuần này. - Dấu vân tay của business rule. Các rule trong script chỉ được hiện thực ở Lovable: mặc định reservation 18 tháng (
L:src/pages/admin/AdminProgrammes.tsx:110,209,247), sổ cái điều chỉnh âm (“Use a negative value to subtract. 1,000 CU = 1 MT”,L:src/pages/admin/AdminProgrammes.tsx:1463), khóa settingobfuscate_verification_idsmặc định BẬT (L:src/hooks/useObfuscateVerificationIds.ts:4, toggle ởL:src/pages/admin/AdminSettings.tsx:169), và mô hình CU rate theo product category (L:src/pages/admin/AdminProductCategories.tsx:144). Backend REST thật của Fibretrace không có khái niệm nào trong số đó — “real backend has noexpires_atconcept anywhere (confirmed 2026-08-18)” (.local/lovable/sync-20260819/port-plan.md:79). - Khớp bối cảnh. Message của Malcolm nói về bản MVP dùng để demo, về demo modal, và về khả năng làm một “QC modal account-switcher tab” — mà demo modal (
DemoNavBar) chỉ tồn tại trong app Lovable (L:src/components/DemoNavBar.tsx:15-28).
Một lưu ý về tiền đề: giả định rằng monet không có mặt admin nào là không đúng theo nghĩa đen — monet có route một khối /admin 13 trang (M:src/App.tsx:167-184) và 4 trong 5 trang owner (M:src/App.tsx:151-154). Nhưng những trang đó là một bản port sớm và nay đã cũ: chúng lạc hậu so với mặt admin của Lovable từ 5 màn hình trở lên, và bảng dữ liệu của chúng gần như toàn bộ là stub no-op (mục b). Kết luận thực tế vẫn thế — không thể chạy test route admin trên monet.
b) Ma trận phủ route
Nền dữ liệu của monet, đối chiếu thực tế: M:src/lib/apiAdapter.ts đăng ký 50 bảng trong ALL_TABLES (:109-128); chỉ 12 bảng có mapper thật (company_modules:142, company_api_access:154, app_settings:161, company_users:263, company_partners:304, company_details:367, scanners:440, audits:462, facilities:533, invoices:577, companies:614, collections:647); 38 bảng còn lại rơi xuống stub no-op trả về []. Mọi thao tác ghi qua fake client đều throw MutationNotImplementedError bất kể bảng nào (M:src/lib/apiAdapter.ts:835-858) — ghi chỉ “được hỗ trợ” ở chỗ nào trang đó đi vòng qua adapter để gọi thẳng mutation RTK Query thật (ví dụ tạo facility). Phần resolve API của port plan 2026-08-19 xác nhận cửa sổ này: EXISTS=0, 9 GAP, 3 PARTIAL (.local/lovable/sync-20260819/port-plan.md:4,69-189), và state.json mang 10 unit known_unported — toàn bộ domain PO/claims/programmes đã bị BE chặn từ tháng 6.
| Route | Case QC | Lovable origin/main |
Router của monet | Tầng dữ liệu monet | Chạy được trên monet? |
|---|---|---|---|---|---|
/ (home) |
M-07, R-12 | L:src/App.tsx:165 |
M:src/App.tsx:126 |
company_modules/app_settings đã wire; mọi KPI của PO/claim là stub | MỘT PHẦN — KPI rỗng vì lý do BE đã biết |
/signup, /signup/status |
A-10 | L:src/App.tsx:151-152 |
KHÔNG CÓ | — | KHÔNG — thiếu route |
/admin/programs |
A-01, A-02 | L:src/App.tsx:215 (tên programmes cũ redirect, :216) |
KHÔNG CÓ theo tên này (chỉ còn /admin/programmes cũ, M:src/App.tsx:168-169) |
fibre_programmes stub (apiAdapter.ts:178-183), programme_reservations stub (:233) |
KHÔNG |
/admin/reservation-requests |
A-03, A-04, R-04 | L:src/App.tsx:222 |
KHÔNG CÓ | reservation_requests thậm chí không có trong ALL_TABLES |
KHÔNG |
/admin/companies |
A-05…A-09 | L:src/App.tsx:219 |
M:src/App.tsx:170 |
companies/company_details/company_modules đã wire; programme_participants/programme_producers là stub (:230-231); ghi thì throw |
MỘT PHẦN — danh sách hiện ra, nhưng không đăng ký được |
/admin/signup-requests |
A-10 | L:src/App.tsx:221 |
KHÔNG CÓ | signup_requests không có trong ALL_TABLES |
KHÔNG |
/admin/facilities |
A-11 | L:src/App.tsx:225 |
M:src/App.tsx:173 |
facilities ĐÃ WIRE (:533) |
ĐỌC thì được |
/admin/scanners |
A-11 | L:src/App.tsx:224 |
M:src/App.tsx:172 |
scanners ĐÃ WIRE (:440); scanner_facility_assignments stub (:381) |
MỘT PHẦN |
/admin/licensing |
A-12 | L:src/App.tsx:226 |
M:src/App.tsx:174 |
facility_licenses stub (:237) |
KHÔNG — vỏ rỗng |
/admin/overrides |
A-13 | L:src/App.tsx:223 |
KHÔNG CÓ | — | KHÔNG |
/admin/claim-verifications |
A-14 | L:src/App.tsx:234 |
KHÔNG CÓ (chỉ có /admin/verifications, M:src/App.tsx:179) |
claim_verifications không có trong ALL_TABLES; verifications/sessions là stub gắn nhãn “BE-blocked” (:200-209) |
KHÔNG |
/admin/settings |
A-15 | L:src/App.tsx:244 |
KHÔNG CÓ — monet không có AdminSettings.tsx nào |
— | KHÔNG |
/admin/fibre-production |
P-05 (dự kiến) | L:src/App.tsx:232 |
M:src/App.tsx:180 |
production_records stub (:234) |
KHÔNG — vỏ rỗng |
/owner |
O-01, A-09 | L:src/App.tsx:190 |
KHÔNG ĐƯỢC ROUTE — OwnerDashboard có import (M:src/App.tsx:73) nhưng chưa bao giờ được gắn <Route>; code chết |
— | KHÔNG |
/owner/certificates |
O-02 | L:src/App.tsx:192 |
M:src/App.tsx:153 |
program_certificates(+assignments) stub |
KHÔNG — vỏ |
/owner/documents |
O-02 | L:src/App.tsx:191 |
M:src/App.tsx:154 |
program_documents(+assignments) stub |
KHÔNG — vỏ |
/owner/program-uptake |
O-03 | L:src/App.tsx:194 |
M:src/App.tsx:152 |
stub | KHÔNG — vỏ |
/owner/program-record |
O-03 | L:src/App.tsx:193 |
M:src/App.tsx:151 |
stub | KHÔNG — vỏ |
/sdu |
P-01, P-02 | L:src/App.tsx:184 |
M:src/App.tsx:143 |
sliver_delivery_units (:236) / sdu_activity_logs stub |
KHÔNG — vỏ |
/fibre-creation |
P-03…P-06 | L:src/App.tsx:183 |
M:src/App.tsx:142 |
production_records (:234) / pigment_orders (:228) stub |
KHÔNG — vỏ |
/facilities |
M-01 | L:src/App.tsx:185 |
M:src/App.tsx:144 |
facilities ĐÃ WIRE (:533) |
CÓ (gần chạy được nhất) |
/facilities/add |
M-01 | L:src/App.tsx:140 |
M:src/App.tsx:111 |
hook mutation facilitiesApi thật (đi vòng qua adapter) |
CÓ |
/scanners |
M-02, A-11 | L:src/App.tsx:179 |
M:src/App.tsx:141 |
scanners ĐÃ WIRE (:440) |
ĐỌC thì được |
/verifications (Scan History) |
M-03 | L:src/App.tsx:177 |
M:src/App.tsx:138 |
verifications/sessions stub, “BE-blocked” (:200-209) |
KHÔNG — vỏ |
/partners |
M-04 | L:src/App.tsx:188 (/settings/partners cũ redirect, :189) |
KHÔNG CÓ — monet chỉ có /settings/partners (M:src/App.tsx:161) |
company_partners ĐÃ WIRE (:304) |
MỘT PHẦN — tính năng có, nhưng ở đường dẫn cũ |
/link-to-po |
M-05, M-06 | L:src/App.tsx:176 |
M:src/App.tsx:134 |
purchase_orders/purchase_order_verifications/purchase_order_evidence_packs đều là stub |
KHÔNG — vỏ |
/purchase-orders |
R-01, R-02 | L:src/App.tsx:173 (+ trang chi tiết :id :174) |
M:src/App.tsx:132 |
purchase_orders stub |
KHÔNG — vỏ |
/claim-position |
R-03, R-04, R-05, A-02 | L:src/App.tsx:170-171 (gồm cả :id) |
M:src/App.tsx:129 (không có :id; có /claim-position-list phẳng riêng, :130) |
fibre_programmes/programme_reservations stub |
KHÔNG — vỏ |
/ready-to-claim |
R-06, R-07 | L:src/App.tsx:175 |
M:src/App.tsx:133 |
cùng bộ stub PO/claim | KHÔNG — vỏ |
/claims |
R-08…R-11 | L:src/App.tsx:172 |
M:src/App.tsx:131 |
production_claims stub (:235) |
KHÔNG — vỏ |
/insights |
R-13 | KHÔNG CÓ (chỉ khớp chữ ở L:src/components/EmptyProgrammeHealthCard.tsx:51) |
KHÔNG CÓ | — | KHÔNG — không tồn tại ở đâu cả |
Tổng kết (31 route): Lovable origin/main có 30/31 (thiếu /insights). Monet: 7 route có dữ liệu wire ít nhất một phần (/, /admin/companies, /admin/facilities, /admin/scanners, /facilities, /facilities/add, /scanners), 14 route có route nhưng chỉ là vỏ rỗng (toàn bộ trang owner, /sdu, /fibre-creation, /verifications, /link-to-po, /purchase-orders, /claim-position, /ready-to-claim, /claims, /admin/licensing, /admin/fibre-production), 10 route không có (/signup(+status), /admin/programs theo đúng tên, /admin/reservation-requests, /admin/signup-requests, /admin/overrides, /admin/claim-verifications, /admin/settings, /owner, /partners, /insights).
Hệ quả thực tế: hôm nay không một case nào trong 50 case chạy được end-to-end trên monet — mọi đường ghi hoặc throw MutationNotImplementedError, hoặc bị chặn bằng toast (“backend pending”), trừ việc tạo facility. Nếu ai đó đem script này chạy lên monet, các case fail ở toàn bộ nhóm A/O/P, M-03…M-07, và R-01…R-13 đều là khoảng trống BE đã biết, không phải bug — nộp chúng lên chỉ là trùng lặp với .local/backend-specs/integration-audit/ và các block beSpecForGap trong port plan. Chỉ M-01 (facilities) và phần chỉ-đọc của M-02/A-11 là thực sự chạm vào phần wiring thật của monet.
c) Các business rule được ghi trong script
Đã đối chiếu chéo với .local/business-logic/, ~/.claude/memory/fibretrace/, và các bản ghi sync Lovable (research do một agent chỉ-đọc thực hiện; các câu trích đã được kiểm lại với file).
| # | Rule (X:6-11) | Trạng thái so với kiến thức đã ghi nhận |
|---|---|---|
| 1 | 1 CU = 1 kg; CU = qty × net weight × blend % | ĐÃ GHI NHẬN TỪ TRƯỚC — nhưng công thức phát biểu như vậy LỆCH so với app. Đã ghi: “CU/piece = baseline_net_weight_kg × blend% × loss_multiplier (1000 CU = 1 MT)” (~/.claude/memory/fibretrace/reference_claim_units_product_categories_fibretrace-monet.md:23). Bản thân app cũng nói y hệt: “A CU is one kilogram of raw marked fibre: baseline weight x blend ratio x internal loss multiplier” (L:src/pages/admin/AdminProductCategories.tsx:144), và loss multiplier được cố ý để chỉ dùng nội bộ (...md:29). Rule của QC bỏ mất loss_multiplier — tester tự tính CU kỳ vọng bằng qty × weight × blend sẽ ra con số không khớp app ở mọi chỗ loss_multiplier ≠ 1. Riêng “1 CU = 1 kg” thì nhất quán ở mọi nơi. |
| 2 | Blend % lấy từ cấu hình product-category của admin, không bao giờ hard-code | ĐÃ GHI NHẬN, khớp (reference_claim_units_product_categories_fibretrace-monet.md:29: product_categories.default_blend_pct, CRUD admin ở AdminProductCategories.tsx). |
| 3 | Fibre Producer chỉ có qua programme registration; SDU/EWR là feature gate, không phải persona | Giải quyết một ngã ba đã ghi nhận. Hook cũ nói ngược lại: isProducer = company_modules("sdu").enabled OR ≥1 dòng programme_producers (.local/business-logic/persona-case-matrix.md:20, usePersona.ts:34). Hook mới thì khớp chính xác: isProducer = ≥1 dòng programme_producers (persona-case-matrix.md:31, usePersonaContext.ts:36). Rule này trên thực tế tuyên bố usePersonaContext là canonical và đánh dấu mệnh đề SDU-OR cũ là bug cần cho nghỉ — đáng xác nhận lại với Malcolm (P-01 chính là case test đúng điều này). |
| 4 | ID/GUID bị che mặc định, chỉ mở khi đã link vào claim | ĐÃ GHI NHẬN, khớp (reference_verification_id_obfuscation_fibretrace-monet.md:27-31: visibility = NOT app_settings['obfuscate_verification_ids'] OR session_is_claim_linked, mặc định true). Rule 4 cộng A-15 còn thu hẹp câu hỏi treo số 3 của memory đó (che ở server hay ở client): nó xác nhận ý định sản phẩm; phần cơ chế thì vẫn treo. |
| 5 | Mặc định hết hạn 18 tháng; cho phép nhập giá trị âm | ĐÃ GHI NHẬN, khớp khá sát (reference_reservation_requests_expiry_fibretrace-monet.md:3,16,26-27). Đóng luôn câu hỏi treo số 3 của memory đó (“sổ cái theo từng lần điều chỉnh gồm cả delta âm, hay một giá trị reserved_mt ghi đè?” — ...md:58): script QC nay test mô hình sổ cái như hành vi kỳ vọng, nên sổ cái CHÍNH LÀ quyết định sản phẩm. Lưu ý đây đúng là phần GAP của unit 14 trong port plan — BE thật không có expires_at lẫn mục âm trong sổ cái (port-plan.md:145). |
| 6 | reserved ≥ nominated ≥ claimed phải khớp nhau | MỚI. Không bản ghi nào trước đó phát biểu bất đẳng thức ba vế này; thứ gần nhất là một phép kiểm demand-vs-supply hai vế trong OwnerDashboard (reference_programme_owner_domain_be_gap_fibretrace-monet.md:162). Đáng lưu vào ghi chú business-logic như một invariant hạng nhất (X-01, O-03, R-03, R-06 đều test các mặt của nó). |
Hai câu hỏi treo đã biết:
- Q1 — nhãn CU (“Claim Unit (CU)” hay “credit units”), treo từ 2026-08-18 (
.local/lovable/sync-20260818/RUN-SUMMARY.md:30, được xác nhận vẫn treo trongsync-20260819/RUN-SUMMARY.md:104). Tài liệu này KHÔNG chốt. Bản thân script viết “1 CU (Claim Unit / credit unit)” (X:6), O-01 viết “credit units (CU)” (X:106), còn wording kỳ vọng của X-02 là “Claim Unit (CU) / credit units” (X:276) — nó canon hóa CẢ CẶP chứ không chọn bên thắng. Ai kỳ vọng tài liệu này đóng được đợt sweep thuật ngữ (port plan unit 9) sẽ thất vọng; hỏi vào thứ Năm. - Q2 — đổi tên Purchase Order thành Nomination. Chốt được một phần. X-02 yêu cầu “Nominations (not Purchase Order)” ở mức wording UI (X:276) — cái đó chốt được hướng đi của thuật ngữ HIỂN THỊ. Nhưng bản thân script vẫn viết “Create a nomination (PO)” (X:198), “Link your Purchase Orders > New nomination” (X:200), route mọi thứ qua
/purchase-orders, và A-07 gọi menu là “Link your POs” (X:56). Câu hỏi treo ghi trongreference_po_domain_be_gap_fibretrace-monet.md:146— liệu BẢNG/domain bên dưới có đổipurchase_ordersthànhnominationshay không — vẫn treo (cũng được gắn cờ “enum unconfirmed post-2026-08-18 rename” trongport-plan.md:136).
d) Dựng dữ liệu test (yêu cầu tài khoản mới của Malcolm)
Mọi phát hiện đều kiểm tại Lovable origin/main (một lượt rà trước đó dựa trên working tree cũ đã kết luận sai rằng signup và reservation request không tồn tại — chúng có ở HEAD). Nói mô hình auth trước, vì mọi thứ treo lên nó: đăng nhập là một phép tra email trong company_users (ilike), mật khẩu chỉ bị kiểm là khác rỗng, và mã 2FA là một mã demo hiển thị ngay trên chính màn hình đăng nhập (L:src/pages/Login.tsx:102-115,151). “Email” (mời, duyệt) đều là mô phỏng — chỉ append vào localStorage["fibretrace_signup_emails"] (L:src/lib/signup.ts:67-70), không bao giờ thực sự gửi đi. Nên việc tạo và vào tài khoản mới là rẻ; không cần hộp thư thật nào.
Thứ tự dựng và ai tạo được cái gì:
| Bước | Object | Màn hình / thao tác ghi | Persona | Tự phục vụ được? |
|---|---|---|---|---|
| 0 | Product categories (blend %) | /admin/product-categories, CRUD product_categories (L:src/pages/admin/AdminProductCategories.tsx) |
FT Admin | CHỈ ADMIN. Bị thiếu hoàn toàn khỏi checklist môi trường của script, dù R-01/A-13/rule 2 đều phụ thuộc vào nó |
| 1 | Fibre programme | /admin/programs, fibre_programmes.insert (L:src/pages/admin/AdminProgrammes.tsx:257); default_reservation_term_months mặc định 18 (:247); form không có field blend % |
FT Admin | CHỈ ADMIN |
| 2 | Company + user | Tự phục vụ: wizard 4 bước ở /signup insert vào signup_requests kèm company_type/tier (L:src/pages/Signup.tsx:191-192) → admin duyệt tại /admin/signup-requests, thao tác này bootstrap luôn companies+company_details (kèm type/tier, :70-77)+facilities+company_users+notification trong một lần (L:src/pages/admin/AdminSignupRequests.tsx:63-108). Hoặc đường trực tiếp: admin quick-create chỉ gồm name+code (L:src/pages/admin/AdminCompanies.tsx:197-199) cộng user (L:src/pages/admin/AdminUsers.tsx:68). Đường thứ ba: mời partner hàng loạt bằng CSV tạo ra company placeholder unclaimed:true kèm token mời, sau đó được nhận qua /signup?claim=<token> (L:src/components/partners/ImportPartnersCsvModal.tsx:104-140, Signup.tsx:75-113) |
Bất kỳ ai (signup) + FT Admin (duyệt) | CÓ, kèm một bước admin duyệt. company_type nằm ở company_details, nhưng theo rule 3 thì persona vẫn đến từ programme registration (dòng dưới) |
| 3 | Programme registration (participant / manufacturer / producer / owner) | Các dialog con của AdminProgrammes: participant (L:...AdminProgrammes.tsx:448), manufacturer (:508), producer + company owner (:262-270 — xóa-rồi-insert nên cưỡng chế tối đa một company owner mỗi programme; trang /admin/program-owners đứng riêng ngày xưa đã bị bỏ ở HEAD); riêng cờ hiển thị owner thì qua company_modules("program_owner") (L:src/pages/admin/AdminCompanies.tsx:254) |
FT Admin | CHỈ ADMIN |
| 4 | Reservation (+ điều chỉnh âm) | Panel reservation của programme, programme_reservations.insert; ở đó cho phép số âm (“Use a negative value to subtract”, L:...AdminProgrammes.tsx:542,1463; không có kiểm sàn khi insert override thủ công, :568,598). Phía retailer yêu cầu: AddReservationModal → reservation_requests.insert (L:src/components/AddReservationModal.tsx:167-173; nút submit bị disable khi addCu <= 0, :158), duyệt tại /admin/reservation-requests nơi thao tác approve throw nếu cu <= 0 (L:src/pages/admin/AdminReservationRequests.tsx:97-135, kiểm sàn ở :101) |
FT Admin (cấp) / Tier 0 (yêu cầu) | Yêu cầu thì tự phục vụ; cấp thì CHỈ ADMIN. Nhập số âm CHỈ khả thi qua panel programme, không bao giờ qua hàng đợi yêu cầu |
| 5 | Facility license, rồi facility | Cấp license: /admin/licensing (facility_licenses). Facility: tự phục vụ ở /facilities/add nhưng bị gate cứng theo số license còn trống; đường admin thì qua /admin/facilities |
FT Admin (license), Tier 1 (facility) | Facility chỉ tự phục vụ được SAU KHI admin cấp license |
| 6 | Scanner | Tạo + gán tại /admin/scanners. Trang /scanners phía company KHÔNG có nút yêu cầu trong app — cái “request” thực ra là một mailto gửi support (L:src/pages/Scanners.tsx:154-165) |
FT Admin | CHỈ ADMIN (bước “request” của M-02 nằm ngoài hệ thống) |
| 7 | Thiết bị SDU | /admin/sdu, sliver_delivery_units.insert (L:src/pages/admin/AdminSDU.tsx:88). Trang /sdu phía company không đăng ký được thiết bị |
FT Admin | CHỈ ADMIN |
| 8 | Scan / verification | Chỉ có bộ mô phỏng Demo Scan (DemoScanModalV2 chuỗi insert: collection :570 → verification :580 → scans :656 → audits :710) — app này không có ingest từ phần cứng hay BE. M-03 cho phép rõ ràng việc “simulate” |
Tier 1 | CÓ (mô phỏng) |
| 9 | Production record (SDU / EWR / thủ công) | Insert thủ công ở /fibre-creation (L:src/pages/FibreCreation.tsx:441); qua SDU thì DemoSDUModal.tsx:165; qua EWR thì DemoEWRModal.tsx:49 (source:"ewr_demo") — EWR chỉ là mô phỏng; không tồn tại tích hợp EWR thật nào |
Tier 4 | CÓ (thủ công + mô phỏng), sau các bước 3/5/7 |
| 10 | Nomination (PO) + partner | Tạo/import PO tại /purchase-orders (import CSV insert qua ImportPoCsvModal); mời partner bằng mã 3 chữ cái, khớp ilike không phân biệt hoa thường, tại /partners (L:src/pages/settings/SettingsPartners.tsx:160-177) |
Tier 0 / Tier 1 | CÓ |
| 11 | Bật/tắt module Insights | KHÔNG TỒN TẠI. Registry module đúng bằng billing, verified_cta, verifications_menu, scanners_menu, program_owner (L:src/pages/admin/AdminCompanies.tsx:81); không có route hay page /insights ở đâu cả |
— | BỊ CHẶN — không ai tạo được |
Chuỗi phụ thuộc: 0 → 1 → 2 → 3 → {4, 5} → {6, 7} → {8, 9, 10}. Không thứ gì cần seed database hay việc của BE, trừ mục 11 (tính năng không tồn tại) — mọi thứ còn lại đều đã có form tạo chạy được ở HEAD.
Cái tab QC account-switcher có giúp không? Một phần. Demo modal hiện tại là một danh sách cứng gồm 7 persona seed (L:src/components/DemoNavBar.tsx:15-28 — Tier 4 GIN “SUNDOWN”, Tier 4 rPET, Tier 1, Tier 2, Tier 0 WALMART, Program Owner, cộng một Tier 0 rỗng chỉ bật cho dev); switchUser() fetch lại đúng các user ID cố định đó (:53-62) và không nhìn thấy được company mới tạo. Nên đúng — một tab switcher liệt kê được tài khoản bất kỳ / tài khoản mới sẽ bỏ được vòng lặp đăng xuất → nhập email → nhập 2FA demo mỗi lần nhảy persona, và nó là công cụ chuyển đổi duy nhất ngoài admin Impersonate (L:src/pages/admin/AdminUsers.tsx:83-84,180), vốn đã có và chạy được hôm nay. Nhưng chuyển đổi không phải ma sát thật: tạo object mới là. Các bước 0-1 và 3-7 đều bị gate bởi FT Admin, nên hoặc mọi tester đều được cấp quyền admin (khối /admin bị gate bởi setting adminLoginRequired, L:src/components/AdminLayout.tsx:60-69), hoặc một người dựng sẵn môi trường theo chuỗi trên. Cái switcher không giải quyết được xương sống bị gate bởi admin, cũng không giải quyết hai tính năng còn thiếu (Insights, form thêm override).
Một mâu thuẫn trực tiếp với chính rule của Malcolm: R-13 nói “Insights module (Walmart only in test data)” (X:258) — nhưng WALMART đúng là một trong các company thuộc demo modal mà tester bị cấm đụng vào, và cũng không có toggle admin nào để bật Insights cho một company mới. Viết như vậy thì R-13 bất khả thi gấp đôi: tính năng không tồn tại, mà chỗ dữ liệu duy nhất được nêu tên lại là một tài khoản bị cấm.
e) Rủi ro và lỗ hổng trong chính script
Mâu thuẫn nội tại:
- A-01 chọi rule 2 (blend %). Bước 2 của A-01 bảo đặt “default blend %” trên programme và kỳ vọng “no blank blend %” (X:25-26), nhưng rule 2 (X:7) lại nói blend % nằm ở cấu hình product-category — và form tạo programme ở HEAD hoàn toàn không có field blend nào (payload insert: name/description/status/dates/pigment/fibre_type/country/heatmap/logo, vùng
L:src/pages/admin/AdminProgrammes.tsx:257;default_reservation_term_monthslà giá trị số mặc định duy nhất,:247). A-01 sẽ “fail” ở một field mà theo thiết kế vốn nằm chỗ khác. - Rule 1 bỏ mất loss multiplier mà chính app có áp (
L:src/pages/admin/AdminProductCategories.tsx:144; memoryreference_claim_units_product_categories...md:23). Bất kỳ tester nào tự tính tay CU = qty × weight × blend sẽ nộp báo cáo lệch sai ở các category có loss_multiplier ≠ 1 (mà multiplier lại chỉ dùng nội bộ nên họ thậm chí không nhìn thấy). - X-02 chọi chính vốn từ vựng của script. X-02 đòi “Nominations (not Purchase Order)” và “Verification Records (not Claims)” (X:276), trong khi chính script viết “Create a nomination (PO)” (X:198), “Link your Purchase Orders” (X:200), “Link your POs” (X:56), và route qua
/purchase-orderslẫn/claims. Nếu URL cũng bị tính là “wording” thì X-02 không bao giờ pass được; cần định nghĩa phạm vi = chỉ phần copy nhìn thấy được. - A-04 mâu thuẫn với phần hiện thực ngay tại route mà nó nêu tên. A-04 kỳ vọng một mục CU âm được “accepted and saved… no validation error blocking the minus sign” tại
/admin/reservation-requests(X:39-41) — nhưng hàng đợi đó chủ động từ chối giá trị không dương: đường approve throw nếucu <= 0(L:src/pages/admin/AdminReservationRequests.tsx:101) và modal yêu cầu phía retailer disable submit khiaddCu <= 0(L:src/components/AddReservationModal.tsx:158). Bề mặt duy nhất nhập được số âm là panel reservation của programme tại/admin/programs(“Use a negative value to subtract”,L:src/pages/admin/AdminProgrammes.tsx:542,588,1463). Viết như hiện tại, A-04 sẽ fail tại route được nêu tên theo đúng thiết kế — hoặc route bị ghi nhầm, hoặc hàng đợi được dự định sẽ có thêm khả năng nhập số âm.
Các case đang test thứ không tồn tại (sẽ fail vì một lý do đã biết, không phải bug):
- A-08 + R-13 (Insights) — không có toggle module, không có route, ở bất cứ đâu (mục d, item 11). Cộng thêm mâu thuẫn Walmart ở trên.
- A-13 (overrides) —
/admin/overridesở HEAD là một báo cáo calibration/audit CHỈ ĐỌC (đọc các dòng PO so với giá trị mặc định của category, tính delta, xuấtrate-and-quantity-overrides.csv; không có lời gọi.insert(nào trong file,L:src/pages/admin/AdminOverrides.tsx:48-84,161-175). Bước 1 “Add a rate/quantity override” không có UI nào trên trang đó; override có vẻ phát sinh từ việc sửa blend/qty trên một dòng nomination. Hoặc bước đó có nghĩa là “sửa một dòng nomination rồi quan sát nó xuất hiện ở /admin/overrides”, hoặc phần UI thêm mới vẫn còn phải xây. - P-06 (giới hạn sản xuất) — không tìm thấy phần kiểm giới hạn allocation nào trong
FibreCreation.tsxở HEAD (chỉ có các lời gọi query.limit(1); không định vị được guard “exceeds allocation” nào — chưa kiểm được, có thể tồn tại phía server, nhưng phía client không có gì nêu tên một giới hạn). Dự kiến case này sẽ fail như đang viết. - M-02 (yêu cầu một scanner) — cái “request” trong app là một mailto gửi support (
L:src/pages/Scanners.tsx:154-165); nút “request CTA” mà case kỳ vọng thì có tồn tại, nhưng đường giao của nó là email ngoài hệ thống, nên bước 2 “Admin assigns it” không thể được kích hoạt bởi chính cái request đó.
Lỗ hổng về khả năng quan sát:
- Email mời/duyệt đều là mô phỏng vào
localStorage["fibretrace_signup_emails"](L:src/lib/signup.ts:67-70). Việc “Owner user receives an invite” của A-09 và email duyệt của A-10 chỉ quan sát được qua cái log demo đó hoặc qua toast — tiêu chí pass nên ghi rõ điều này. - X-05 (cô lập giữa các persona) — kiểm soát truy cập ở đây là auth demo phía client:
/adminchỉ bị gate khi settingadminLoginRequiredđược bật (L:src/components/AdminLayout.tsx:60-69), đăng nhập chấp nhận mọi giá trị mật khẩu, và mã 2FA thì in ngay trên trang đăng nhập (L:src/pages/Login.tsx:151). Kỳ vọng “access denied” cần nêu rõ các setting auth như một điều kiện tiên quyết, còn “không bao giờ thấy dữ liệu của company khác” là một phép kiểm phạm vi dữ liệu trong một app lọc ở phía client — kiểm sâu chuyện này nằm ngoài tầm với của QC. - Thiếu file CSV đi kèm. Tài liệu bảo tester ghi kết quả vào
fibretrace-qc-test-script.csv(X:4), nhưng file này không nằm trong những gì chúng ta nhận được (.local/qc-test-script/chỉ có bản docx).
Phụ thuộc và thứ tự không được nêu:
- Thứ tự section được quy định bị M-05 làm gãy. “Run the sections in order” (X:4), nhưng M-05 (section 4) cần “a shared nomination line” mà chỉ R-01 (section 5) mới tạo ra (X:180 so với X:200). Thứ tự tối thiểu chạy được: A → R-01/R-02 (retailer tạo và chia sẻ nomination) → M-01…M-07 → phần còn lại của R → O → X. Tương tự, O-03 và X-01 cần claim từ R-07/R-08 đã tồn tại.
- Việc dựng product category là một điều kiện tiên quyết bị giấu (R-01, A-13, rule 2 đều phụ thuộc
/admin/product-categories; không case A nào tạo category và checklist môi trường thì bỏ sót chúng). - Các cặp phụ thuộc case-với-case không được ghi nhãn bên trong từng section: A-02 cần participant của A-07; A-03 cần request của R-04 (section admin chạy trước section retailer vốn là nơi sinh ra request — nên A-03 cần ít nhất một request dựng sẵn, hoặc phải quay lại làm sau R-04); A-14 cần claim (R-07/R-08) và scan (M-03); phần “over-commitment red” của O-01 cần nomination vượt quá capacity, tức phải cố ý raise dư ở R-01.
Khả năng chạy song song: sau khi xương sống FT Admin (A-01…A-02, A-05…A-12) và product category đã dựng xong, chuỗi Producer (P-01…P-06) và chuỗi Manufacturer+Retailer (R-01→M-01…M-07→R-03…R-12) độc lập với nhau và chạy song song được trên cùng một programme; O và X chạy cuối (chúng đối soát đầu ra của các nhóm kia). Hai tester cũng có thể song song hoàn toàn bằng cách dựng hai programme độc lập.
f) Đề xuất chia việc + câu hỏi cho thứ Năm
Giả định: việc test diễn ra trên bản Lovable MVP đang chạy, với dữ liệu mới gắn nhãn nia-/nhãn tester theo thứ tự dựng ở mục (d); một người giữ quyền FT Admin.
| Ai | Section | Case | Ước lượng công |
|---|---|---|---|
| Tester A (giữ FT Admin) | Dựng môi trường (d) + Section 1 + X-05/X-06 | A-01…A-15 (A-08/A-13 dự kiến bị chặn), 2 case X | 0,5 ngày dựng môi trường + 1 ngày test |
| Tester B | Section 3 + Section 4 | P-01…P-06, M-01…M-07 (cần R-01 từ Tester C trước) | 1 ngày |
| Tester C | Section 5 + X-01…X-04 | R-01…R-13 (R-13 dự kiến bị chặn), 4 case X | 1,5 ngày |
| Ai rảnh trước | Section 2 (sau khi đã có claim) | O-01…O-03 | 0,5 ngày |
Tổng khoảng 4,5 tester-day cho một lượt chạy đầy đủ, trừ đi khoảng 3 case hiện không test được (A-08, A-13, R-13). Bình Lê ở vai điều phối/review thì hợp với Tester A (xương sống admin), vì vai đó quyết định trình tự cho mọi người khác.
Câu hỏi cho Malcolm (mỗi câu gắn với một phát hiện ở trên):
- (e5/d11) Insights: ở Lovable HEAD không có route
/insightsvà cũng không có toggle module Insights — A-08/R-13 đang test thứ anh sắp xây, hay nên bỏ khỏi vòng này? Và R-13 nêu tên Walmart — một company thuộc demo modal mà chúng tôi được dặn không đụng vào. Rule nào thắng? - (e6)
/admin/overrideslà một báo cáo calibration chỉ đọc, không có form “add override” — vậy ý định của A-13 có phải là “sửa blend/qty trên một dòng nomination, rồi kiểm tra nó xuất hiện ở đây” không? Nếu đúng thì chúng tôi sẽ viết lại bước đó. - (e1/e13) Blend % thực ra được đặt ở đâu — form programme không có field blend nào; chỉ
/admin/product-categoriesmangdefault_blend_pct. A-01 có nên bỏ bước đó không, và checklist môi trường có nên thêm “đã cấu hình product categories” thành bước 0 không? - (e2) Rule 1 bỏ mất loss multiplier nội bộ mà app có áp (
CU = baseline weight × blend × loss multiplier, theo đúng mô tả của chính UI admin). Với phép tính của QC, tester nên chỉ giả định các category có loss_multiplier = 1, hay được cấp giá trị multiplier? - (c/Q1) Script dùng cả “Claim Unit” lẫn “credit unit” — X-02 yêu cầu chúng tôi verify “consistent wording”, vậy nhãn nào là canonical? (Treo từ 2026-08-18; cũng đang chặn đợt sweep thuật ngữ.)
- (e12) “Run the sections in order” gãy tại M-05, vốn cần một nomination do R-01 (section 5) chia sẻ. Xác nhận giúp thứ tự dự định là A → R-01/R-02 → M → phần còn lại của R → O → X.
- (e9) Email mời/duyệt chỉ rơi vào log email demo trong app (localStorage), không vào hộp thư thật — kiểm cái log đó có phải là tiêu chí pass được chấp nhận cho A-09/A-10 không?
- (d) Việc dựng môi trường bị gate bởi FT Admin ở 7 trên 11 bước (programme, registration, reservation, license, scanner, SDU, product category). Tất cả tester đều được cấp quyền admin, hay một người dựng sẵn? Liên quan: cái tab switcher anh đề nghị giúp được việc nhảy persona (tài khoản mới không nằm trong demo modal, và admin Impersonate thì vốn đã có) — nhưng nó không bỏ được phần tạo object bị gate bởi admin. Anh vẫn muốn làm chứ?
- (e11) File CSV theo dõi đi kèm (
fibretrace-qc-test-script.csv) chưa được đính kèm — nhờ anh gửi để ghi kết quả theo từng bản phát hành. - (e10) Với X-05, những setting auth nào nên được BẬT trong lúc QC (
adminLoginRequired, v.v.)? Với kiểu đăng nhập demo (mật khẩu nào cũng được, mã 2FA in trên màn hình), “access denied” chỉ đúng nếu các setting đó được đặt. - (e4) A-04 kỳ vọng một mục CU âm được chấp nhận tại
/admin/reservation-requests, nhưng hàng đợi đó từ chốicu <= 0khi approve — điều chỉnh âm chỉ tồn tại trên panel reservation của programme. A-04 nên nhắm vào bề mặt nào, và hàng đợi có được dự định chấp nhận số âm hay không?
Ghi chú phương pháp: ba agent research chỉ-đọc đã fan out (ma trận route, đối chiếu business-logic, chuỗi dữ liệu test); mọi claim chịu lực ở trên đều được session tổng hợp kiểm lại đối chiếu với origin/main của clone Lovable, vì working tree của clone lệch 4.264 commit so với ref — hai kết luận của agent (không có luồng signup; không có luồng reservation request) là sản phẩm của cây cũ và đã được sửa lại ở đây. Clone Lovable không bị chỉnh sửa: mọi thao tác đọc đều dùng git show/git grep trên ref đã fetch.