# SPEC — Supplier Excel-import CLOSE-REVIEW (đóng spec trước deploy) — 12-07-2026

> `/fable-clone review` đóng-spec (anh-directed): soi toàn feature BE+FE + chốt adjust + GO/NO-GO deploy. Opus 4.8 MAX. Feature = Supplier Phase B Approach A (upload Excel NCC).

## Trạng thái feature (code-complete)
- **BE** (implementer-backend, build EXIT-0): entity +SourceUpdatedAt/By · Mig 63 `AddSupplierImportSourceFields` 3-file · `SupplierExcelImportService` (PreviewAsync/ConfirmAsync) · 2 CQRS command · 2 endpoint `import/preview`+`import/confirm` [Authorize Admin,CatalogManager] · DTO · DI.
- **Test** (test-specialist): `SupplierExcelImportServiceTests` 10 test → `dotnet test` **450 PASS** (440→450), 0 prod-bug. Case-collation test có RĂNG (SQLite BINARY → dedup ở service OrdinalIgnoreCase).
- **FE** (implementer-frontend, npm build ×2 PASS): `SupplierImportDialog.tsx` 2-app byte-identical SHA-verified + `SuppliersPage` nút "Import Excel NCC". upload→preview(layoutValid/counts/table)→confirm→toast+invalidate.
- **5 decision** đã áp: Code=col4 · +2 field · fill-nulls-safe · Type-lạ→NhaCungCap · A-scoped-layout-file-này.

## 🔴 ADJUST đã biết (bake trong pha adjust sau review)
`ExpectedHeaderTokens` trong `SupplierExcelImportService.cs:35-67` = BEST-GUESS (file thật chưa ở repo lúc scaffold) → hiện **reject file thật**. Bake 30 token THẬT (đã extract từ Excel, `NormalizeHeader` upper+collapse nên tolerant):
```
STT · GÓI THẦU · PHÂN LOẠI (NTP/NCC/Cả hai) · TÊN VIẾT TẮT (Dùng trong HĐ) · TÊN CÔNG TY (Đầy đủ, đúng pháp lý) · ĐỊA CHỈ XUẤT HÓA ĐƠN (Địa chỉ đăng ký kinh doanh) · ĐỊA CHỈ VĂN PHÒNG (nếu có) · SỐ ĐIỆN THOẠI CÔNG TY · FAX · SỐ TÀI KHOẢN+ TÊN+CN. NGÂN HÀNG (Đầy đủ, đúng pháp lý) · SỐ TK PHỤ (nếu có) · MÃ SỐ THUẾ · NGƯỜI ĐẠI DIỆN PHÁP LUẬT · CHỨC VỤ ĐẠI DIỆN · GIẤY ỦY QUYỀN (số, ngày, người ủy quyền) · Link GUQ · Link GPKD · Link HSNL · NGƯỜI LIÊN HỆ CHÍNH · CHỨC VỤ NGƯỜI LH · SĐT CHÍNH · EMAIL · ĐỊA CHỈ GỬI THƯ · NGƯỜI NHẬN THƯ/ SDT · NGUỒN GIỚI THIỆU · NGƯỜI PHỤ TRÁCH (PMH) · TÌNH TRẠNG HIỆN TẠI · GHI CHÚ / LÝ DO BLACKLIST · NGÀY CẬP NHẬT CUỐI · NGƯỜI CẬP NHẬT
```
Test Case-9 dùng reflection → tự lật `LayoutValid=true` khi bake, 0-test-edit.

## Checklist review (2 lane đối kháng)
- **L1 (BE + adjust):** verify case-fix (OrdinalIgnoreCase preview+confirm) · fill-nulls không đè non-null · all-or-nothing · parser abs-index+#REF!+backslash-raw · Type/Status map · Mig 63 reversible. Confirm bake ExpectedHeaderTokens (30 real-token) đủ + đúng thứ tự cột→field. Bất kỳ BE gap trước deploy.
- **L2 (FE + e2e + deploy):** FE flow upload/preview/confirm khớp contract (enum-int, camelCase, rows round-trip verbatim) · 2-app mirror · error-handling (layoutValid=false, errorCount>0 disable) · e2e (upload file thật → preview → confirm sau khi bake header) · deploy-risk trên prod ERP live (4 NCC file này ĐÃ ở prod qua seed → confirm no-op an-toàn, không nhân đôi) · GO/NO-GO.
