[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:
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,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.
|
||||
@ -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'") vì `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 FAIL→fix→re-push.
|
||||
|
||||
**Cơ chế:** `Api.csproj` (và mọi csproj con `src/Backend/*`) KHÔNG reference `tests/*` → build nó KHÔNG compile tests. CI chạy `dotnet build SolutionErp.slnx` / `dotnet test` = build CẢ tests → bắt call-site cũ. Đổi chữ ký record command/DTO/entity ctor = **spec change** (CLAUDE.md §7 "spec change = sửa test cũ + code chung commit").
|
||||
|
||||
**Guard:** đổi chữ ký 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
|
||||
|
||||
Reference in New Issue
Block a user