[CLAUDE] Docs: S59 session-end closeout - 10 dot ship prod-verified #273->#282 + gotcha #61/#62 + harvest gate PASS 5/5
- Session log MOI 2026-06-11-S59-wipe-tree-pmh-uat-batch.md (wipe testing data + tree 4 tang + 71 ma PMH + 6 vong UAT realtime, bundle FINAL B1DtNT9C/D6uF3Mln Run #282). - STATUS/HANDOFF flush S59 (header + table + In Progress + Recently Done + bundle line). - gotchas.md +2: #61 sqlcmd -f 65001 (console mojibake vs data-hong-that) + #62 rename natural-key DB-truoc-code-sau (seed per-code idempotent). CLAUDE.md root cite 62. - Agent-memory 5 file: cicd x9 run entries + UTC-annotate #275 + bundle status-line final, inv-codebase recon S59 + curate S51->archive, H1 x2 + H2 x2 closeout entries. - H2 GATE PASS 5/5 (0 miss, 0 on-behalf can append) + H1 ALL-4-FRESH (cross-count verified: gotcha 62 x3 nguon, bundle 4-source). RAG: 2 chunk S59 stored, rerank 0.875. - Chore monthly 07-01: curate cicd L1 ~56KB + inv 32.9KB + STATUS/HANDOFF re-tier (uu tien).
This commit is contained in:
@ -2,7 +2,26 @@
|
||||
|
||||
> **Tiering rule (S40):** giữ **2-3 session gần nhất**. Cũ hơn → `docs/changelog/sessions/`. Full brief history pre-S40 → `docs/_archive/HANDOFF-preS40-fullhistory.md`.
|
||||
|
||||
**Last updated:** 2026-06-11 (Session 58 — **5 đợt prod-verified Run #382/#383/#384/#386** (#385 cancelled-supersede-benign): lock-demo-user fix (việc sếp deadline 15:00 ĐÓNG TRỌN — gotcha #60/E-008/AS-12, root cause password 11<12 từng phát hiện S22 nhưng const không fix) + tạm ẩn HRM/Office/Cá nhân + Danh mục cuối (`6c5fd26` #383) + **fe-user redesign theo UI/UX guide AI_INFRA giữ brand** (`e959f72` #384) + **brand polish ×2 app "thấy rõ"** (`ea793a4`: stripe 4px đỉnh + thead brand) + **PE gộp Tên-gói-thầu = chọn Hạng-mục** (anh Kiệt FDC chốt, `3ebaf84` #386 — bundle final admin `DMm9rtNA`/user `BUkOMn_Y`). Email AI_INFRA processed (guide + ACK H4 ACCEPT). Test **240**. → session log `2026-06-11-S58-lock-fix-hide-modules-redesign-pe-merge.md`. Root cause 2 tầng: lock-list = population Dev-only + `DemoUserPassword` 11 ký tự < prod RequiredLength=12 → CreateAsync silent-fail từ trước tới giờ (= "helpdesk inert" S56). Fix union 20 UAT email + password 12 ký tự → prod 55 user/34 locked, nv.cao+nv.truong sống, 5 real staff tạo. gotcha #59+#60. Commit `5998163`. Prev S57bis — **PE gắn Hạng mục (Mig 49) + Pe all-role + menu Cá nhân + Harness-4 runtime-VERIFIED**. Test 228→**240**. Bundle `CP4CB1ym`/`BmZ3VHnm`. Commit `17b23a4`+`dd117b7` → Run #381 PASS+1PARTIAL (lock NO-OP → RESOLVED S58). Prev S56 — **Pre-golive verify sweep + golive-harden 4 fix — Run #379 PASS, code golive-ready**. WF1 `pre-golive-verify` 7-stream + adversarial → 6 PASS/1 CONCERN/0 blocker = GO (key finds = ops not code). WF2 `golive-harden` fix 4: #3 LeaveBalance lost-update→atomic ExecuteUpdate+Serializable tx (NO mig) · #5 ItTicket authz Forbidden-trước-NotFound · #6 DocxRenderer null-guard · #4 Travel/Vehicle ApproveV2 tests. Test 216→**228**. Bundle FROZEN `4SUwDLD8`/`XdKzt9LL`. `sys.tables` re-ground 92→**93**. gotcha **#58** NEW. reviewer StructuredOutput-fail→em main đỡ. **2 ops VPS pending** (gán user IT + tzutil UTC+7). FE Phase 2 redesign **deferred** (recon ready). Commit `a20cde8`. Prev S55 — **Nạp master data thật từ Excel (62 dự án + 71 hạng mục + 3 NCC) + Project +4 cột (Mig 48) — prod-verified**. HMW-mode ON. Commit `69cb393` → Run #377 PASS ~4m33s. Test 216 (compile-fix only). Bundle admin `B-d6893W`/user `XdKzt9LL`. `SeedRealMasterDataAsync` ungated idempotent → coexist demo. 2 agent return truncated (BE+reviewer) → em main disk/runtime-recover. Prev S54 — IT staff tự reassign ticket (cross-stack authz) — prod-verified. 1 code commit `ca4b602` → Run #376 PASS ~4m18s. Test 203→**216**. Bundle admin `DfCfHUE9`→`DmjI8Cmn`/user `_3S0BPJ2`→`YxL_MljK` (cả 2 rotate). NO migration. Task 1 Phase 9 Ops anh dừng. ⚠️ residual: 3 agent ghi MEMORY nhầm `src/Backend/.claude` → em main reconcile. Prev S53: gotcha #57 EXT Master Mig 47 + P11-D/E + database-agent verified-runtime.)
|
||||
**Last updated:** 2026-06-11 tối (Session 59 — **6 đợt ship prod-verified Run #273→#278**: wipe transactional testing data (10 PE + 7 HĐ demo + 64 notif = 0, mã reset → phiếu thật đầu tiên team tạo = **PE/2026/A/001** ✓) `56882ac` #273 · PE tree Panel 1 chốt 4 tầng **Năm > Dự án > Hạng mục > Phiếu** `0eafcd3` #274 · dọn 15 mã hạng mục demo "tự đẻ" (chị Trà Sol) + gỡ seed gốc, WorkItems 86→**71** `bbd1554` #275 · **rename 71 mã đúng format PMH anh Kiệt** (`MAT-n`/`SUB-n`/`MEP-SUB-n`/`MEP-EQU-n` + tên "STT nhóm tên"; **DB-trước-code-sau** gotcha #62 + sqlcmd `-f 65001` gotcha #61) `c869d26` #276 · UAT vòng 1: NEW `ui/SearchableSelect` gõ-lọc bỏ dấu (Hạng mục/Dự án) + auto Địa điểm + điều khoản đa dòng `faed59f` #277 · UAT vòng 2 (anh chốt ×2): ẩn Trả lại/Từ chối khi tự duyệt phiếu mình soạn + quick-add NCC ngay form (POST /suppliers any-auth, authz probe 4/4) + NCC gõ-tìm A-Z + upload multi-file `9c330d2` #278 · UAT vòng 3-6 realtime (#279/#281 cancelled-supersede-benign): bảng NCC table-fixed `f21c55d` + bỏ ô Tên ngân sách `69997da` #280 + GỠ field Điều khoản TT mọi form `80b64dd` + bỏ nút Thêm hạng mục `792c030` **#282 FINAL**. Tổng 10 đợt (8 PASS + 2 cancelled-benign). Bundle FINAL admin **`B1DtNT9C`**/user **`D6uF3Mln`**. Test 240. Gotchas 62. 0/14 spawn truncated. → session log `2026-06-11-S59-wipe-tree-pmh-uat-batch.md`. Prev S58 — **5 đợt prod-verified Run #382/#383/#384/#386** (#385 cancelled-supersede-benign): lock-demo-user fix (việc sếp deadline 15:00 ĐÓNG TRỌN — gotcha #60/E-008/AS-12, root cause password 11<12 từng phát hiện S22 nhưng const không fix) + tạm ẩn HRM/Office/Cá nhân + Danh mục cuối (`6c5fd26` #383) + **fe-user redesign theo UI/UX guide AI_INFRA giữ brand** (`e959f72` #384) + **brand polish ×2 app "thấy rõ"** (`ea793a4`: stripe 4px đỉnh + thead brand) + **PE gộp Tên-gói-thầu = chọn Hạng-mục** (anh Kiệt FDC chốt, `3ebaf84` #386 — bundle final admin `DMm9rtNA`/user `BUkOMn_Y`). Email AI_INFRA processed (guide + ACK H4 ACCEPT). Test **240**. → session log `2026-06-11-S58-lock-fix-hide-modules-redesign-pe-merge.md`. Root cause 2 tầng: lock-list = population Dev-only + `DemoUserPassword` 11 ký tự < prod RequiredLength=12 → CreateAsync silent-fail từ trước tới giờ (= "helpdesk inert" S56). Fix union 20 UAT email + password 12 ký tự → prod 55 user/34 locked, nv.cao+nv.truong sống, 5 real staff tạo. gotcha #59+#60. Commit `5998163`. Prev S57bis — **PE gắn Hạng mục (Mig 49) + Pe all-role + menu Cá nhân + Harness-4 runtime-VERIFIED**. Test 228→**240**. Bundle `CP4CB1ym`/`BmZ3VHnm`. Commit `17b23a4`+`dd117b7` → Run #381 PASS+1PARTIAL (lock NO-OP → RESOLVED S58). Prev S56 — **Pre-golive verify sweep + golive-harden 4 fix — Run #379 PASS, code golive-ready**. WF1 `pre-golive-verify` 7-stream + adversarial → 6 PASS/1 CONCERN/0 blocker = GO (key finds = ops not code). WF2 `golive-harden` fix 4: #3 LeaveBalance lost-update→atomic ExecuteUpdate+Serializable tx (NO mig) · #5 ItTicket authz Forbidden-trước-NotFound · #6 DocxRenderer null-guard · #4 Travel/Vehicle ApproveV2 tests. Test 216→**228**. Bundle FROZEN `4SUwDLD8`/`XdKzt9LL`. `sys.tables` re-ground 92→**93**. gotcha **#58** NEW. reviewer StructuredOutput-fail→em main đỡ. **2 ops VPS pending** (gán user IT + tzutil UTC+7). FE Phase 2 redesign **deferred** (recon ready). Commit `a20cde8`. Prev S55 — **Nạp master data thật từ Excel (62 dự án + 71 hạng mục + 3 NCC) + Project +4 cột (Mig 48) — prod-verified**. HMW-mode ON. Commit `69cb393` → Run #377 PASS ~4m33s. Test 216 (compile-fix only). Bundle admin `B-d6893W`/user `XdKzt9LL`. `SeedRealMasterDataAsync` ungated idempotent → coexist demo. 2 agent return truncated (BE+reviewer) → em main disk/runtime-recover. Prev S54 — IT staff tự reassign ticket (cross-stack authz) — prod-verified. 1 code commit `ca4b602` → Run #376 PASS ~4m18s. Test 203→**216**. Bundle admin `DfCfHUE9`→`DmjI8Cmn`/user `_3S0BPJ2`→`YxL_MljK` (cả 2 rotate). NO migration. Task 1 Phase 9 Ops anh dừng. ⚠️ residual: 3 agent ghi MEMORY nhầm `src/Backend/.claude` → em main reconcile. Prev S53: gotcha #57 EXT Master Mig 47 + P11-D/E + database-agent verified-runtime.)
|
||||
|
||||
---
|
||||
|
||||
## S59 (2026-06-11 chiều→tối) — Wipe testing + tree 4 tầng + 71 mã PMH + UAT 6 vòng (10 commit prod-verified #273→#282)
|
||||
|
||||
**Anh: forward Zalo anh Kiệt (xóa testing + tree theo hạng mục) → chốt tree "Năm chứa Dự án chứa Hạng mục" → forward chị Trà Sol (dọn mã tự chế, "không đẻ thêm mã công ty khác") → anh Kiệt chốt format mã ("MEP-SUB-1 — 1 MEP Sub MEP (Full), đúng kiểu vậy") → 6 vòng screenshot UAT realtime (11 điểm — 4 vòng cuối chen giữa session-end: table-fixed bảng NCC, bỏ Tên ngân sách, GỠ Điều khoản TT mọi form, bỏ nút Thêm hạng mục) → "Chốt làm đi nhé" (session-end).**
|
||||
|
||||
**Done (10 commit — 8 Run PASS + 2 cancelled-supersede-benign, đều prod-verify):** xem STATUS S59 entry / session log chi tiết. Điểm phải nhớ cho session sau:
|
||||
- **Prod baseline SẠCH cho testing thật:** PE/HĐ/Notif từ 0, mã từ `…/001`, WorkItems = ĐÚNG 71 mã PMH format mới (`MAT-1` — "1 Mat Bê tông"…), 7 workflow ghim, master 70 dự án/22 NCC nguyên. Phiếu UAT thật của team ĐÃ tồn tại (PE/2026/A/001+) — **KHÔNG wipe nữa khi chưa hỏi**.
|
||||
- **Quy trình rename natural-key (gotcha #62):** UPDATE DB prod+Dev TRƯỚC → push seed mới SAU (per-code idempotent, sai thứ tự = nhân đôi). **sqlcmd file tiếng Việt (gotcha #61):** `-f 65001` + verify qua API JSON, đừng tin console VPS.
|
||||
- **SearchableSelect** (`components/ui/SearchableSelect.tsx` ×2 app) = combobox chuẩn mới cho dropdown lớn — fold bỏ dấu, tái dùng cho dropdown users/khác khi cần.
|
||||
- **Suppliers authz asymmetric S59:** POST = any-auth (quick-add) · PUT/DELETE = Admin+CatalogManager (giữ S57) — probe live 4/4 OK. WorkItems/Catalogs write vẫn khóa nguyên.
|
||||
|
||||
**🔴 NEXT SESSION (anh pick):**
|
||||
- **Ops của anh (giữ từ S58):** ① `tzutil /g` VPS confirm `SE Asia Standard Time` · ② email anh Chương → dọn typo `chuong.phan@solution.com.vn` · ③ báo 5 real staff password `User@1234567` + đổi · ④ gán người thật CNTT → lock nv.cao/nv.truong.
|
||||
- **🟪 test-after guard:** `LockDemoSampleUsersAsync` (S58) + suppliers asymmetric authz (S59) — IdentityFixture sẵn.
|
||||
- **PE polish sâu** (PeDetailTabs 111KB session riêng) · **PermissionGuard per-route** khi golive HRM/Office · **Phase 9 Ops** (SMTP/backup/creds/UAT).
|
||||
- **Monthly audit 2026-07-01:** **STATUS/HANDOFF re-tier (defer ×2 — ƯU TIÊN)** · curate L1 cicd-monitor ~46KB + investigator-codebase 32.9KB · schema-diagram §16+ ERD Mig 32-49.
|
||||
- **Cert** `api.solutions.com.vn` expire ~2026-07-23 (auto-renew ~06-23).
|
||||
|
||||
---
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,60 @@
|
||||
# Session 59 — 2026-06-11 (chiều→tối) — Wipe testing data + PE tree 4 tầng + 71 mã PMH + 6 vòng UAT feedback (10 đợt ship prod-verified)
|
||||
|
||||
> **10 commit code → 8 Gitea Run PASS + 2 cancelled-supersede-benign (#273→#282), tất cả prod-verified.** Anh: `/session-start` → forward Zalo anh Kiệt FDC (2 việc) → chốt tree follow-up → forward chị Trà Sol (dọn mã tự chế) → anh Kiệt chốt format mã → 6 vòng screenshot UAT feedback realtime (4 vòng cuối chen giữa session-end) → "Chốt làm đi nhé" (session-end).
|
||||
> Bundle FINAL: admin **`B1DtNT9C`** / user **`D6uF3Mln`** (Run #282 `792c030`). Test **240/240** (verify local ×2 + CI gate ×8). HMW-mode ON nguyên session nhưng mọi việc chạy Agent-tool spawn lẻ (không Workflow fan-out — task vừa, em main solo + recon/cicd spawn).
|
||||
|
||||
## Đợt 1 — Wipe transactional testing data prod (anh Kiệt: "xoá các cái testing trước đi em") — `56882ac` → Run #273
|
||||
|
||||
- 🟦 investigator-codebase recon prod: chỉ 3 cụm test data — **10 PE** (A/031-040, cả 10 WorkItemId NULL) + child 252 rows · **7 Contracts `[DEMO]`** + 30 child · **64 Notifications**; mọi module khác 0. Workflows: 7 ghim active + 1 V2 cũ inactive. Uploads: 19 folder PE vs 10 PE (~10 orphan từ Plan R S23). Generator PE/Contract đều INSERT-if-missing → DELETE sequence = reset mã an toàn.
|
||||
- Anh chốt (AskUserQuestion): **wipe cả 3 cụm + reset mã về 0**.
|
||||
- `scripts/s59-wipe-testing-data.sql` (pattern Plan R S23, QUOTED_IDENTIFIER ON): DELETE PE (cascade, Quotes NO_ACTION pass nhờ cascade Details→Quotes) → Contracts → Notifications → 1 AwV2 inactive (`IsActive=0 AND IsUserSelectable=0`) → PeSeq+CtSeq. AFTER exact: PE/child/Ct/Notif = 0 · AwV2 7/7 active · KEEP Projects 70 / WorkItems 86 / Suppliers 22 / Users 55 / Templates 9 / WfDefV1 10. Uploads orphan rd+md lại (ssh từng lệnh — quoting 3 lớp vỡ tại `&`, tách lệnh đơn).
|
||||
- **Run #273 PASS** ~3m34s: bundle ×2 rotate (`R9uGRxvw`/`DikfX1RD`) + **app-recycle KHÔNG resurrect** (DemoSeed:Disabled gate held — verify THẬT qua recycle, không trên giấy). Team vào testing chiều: phiếu thật đầu tiên ra đúng **PE/2026/A/001** (sequence reset đúng thiết kế).
|
||||
|
||||
## Đợt 2+3 — PE Panel 1 tree regroup (2 vòng theo chỉ đạo) — `56882ac` (v1) + `0eafcd3` → Run #274
|
||||
|
||||
- Anh Kiệt v1: "Tên dự án (2026) → Hạng mục công việc → Phiếu cần duyệt" (thứ tự label "Dự án - Năm" — mirror folder Outlook FDC). Ship trong `56882ac`: node gộp `(Dự án, Năm-tạo-phiếu)` label "Tên (Năm)" → Hạng mục (`workItemId` Mig 49 — list DTO đã có sẵn `workItemName` S57bis nên FE-only) → phiếu. Bỏ tầng NCC (vẫn ở card/detail).
|
||||
- Anh hỏi lại "Dự án→Năm hay Năm→Dự án?" → chốt follow-up: **"Năm chứa Dự án, Dự án chứa Hạng mục"** → `0eafcd3`: tree 4 tầng 📅 **Năm (DESC, bg-slate-50) → 📁 Dự án (A-Z vi) → 🧱 Hạng mục (A-Z vi) → phiếu (createdAt DESC)**. `yearGroups` useMemo thay `projectGroups`, expand-state localStorage key bump v3.
|
||||
- **Run #274 PASS** ~4m51s: bundle ×2 rotate (`DuU7OTym`/`DWyeTzf3`), PE wipe held.
|
||||
|
||||
## Đợt 4 — Dọn 15 mã hạng mục tự chế (chị Trà Sol: "xóa cái đám phần thô phần hoàn thiện… MÀ ANH TỰ ĐẺ RA") — `bbd1554` → Run #275
|
||||
|
||||
- Prod 86 = 71 real PMH + **15 demo seed cũ** (Phần thô 5 + Hoàn thiện 6 + Cơ điện 3 + Khác 1 — DAO-MONG, SON-NUOC, TRAT-TUONG…). Đối chiếu **71/71 real khớp từng dòng bảng PMH** anh paste (4 nhóm 16/30/9/16 — S55 nạp từ chính Excel này).
|
||||
- Fix kép: (a) **GỠ HẲN block seed demo** khỏi `DbInitializer` (guard `!AnyAsync()` vốn chống resurrect khi bảng còn data, nhưng DB mới tinh sẽ đẻ lại — diệt gốc theo "không đẻ thêm mã của công ty khác vô"); (b) `scripts/s59-wipe-demo-workitems.sql` DELETE 15 codes prod + LocalDB Dev → 71.
|
||||
- **Run #275 PASS** ~3m44s: bundle ×2 FROZEN (BE-only đúng) + **app-recycle giữ 71** (demo codes = 0, seed real idempotent add 0). INFO: PE = 1 (phiếu UAT thật A/001 — không phải resurrect).
|
||||
|
||||
## Đợt 5 — Rename 71 mã theo format PMH anh Kiệt chốt ("MÃ CV gồm chữ MEP-SUB-1 rồi tên 1 MEP Sub MEP (Full) — đúng kiểu vậy") — `c869d26` → Run #276
|
||||
|
||||
- Mapping: `VT-nn→MAT-n` · `TP-nn→SUB-n` · `MEP-0n→MEP-SUB-n` · `TB-nn→MEP-EQU-n`; Name = `"STT nhóm tên"` (`1 Mat Bê tông`, `1 MEP Sub MEP (Full)`…). Category 4 nhóm giữ.
|
||||
- **Thứ tự sống còn (gotcha #62 NEW):** SQL UPDATE rename (GIỮ Id) chạy prod + Dev **TRƯỚC** push — seed per-code idempotent mà deploy trước sẽ INSERT 71 mã mới cạnh 71 cũ = 142. Run #276 verify **đúng 71**.
|
||||
- **Encoding (gotcha #61 NEW):** sqlcmd đọc file UTF-8 tiếng Việt PHẢI `-f 65001`; console VPS mojibake = display-only — verify data thật qua LocalDB console (đúng dấu) + **API JSON prod** (login admin → GET /catalogs/work-items → `"2 MEP Sub Hệ thống trung thế"` nguyên vẹn).
|
||||
- FE sort numeric-aware 3 chỗ ×2 app (mã không pad → string-sort xếp "MAT-10" trước "MAT-2"): 2 dropdown (`select:` sort `localeCompare(…, {numeric:true})`) + tree workItemName. Spec provenance `master-import-data.generated.md` sync 71 dòng + note mapping.
|
||||
- **Run #276 PASS** ~4m33s: bundle ×2 rotate (`BBA0KSWu`/`DzdTI18G`), spot MEP-SUB-1 đúng.
|
||||
|
||||
## Đợt 6 — UAT feedback vòng 1 (4 điểm form tạo phiếu, screenshot 16:40) — `faed59f` → Run #277
|
||||
|
||||
- **NEW `ui/SearchableSelect.tsx`** (~140 LOC, không lib ngoài): combobox gõ-để-lọc, **fold bỏ dấu tiếng Việt** (NFD strip U+0300-036F + đ→d — gõ "be tong" trúng "Bê tông"), keyboard ↑↓/Enter/Esc, clear ✕, listbox absolute z-50, style mirror ui/Input density S55.
|
||||
- Áp: **Hạng mục + Dự án** ở PeWorkspaceCreateView + PeHeaderForm (HeaderForm giữ placeholder "Giữ nguyên: …" cho phiếu cũ). **Auto Địa điểm**: chọn dự án tự điền từ `Project.Location` (S55), chỉ ghi đè khi user chưa gõ tay (track `lastAutoLoc` ref). **Điều khoản thanh toán nhập tay**: Input 1 dòng → Textarea 3 dòng (CreateView + PeDetailTabs inline-edit; render detail đã `whitespace-pre-wrap` sẵn từ trước).
|
||||
- **Run #277 PASS** ~4m09s: bundle ×2 rotate (`ex7Tc92G`/`DzUeSk96`).
|
||||
|
||||
## Đợt 7 — UAT feedback vòng 2 (3 điểm, screenshot 16:52) — `9c330d2` → Run #278
|
||||
|
||||
- Anh chốt 2 quyết định (AskUserQuestion): **(1) ẨN CẢ Trả lại + Từ chối** khi người duyệt = người soạn (`drafterUserId === currentUser.id` — PeWorkflowPanel skip 2 nút trong map; hủy phiếu = nhờ cấp khác Từ chối / Xóa phiếu Nháp); **(2) CHO PHÉP quick-add NCC**: `SuppliersController` POST hạ `Roles=Admin,CatalogManager` → `[Authorize]` any-auth (PUT/DELETE giữ khóa S57) + AddSupplierDialog nút "+ NCC mới" form nhanh (Mã/Tên/Loại/SĐT/Email) → POST → invalidate + auto-select vào phiếu.
|
||||
- NCC dropdown → SearchableSelect sort A-Z theo mã. **Upload nhiều file 1 lần**: input `multiple` + `onPick` async upload tuần tự `mutateAsync` từng file (×2 chỗ: báo giá per-NCC + bảng so sánh — replace_all 2 occurrences identical).
|
||||
- Test 240/240 local TRƯỚC push (BE authz + seed đổi trong session). **Run #278 PASS** ~3m45s: bundle ×2 rotate (`BSh2fG2X`/`D22KfpPc`) + **authz probe live 4/4**: unauth POST **401** (mở quyền ≠ anonymous) · nv.test POST **201** (id tạo thật) · nv.test DELETE **403** (khóa giữ) · admin cleanup 204→404 (tombstone soft-delete by-design). Suppliers active 22 giữ.
|
||||
|
||||
## Đợt 8-10 — UAT vòng 3-6 realtime (chen giữa session-end, anh forward liên tục) — `f21c55d`/`69997da`/`80b64dd`/`792c030` → Run #279-cancelled/#280/#281-cancelled/#282 FINAL
|
||||
|
||||
- **Vòng 3 — "thêm file giao diện bị thay đổi không cân xứng" (`f21c55d`):** bảng NCC tham gia auto-layout → cell File (chip tên dài 8.2MB) phình, bóp dọc cột NCC. Fix `table-fixed` + width % từng cột (NCC 24/SĐT 9/Email 14/ĐKTT 14/File 22/Tiền 12/action w-10) + `min-w-[860px]` (hẹp → scroll ngang wrapper) + email span block truncate. Chip file truncate sẵn — kích hoạt khi cell khóa width.
|
||||
- **Vòng 4 — "chỗ tên ngân sách bỏ đi nhé" (`69997da` #280):** bỏ ô "Tên (không bắt buộc)" ngân sách nhập tay (user không hiểu "ý nghĩa dự phòng là gì") — chỉ còn Số tiền. Payload `budgetManualName: null`; PeHeaderForm `hasManual` detect thêm theo amount (phiếu mới name-null vẫn nhận đúng manual mode). Tên cũ hiện read-only, về null khi lưu lần tới.
|
||||
- **Vòng 5 — "điều khoản thanh toán bỏ nốt ra luôn tất cả các form" (`80b64dd`):** GỠ field phiếu-level khỏi CẢ 3 form (CreateView: Select preset + Textarea custom + PAYMENT_PRESETS/PAYMENT_CUSTOM/paymentMode drop, −142 LOC · HeaderForm + DetailTabs inline-edit: bỏ Textarea, state giữ → save giữ nguyên data cũ). GIỮ: cột "Điều khoản TT" per-NCC bảng so sánh (data từng NCC, khác field) + display read-only phiếu cũ.
|
||||
- **Vòng 6 — "bỏ luôn cái nút thêm hạng mục" (`792c030` #282):** gỡ nút "+ Thêm hạng mục" ItemsTab — 1 phiếu = 1 hạng mục chọn từ header (S57bis/S58), hạng mục đầu auto-seed khi tạo. AddItemDialog giữ dead-code flip lại dễ.
|
||||
- **2 run cancelled (#279, #281) = supersede-BENIGN** (Gitea concurrency-cancel khi push đè lúc UAT góp ý realtime ~1s gap): cicd ancestor-verify `git merge-base --is-ancestor` TRUE cả 2 — mọi fix preserved trong HEAD, ships qua run kế (#280, #282). Pattern lặp #385 S58 — cicd-monitor giờ xử lý chuỗi này thành thạo (con final-v2 tự phát hiện supersede + verify run MỚI thay vì báo fail).
|
||||
|
||||
## Closeout & lessons
|
||||
|
||||
- **0/14 spawn truncated** (H1×2 + H2×2 bootstrap/closeout + investigator recon + cicd ×9) — lần đầu sau nhiều session; verdict-FIRST + entry gọn + prompt scoped works.
|
||||
- **gotcha #61** (sqlcmd -f 65001 + verify-qua-API-JSON) + **#62** (rename natural-key: DB-trước-code-sau) NEW → 62 total.
|
||||
- Quy trình "destructive prod" giữ chuẩn: recon → AskUserQuestion chốt scope → script committed vào repo → chạy → verify exact-count → cicd re-verify sau app-recycle.
|
||||
- cicd-monitor MEMORY ~56KB > cap 30KB (9 cicd-spawn/ngày, H2 đo 54KB giữa session + 2 entry cuối) → chore-flag curate L2 monthly 2026-07-01 (FIFO top vẫn inject OK). H2 GATE PASS 5/5 + H1 ALL-4-FRESH (cross-count verified); 2 fix theo H2 flag: UTC-annotate entry #275 + bundle status-line tự cập bởi cicd final-v2.
|
||||
- Ops note benign: `GET /api/suppliers` trả page đầu (20) — đếm thật qua DB (22); không UI nào dùng sai.
|
||||
- Pending (carry): test-after guard cho `LockDemoSampleUsersAsync` (S58) + asymmetric authz suppliers POST/PUT-DELETE (S59) → test-specialist khi UAT ổn; 4 ops của anh (tzutil / email anh Chương / báo password 5 staff / lock nv.cao-truong khi gán thật); PermissionGuard per-route khi golive HRM/Office; Phase 9 Ops; monthly audit 2026-07-01.
|
||||
@ -1096,6 +1096,34 @@ for h in resp.points: # ← .points không phải iterable trực tiếp
|
||||
|
||||
---
|
||||
|
||||
### 61. sqlcmd chạy file .sql chứa tiếng Việt PHẢI `-f 65001` — console mojibake là display-only nhưng thiếu flag thì DATA hỏng thật (Session 59)
|
||||
|
||||
**Triệu chứng:** Output sqlcmd trên VPS hiện `H? th?ng trung th?`, `Ph?n th<74>` — không phân biệt được "console hiển thị sai" (vô hại) với "data trong DB đã hỏng" (thảm họa, nhất là với UPDATE/INSERT chứa nvarchar tiếng Việt).
|
||||
|
||||
**Root cause 2 lớp:** (1) Console VPS codepage OEM → mọi output Unicode đều mojibake = **display-only**, data vẫn đúng. (2) NHƯNG sqlcmd mặc định cũng đọc **input file** theo OEM codepage — file `.sql` UTF-8 no-BOM (như Write tool tạo) chứa `N'Bê tông'` sẽ bị decode sai → **ghi vào DB chuỗi hỏng THẬT**. Hai hiện tượng nhìn giống hệt nhau trên console.
|
||||
|
||||
**Fix + phòng tái diễn (S59 proven):** (1) Mọi lệnh `sqlcmd -i <file>` với file chứa tiếng Việt → thêm **`-f 65001`** (đọc input UTF-8). (2) **KHÔNG kết luận data đúng/hỏng từ console VPS** — verify độc lập: chạy cùng file trên LocalDB local (console local hiện tiếng Việt đúng) + curl API prod đọc JSON (UTF-8 end-to-end). S59 rename 71 WorkItems: console VPS mojibake nhưng API JSON trả `"2 MEP Sub Hệ thống trung thế"` nguyên vẹn → data đúng.
|
||||
|
||||
**References:** `scripts/s59-rename-workitems-pmh.sql` (run với `-f 65001`) · verify pattern: login admin → GET `/api/catalogs/work-items` JSON.
|
||||
|
||||
---
|
||||
|
||||
### 62. Đổi mã (natural-key) của data có seed per-code idempotent — PHẢI UPDATE DB prod TRƯỚC khi deploy seed mới, sai thứ tự = nhân đôi rows (Session 59)
|
||||
|
||||
**Triệu chứng tiềm năng (đã né):** Seed kiểu `SeedRealMasterDataAsync` so khớp theo `Code` (`if (existingCodes.Contains(code)) continue`). Đổi 71 mã WorkItems `VT-01→MAT-1`… nếu **push code trước**: app restart chạy seed với tuples MỚI → thấy 71 mã mới "chưa tồn tại" (DB còn mã cũ) → INSERT 71 row mới = **142 rows trùng tên khác mã** trên prod.
|
||||
|
||||
**Quy trình đúng (S59 proven, Run #276 verify 71 — không phải 142):**
|
||||
1. Viết SQL `UPDATE … SET Code=mới, Name=mới WHERE Code=cũ` (**GIỮ NGUYÊN Id** — record đang được trỏ tới không gãy; phiếu PE/2026/A/001 vừa tạo vẫn đúng hạng mục).
|
||||
2. Chạy SQL trên **prod + LocalDB Dev** trước.
|
||||
3. Sửa seed tuples trong code → commit + push SAU. App restart: seed thấy đủ mã mới → add 0.
|
||||
4. cicd verify count ĐÚNG N (N×2 = FAIL nghiêm trọng — đưa vào prompt verify).
|
||||
|
||||
**Tổng quát:** idempotent-by-natural-key chỉ an toàn khi key bất biến — mọi rename key phải đổi DB và seed "cùng khoảnh khắc" theo thứ tự **DB-trước-code-sau** (với CI auto-deploy-on-push).
|
||||
|
||||
**References:** `scripts/s59-rename-workitems-pmh.sql` · `DbInitializer.cs` SeedRealMasterDataAsync · gotcha #57 họ hàng (soft-delete vs UNIQUE filtered) · Run #276 cicd verdict.
|
||||
|
||||
---
|
||||
|
||||
## Checklist debug bug mới
|
||||
|
||||
1. Build pass không? → fail → check using + package version compat
|
||||
|
||||
Reference in New Issue
Block a user