[CLAUDE] Docs: S91 closeout — go-live wipe + seed-gate + user-change-password + backup (gotcha #75/#76)

Closeout phiên go-live 26/06 (4 commit prod-verified đã push: guide-fix 159b69d · wipe ba42c59
· seed-gate 55494ad · user-change-password e81e87f + backup local).
- STATUS/HANDOFF +S91 entry, state re-ground: Mig 59 · 88 bang · 431 test (45D+386I) · gotcha 76
  · menu 54 · bundle admin DgQyuG7f/user BmbQon23 · prod 17 user/7 NCC/0 PE-HD
- gotchas #75 (SeedDemoMasterData ungated per-code -> resurrect NCC demo moi restart)
  + #76 (deploy render appsettings.Production.json tu .example, KHONG file gitignored)
- session log 2026-06-26-S91 + feedback_wipe_durability_check_reseed (user memory)
- harvest cicd-monitor + test-specialist diary (self-written, verified)
- .gitignore +backups/ +*.bak

Docs/memory-only -> CI skip (paths-ignore docs/** + **/*.md + .gitignore).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-06-26 13:07:01 +07:00
parent e81e87ff9f
commit f98a743074
9 changed files with 148 additions and 28 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,43 @@
# S91 (2026-06-26) — Go-live day: guide fix + wipe + seed-gate + user-change-password + backup local
**Mode:** HMW-mode ON · em-main-led (security-sensitive + #53 risk → KHÔNG fan-out lớn, báo-trước) · 4 sub spawn (tooling-auditor + harvest-curator @start · cicd-monitor + test-specialist trong feature).
**Trigger:** anh forward email anh Kiệt SOL-IT "THÔNG BÁO GO-LIVE Trình duyệt So sánh Giá — 26/06, Phase-01 Phòng Mua hàng (PRO) + Kiểm soát chi phí (CCM)". Sau đó: wipe data cũ ("múc nó phát em") → user-change-password ("user chưa tự đổi pass được hả em") → backup local ("sao lưu local tk các thứ để dùng lại").
## 4 commit prod-verified (+ backup local)
### #1 `159b69d` — Guide Word bỏ "Từ chối" + fix caption (docs-only, CI-skip)
Guide `docs/Huong-dan-Duyet-NCC.docx` (đã đính kèm email go-live, phát toàn công ty) còn ghi **"Từ chối" 2 chỗ** (Bước 4 + caption Hình 9) — app gỡ nút Từ chối từ S60, chỉ còn **Duyệt/Trả lại**. Caption Hình 9 còn **mâu thuẫn với ảnh nó chú thích** (ảnh chụp S90 = 2 nút, caption = 3). + 12 caption "Hinh"→"Hình" (thiếu dấu từ S90 ASCII-gen). Sửa qua skill docx **unpack→edit XML→repack** (giữ nguyên 13 ảnh: 1 logo+12 màn). Pack `--validate false` (validator dính bug cp1252 đọc UTF-8 VN, kể cả numbering.xml không sửa). Verify độc-lập **python-docx strict-open**: Từ chối=0, caption=12, media=13.
### #2 `ba42c59` — Wipe go-live `scripts/s91-wipe-golive.sql` (prod-executed)
anh Kiệt "xóa data cũ" trước go-live. Recon prod read-only → PE=16 · PeWorkItemBudgets=16 · Notifications=94 · Suppliers=26 [19 demo tháng-4 + 3 thật 06-09 + 4 thật 06-23] · Users=17 · Projects=70 · WorkItems=71. **AskUserQuestion ×2 chốt scope:** budgets→xóa hết · suppliers→GIỮ 7 thật (CreatedAt≥06-01), xóa 19 demo (`<06-01`). ⚠️ **S85 cắt theo 06-11 = SAI cho lần này** (4 NCC thật nằm SAU 06-11) → recon-before-change bắt; dùng mốc 06-01 (demo toàn tháng-4, thật toàn tháng-6). **Backup bước-0** `SolutionErp_S91_pregolivewipe.bak` (XACT_ABORT + `-b` abort-trước-wipe). **2 guard atomic:** PE>16→ABORT [chống xóa phiếu thật mới tạo go-live-day] · Suppliers-deleted≠19→ROLLBACK. Kết quả: PE/budgets/notif/contracts→0, Suppliers→7, cascade child→0, PeSeq→0 (**phiếu thật đầu tiên = PE/2026/A/001**).
### #3 `55494ad` — Gate SeedDemoMasterData (root-cause: chống resurrect NCC demo)
**Phát hiện TRƯỚC khi deploy:** `SeedDemoMasterDataAsync` (DbInitializer.cs:111) chạy **UNGATED** (ngoài mọi `if (!demoSeedDisabled)`) + per-code idempotent → 18 NCC demo (codes thiếu sau wipe) sẽ TỰ Add lại mỗi restart/IIS-recycle → wipe KHÔNG bền (gotcha **#75**). Fix gate sau `DemoSeed:Disabled` (prod=true, mirror Contracts/PE/Workflow demo). Verify config-flow: prod `appsettings.Production.json` render từ `.example` mỗi deploy (KHÔNG file gitignored — gotcha **#76**), `.example` không có DemoSeed → fallback `appsettings.json Disabled=true` → gate hiệu-lực. Deploy → **verify demo_codes=0 qua 2 restart** (binary Last-Modified fresh + count THẬT từ prod, KHÔNG tin cicd-monitor garbled-return).
### #4 `e81e87f` — User tự đổi mật khẩu (BE + FE 2-app + 10 test)
anh Kiệt "user chưa tự đổi pass được hả em" → đúng (chỉ admin Reset hộ, KHÔNG self-service). AskUserQuestion → build cả 2 app. **BE:** `Auth/Commands/ChangePassword/ChangePasswordCommand` + `POST /api/auth/change-password [Authorize]` — lấy user qua `ICurrentUser.UserId`; `UserManager.ChangePasswordAsync` verify mật khẩu HIỆN TẠI (Identity); fail-`PasswordMismatch`→field `CurrentPassword` "Mật khẩu hiện tại không đúng."; rule ≥12 + khác-cũ (validator); vô hiệu refresh token sau đổi (mirror ResetPassword). **FE 2-app SHA-mirror:** `ChangePasswordDialog` (3 ô current/new/confirm + validate client) wire vào `TopBar` UserMenu ("Đổi mật khẩu" trên "Đăng xuất"). **Test:** +10 `ChangePasswordCommandTests` (đúng/sai pass-cũ keyed-field, <12 boundary, ==, chưa-auth/UserId-null/not-found, RefreshToken-cleared). **Bug self+cross-caught:** CS0104 `ValidationException` ambiguous (FluentValidation vs custom) em-main bắt qua build TRƯỚC test-specialist return (test-specialist độc-lập bắt CÙNG bug = 2-observer-converge). Full suite **422→431**.
### + Backup local (anh "sao lưu local tk các thứ để dùng lại")
`backups/SolutionErp_golive_clean_2026-06-26.bak` (21MB, full DB clean go-live state) + `backups/accounts.txt` (17 tk: email·tên·status·phòng·role, clean -W). `.gitignore` +`backups/`+`*.bak`. backups/ trong Dropbox sync cloud (flag anh).
## Cách chạy (em-main-led)
Browser-guide định chụp [#74 carry] Chrome-MCP screenshot **kẹt SPA-SignalR document_idle** (CDP capture/eval timeout) + browser chưa-login eoffice anh "à thôi tự check" defer. Security-feature (change-password) = em-main-led BE+FE (báo-TRƯỚC: cross-stack+security-sensitive+#53-risk) + test-specialist (10 test, return tốt) + build/test gate thay reviewer/cicd fan-out. **#53:** cicd-monitor return GARBLED (lạc sang memory-curate) em-main self-verify từ prod (suppliers=7, demo_codes=0, endpoint 401, binary timestamp).
## State THẬT (re-ground)
Mig **59** · 88 bảng · **431 test** (45D + 386I, +10 ChangePassword) · gotcha **76** (+#75 +#76) · menu 54 · bundle admin **`DgQyuG7f`**/user **`BmbQon23`** · prod **17 user / 7 NCC / 70 dự án / 71 hạng mục / 0 PE-HĐ** (clean go-live).
## Lessons
- **Wipe KHÔNG bền nếu không gate re-seed** (#75, `feedback_wipe_durability_check_reseed`): xóa data = triệu chứng; nguồn re-populate (DbInitializer seeder ungated per-code) gốc. TRƯỚC/SAU prod-wipe audit seeder. Root-cause>symptom (mirror #73/S85).
- **Deploy render prod-config từ `.example`** (#76): sửa config-gitignored = vô-tác-dụng; effective = appsettings.json ⊕ rendered-.example.
- **inspect-before-change prod**: S85 supplier-cut-date stale → recon thật bắt 4 NCC-thật-sau-mốc (mirror `feedback_prod_config_inspect_before_change`).
- **em-main-led security-feature**: báo-trước-khi-lệch HMW-auto-Workflow (mode-ON) hợp-lệ cho security-sensitive; build/test gate + test-specialist độc-lập = đủ rigor; #53 cicd garbled → self-verify-prod.
## NEXT
- **🔴 anh:** ⚠️ restart CLI · review guide docx Word · đóng 2 tab eoffice em mở · UAT đổi-mật-khẩu (avatar→Đổi mật khẩu).
- **🔴 em:** curate test-specialist L1 OVER (carry nhiều session) · monthly 2026-07-01 (re-tier mega-line STATUS/HANDOFF bloat · ef-core SKILL Mig→59 · docs/CLAUDE Budget-removed · 3 vocab-fork alias-map).
- **Pending product:** Section B cột Dự-án · Ngưỡng giá CEO Mig 54 Designer UAT · "C" chuyển phiếu→dự án chờ spec.
## §L closeout
- §L.a: 0 RCA hard (CS0104 + seed-resurrect đều CAUGHT pre-prod = gate hoạt động, không phải prod-bug). Wipe/deploy đúng quy-trình (backup+guard+verify).
- §L.b: (a) STATUS+HANDOFF +S91 ✓ · (c) sleep-check `last_sleep_at=2026-06-25` <7d skip · test-specialist L1 OVER carry-flag · (d) spawn-record: tooling-auditor[start/CLEAN-diff] · harvest-curator[start/CLEAN] · cicd-monitor[deploy-verify/return-GARBLED-#53em-main self-verify-prod] · test-specialist[+10 test/return-OK/bắt-CS0104] · (g) tooling: 0 skill/plugin mới · (h) User-Mark: 4 Active-High display-only, 0 governance-decision-mới = n-a.
- INFRA-ADOPTION: **N/A** (no AI_INFRA infra adoption pure product/ops + doc).

View File

@ -1280,6 +1280,24 @@ for h in resp.points: # ← .points không phải iterable trực tiếp
3. **Crop:** bỏ chrome trình-duyệt top + taskbar bottom (top=92/bottom=72). Banner CDP **"Claude started debugging this browser"** hiện sau mỗi `navigate` (CDP re-attach), tự ẩn sau vài giây ảnh chụp ngay-sau-navigate cần crop top146; verify nhanh bằng **montage dải-trên 12 ảnh** đọc 1 lần.
4. **Chèn:** `python-docx` `cell...add_picture(width=Inches(6.0))` A4 content = **6.27"** nên 6.3" TRÀN; dùng 6.1".
---
### 75. Seed demo UNGATED + per-code idempotent → RE-ADD data đã wipe mỗi restart (wipe KHÔNG bền) (Session 91)
**Triệu chứng:** Sau wipe 18 NCC demo (`s91-wipe-golive.sql`) cho go-live sạch, định deploy `SeedDemoMasterDataAsync` (DbInitializer.cs:111) chạy NGOÀI mọi `if (!demoSeedDisabled)` + idempotent per-code (`existingSupplierCodes.Contains(s.Code) ? continue : Add`). Code 18 NCC demo giờ THIẾU (đã xóa) mỗi restart/IIS-recycle TỰ Add lại Suppliers 725, undo go-live clean.
**Cơ chế:** wipe = triệu chứng; nguồn re-populate (seed) gốc. Demo seed cố-ý-ungated (Production.json comment "KEEP SeedMasterData") để giữ data UAT nhưng go-live cần demo GONE. Khác user test (38): S89 đã gỡ KHỎI MẢNG `SeedDemoUsers` không resurrect.
**Fix (root-cause, `55494ad`):** gate `SeedDemoMasterDataAsync` sau `DemoSeed:Disabled` (=true prod, mirror Contracts/PE/Workflow demo đã gated). Prod skip wipe BỀN; Dev (false) vẫn seed local. **Verify:** deploy restart 2× `demo_codes=0` (binary Last-Modified fresh + count THẬT từ prod). **Quy tắc:** TRƯỚC/SAU mọi prod data-wipe audit DbInitializer seeder cho ungated per-code re-seed (resurrect). Liên-quan #73 / `feedback_root_cause_over_symptom`.
### 76. `deploy.yml` render `appsettings.Production.json` từ `.example` template mỗi deploy → prod config KHÔNG lấy từ file gitignored (Session 91)
**Triệu chứng:** Sửa `appsettings.Production.json` (gitignored) tưởng đổi config prod vô-tác-dụng; `git add` báo file ignored.
**Cơ chế:** `deploy.yml:146-154` mỗi deploy đọc `appsettings.Production.json.example` (tracked) `ConvertFrom-Json` set `DB_CONNECTION`+`JWT_SECRET` từ secrets **ghi đè** `C:\inetpub\...\appsettings.Production.json`. File local gitignored KHÔNG bao giờ deploy. Effective config = `appsettings.json` (tracked) rendered-Production.json (từ `.example`).
**Fix/Quy tắc:** đổi prod config = sửa `.example` (tracked) HOẶC `appsettings.json`, KHÔNG file local gitignored. `.example` KHÔNG `DemoSeed` prod fallback `appsettings.json DemoSeed:Disabled=true` (đúng fallback đã giữ Contracts/PE gated nhiều tháng gate #75 hiệu-lực prod).
**An toàn prod:** chỉ XEM/scroll/screenshot KHÔNG bấm nút mutate (Gửi duyệt/Duyệt/Trả lại/Tạo ). Mở `+ Thêm mới` (form `?mode=new`) KHÔNG tạo draft cho tới khi sửa field (auto-save on-edit).
**References:** `$env:TEMP\guideshots\capture.ps1` (session-scratch) · `docs/Huong-dan-Duyet-NCC.docx`. Pattern reusable user-memory `pattern_prod_screenshot_to_docx`.