[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-fix159b69d· wipeba42c59· seed-gate55494ad· user-change-passworde81e87f+ 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:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -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, ==cũ, 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) là 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-#53→em-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).
|
||||
@ -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 top≈146; 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 7→25, undo go-live clean.
|
||||
|
||||
**Cơ chế:** wipe = triệu chứng; nguồn re-populate (seed) là gốc. Demo seed cố-ý-ungated (Production.json comment cũ "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 có `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 HĐ). 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`.
|
||||
|
||||
Reference in New Issue
Block a user