Commit Graph

11 Commits

Author SHA1 Message Date
30a99aa03f [CLAUDE] Hrm: P11-C Vehicle+Driver catalogs (Mig 44) + gotcha #57 filtered-unique 3 HRM catalog (Mig 45)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m18s
P11-C: extend HrmConfigs +2 kind (Vehicle/Driver) declarative. Mig 44 AddVehicleAndDriverCatalogs (2 table filtered-unique Code, tables 91->93). Domain entity + EF config (filtered day-1) + 2 DbSet + HrmConfigFeatures Region5/6 CRUD + Controller +2 route-group (GET public / write Roles=Admin) + MenuKeys +2 +All (auto Admin perm) + DbInitializer 2 menu leaf + idempotent seed 2 veh/2 drv. FE declarative KIND_CONFIG +2 kind x2 app (SHA256 mirror) + 4-place (types/page/menuKeys/Layout staticMap), :kind-driven no new route.

gotcha #57 (bundled; OtPolicy missed in backlog, caught via grep) - Mig 45 FilterHrmCatalogUniqueIndexesByIsDeleted: LeaveType+ShiftPattern+OtPolicy bare .IsUnique() -> .HasFilter([IsDeleted]=0) (recreate-on-soft-deleted-slot 500 fix, mirror Holiday Mig 43). Tests +5 HrmConfigFilteredUniqueTests (181->186 PASS) test-before RED->GREEN. Reviewer caught FE<->BE Driver required-field mismatch -> fixed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 10:32:28 +07:00
e54a22de0c [CLAUDE] Domain+App+Infra+Api+FE-Admin+FE-User: S38 G-O4+G-O5+G-O6+G-P1+G-H3 SKELETON full-stack
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m53s
Phase 10.3-10.4 SKELETON 5 plan combo finish — Mig 39+40 + BE skeleton 7 module +
FE 2 app SHA256 IDENTICAL + 11 menu key. UAT visible end-to-end.

⚠️ SKELETON Phase 1 trade-off rõ:
  - Status flat 5-state WorkflowAppStatus enum share Leave/OT/Travel/Vehicle
  - ApproveV2 workflow advance DEFER Phase 11 (Drafter Create OK, Approve flow chưa wire)
  - LevelOpinions per-module DEFER Phase 11
  - LeaveBalance calc + Auto-assign + SLA timer DEFER Phase 11
  - CodeGen atomic + MaDonTu/MaTicket gen DEFER Phase 11
  - Vehicle catalog + Driver catalog DEFER Phase 11 (free text VehicleLicense)
  - ItTicketComments thread DEFER Phase 11 (free text Resolution field)

Mig 39 (em main solo): 5 entity Workflow Apps schema
  - LeaveRequest (G-O4, FK LeaveType Hrm Mig 35, ApplicableType=5)
  - OtRequest (G-O4, FK OtPolicy optional, ApplicableType=6)
  - TravelRequest (G-O4, reuse ApplicableType=4 Proposal)
  - VehicleBooking (G-O5, free text vehicle, ApplicableType=7)
  - ItTicket (G-O6, NO workflow V2 — kanban status flow)

Mig 40 (em main solo): Attendance entity (G-P1)
  - GPS lat/long check-in/out + Source enum Web/Mobile/Device
  - UNIQUE composite (UserId, AttendanceDate)
  - WorkHours computed simple diff (NO OtPolicy multiplier yet)

BE CQRS (em main solo, single mega ~1100 LOC):
  - WorkflowAppsFeatures.cs 7 region (5 module Create+List + Attendance CheckIn/Out/GetMonth + HrDashboard)
  - 7 Controller: /api/leave-requests + /ot-requests + /travel-requests + /vehicle-bookings + /it-tickets + /attendances + /hr/dashboard
  - Class-level [Authorize] any authenticated
  - 13 endpoint total

FE 2 app (em main solo fallback gotcha #53 risk):
  - types/workflowApps.ts × 2 SHA256 IDENTICAL 77470e182a15de88 (all DTOs + Status badge)
  - WorkflowAppsListPage.tsx × 2 IDENTICAL 58139d0301a60ddf — generic declarative KIND_CONFIG handles 4 module (Leave/OT/Travel/Vehicle)
  - ItTicketsPage.tsx × 2 IDENTICAL d3062de2f54c794c — kanban 5 status column
  - MyAttendancePage.tsx × 2 IDENTICAL 86da48ae147db012 — GPS check-in/out + tháng calendar
  - HrmDashboardPage.tsx × 2 IDENTICAL d9c6c12a5a8694f8 — 4 KPI card + gender ratio + status breakdown
  - Pattern 16-bis 9× cumulative (App.tsx +4 routes + menuKeys +8 const + Layout staticMap +7 entry)
  - 7 amber banner "Skeleton Phase 1 — full feature Phase 11" rõ ràng UAT

Menu seed: +11 const + SeedMenuTreeAsync 8 row (Off_DonTu sub-group + 3 leaf + Off_DatXe + Off_ItTicket + Off_ChamCong + Hrm_Dashboard).
DbInitializer Sample workflow seed DEFER (workflows V2 already seeded từ S29+S37 reuse — admin clone tạo riêng per ApplicableType=5/6/7).

Verify:
- dotnet build PASS 0 error 2 pre-existing warning
- dotnet test 130/130 PASS baseline preserve
- npm build × 2 PASS clean
- SHA256 verify 5 file × 2 app all IDENTICAL

Plan G-* progress 11/11  (100% COMPLETE):
   G-H1 (S33) + G-O1 (S34) + G-H2 (S35) + G-O2 (S36) + G-O3 (S37) +
   G-O4 + G-O5 + G-O6 + G-P1 + G-H3 (S38 skeleton)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 16:19:42 +07:00
de1c378279 [CLAUDE] Domain+App+Infra+Api+FE-Admin+FE-User: S37 Mig 37 enum + Plan G-O3 Đề xuất full-stack
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m53s
Phase 10.3 G-O3 Đề xuất (Proposal) — Mig 37 enum extend +5 values + Mig 38
Proposal schema + BE CQRS 8 endpoint + FE 2 app SHA256 IDENTICAL.

Mig 37 (em main solo): extend ApprovalWorkflowApplicableType enum +5 values
  ProposalGeneral=4 / LeaveRequest=5 / OtRequest=6 / VehicleBooking=7 / ItTicket=8
  cookie-cutter Mig 22 pattern (Up/Down empty — enum mức Domain).

Mig 38 (em main solo): 4 entity Proposal (Code DX/YYYY/NNN) + ProposalAttachment
  + ProposalLevelOpinion (UNIQUE composite PEId+LevelId mirror PE Mig 26) +
  ProposalCodeSequence (Prefix PK atomic seq). 4 EF Config + 2 DbContext mod.

BE CQRS (em main solo ~700 LOC ProposalFeatures.cs sau Implementer truncate phase
exploration gotcha #53 5th + 529 Overload):
  - 4 Header handler (List paged + GetById detail + Create + UpdateDraft owner-OR-admin)
  - 4 Workflow handler (Submit gen MaDeXuat atomic + Approve UPSERT LevelOpinion advance + Reject + Return)
  - SERIALIZABLE transaction CodeGen
  - DTOs nested LevelOpinion với Step+Level metadata JOIN

ProposalsController 8 endpoint /api/proposals (List/GetById/Create/Update/Submit/Approve/Reject/Return)
class-level [Authorize] + handler-level owner-OR-admin guard.

DbInitializer: SeedSampleProposalWorkflowV2Async ~40 LOC seed QT-DX-V2-001 IsUserSelectable=true
NOT gated DemoSeed per gotcha #51. SeedMenuTreeAsync +4 row (Off_DeXuat sub-group + 3 leaf).

FE 2 app (em main solo + Implementer 529 fail fallback):
  - types/proposal.ts × 2 SHA256 IDENTICAL 95607052ff1138f2
  - ProposalsListPage.tsx × 2 IDENTICAL 603f0d9cf74cd09a — table 6 cột + Status badge + filter
  - ProposalCreatePage.tsx × 2 IDENTICAL 6aed3a76563dd576 — Form Header card
  - ProposalDetailPage.tsx × 2 IDENTICAL 3dc229ea8dcc9bc0 — 3 Section + WorkflowActions
  - Pattern 16-bis 8× cumulative (App.tsx + menuKeys + Layout staticMap 3 entry)

Verify:
- dotnet build PASS 0 error 2 warning pre-existing DocxRenderer
- dotnet test 130/130 PASS baseline preserve
- npm build × 2 PASS (fe-admin 14.72s + fe-user 6.40s)
- SHA256 verify 4 file × 2 app all IDENTICAL

Pattern reinforced cumulative S37:
- Pattern 12-bis cross-module mirror 11× (PE V2 → Proposal V2 ApproveV2)
- Pattern 16-bis 4-place mirror cross-app 8×
- gotcha #53 5th occurrence Implementer mid-exploration truncation + 529 Overload 1× — em main solo fallback proven

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 15:51:14 +07:00
f45090b654 [CLAUDE] Domain+App+Infra+Api+FE-Admin+FE-User: S36 Plan G-O2 Phòng họp Mig 36 + BE CRUD + FE 2 app
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m55s
Phase 10.2 G-O2 Phòng họp BookingCalendar — Mig 36 schema + BE CQRS + FE 2 app
mirror cookie-cutter G-H2 HrmConfig pattern. Standalone không depend workflow.

BE schema (Mig 36 — em main solo Step 4):
- 4 Domain new: MeetingRoom catalog + MeetingBooking header + MeetingBookingAttendee
  join table N-to-N (NOT JSON per Investigator verdict) + Enums (MeetingBookingStatus
  3-state: Confirmed/Cancelled/Completed)
- 3 EF Config: UNIQUE Code + composite index (RoomId, StartAt) range query + UNIQUE
  composite (BookingId, UserId) join
- FK strategy: Room→Restrict (preserve history) + Booking→Cascade attendees +
  User→Restrict (denorm FullName+Email tránh cascade wipe)
- Mig 36 3-file rule + ApplicationDbContextModelSnapshot updated + apply Dev+Design DB

BE CQRS (~584 LOC — Implementer Case 2):
- MeetingFeatures.cs 479 LOC 9 handler: 4 Room CRUD + 5 Booking (List + GetById +
  Create + Update + Cancel)
- SERIALIZABLE transaction overlap check via EXISTS query — throw 409 Conflict
  "Phòng đã được đặt trong khoảng thời gian này"
- MeetingRoomsController 49 LOC + MeetingBookingsController 56 LOC — class-level
  [Authorize] + Roles="Admin" for write
- Application.csproj +Microsoft.EntityFrameworkCore.Relational package (em main fix
  IsolationLevel overload — Implementer gotcha #53 4th truncation diagnose mid-task)
- MenuKeys.cs +4 const (Off_PhongHop sub-group + View/Manage/Book leaf)
- DbInitializer +SeedMeetingRoomsAsync 4 sample (PH-A Phòng họp lớn cap=20 + PH-B
  cap=8 + PHG-501 Giám đốc cap=6 + ONL-1 Online Zoom cap=50) — NOT gated DemoSeed
  per gotcha #51 INFRASTRUCTURE seed

FE 2 app (~1770 LOC × 2 — Implementer Case 2):
- types/meeting.ts × 2 SHA256 IDENTICAL (ce0ad9c6d017cde2) — DTO interface mirror
- MeetingCalendarPage.tsx × 2 SHA256 IDENTICAL (d6d160ae1e4f2285) ~530 LOC — custom
  HTML 7-day grid 8h-20h slot, NO FullCalendar dep (~80 KB bundle saved per
  Investigator verdict alternative)
- MeetingRoomsPage.tsx × 2 SHA256 IDENTICAL (ba35a7ef379a5e9c) ~270 LOC — admin
  catalog CRUD table + Dialog
- 4-place mirror Pattern 16-bis 7× cumulative: types + page + App.tsx route +
  menuKeys + Layout staticMap 3 entry (gotcha #50 silent sidebar drop prevention)

Verify:
- dotnet build SolutionErp.slnx PASS 0 error 2 pre-existing DocxRenderer warning
- dotnet test 130/130 PASS baseline preserve (58 Domain + 72 Infra)
- npm build × 2 app PASS 0 TS error (fe-admin 16.91s bundle 1490 KB / fe-user 8.56s
  bundle 1404 KB, +23 KB gzip both)

Pattern reinforced cumulative S36:
- Pattern 12-bis cross-module mirror 10× (PE → Contract V2 → Hrm → Office)
- Pattern 16-bis 4-place mirror cross-app 7×
- Smart Friend Implementer truncation gotcha #53 4th — mitigation tight brief WORK
  (FE 2 app no truncation, BE truncate diagnose mid only)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 15:06:12 +07:00
07b3f3b284 [CLAUDE] Domain+App+Infra+FE-Admin+FE-User: S34 Plan 4 G-H2 Mig 35 schema foundation
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m30s
Phase 10.2 G-H2 Cấu hình HRM — 4 catalog lookup foundation deploy (BE CRUD +
FE forms DEFER S35 cho clean handoff).

Mig 35 `AddHrmConfigs` — 4 table mới:
- LeaveTypes (Code unique + Name + DaysPerYear decimal(5,2) + IsPaid +
  RequiresAttachment) — 5 sample seed (ANNUAL 12d + SICK 30d + MATERNITY 180d
  + COMPASSIONATE 3d + UNPAID 0d)
- Holidays (Year + Date UNIQUE composite + Name + IsRecurring + IsPaid) —
  10 sample VN 2026 (Tết Dương + 5 Tết Nguyên đán placeholder + Giỗ tổ +
  30/4 + 1/5 + 2/9 + Quốc khánh)
- ShiftPatterns (Code unique + Name + StartTime/EndTime TimeOnly + BreakMinutes +
  WorkDays comma string) — 3 sample (HC 8-17 T2-T6 + CA1 6-14 T2-T7 + CA2 14-22)
- OtPolicies (Code unique + 3 Multiplier decimal(4,2) + 3 MaxHours int) —
  1 sample STANDARD (1.5x/2.0x/3.0x weekday/weekend/holiday + 4h/40h/200h cap
  Luật Lao động VN 2019)

Files:
- Domain/Hrm/{LeaveType,Holiday,ShiftPattern,OtPolicy}.cs (4 entity AuditableEntity)
- Infrastructure/Persistence/Configurations/{LeaveType,Holiday,ShiftPattern,OtPolicy}Configuration.cs (4 EF Config UNIQUE indexes)
- IApplicationDbContext + ApplicationDbContext +4 DbSet
- Migrations/20260527075940_AddHrmConfigs.{cs,Designer.cs} + Snapshot updated (3-file rule)
- DbInitializer.SeedHrmConfigsAsync ~120 LOC seed sample (NOT gated DemoSeed per gotcha #51)
- MenuKeys.cs +HrmConfig sub-group + 4 leaf (LeaveTypes/Holidays/Shifts/OtPolicies) Order=2 dưới Hrm
- DbInitializer.SeedMenuTreeAsync +5 entry (sub-group + 4 leaf)
- fe-admin + fe-user menuKeys.ts +5 const mirror BE (Pattern 16-bis sync)

Verify:
- dotnet build PASS (2 warn DocxRenderer baseline, 0 error)
- dotnet test 130/130 PASS baseline preserve
- Mig 35 applied LocalDB SolutionErp_Dev — verified via dotnet ef database update
- 4 catalog table created + 5+10+3+1 = 19 sample row seed

Defer S35:
- Task 2 BE CQRS 4 catalog CRUD (16 endpoint) — Implementer Case 2 cookie-cutter
- Task 4 FE 2 app 4 catalog page (list/create/edit dialog) — Implementer Case 2

Cumulative S34 mig: 34 → 35 (+1). Tables 67 → 71 (+4). Menu keys 64 → 69 (+5).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 15:04:10 +07:00
61e9ce5b3b [CLAUDE] Domain+App+Api+Tests+FE-Admin+FE-User: S34 Plan 3 Phase 1.5 batch 4 item
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m48s
Phase 1.5 backlog G-H1 EmployeeProfile hardening batch (Items 6+2+1+4 of 6).

Item 6 — menuKeys FE drift sync × 2 app:
- fe-admin add: Catalogs + 4 Catalog leaves + Workflows + Budgets + Bg_List/Create/Pending (10 key)
- fe-user add: Budgets + Bg_List/Create/Pending + ApprovalWorkflowsV2 + 2 AwV2 leaf + MenuVisibility + Workflows (8 key)
- Cả 2 file giờ identical mirror BE MenuKeys.cs (28 key cumulative)

Item 2 — UpdateEmployeeProfileCommand bool→bool? safe partial update:
- 3 field IsCommunistParty/IsYouthUnion/IsTradeUnion → bool?
- Handler: HasValue check, null = giữ giá trị cũ (Reviewer minor #(b) S33 fixed)
- FE không bắt buộc gửi 3 field every PUT — tránh accidental reset

Item 1 — EmployeesController per-action policy (gotcha #44 mitigation):
- Class-level [Authorize(Policy = "Hrm_HoSo.Read")] — non-admin thiếu Read → 403
- POST [Authorize(Policy = "Hrm_HoSo.Create")]
- PUT  [Authorize(Policy = "Hrm_HoSo.Update")]
- DELETE [Authorize(Policy = "Hrm_HoSo.Delete")]

Item 4 — Test bundle Phase 1.5 (+10 [Fact], baseline 120 → 130/130 PASS):
- EmployeeCodeGeneratorTests (3 [Fact]) — atomic SERIALIZABLE NV/YYYY/NNNN
  + first call + sequential increment + year boundary preserve old year
- CreateEmployeeProfileCommandTests (4 [Fact]) — Create handler edge case
  + first profile + duplicate UserId Conflict + soft-deleted Conflict-restore
  + UserNotFound NotFoundException
- ListEmployeesQueryTests (3 [Fact]) — filter + paging logic
  + status filter + departmentId filter + search by EmployeeCode partial

Implementer Case 3 test gen caught spec mismatch (allow new after soft-delete
vs throws Conflict-restore) — chose CODE source of truth + renamed test
documenting discriminator message branch. Em main verify behavior correct
(admin UX khôi phục thay vì tạo mới — explicit flow defer Phase 1.5+).

Verify:
- dotnet build PASS (2 warn DocxRenderer baseline, 0 error)
- dotnet test 130/130 PASS (58 Domain + 72 Infra = +10)
- 4 endpoint /api/employees policy wired (gotcha #44 active mitigation)
- 4 MEMORY agent updated post-spawn (CICD Run #238 + Implementer test bundle)

Deferred Phase 1.5 next batch:
- Item 3 Satellite CRUD endpoints (WorkHistory/Education/FamilyRelation/Skill/
  Document) + FE inline edit forms — heavy ~2-3h
- Item 5 UAT smoke non-admin role verify silent 403 catch — defer post-deploy

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 13:57:08 +07:00
ea440da990 [CLAUDE] Domain+App+Api+Infra+FE-Admin+FE-User: S34 Plan 2 G-O1 Danh bạ nội bộ
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m46s
Phase 10.2 Văn phòng số — Internal Directory (1 endpoint reuse Users +
EmployeeProfiles + Departments, FE card grid avatar/dept/email/phone/Ext).

BE Task 1+2 (em main solo):
- Application/Office/DirectoryFeatures.cs — GetDirectoryQuery + DirectoryItemDto
  12 field LEFT JOIN Users.IsActive + Departments + EmployeeProfiles
- Api/Controllers/DirectoryController.cs — GET /api/directory?search=&departmentId=
  class-level [Authorize] (mọi authenticated NV tra cứu danh bạ nội bộ)
- MenuKeys.cs +Off+OffDanhBa const + All[] update
- DbInitializer.SeedMenuTreeAsync Off Order=29 + OffDanhBa Order=1 dưới Off

FE Task 3 (Implementer Case 2 Pattern 16-bis 4-place mirror cross-app — 5×):
- types/directory.ts SHA256 7349d9f64e78 × 2 app IDENTICAL
- pages/office/InternalDirectoryPage.tsx SHA256 2aa7e0eed2c8 × 2 app IDENTICAL
  Card grid responsive 1/2/3/4 col + filter dept dropdown + search input
  Avatar 14×14 initials gradient PALETTE 6 màu (Pattern 14 Tailwind JIT)
  EmployeeCode badge + Department emerald badge + email mailto + phone tel
  Internal phone Ext: amber badge + empty/loading state Vietnamese 100%
- App.tsx route /directory × 2 app
- lib/menuKeys.ts Off+OffDanhBa const × 2 app
- components/Layout.tsx resolvePath staticMap Off_DanhBa:/directory × 2 app
  (gotcha #50 — 5 places mirror crossapp DON'T MISS)

Verify:
- dotnet build PASS (2 warn DocxRenderer existing, 0 error)
- dotnet test 120/120 PASS (58 Domain + 62 Infra baseline preserve)
- npm build × 2 app PASS 0 TS err (fe-admin 1436KB / fe-user 1350KB)

Implementer MEMORY Pattern 16-bis reinforced 5× cumulative (S29 Plan CA HF1 +
S29 Plan B Chunk D + S33 Plan B G-H1 Task 5 + S34 Plan G-O1 Task 3).

Endpoint smoke pending CICD post-deploy Stage 4 (Run #XXX expected ~3m30s).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 13:39:10 +07:00
9616ae219c [CLAUDE] FE-Admin+FE-User: Plan B G-H1 Task 5 — EmployeesPage 2-panel + EmployeeCreatePage cookie-cutter mirror
Phase 10.1 G-H1 Phase 2 Task 5 — FE 2 app cookie-cutter mirror PE pattern.
Phase 1 ULTRA-MINIMAL scope (Implementer afdc812 scaffold):
- 2-panel ListPage (filter left + list+detail right, KHÔNG 3-panel vì Hrm
  no workflow)
- 6-section inline collapsible detail (Cơ bản/Công tác/Đào tạo/Thân nhân/
  Kỹ năng/Hồ sơ) — NO separate DetailTabs component file
- CreatePage Header form minimal (UserId picker + Status + DateOfBirth +
  Gender + Phone + HireDate + Nationality)
- Display read-only Phase 1 satellite (no inline edit — defer Phase 1.5)

## Files (6 new + 6 modified × 2 app = 12)

### NEW (3 × 2 app, SHA256 IDENTICAL cross-app mirror)

| File | LOC | SHA256 prefix |
|------|----:|---|
| `fe-{admin,user}/src/types/employee.ts` | 283 | CCFC70666568 |
| `fe-{admin,user}/src/pages/hrm/EmployeesListPage.tsx` | 417 | DC859C897C5C |
| `fe-{admin,user}/src/pages/hrm/EmployeeCreatePage.tsx` | 178 | C796F25D01AC |

10 const-object enum mirror BE Domain.Hrm.Enums + DTOs:
- EmployeeStatus/Gender/MaritalStatus/EmployeeType/DegreeLevel/
  EducationMode/GradeLevel/FamilyRelationKind/SkillKind/EmployeeDocumentType
- EmployeeListItem + EmployeeDetail + 5 satellite DTO type

### MODIFIED (3 × 2 app)

- `fe-{admin,user}/src/lib/menuKeys.ts` — +Hrm + HrmHoSo const
- `fe-{admin,user}/src/components/Layout.tsx` — +Hrm_HoSo:'/employees' staticMap
  (LESSON Plan CA Hotfix 1 gotcha #50: page route mới phải thêm staticMap
  entry cùng commit, else silent sidebar drop)
- `fe-{admin,user}/src/App.tsx` — +2 route /employees + /employees/new

## Pattern reinforcement

- **Pattern 16-bis 4-place mirror cross-app** reinforced 4× cumulative (S29
  Plan CA HF1 + S29 Plan B Chunk D + S33 Task 5 admin + S33 Task 5 user).
  Comment header trong Layout.tsx ghi explicit Plan CA Hotfix 1 #50 lesson.
- **Pattern 12-bis cross-module entity FE port PE → Hrm** reinforced 4× (Plan
  B Chunk C Mig 33 + G-H1 Task 4 BE + Task 5 FE types mirror PE types/page
  structure mirror PE 2-panel scope-down 3→2 panel).

## Reviewer ae752c0 verdict: PASS (commit 0e191de earlier)

- Smart Friend 6× cumulative clean (em main + Implementer quality genuine)
- gotcha #50 Layout staticMap mirror ✓ (cả fe-admin + fe-user)
- menuKeys.ts FE drift pre-existing intentional (fe-admin minimal vs fe-user
  expanded Catalogs/Suppliers/Projects/Departments) — NOT blocking, follow-up
  task add Budgets/Catalogs to fe-admin OR document intentional minimal scope.

## Verify

- fe-admin npm build: PASS 21.4s · 0 TS6 err · 1,431 KB bundle
- fe-user npm build: PASS 9.2s · 0 TS6 err · 1,345 KB bundle
- dotnet build: PASS 1.59s · 0 warn 0 err (no BE change)
- dotnet test: 120/120 PASS baseline preserved

## Defer Phase 1.5 (per Reviewer recommend)

1. PermissionGuard wrapper menuKey HrmHoSo + per-action Hrm_HoSo_View/Create
2. Convert 3 bool field UpdateCommand thành bool? safe partial update
3. Satellite CRUD endpoint + form (WorkHistory/Education/FamilyRelation/
   Skill/Document)
4. Test bundle (Create UNIQUE conflict + List filter + codeGen race)
5. Add Bg_*/Catalog* to fe-admin menuKeys.ts sync với fe-user

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 20:27:25 +07:00
06a441cf4e [CLAUDE] FE-User: Plan CA Chunk B — Move 4 master pages từ fe-admin → fe-user
- Copy SuppliersPage/ProjectsPage/DepartmentsPage/CatalogsPage (948 LOC mirror)
- Extend menuKeys.ts với 5 key Catalogs* (CatalogUnits/Materials/Services/WorkItems)
- Add 7 route App.tsx (/master/suppliers + /master/projects + /master/departments + 4 catalogs tab)
- fe-user component parity verified (DataTable, PageHeader, PermissionGuard, 6 shadcn ui)

Verify:
- fe-user npm run build PASS 0 TS err (1916 modules, 14.14s)
- 4 file SHA256 byte-identical mirror fe-admin (all 4 hash match)
- 0 BE touch (Chunk A em main solo parallel)

Pending Chunk C: sidebar filter 2 app (fe-admin HIDE 9 menu, fe-user SHOW)
Pending Chunk D: smoke verify + role demo user

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 10:56:11 +07:00
a737196b21 [CLAUDE] FE-Admin+FE-User: PurchaseEvaluation pages (3-panel list + tabs detail)
Types + pages + components cho module Duyệt NCC ở cả 2 FE (copy-share).

Pages:
 - PurchaseEvaluationsListPage: 3-panel lg:grid-cols-[340px_1fr_360px]
   * Panel 1: list filter theo type/phase/search + pendingMe inbox mode
   * Panel 2: PeDetailTabs (Thông tin/NCC/Hạng mục/Duyệt/Lịch sử)
   * Panel 3: PeWorkflowPanel với timeline + nextPhase buttons
   * Mobile fallback fullpage /purchase-evaluations/:id
 - PurchaseEvaluationCreatePage: form create/edit header (Type / Tên gói thầu
   / Dự án / Địa điểm / Mô tả / PaymentTerms JSON). Suppliers+Details+Quotes
   thêm sau khi save ở Detail tabs.

Components:
 - PeDetailTabs: 5 tab + dialogs (AddSupplier/EditSupplier/DetailDialog/
   QuoteDialog) + matrix N NCC × M hạng mục clickable cells + select winner
 - PeWorkflowPanel: policy timeline từ BE workflow.activePhases + transition
   confirmation dialog với comment

Routes (cả 2 app):
 - /purchase-evaluations (+ ?type=1|2&pendingMe=1&id=...)
 - /purchase-evaluations/new (+ ?type / ?id để edit)
 - /purchase-evaluations/:id (mobile fullpage)

Menu resolver:
 - Pe_<Code>_List → /purchase-evaluations?type=N
 - Pe_<Code>_Create → /purchase-evaluations/new?type=N
 - Pe_<Code>_Pending → /purchase-evaluations?type=N&pendingMe=1
 - PeWf_<Code> (fe-admin only) → /system/pe-workflows/<code>

Skip MVP: PE Workflow admin designer UI, PE Attachments. TS build pass
cả 2 app.
2026-04-23 16:56:26 +07:00
7e957a7654 [CLAUDE] Phase3: Workflow MVP — 9-phase state machine + code gen + FE Inbox/Detail
Backend Contracts domain (5 entities):
- Contract aggregate: Phase (9 enum), SlaDeadline, MaHopDong, BypassProcurementAndCCM, DraftData, SlaWarningSent
- ContractApproval: FromPhase → ToPhase, ApproverUserId (null = system auto-approve), Decision, Comment
- ContractComment: thread theo Phase current
- ContractAttachment: FileName + StoragePath + Purpose (DraftExport/ScannedSigned/SealedCopy)
- ContractCodeSequence: Prefix PK + LastSeq — atomic gen

EF configs:
- Unique MaHopDong filtered [MaHopDong] IS NOT NULL
- Indexes: Phase+IsDeleted, SupplierId, ProjectId, SlaDeadline, ContractId+ApprovedAt, ContractId+CreatedAt
- Cascade delete Approvals/Comments/Attachments khi Contract xoa
- Query filter IsDeleted
- Migration AddContractsWorkflow (DB 19 tables)

Workflow service:
- IContractWorkflowService.TransitionAsync:
  - Adjacency check qua Transitions Dict<(from,to), roles[]> (12 transitions)
  - Role guard: user phai co role ∈ allowed
  - Admin bypass (role Admin pass moi check)
  - System bypass (userId=null + Decision=AutoApprove → cho SLA job sau nay)
  - Bypass CCM: BypassProcurementAndCCM=true cho phep DangInKy → DangTrinhKy skip phase 6
  - Gen ma HD khi chuyen DangDongDau (idempotent — khong gen lai neu da co)
  - Reset SlaDeadline = UtcNow + PhaseSla
  - Insert ContractApproval row

Code generator (RG-001):
- 7 format theo ContractType: HDTP / HDGK / NCC / HDDV / MB + 2 framework (year prefix)
- BeginTransactionAsync(Serializable) + ContractCodeSequences UPSERT → atomic
- Idempotent: neu MaHopDong da co thi skip

CQRS (8 feature, ContractFeatures.cs):
- CreateContractCommand + Validator + Handler (set SlaDeadline = +7d)
- UpdateContractDraftCommand (chi khi Phase=DangSoanThao)
- TransitionContractCommand (delegate → WorkflowService)
- AddCommentCommand (phase = hien tai)
- ListContractsQuery (PagedResult + filter phase/supplier/project/search)
- GetMyInboxQuery (map Phase → actor roles, filter theo role user)
- GetContractQuery (detail + approvals + comments + attachments + resolve user names)
- DeleteContractCommand (soft, block > DangInKy)

Controller:
- ContractsController 8 endpoint: GET list/inbox/detail, POST create/transition/comment, PUT update, DELETE

Frontend fe-admin (2 page moi):
- types/contracts.ts: ContractPhase const + Label + Color maps + types
- components/PhaseBadge.tsx
- pages/contracts/ContractsListPage.tsx: filter phase + search + click → detail
- pages/contracts/ContractDetailPage.tsx: 2-col layout (info+comments | timeline), action dialog select target phase + comment

Frontend fe-user (4 page moi + 14 file shared):
- cp 14 file shared tu fe-admin (menuKeys, types/*, DataTable, PhaseBadge, Dialog, Textarea, Select, apiError, usePermission, PermissionGuard)
- AuthContext update: load menu tu /menus/me + cache
- Layout: menu fixed 3 muc + user info + roles display
- InboxPage: list HD cho role user xu ly (sort theo SLA)
- ContractCreatePage: form chon loai + template + NCC + du an + gia tri + bypass CDT
- ContractDetailPage: duplicate fe-admin pattern (convention)
- MyContractsPage: list HD cua toi
- App.tsx: 4 route moi

E2E verified:
- Setup Supplier + Project
- POST /contracts → 201 + phase=2
- POST /contracts/{id}/transitions x7 → di het 9 phase
- Final: MaHopDong = "FLOCK 01/HĐGK/SOL&PVL2026/01" dung format RG-001
- Approvals: 7 rows audit day du

Docs:
- .claude/skills/contract-workflow/SKILL.md: placeholder → full spec voi state machine, SLA table, role matrix, 7 code format, code pointers, API, E2E workflow, pitfalls
- docs/changelog/sessions/2026-04-21-1330-phase3-workflow.md: session log
- docs/STATUS.md: Phase 3 MVP done, next Phase 4
- docs/HANDOFF.md: update phase status + file tree + commit log + testing points
- docs/changelog/migration-todos.md: tick Phase 3 MVP items + add iteration 2 list

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 12:26:09 +07:00