[CLAUDE] Docs: S65 session-end closeout — HRM go-live + Hồ sơ NS master-detail + Department hierarchy + PE Link hồ sơ (6 deploy #289→#295)

Closeout S65 (~6 deploy prod-verified, anh + anh Kiệt FDC UAT realtime):
- STATUS/HANDOFF S65 (Mig 52 · 88 bảng · 263 test · 65 gotcha · menu 53 · bundle admin BDwV5d0X / user DbVv6rsf Run #295) + session log #289→#295.
- gotcha #65 (build csproj con ≠ dotnet build slnx gồm tests → CS7036 Run #291 FAIL-gated; fix +trailing-optional sweep).
- CLAUDE.md root Mig 50→52 + PE row +Mig 52.
- Harvest: H2 GATE 2-MISS closed — 2 on-behalf record (PE-Workflow FE + reviewer empty-return #53) → impl-frontend + reviewer agent-memory. H1 tooling CLEAN (roster/skill/plugin 11/6/18).
- Memory (user-global): +feedback_workflow_fanout_reliability.
Carry-P1: cicd-monitor L1 82KB curate-L2 · mirror Employee page→fe-admin · test-after (HoSoLink/ParentId/HRM-perm).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-06-16 11:56:03 +07:00
parent 456c7a721b
commit fe28ca3993
12 changed files with 148 additions and 16 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,62 @@
# S65 (2026-06-16) — HRM go-live + Hồ sơ Nhân sự master-detail (giống NamGroup) + Department hierarchy + PE Link hồ sơ
> ~6 deploy prod-verified Run #289→#295. Anh + anh Kiệt FDC UAT realtime (kiểu rapid-loop như S59). Workflow fan-out chạy THẬT lần đầu.
## Bối cảnh
Anh `/session-start` → chuỗi yêu cầu realtime từ screenshot eoffice + Zalo anh Kiệt FDC:
1. Screenshot eoffice "Public cho tất cả User module NHÂN SỰ".
2. "Trang trí toàn bộ giao diện cho đẹp, font/màu sắc" (đơn điệu).
3. Screenshot NamGroup HRM "bố trí hồ sơ nhân sự giống thế này".
4. Zalo anh Kiệt: "mục E Link hồ sơ (NAS hyperlink) dưới mục D" + "Dự trù PRO → Ngân Sách PRO".
5. "Sao không workflow fan-out ra?" (meta — HMW-mode ON).
6. "Gốc SOLUTION COMPANY rồi fan-out xuống phòng ban".
7. "Chữ đen đơn điệu đổi lại + panel phòng ban trên/User dưới + trang trí màu".
`/session-end`.
## Done — 6 deploy (Run #289→#295)
### #289 (`4004481`) — Public Hồ sơ Nhân sự cho mọi role (BE seed, em main solo)
- `SeedAllRolesHrmProfileReadPermissionsAsync` (DbInitializer): grant CanRead `Hrm`+`Hrm_HoSo` 13 role, gọi **SAU** `RevokeTemporarilyHiddenModulesAsync` (S58) để thắng revoke. **Upgrade-only** (nâng false→true trên row prod đã bị revoke set false — KHÔNG skip-existing như nhánh non-Pe; tránh NO-OP class S58). Giữ ẩn Dashboard NS + 6 `Hrm_Config*`.
- **Insight:** `EmployeesController` dùng policy-based `[Authorize(Policy="Hrm_HoSo.Read")]` (resolve qua `MenuPermissionHandler` đọc thẳng permission matrix) → grant CanRead mở **luôn cả menu lẫn API** trong 1 phát, không dính gotcha #44 (mở menu nhưng controller chặn cứng). FE 0 đổi (menu BE-driven).
- 🟥 reviewer PASS 7/7 (ordering · upgrade-path · scope · read-only · no-regression · idempotent · no-write-path). 🟩 cicd: non-admin GET /employees **200** (was 403), POST/PUT/DELETE **403**, DB 13 role CanRead=1.
### #290 (`c98030f`, 14 file) — Redesign màu foundation fe-user (🩷 designer)
- `index.css`: accent palette teal/violet/**amberx**/**greenx** (đặt tên né trùng built-in Tailwind) stop 50/100/500/600/700 + utilities `.app-gradient-brand`/`.card-accent`/`.icon-chip`/`.stat-value` + heading 600→700 + `.label-eyebrow` brand-600.
- primitives: Button gradient primary/danger · Input/Select/Textarea focus-glow mạnh · Dialog title-bar gradient · Label brand-600. **variant/size keys STABLE** (build PASS = type-contract intact, đòn bẩy TS strict).
- shell: Layout stripe + logo cap · PageHeader title lớn/đậm + accent bar · TopBar gradient hairline · DataTable thead gradient brand. brand #1F7DC1 + Be Vietnam Pro GIỮ.
- ⚠️ designer return bị cắt #53 (đang dựng showcase) → em main recover-disk: 14 file thuần className + 2 color-map (`contract/PE` phase color -700→-800), self-review toàn bộ + build PASS.
### #292 (`0f44d97` + `6ce5803` test-fix, Mig 51) — Department hierarchy + picker
- 🟨 implementer-backend: `Department.ParentId Guid?` **loose-Guid no-FK** (convention PE) + `GET /api/departments/tree` (`GetDepartmentTreeQuery`: load phẳng → đếm NV active GROUP BY `User.DepartmentId` [**recon catch: `EmployeeProfile` KHÔNG có DepartmentId**, link qua User Mig 11] → ráp cây in-memory + rollup TotalEmployeeCount + cycle-guard HashSet). Mig 51 `AddDepartmentParentId` (AddColumn+CreateIndex, no new table).
- em main A2: Create/Update command +ParentId + Update **cycle-guard** (chặn tự-làm-cha + đi ngược chuỗi cha gặp lại Id = vòng A→B→A).
- 🟧 implementer-frontend: picker "Phòng cha" fe-admin DepartmentsPage (Select + load-all query + exclude-self + cột "Thuộc"). Self-service org chart (anh chốt vs seed).
- ⚠️ **gotcha #65** (Run #291 FAIL CS7036): em build `Api.csproj` lẻ (không gồm tests) → push → CI `dotnet build slnx` bắt `CreateDepartmentCommand +ParentId` positional-required vỡ `MasterCatalogFilteredUniqueTests.cs:63` 4-arg. Fix +5th arg → Run #292 PASS. Lesson: đổi chữ ký BE → build full slnx trước push.
### #293 (`318860a` Phase B + `5a0aaa4` PE) — Employee master-detail + PE Link hồ sơ
- **Phase B** (🩷 designer, EmployeesListPage 1201-LOC rewrite): 3-panel master-detail (cây tổ chức consume `/tree` + list + chi tiết **5 tab** Tổng quan/Thân nhân/Trình độ/Kinh nghiệm/Hợp đồng + avatar header). **Giữ 100% 5 satellite CRUD** (16 endpoint, grep-verified). Recon: HRM port từ NamGroup nên model+satellite ~90% sẵn — chỉ thiếu org-tree + re-skin. Designer self-caught `网络Placeholder` mojibake import.
- **PE** (🔥 **Workflow fan-out** `pe-hoso-link-rename-pro` BE∥FE→review): Mig 52 `AddHoSoLinkToPurchaseEvaluation` (PE +`HoSoLink string?` hyperlink NAS — anh Kiệt "copy link thư mục NAS paste vào, dạng hyperlink"; `<a target=_blank rel=noopener>` null-safe; Create/Update **+trailing-optional =null** → backward-compat 0 call-site break) + rename "Dự trù PRO"→"Ngân sách PRO" (row+badge) ×2 app SHA256-mirror.
- ⚠️ **Workflow: FE+reviewer return RỖNG** (#53 die-empty trong fan-out) → em main recover-disk + self-gate: build ×3 PASS + mirror SHA256 + grep rename → **bắt badge "DỰ TRÙ PRO" sót** (agent đổi row label 1120/1126 nhưng sót badge 1078) → vá ×2 app.
### #294 (`ec517f7`) — Gốc cây "SOLUTION COMPANY"
- Anh: "để SOLUTION COMPANY rồi fan-out xuống phòng ban". Gộp nút "Tất cả phòng ban" + list phẳng thành 1 node gốc công ty (chevron `companyOpen` mở mặc định + bấm tên = pickDept(null) tất cả + CountBadge tổng) chứa phòng ban TreeNode depth=1 toả xuống (cha-con giống NamGroup "Nam Group").
### #295 (`456c7a7`) — Employee refine 2-cột + tô màu (🩷 designer)
- Anh góp ý live (screenshot eoffice): (1) layout 2 cột giống NamGroup gốc — cột TRÁI dọc = cây tổ chức (trên) + danh sách NV (dưới) chồng nhau · cột PHẢI = chi tiết rộng; (2)+(3) chữ đen đơn điệu → tô màu accent panel chi tiết (icon-chip/heading-700/rail/nhãn brand-tint).
- Designer (return ĐẦY ĐỦ lần này) tự bắt 2 bug: accent `-800` không tồn tại palette → `-700`; rail `before:content` thiếu.
## Lessons / insight
- **Workflow fan-out THẬT lần đầu** (`feedback_workflow_fanout_reliability`): parallelism thật (BE∥FE file-disjoint) NHƯNG return-reliability kém (2/3 empty #53) + reviewer-stage không tin được → verify-heavy prod task em main VẪN tự gác = tương đương spawn lẻ. Chọn tool theo bản chất task.
- **gotcha #65:** build csproj con ≠ `dotnet build slnx` (gồm tests) → miss test-compile khi đổi chữ ký command. Trailing-optional `=null` (HoSoLink) backward-compat vs positional-required (ParentId) vỡ test.
- **Policy-based authz** (`Hrm_HoSo.Read` qua MenuPermissionHandler) = mở quyền 1 phát cả menu+API, tránh gotcha #44.
- HRM module port từ NamGroup nên Employee model+5-satellite ~90% sẵn → "giống NamGroup" = re-skin + org-tree, không build mới.
## State sau S65
- **Mig 52** (51 AddDepartmentParentId + 52 AddHoSoLink — cả 2 AddColumn-only) · **88 bảng** · **263 test** (45D+218I, unchanged test-after defer) · **65 gotcha** · **menu 53**.
- Bundle final: admin **`BDwV5d0X`** / user **`DbVv6rsf`** (Run #295).
- HARVEST: H2 GATE 🟡 2-MISS (PE-Workflow FE+reviewer empty) → 2 on-behalf record APPEND. H1 tooling CLEAN (roster/skill/plugin), docs count-flush Mig 50→52. cicd-monitor L1 **82KB over-cap P1** (next-session curate).
## Carry → next session
- Mirror Employee page (+ gốc SOLUTION COMPANY + màu) sang **fe-admin** (fe-user only).
- test-after: HoSoLink + Department.ParentId/cycle-guard + HRM-permission seed.
- 🔴 cicd-monitor 82KB curate-L2 P1 · ef-core SKILL Mig flush · docs/CLAUDE.md full · schema-diagram §16+ ERD (monthly).
- Ops anh (S58/S59 carry): tzutil · anh Chương typo · 5 staff password · gán CNTT.

View File

@ -1148,6 +1148,20 @@ for h in resp.points: # ← .points không phải iterable trực tiếp
---
### 65. Build csproj con (vd `SolutionErp.Api.csproj`) ≠ `dotnet build SolutionErp.slnx` (gồm tests) — đổi chữ ký record command lọt test-compile → CI CS7036 FAIL-gated (Session 65)
**Triệu chứng:** thêm `ParentId` làm tham số positional thứ 5 BẮT BUỘC vào `CreateDepartmentCommand`; build local `dotnet build src/Backend/SolutionErp.Api/SolutionErp.Api.csproj` PASS push **CI test-gate FAIL CS7036** Run #291 ("no argument for required parameter 'ParentId'") `MasterCatalogFilteredUniqueTests.cs:63` còn gọi 4-arg. Deploy bị chặn (prod NGUYÊN test-gate làm đúng việc), tốn 1 vòng FAILfixre-push.
**Cơ chế:** `Api.csproj` ( mọi csproj con `src/Backend/*`) KHÔNG reference `tests/*` build KHÔNG compile tests. CI chạy `dotnet build SolutionErp.slnx` / `dotnet test` = build CẢ tests bắt call-site . Đổi chữ record command/DTO/entity ctor = **spec change** (CLAUDE.md §7 "spec change = sửa test + code chung commit").
**Guard:** đổi chữ BE (1) `dotnet build SolutionErp.slnx` FULL (gồm tests) TRƯỚC push, KHÔNG build csproj con lẻ; (2) grep repo-wide `new <Command>(` (gồm `tests/`) sửa mọi call-site; (3) cân nhắc **trailing optional `= null`** (như `CreatePurchaseEvaluationCommand +HoSoLink` Mig 52 backward-compat, 0 call-site break) đối lại positional-required (`CreateDepartmentCommand +ParentId` vỡ test).
**Credit:** 🟩 cicd-monitor S65 Run #291 FAIL-detect (reproduced local CS7036) em main fix `MasterCatalogFilteredUniqueTests.cs:63` +5th arg `null` `6ce5803` Run #292 PASS.
**References:** `MasterCatalogFilteredUniqueTests.cs:63` · `DepartmentFeatures.cs` (CreateDepartmentCommand) · Run #291 FAIL / #292 PASS · CLAUDE.md §7.
---
## Checklist debug bug mới
1. Build pass không? fail check using + package version compat