[CLAUDE] Docs: S69 session-end closeout — Văn phòng số golive + PE cờ gấp/ngưỡng (Run #305-308)
Flush docs sau buổi sản phẩm cực lớn (4 deploy prod-verified, 2 workflow fan-out). - STATUS.md + HANDOFF.md: S69 header + Recently Done + In-Progress + count (Mig 52→53 · test 286→306 · menu 53→54 · gotcha 66→68 · bundle BgNCjwsG/CBvh0vtf Run #308) + Phase (Văn phòng số golive + PE cờ gấp/ngưỡng). - gotchas.md: +2 (#67 Tailwind accent palette thiếu-stop vỡ-màu-im-lặng · #68 stale-diagnostic-background-agent → chỉ tin build sau-cùng). - session log 2026-06-17-S69-vanphong-golive-pe-urgent-threshold.md. - CLAUDE.md (root): Mig 53 · PE module +Mig 53 · test 306 · gotcha 68. - ef-core-migration SKILL: +Mig 53 row AddPeUrgentAndCeoApprovalThreshold + count 52→53 (H1 flush). - harvest: cicd-monitor MEMORY #308 (H2 orphan commit). H2 GATE PASS · H1 0 new-alloc. curate-debt P1 next session: cicd-monitor 65.2KB worst. C (chuyển phiếu→dự án) chờ anh Kiệt spec. 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
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: ef-core-migration
|
||||
description: Tạo/sửa/revert EF Core 10 migration cho SOLUTION_ERP. Dùng khi thêm entity mới, thay đổi schema, rollback migration, debug DesignTimeDbContextFactory fail. Đã có 52 migration sẵn (Init → AddHoSoLinkToPurchaseEvaluation Mig 52, S65). Snapshot + Designer + Migration 3-file rule bắt buộc commit đủ.
|
||||
description: Tạo/sửa/revert EF Core 10 migration cho SOLUTION_ERP. Dùng khi thêm entity mới, thay đổi schema, rollback migration, debug DesignTimeDbContextFactory fail. Đã có 53 migration sẵn (Init → AddPeUrgentAndCeoApprovalThreshold Mig 53, S69). Snapshot + Designer + Migration 3-file rule bắt buộc commit đủ.
|
||||
when-to-use:
|
||||
- "thêm migration"
|
||||
- "EF Core migration"
|
||||
@ -16,7 +16,7 @@ when-to-use:
|
||||
|
||||
> **Context:** .NET 10 + EF Core 10 + SQL Server. DbContext: `ApplicationDbContext` ở `Infrastructure/Persistence/`. Startup: `SolutionErp.Api`.
|
||||
|
||||
## Migration history (52 migration hiện có)
|
||||
## Migration history (53 migration hiện có)
|
||||
|
||||
| # | Name | Tables added / changed |
|
||||
|---|---|---|
|
||||
@ -72,6 +72,7 @@ when-to-use:
|
||||
| **50** | **`ReplaceBudgetModuleWithPeWorkItemBudgets`** | **🎯 S61 (2026-06-13) — bảng mới `PeWorkItemBudgets` (1 record/cặp Dự án × Hạng mục, UNIQUE filtered `[IsDeleted]=0`) + **DROP module Budget cũ** (Budgets/BudgetDetails/BudgetApprovals/BudgetChangelogs…) + PE/Contracts DROP `BudgetId` + **backfill `BudgetManualAmount→BudgetPeriodAmount` TRƯỚC DropColumn** (phiếu UAT giữ số) + DELETE menu/permission `Bg_*` IN-list children-first. ⚠️ database-agent advise: KHÔNG FK vật lý PE/Contracts→Budgets → no DropForeignKey · DropIndex TRƯỚC DropColumn (SQL 5074) · IN-list thay LIKE `Bg_%`. Ngân sách giờ per-gói-thầu nhập theo role PRO/CCM. **gotcha #63** (EF scaffold RenameColumn SAI-semantics → Add+UPDATE+Drop) + **#64** (`dotnet ef database update` áp Design-DB 0-rows ≠ Dev-DB → backfill chạy thật lần đầu trên prod).** |
|
||||
| **51** | **`AddDepartmentParentId`** | **🎯 S65 — Department.ParentId `Guid?` loose-Guid (KHÔNG FK vật lý — org-tree phân cấp; `GET /departments/tree` ráp cây in-memory + rollup count theo `User.DepartmentId` + cycle-guard HashSet chặn tự-cha + vòng A→B→A). AddColumn-only, no new table.** |
|
||||
| **52** | **`AddHoSoLinkToPurchaseEvaluation`** | **🎯 S65 — PE.HoSoLink `nvarchar(1000)?` hyperlink NAS (mục "e. Link hồ sơ", FE `<a target=_blank rel=noopener>` null-safe). AddColumn-only, no new table.** |
|
||||
| **53** | **`AddPeUrgentAndCeoApprovalThreshold`** | **🎯 S69 — PE +`IsUrgentByPro`/`IsUrgentByCcm` (bit, cờ gấp PRO đỏ/CCM xanh) + ApprovalWorkflow +`CeoApprovalThreshold` `decimal(18,2)?` (ngưỡng gói CEO — CCM role CostControl duyệt-final khi winnerQuoteTotal < ngưỡng). 3 AddColumn, no new table. anh Kiệt FDC.** |
|
||||
|
||||
Total: **88 bảng** dbo + `__EFMigrationsHistory` (re-ground S62 cicd `sys.tables`; last Mig 50 net 93→88 — Mig 51+52 đều AddColumn-only, không đổi số bảng). Xem `docs/database/schema-diagram.md` migration table + §11-15 module ERD (§16+ Mig 27-52 chi tiết pending).
|
||||
|
||||
@ -281,7 +282,7 @@ sqlcmd -S .\SQLEXPRESS -d SolutionErp -U vrapp -P <pw> -i migrate.sql
|
||||
|
||||
## Code pointers
|
||||
|
||||
- `src/Backend/SolutionErp.Infrastructure/Persistence/ApplicationDbContext.cs` — DbSet cho 88 bảng (52 migration)
|
||||
- `src/Backend/SolutionErp.Infrastructure/Persistence/ApplicationDbContext.cs` — DbSet cho 88 bảng (53 migration)
|
||||
- `src/Backend/SolutionErp.Infrastructure/Persistence/DesignTimeDbContextFactory.cs` — EF tooling factory
|
||||
- `src/Backend/SolutionErp.Infrastructure/Persistence/DbInitializer.cs` — seed + warn + migrate runtime + backfill (idempotent reconcile pattern)
|
||||
- `src/Backend/SolutionErp.Infrastructure/Persistence/Configurations/` — IEntityTypeConfiguration<T> per entity
|
||||
|
||||
@ -50,20 +50,20 @@ Kiến trúc: **.NET 10 Clean Architecture + 2 React FE (admin + user) + SQL Ser
|
||||
- Audit fields: `CreatedAt`, `UpdatedAt`, `CreatedBy`, `UpdatedBy` (`BaseEntity`)
|
||||
- Soft delete: `IsDeleted`, `DeletedAt`, `DeletedBy` (`AuditableEntity`)
|
||||
- Migrations: `dotnet ef migrations add <Name> --project src/Backend/SolutionErp.Infrastructure --startup-project src/Backend/SolutionErp.Api`
|
||||
- **Hiện có 52 migration → 88 bảng** (+S65: Mig 51 `AddDepartmentParentId` Department.ParentId loose-Guid no-FK org-tree phân cấp + Mig 52 `AddHoSoLinkToPurchaseEvaluation` PE HoSoLink nvarchar(1000) hyperlink NAS — cả 2 AddColumn no new table, tables giữ 88. Phase 10 COMPLETE + Phase 11 P11-A→F done — Mig 34-42 HRM/Office/WorkflowApps/Attendance + Contract V2 (32-33) + WireWorkflowApps V2 (41) + LeaveBalance (42) + Holiday filtered-unique (43, S45) + Vehicle/Driver catalog (44, S51) + HRM-catalog filtered-unique 3× (45, S51) + ItTicket SLA (46, S52) + Master filtered-unique 3× (47, S53 gotcha #57 EXT) + Project master fields Year/Investor/Location/Package (48, S55 — AddColumn no new table, kèm nạp 62 dự án + 71 hạng mục + 3 NCC real data từ Excel qua `SeedRealMasterDataAsync` ungated idempotent) + PE gắn Hạng mục công việc WorkItemId loose-Guid KHÔNG FK vật lý (49, S57bis — AddColumn+CreateIndex, no new table) + **Mig 50 `ReplaceBudgetModuleWithPeWorkItemBudgets` (S61, 2026-06-13) — XÓA module Budget cũ, thay bằng `PeWorkItemBudgets` ngân sách per-gói-thầu (1 record/cặp Dự án × Hạng mục, nhập theo role PRO/CCM, vượt ngân sách = cảnh báo mềm cho lưu S62); backfill `BudgetManualAmount→BudgetPeriodAmount` TRƯỚC DropColumn (phiếu UAT giữ số); net bảng 93→88; gotcha #63/#64**. V2 schema history S29-era bên dưới giữ nguyên — Mig 32+33 Plan B Contract V2 cookie-cutter mirror PE Mig 22-26 (S29). Mig 26 `AddPeLevelOpinionsForV2`: bảng mới `PurchaseEvaluationLevelOpinions` UNIQUE composite (PEId, LevelId), FK Cascade Pe + Restrict Level. Section 5 "Ý kiến cấp duyệt" V2 dynamic theo workflow đã pin: forEach Step (Phòng) → forEach Level (Cấp) → forEach NV → 1 OpinionBox. Service `ApproveV2Async` UPSERT auto khi NV duyệt — Q1=1B (sync gắn với Duyệt, KHÔNG form input rời). SignedByUserId track signer thật, FE banner "Admin duyệt thay" khi !== ApproverUserId. Comment empty → "(duyệt — không ý kiến)" placeholder. Phiếu V1 legacy fallback Mig 15 4 box readOnly (data history). Mig 25 `AddIsUserSelectableToApprovalWorkflows`: ALTER `ApprovalWorkflows` +`IsUserSelectable bit` (admin pin/unpin workflow nào cho user pick lúc create phiếu, multi-select độc lập IsActive). Backfill `WHERE IsActive=1 SET 1` giữ behavior cũ. Designer +badge "Cho user chọn" + button Ghim/Bỏ ghim. Workspace filter dropdown chỉ workflows `IsUserSelectable=true`. Mig 22-24 V2 schema (Session 17): `ApprovalWorkflows`/Steps/Levels — Quy trình > Bước (Phòng) > Cấp (N NV cụ thể qua ApproverUserId, OR-of-N cùng cấp). PE.ApprovalWorkflowId pin V2. PE.CurrentApprovalLevelOrder track. State machine 5 trạng thái: Nháp / Đã gửi duyệt / Trả lại (Phase riêng TraLai=98) / Từ chối / Đã duyệt. PE Service V2 wire match `actor.Id == ApproverUserId`. Contract V2 ĐÃ WIRE (Mig 32+33 Plan B S29 — cookie-cutter mirror PE V2: `ApproveV2Async` + `ContractLevelOpinions` UPSERT + Workspace V2 Select dropdown). Mig 21 V1 flat workflow vẫn live cho phiếu cũ.)
|
||||
- **Hiện có 53 migration → 88 bảng** (+S69: Mig 53 `AddPeUrgentAndCeoApprovalThreshold` — PE +IsUrgentByPro/Ccm cờ gấp PRO/CCM + ApprovalWorkflow +CeoApprovalThreshold ngưỡng CCM duyệt-final, 3 AddColumn no new table. +S65: Mig 51 `AddDepartmentParentId` Department.ParentId loose-Guid no-FK org-tree phân cấp + Mig 52 `AddHoSoLinkToPurchaseEvaluation` PE HoSoLink nvarchar(1000) hyperlink NAS — cả 2 AddColumn no new table, tables giữ 88. Phase 10 COMPLETE + Phase 11 P11-A→F done — Mig 34-42 HRM/Office/WorkflowApps/Attendance + Contract V2 (32-33) + WireWorkflowApps V2 (41) + LeaveBalance (42) + Holiday filtered-unique (43, S45) + Vehicle/Driver catalog (44, S51) + HRM-catalog filtered-unique 3× (45, S51) + ItTicket SLA (46, S52) + Master filtered-unique 3× (47, S53 gotcha #57 EXT) + Project master fields Year/Investor/Location/Package (48, S55 — AddColumn no new table, kèm nạp 62 dự án + 71 hạng mục + 3 NCC real data từ Excel qua `SeedRealMasterDataAsync` ungated idempotent) + PE gắn Hạng mục công việc WorkItemId loose-Guid KHÔNG FK vật lý (49, S57bis — AddColumn+CreateIndex, no new table) + **Mig 50 `ReplaceBudgetModuleWithPeWorkItemBudgets` (S61, 2026-06-13) — XÓA module Budget cũ, thay bằng `PeWorkItemBudgets` ngân sách per-gói-thầu (1 record/cặp Dự án × Hạng mục, nhập theo role PRO/CCM, vượt ngân sách = cảnh báo mềm cho lưu S62); backfill `BudgetManualAmount→BudgetPeriodAmount` TRƯỚC DropColumn (phiếu UAT giữ số); net bảng 93→88; gotcha #63/#64**. V2 schema history S29-era bên dưới giữ nguyên — Mig 32+33 Plan B Contract V2 cookie-cutter mirror PE Mig 22-26 (S29). Mig 26 `AddPeLevelOpinionsForV2`: bảng mới `PurchaseEvaluationLevelOpinions` UNIQUE composite (PEId, LevelId), FK Cascade Pe + Restrict Level. Section 5 "Ý kiến cấp duyệt" V2 dynamic theo workflow đã pin: forEach Step (Phòng) → forEach Level (Cấp) → forEach NV → 1 OpinionBox. Service `ApproveV2Async` UPSERT auto khi NV duyệt — Q1=1B (sync gắn với Duyệt, KHÔNG form input rời). SignedByUserId track signer thật, FE banner "Admin duyệt thay" khi !== ApproverUserId. Comment empty → "(duyệt — không ý kiến)" placeholder. Phiếu V1 legacy fallback Mig 15 4 box readOnly (data history). Mig 25 `AddIsUserSelectableToApprovalWorkflows`: ALTER `ApprovalWorkflows` +`IsUserSelectable bit` (admin pin/unpin workflow nào cho user pick lúc create phiếu, multi-select độc lập IsActive). Backfill `WHERE IsActive=1 SET 1` giữ behavior cũ. Designer +badge "Cho user chọn" + button Ghim/Bỏ ghim. Workspace filter dropdown chỉ workflows `IsUserSelectable=true`. Mig 22-24 V2 schema (Session 17): `ApprovalWorkflows`/Steps/Levels — Quy trình > Bước (Phòng) > Cấp (N NV cụ thể qua ApproverUserId, OR-of-N cùng cấp). PE.ApprovalWorkflowId pin V2. PE.CurrentApprovalLevelOrder track. State machine 5 trạng thái: Nháp / Đã gửi duyệt / Trả lại (Phase riêng TraLai=98) / Từ chối / Đã duyệt. PE Service V2 wire match `actor.Id == ApproverUserId`. Contract V2 ĐÃ WIRE (Mig 32+33 Plan B S29 — cookie-cutter mirror PE V2: `ApproveV2Async` + `ContractLevelOpinions` UPSERT + Workspace V2 Select dropdown). Mig 21 V1 flat workflow vẫn live cho phiếu cũ.)
|
||||
|
||||
### Modules
|
||||
|
||||
| Module | Namespace | Migration | Trạng thái |
|
||||
|---|---|---|---|
|
||||
| Contract (HĐ) | `Domain/Contracts/` | 1-11 | Feature-complete (7 ContractType × 9 phase) |
|
||||
| PurchaseEvaluation (Duyệt NCC tiền-HĐ) | `Domain/PurchaseEvaluations/` | 12,13,15,49,50,52 | Feature-complete — +Hạng mục (Mig 49) +ngân sách per-gói-thầu role PRO/CCM (Mig 50, vượt=cảnh báo mềm S62) +**Link hồ sơ NAS hyperlink (Mig 52, S65)**. Export PDF pending |
|
||||
| PurchaseEvaluation (Duyệt NCC tiền-HĐ) | `Domain/PurchaseEvaluations/` | 12,13,15,49,50,52,53 | Feature-complete — +Hạng mục (Mig 49) +ngân sách per-gói-thầu role PRO/CCM (Mig 50) +Link hồ sơ NAS (Mig 52) +**cờ gấp PRO/CCM + CCM duyệt-final theo ngưỡng giá trị (Mig 53, S69)**. Export PDF pending |
|
||||
| ~~Budget (Ngân sách dự án)~~ | — | 14 → **Mig 50 DROP** | ⚠️ **REMOVED S61** — module Budget cũ XÓA, thay bằng PE-budget-per-gói-thầu (`PeWorkItemBudgets`). FE pages/types/menu `Bg_*` gỡ hết |
|
||||
| Master (Supplier/Project/Department) | `Domain/Master/` | 2, 10 | Feature-complete |
|
||||
| Identity (User/Role/Permission/MenuItem) | `Domain/Identity/` | 1, 3, 11 | Feature-complete (30 demo user — 16 sample + 14 Solutions thật) |
|
||||
| Forms (Template + Clause) | `Domain/Forms/` | 4 | Feature-complete |
|
||||
| Notifications | `Domain/Notifications/` | 6 | In-app + SignalR OK, email SMTP TODO |
|
||||
| **Tests** | `tests/SolutionErp.{Domain,Infrastructure}.Tests/` | — | **286 test pass** (45 Domain + 241 Infra) — CI gate + path filter docs-only skip |
|
||||
| **Tests** | `tests/SolutionErp.{Domain,Infrastructure}.Tests/` | — | **306 test pass** (45 Domain + 261 Infra) — CI gate + path filter docs-only skip |
|
||||
|
||||
### Commit convention
|
||||
|
||||
@ -130,7 +130,7 @@ Quy tắc:
|
||||
| [`docs/database/database-guide.md`](docs/database/database-guide.md) | DB conventions + migration workflow + cheatsheet |
|
||||
| [`docs/database/schema-diagram.md`](docs/database/schema-diagram.md) | ⭐ ERD + luồng DB + data flow 88 table (+ §11 PE + §12 ~~Budget~~ DROP + §13 PEDeptOpinions + §14 Contract V2 LevelOpinions; §16+ Mig 32-52 pending) |
|
||||
| [`docs/flows/README.md`](docs/flows/README.md) | Index 6 flow (auth, permission, contract, form, SLA) |
|
||||
| [`docs/gotchas.md`](docs/gotchas.md) | ⭐ 65 bẫy đã gặp — đọc trước khi debug tương tự |
|
||||
| [`docs/gotchas.md`](docs/gotchas.md) | ⭐ 68 bẫy đã gặp — đọc trước khi debug tương tự |
|
||||
| [`.claude/skills/`](.claude/skills/README.md) | 6 skill: contract-workflow, form-engine, permission-matrix, dependency-audit-erp, ef-core-migration, iis-deploy-runbook |
|
||||
| [`docs/guides/vps-setup.md`](docs/guides/vps-setup.md) | ⭐ Master runbook deploy VPS shared với VIETREPORT |
|
||||
|
||||
|
||||
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,52 @@
|
||||
# S69 (2026-06-17) — Văn phòng số (E-Office) port + golive + PE cờ gấp/ngưỡng CCM
|
||||
|
||||
> 4 deploy prod-verified Run #305→#308. HMW-mode ON, 2 workflow fan-out (`office-puro-foundation` 5-agent + `office-puro-reskin-all` 8-agent) + nhiều spawn lẻ. Buổi sản phẩm CỰC LỚN.
|
||||
|
||||
**Anh: `/session-start` → "port Văn phòng số giống PURO NamGroup, CSS giống Hồ sơ NS" `/ultra-on` → (foundation) → "làm hết đi, PE golive rồi giờ còn Văn phòng số" (re-skin all) → "public Văn phòng số cho all user" (golive) → [screenshot Zalo anh Kiệt FDC: cờ gấp + CCM duyệt-final theo ngưỡng + chuyển phiếu→dự án] → "publish + session-end".**
|
||||
|
||||
---
|
||||
|
||||
## #305 `a8bbdae` — Văn phòng số foundation (workflow 5-agent)
|
||||
- **Phát hiện then chốt:** SE ĐÃ CÓ module Office với feature map 1:1 PURO (Danh bạ/Phòng họp/Đề xuất/Đơn từ/Đặt xe/Ticket) → đây là **re-layout + re-skin**, không phải build mới. Anh chốt 2 nhánh: "Nền tảng trước" + "Giữ menu SE (không phẳng-hoá sidebar)".
|
||||
- **Foundation:** sync `fe-admin/src/index.css` ← fe-user (đóng drift S66-S68: heading 600→700, ink #0f172a→#0b1220, label-eyebrow slate→brand-600 + gotcha #66 rule) → 2 app đồng bộ. + 3 shared component `PageHeader`/`KpiCard`/`WidgetCard` (×2 SHA256, tái dùng token Hồ sơ NS) + `OfficeDashboardPage` 2-cột widget kiểu PURO HomePage (reuse data hooks Đề xuất/Đơn từ/Ticket/Phòng họp, đếm client-side, no BE) + menu key `Off_Dashboard` (no-mig idempotent seed dưới Off, giữ ẩn).
|
||||
- **gotcha #67 NEW:** em main fix `KpiCard` activeBorder `-300`→`-500` — accent palette (teal/violet/amberx/greenx) chỉ ship 50/100/500/600/700; `-300` trên teal/violet rơi DEFAULT Tailwind (sai-hệ), amberx/greenx drop hẳn. Build PASS cả 2 → reviewer soi dist CSS mới bắt.
|
||||
- cicd Run #305: bundle admin `Bl2o_kUq`/user `BImrKQNn`, Off_Dashboard seeded, Office still hidden (admin-only).
|
||||
|
||||
## #306 `c556f6c` — re-skin TRỌN 10 page (workflow 7 designer song song + reviewer)
|
||||
- **Phẫu thuật trình bày, giữ 100% logic:** Đề xuất(List/Create/Detail) + Đơn từ/Đặt xe(List/Detail) + Ticket CNTT + Danh bạ + Phòng họp(Calendar/Rooms) + Báo cáo CC(fe-admin) → PURO layout (PageHeader + KpiCard-filter row + card-accent) + CSS Hồ sơ NS. reviewer verify **mọi `api.*`/`queryKey` byte-identical HEAD vs working tree** (logic preserved).
|
||||
- **Cơ chế chống parallel-build-interference:** 7 designer ghi SONG SONG fe-user → **cấm chạy npm build** (project cấm worktree do Windows MAX_PATH) → em main **build-tập-trung 1 lần** + mirror SHA256 sang fe-admin (9 page identical@HEAD verify trước cp) + build fe-admin.
|
||||
- **gotcha #68 NEW:** harness bắn loạt diagnostic `× unused/Element` sau workflow — đều STALE mid-edit snapshot; build sau-cùng exit 0 cả 2 app. Bài học: agent nền → chỉ tin build SẠCH sau-cùng, bỏ qua diagnostic giữa-chừng.
|
||||
- cicd Run #306: bundle admin `Wt54PHYl`/user `B99fMU6X`, 6 Office SPA route 200, Office vẫn ẩn.
|
||||
|
||||
## #307 `1f8947e` — Office golive public (+6 test)
|
||||
- Anh: "public Văn phòng số cho all user eoffice". `SeedAllRolesOfficeModulePermissionsAsync` grant **read+create 16-key allow-list mọi role** (mirror đúng S65 HRM `SeedAllRolesHrmProfileReadPermissionsAsync` — chạy SAU `RevokeTemporarilyHiddenModulesAsync` để THẮNG; upgrade-only nâng false→true).
|
||||
- **Allow-list 16:** Off + Dashboard + DanhBa + PhongHop(View/Book) + DeXuat(List/Create/Inbox) + DonTu(Leave/Ot/Travel) + DatXe + ItTicket.
|
||||
- **Excluded (giữ ẩn):** Off_PhongHop_Manage (admin CRUD phòng) + Off_AttendanceReport (báo cáo riêng-tư) + Off_ChamCong (Cá nhân, golive riêng). HRM (trừ Hồ sơ NS) + Personal VẪN ẩn.
|
||||
- **reviewer PASS security** (2 finding load-bearing): (1) cascade-safe — `Off` KHÔNG phải inherit-root trong GetMyMenuTree (chỉ Contracts/Workflows/PE/PeWf) → excluded-3 giữ false không lan; (2) no write-path opened — Office controller dùng class-`[Authorize]` self-service + per-action `[Authorize(Roles=Admin)]` cho admin-write → CanCreate chỉ mở menu+nút, API authz độc lập menu-key.
|
||||
- **+6 test** `OfficeModulePermissionSeedTests`. cicd **DB-verify sqlcmd: 16/16 allow-list read+create=1 × 13 role**, excluded-3 = 0, HRM/Personal vẫn 0, admin không hạ. Bundle BE-only frozen.
|
||||
|
||||
## #308 `ebd7e1c` — PE cờ gấp PRO/CCM + CCM duyệt-final theo ngưỡng (Mig 53, anh Kiệt FDC, +14 test)
|
||||
- Yêu cầu anh Kiệt sau họp sếp (screenshot Zalo). Anh chốt 4 quyết định (AskUserQuestion): ngưỡng cấu-hình-được · giá-trị = winnerQuoteTotal · cờ gấp visibility-only · nhận diện CCM/CEO theo role.
|
||||
- **B — CCM duyệt-final theo ngưỡng giá trị:** ApprovalWorkflow +`CeoApprovalThreshold` (decimal? admin nhập Designer, **null = luồng tuyến tính cũ → rollout an toàn** dark-launch). `ApproveV2Async`: actor role `CostControl` (CCM) + `winnerQuoteTotal` (tổng ThanhTien NCC được chọn) < ngưỡng → `DaDuyet` luôn, bỏ CEO (guard chưa-ở-slot-cuối). Vai PRO=Procurement, CCM=CostControl, CEO=Director (mapping qua AppRoles).
|
||||
- **A — cờ gấp per-vai (visibility-only):** PE +`IsUrgentByPro`(đỏ)/`IsUrgentByCcm`(xanh). Endpoint `PUT /purchase-evaluations/{id}/urgent` role-gated (Procurement→ByPro, CostControl→ByCcm, Admin→cả 2, khác→Forbidden) + notify CEO (Director) qua `INotificationService.NotifyManyAsync` khi MỚI bật (best-effort try/catch). Q3: KHÔNG đổi luồng.
|
||||
- **FE ×2:** Workflow Designer ô "Ngưỡng giá trị gói CEO" (fe-admin) + PE detail cờ gấp toggle/badge theo role + hint "giá trị gói vs ngưỡng → CCM duyệt-final/cần CEO" + PE list badge.
|
||||
- **+14 test:** `PeCcmThresholdFinalizeTests` 5 (load-bearing: CCM dưới ngưỡng → DaDuyet skip CEO; ≥ ngưỡng → lên CEO; null → linear; non-CCM → không finalize) + `PeUrgentToggleAuthzTests` 9. reviewer PASS security (cascade-safe + no-write-path). cicd Run #308: Mig 53 applied (3 cột, sys.tables=88), endpoint /urgent 401-not-404, bundle admin `BgNCjwsG`/user `CBvh0vtf`.
|
||||
- **C (sau duyệt → chuyển phiếu đến dự án):** anh Kiệt "sẽ làm chi tiết với em để lên form" → DEFERRED, chờ spec.
|
||||
|
||||
---
|
||||
|
||||
## §L AUTO-MAINTAIN
|
||||
- **AS scan / RCA:** 2 truncation #53 (impl-backend truncate giữa fix positional-record DTO → em main fix 2 CS7036 + tự viết endpoint cờ gấp agent chưa kịp; impl-frontend truncate → em main verify-complete-on-disk). 0 production-bug (cả 2 build PASS sau-cùng). Class quen #53 — recover-disk + self-gate, không cần RCA mới.
|
||||
- **gotcha NEW ×2:** #67 (Tailwind accent palette thiếu-stop vỡ-màu-im-lặng) · #68 (stale-diagnostic-background-agent → chỉ tin build sau-cùng). → `feedback_stale_diagnostic_background_agent` (user memory).
|
||||
- **H2 harvest GATE PASS** (1 non-block: PE-CCM-threshold logic test-covered [14 test] not standalone-reviewed — acceptable). 0 corruption/stray/wave. cicd #308 orphan → commit closeout.
|
||||
- **H1 tooling CHỐT:** 0 new skill/plugin/roster (0 new-alloc). Count-flush must-fix: ef-core SKILL Mig 53 + skills/README + dep-audit + root CLAUDE + STATUS + HANDOFF (done closeout). docs/CLAUDE.md full + schema-diagram §16+ = monthly-defer.
|
||||
- **curate-debt P1 (next session):** cicd-monitor **65.2KB** (worst, trend 41→54→56→61→62→65) + inv-codebase 47 + reviewer 43.5 + impl-be 33 over 30KB cap.
|
||||
|
||||
## State THẬT cuối S69
|
||||
**Mig 53 · 88 bảng · 306 test (45D+261I) · 68 gotcha · menu 54 · bundle admin `BgNCjwsG`/user `CBvh0vtf` (Run #308).**
|
||||
|
||||
## 🔴 NEXT
|
||||
- **Anh/anh Kiệt UAT:** (1) cấu hình "Ngưỡng giá trị gói CEO" Workflow Designer + test phiếu < / ≥ ngưỡng; (2) test cờ gấp PRO/CCM → badge + notify CEO; (3) **xác nhận** quy trình đặt CCM(CostControl)-trước-CEO + CEO = role Director (đích notify).
|
||||
- **C** (chuyển phiếu→dự án) chờ anh Kiệt spec form.
|
||||
- **Em:** curate cicd-monitor 65.2KB P1 · doc-flush docs/CLAUDE.md full + schema-diagram §16+ Mig 32-53 (monthly 2026-07-01).
|
||||
- **Ops của anh (giữ S58/S59):** tzutil VPS · anh Chương email typo · 5 real staff password · gán CNTT lock nv.cao/nv.truong.
|
||||
@ -1176,6 +1176,34 @@ for h in resp.points: # ← .points không phải iterable trực tiếp
|
||||
|
||||
---
|
||||
|
||||
### 67. Tailwind v4 — accent palette tự-chế thiếu stop (chỉ 50/100/500/600/700) → dùng `-300` "vỡ màu im lặng": tên-trùng-built-in rơi DEFAULT, tên-tự-chế drop hẳn; build PASS (Session 69)
|
||||
|
||||
**Triệu chứng:** Component `KpiCard` tái dùng có `activeBorder: 'border-{accent}-300'` cho 5 accent. Build PASS 0 error, nhưng active-border render SAI: teal/violet ra tone teal/violet MẶC ĐỊNH Tailwind (khác hệ custom #0ea5a4...), amberx/greenx KHÔNG có border (class drop). brand-300 OK (brand full 50-900).
|
||||
|
||||
**Cơ chế:** `@theme` SE định nghĩa accent palette (teal/violet/amberx/greenx) CHỈ ship `50/100/500/600/700` (brand ngoại lệ full). Tailwind v4: `border-teal-300` — `teal` TRÙNG tên built-in → emit DEFAULT teal-300 (#5eead4, khác --color-teal-*); `border-amberx-300` — `amberx` TỰ CHẾ không có --color-amberx-300 → class drop, không emit. Cả 2 **build KHÔNG báo lỗi** (Tailwind không validate color tồn tại) → phải SOI dist CSS.
|
||||
|
||||
**Guard:** (1) Component tái dùng accent-aware CHỈ dùng stop trong "hợp đồng chung" mọi accent (50/100/500/600/700) — đừng mượn stop chỉ brand có. (2) Nghi "vỡ màu im lặng" → grep dist CSS class tồn tại + đúng `var(--color-...)`. (3) Tên tự-chế (amberx/greenx) AN TOÀN hơn tên-trùng-built-in (teal/violet): miss = drop hẳn (dễ thấy) thay vì rơi-default-sai-tone (ẩn). (4) reviewer dimension "color-trap" = grep added-lines `(teal|violet|amberx|greenx)-(200|300|400|800|900)`.
|
||||
|
||||
**Credit:** reviewer S69 (soi dist Office foundation) → em main fix `activeBorder -300 → -500` ×2 app SHA256.
|
||||
|
||||
**References:** `fe-{user,admin}/src/components/ui/KpiCard.tsx` ACCENT map · `fe-*/src/index.css` @theme accent stops · gotcha #66.
|
||||
|
||||
---
|
||||
|
||||
### 68. IDE TypeScript diagnostic giữa background-agent/workflow = snapshot DỞ-DANG — chỉ tin build SẠCH chạy SAU agent xong (Session 69)
|
||||
|
||||
**Triệu chứng:** Sau workflow re-skin 7 designer song song (+ sau PE-FE agent), harness bắn loạt `× 'X' is declared but never read` / `× Type 'Element' not assignable`. Em suýt sửa theo. Build `npm run build` chạy SAU → **exit 0, 0 error** cả 2 app. Các × đều FALSE-ALARM.
|
||||
|
||||
**Cơ chế:** IDE TS language-server bắn diagnostic theo TỪNG lần save dở-dang của agent (thêm import/state TRƯỚC khi render JSX dùng nó → "unused"; xóa JSX TRƯỚC khi gỡ import → "unused"). Nhiều agent ghi SONG SONG → snapshot càng nhiễu, KHÔNG phản ánh trạng-thái-cuối nhất-quán nào.
|
||||
|
||||
**Guard:** (1) Agent/workflow NỀN: **bỏ qua diagnostic giữa-chừng**, tín hiệu thật = 1 lần build SẠCH chạy SAU agent hoàn-tất (lý do em main build-tập-trung). (2) Đừng vội sửa/cp-đè theo diagnostic — suýt cp đè file vốn đã hoàn chỉnh (2×). (3) Phân biệt diagnostic ai-edit: em main edit real-time → tin; agent nền edit → verify build trước. (4) Cùng họ gotcha #53 (return truncated): disk + build = source-of-truth, KHÔNG tin return/diagnostic suông.
|
||||
|
||||
**Credit:** em main S69 — 2× suýt sửa theo stale-diagnostic (re-skin + PE-FE), build sau-cùng vạch false-alarm.
|
||||
|
||||
**References:** workflow `office-puro-reskin-all` + PE-FE implementer-frontend · gotcha #53 · gotcha #3.
|
||||
|
||||
---
|
||||
|
||||
## Checklist debug bug mới
|
||||
|
||||
1. Build pass không? → fail → check using + package version compat
|
||||
|
||||
Reference in New Issue
Block a user