[CLAUDE] Infra: phân cấp phòng ban (Department.ParentId) + /tree + gán phòng cha

Nền cây tổ chức cho trang Hồ sơ Nhân sự (anh: bố trí giống NamGroup; chốt phân
cấp thật + tự gán phòng cha trong quản lý phòng ban).
- Mig AddDepartmentParentId: +ParentId Guid? loose-Guid (no FK vật lý, convention
  PE) + IX_Departments_ParentId. AddColumn+CreateIndex, no new table, Down reversible
  (DropIndex->DropColumn). Chưa apply (CI/prod seed apply).
- GET /api/departments/tree: ráp cây in-memory + đếm NV active theo User.DepartmentId
  (EmployeeProfile KHÔNG có DepartmentId — link qua User, field phòng ban ở User Mig 11)
  + rollup TotalEmployeeCount + cycle-guard HashSet. Authz = class [Authorize] (= GET list).
- Create/Update +ParentId (write vẫn khóa Admin,CatalogManager). Update có cycle-guard:
  chặn tự-làm-cha + đi ngược chuỗi cha gặp lại Id (chống vòng A->B->A).
Build PASS (0 warn/err full solution). Test-after (test-specialist).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-06-16 10:34:52 +07:00
parent c98030f27c
commit 0f44d9754d
7 changed files with 6370 additions and 4 deletions

View File

@ -8,4 +8,8 @@ public class Department : AuditableEntity
public string Name { get; set; } = string.Empty; // vd "Phòng Kiểm soát Chi phí"
public Guid? ManagerUserId { get; set; } // TPB — Trưởng Phòng ban
public string? Note { get; set; }
// Phân cấp phòng ban (cây tổ chức) — loose-Guid KHÔNG FK vật lý (convention hệ
// này: PE.ProjectId/WorkItemId/SelectedSupplierId đều loose-Guid). Root = null.
public Guid? ParentId { get; set; }
}