4edcd588d8f0b37e3c4eea8c7ed5d8df0bd49811
15 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
| 4edcd588d8 |
[CLAUDE] Domain+Infra: User-kind approver runtime guard + Warning 20% SLA
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m41s
## User-kind approver guard
Trước: WorkflowDefinition Designer cho admin pick User cụ thể vào step
approver, nhưng runtime guard bỏ qua (User-kind treat như DeptManager
fallback per skill doc).
Bây giờ: enable đầy đủ. WorkflowPolicy + UserTransitions parallel dict
(default null cho hardcoded Standard/SkipCcm, populated qua
FromDefinition khi WorkflowStepApprover Kind=User).
IsTransitionAllowed signature update: (from, to, actorRoles, actorUserId?)
- Check Role first (existing behavior)
- Fallback User-kind: actorUserId.ToString() có trong UserTransitions[(from,to)]?
ContractWorkflowService.TransitionAsync dùng IsTransitionAllowed thay
inline check. Error message thêm "{N} user explicit" nếu policy có
User-kind approvers cho transition đó.
FromDefinition cũng update: nếu step CHỈ có User-kind (không Role),
không fallback DeptManager nữa — guard sẽ check user-level. Chỉ
fallback DeptManager nếu step thiếu cả 2.
## Warning 20% SLA
SlaExpiryJob.ProcessWarningsAsync mới — chạy trước ProcessAsync
(auto-approve quá hạn):
- Pull Contracts WHERE !SlaWarningSent && SlaDeadline > now &&
Phase NOT IN (DaPhatHanh, TuChoi, DangDongDau)
- Per phase, threshold = 20% × default SLA (vd Soạn thảo 7 ngày → 33.6h
remaining trigger warning; In ký 1 ngày → 4.8h)
- Compute remaining = SlaDeadline - now; nếu remaining <= threshold
+ còn slot → notify Drafter via INotificationService
- Set SlaWarningSent = true để chỉ warning 1 lần per phase (reset trong
TransitionAsync khi chuyển phase mới)
- NotificationType.SlaWarning (đã có trong enum) + title icon ⚠
## Build
dotnet build BE pass (0 error)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 330d529c92 |
[CLAUDE] Domain+App+Infra: Role ShortName + User Department/Position + 13 demo users (migration 11)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m53s
User feedback: chi tiết hóa Users/Phòng ban + gán roles. Roles label tiếng Việt có Mã (ShortName) + Tên đầy đủ (Description). ## Entity changes ### Role (Domain/Identity/Role.cs) + ShortName (max 50) — Mã viết tắt VN: QTV/BOD/CCM/PRO/FIN/... + Description (đã có) — Tên đầy đủ VN - Identity Name = code English giữ nguyên (FK + [Authorize] attr) ### User (Domain/Identity/User.cs) + DepartmentId Guid? FK Departments (Restrict — không xóa dept nếu user reference) + Position string? max 200 — chức vụ free text ## Migration 11: AddRoleShortNameAndUserDepartment 3-file rule. Apply LocalDB OK. DB total: 36 tables (không tăng — chỉ thêm cột vào existing). ## Seed VN labels (12 roles) | Code | ShortName | Description | |---|---|---| | Admin | QTV | Quản trị viên hệ thống | | Drafter | NV.PB | Nhân viên phòng ban (soạn thảo HĐ) | | DeptManager | TPB | Trưởng phòng ban | | ProjectManager | PM | Giám đốc dự án | | Procurement | PRO | Phòng Cung ứng | | CostControl | CCM | Phòng Kiểm soát chi phí | | Finance | FIN | Phòng Tài chính | | Accounting | ACT | Phòng Kế toán | | Equipment | EQU | Phòng Thiết bị | | Director | BOD | Ban Giám đốc | | AuthorizedSigner | NĐUQ | Người được Ủy quyền ký HĐ | | HrAdmin | HRA | Phòng Nhân sự - Hành chính | SeedRolesAsync idempotent + backfill (existing role thiếu ShortName/ Description → update). ## Seed 13 demo users Default password: User@123456 (warn log để rotate prod). Coverage full org chart: - bod.huynh (Tổng GĐ — Director, BOD dept) - bod.le (Phó GĐ NĐUQ — AuthorizedSigner, BOD dept) - pm.nguyen (PM FLOCK 01 — ProjectManager, PM dept) - ccm.tran (TPB CCM — CostControl + DeptManager, CCM dept) - pro.pham (TPB PRO — Procurement + DeptManager, PRO dept) - fin.do, act.vu, equ.bui, hra.dang (TPB respective dept) - qs.hoang, qs.ngo (Drafter — QS dept) - nv.cao, nv.dinh (Drafter — PRO/FIN dept) Idempotent (skip nếu email đã tồn tại). ## DTOs + Commands updated - RoleDto + ShortName field - UserDto + DepartmentId/DepartmentName/Position - CreateUserCommand + DepartmentId/Position params (defaults null) - UpdateUserCommand + DepartmentId/Position - ListUsersQueryHandler load dept names denormalize per page - UpdateUserCommandHandler set UpdatedAt ## Note FE updates (UsersPage dept dropdown + role label VN) ở commit kế tiếp. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| e27c54702a |
[CLAUDE] Domain+App+Api: 4 master catalogs cho Details (migration 10)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m48s
User feedback: thêm Master Data cho phần Chi tiết (line items) — autocomplete khi user nhập field thay vì gõ tay free text. ## 4 entities mới (Domain/Master/Catalogs/) | Entity | Bảng | Dùng cho HĐ Detail | |---|---|---| | UnitOfMeasure | UnitsOfMeasure | Tất cả 7 type (DonViTinh) | | MaterialItem | MaterialItems | NCC + Mua bán + Nguyên tắc NCC (MaSP/TenSP) | | ServiceItem | ServiceItems | Dịch vụ + Nguyên tắc DV (MaDichVu/TenDichVu) | | WorkItem | WorkItems | Thầu phụ + Giao khoán (HangMuc/MaCongViec) | Common pattern: Code unique (filter IsDeleted=0) + Name + Category + DefaultUnit + AuditableEntity (soft delete) + IsActive flag. ## Migration 10: AddMasterCatalogs 3-file rule (gotcha #17). Total DB: 32 → 36 tables. Apply LocalDB OK. ## Seed defaults (idempotent — skip per-table nếu có row) - 20 UnitsOfMeasure: m2, m3, kg, tấn, lít, ngc (ngày công), giờ, gói, ... - 15 MaterialItems demo: xi măng PCB40, cát vàng, đá 1x2, thép D10, gạch 4 lỗ, sơn lót, ống PVC... - 10 ServiceItems demo: vận chuyển, bảo trì, tư vấn, kiểm định, vệ sinh... - 15 WorkItems demo: đào móng, đổ bê tông, xây tường, trát, lát gạch, sơn nước, lắp điện, lắp nước, thấm chống... ## CQRS (Application/Master/Catalogs/CatalogsFeatures.cs ~290 dòng) Mỗi catalog 5 handlers (List filter q+category, Create với unique code guard, Update, Delete soft). FluentValidation max length per spec EF. ## Controller (Api/Controllers/CatalogsController.cs) 13 endpoints: - GET /api/catalogs/{units|materials|services|work-items} - POST /api/catalogs/{kind} (Admin role) - PUT /api/catalogs/{kind}/{id} (Admin role) - DELETE /api/catalogs/{kind}/{id} (Admin role) Read open cho mọi role (FE Details add form autocomplete cần list). ## Menu (5 mới) - Catalogs (group, Master parent, order 24, "Library" icon) - CatalogUnits "Đơn vị tính" (Ruler) - CatalogMaterials "Vật tư / SP" (Package) - CatalogServices "Dịch vụ" (Wrench) - CatalogWorkItems "Hạng mục công việc" (ListChecks) Admin auto-grant tất cả CRUD action (qua SeedAdminPermissionsAsync loop MenuKeys.All). ## Build dotnet build BE pass (0 error) ## Note FE admin page CatalogsPage + datalist autocomplete trong Details form sẽ ở commit kế tiếp. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 70810e1b34 |
[CLAUDE] Domain+Infra: 7 ContractType-specific Details + ContractChangelog (migration 9)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m37s
User decision: Option B — bảng riêng cho mỗi loại HĐ (chuẩn nhất, schema
chuyên biệt). Plus: ContractChangelog audit log thống nhất Header /
Detail / Workflow / Comment / Attachment.
## 8 entities mới
### Details (7) — Domain/Contracts/Details/
| Bảng | Loại HĐ | Field đặc trưng |
|---|---|---|
| ThauPhuDetails | 1 (Thầu phụ) | HangMuc, KhoiLuong, DonGia, ThoiGianHoanThanh |
| GiaoKhoanDetails | 2 (Giao khoán) | MaCongViec, KhoiLuong, YeuCauKyThuat |
| NhaCungCapDetails | 3 (NCC) | MaSP, ThongSoKyThuat, SoLuong, ThoiGianGiao, XuatXu |
| DichVuDetails | 4 (Dịch vụ) | MaDichVu, ThoiGian, TuNgay/DenNgay |
| MuaBanDetails | 5 (Mua bán) | MaSP, SoLuong, DonGia, ThueVAT (%), XuatXu |
| NguyenTacNccDetails | 6 (Nguyên tắc NCC) | NhomSP, DonGiaToiThieu/ToiDa, DieuKienGiaoHang |
| NguyenTacDvDetails | 7 (Nguyên tắc DV) | LoaiDichVu, DonGiaToiThieu/ToiDa, PhamViDichVu, SLA |
Common base `ContractDetailBase`: ContractId FK + Order + ThanhTien
decimal(18,2) + GhiChu nvarchar(1000) + audit (BaseEntity).
### ContractChangelog (1) — Domain/Contracts/
Unified audit log. Khác ContractApprovals (workflow-only, dùng cho guard
logic) — Changelog là VIEW LAYER cho user đọc lịch sử thao tác:
- EntityType enum: Contract | Detail | Workflow | Comment | Attachment
- Action enum: Insert | Update | Delete | Transition
- PhaseAtChange snapshot
- UserId + UserName denormalize (log readable)
- Summary human-readable + FieldChangesJson [{Field, Old, New}]
- ContextNote (comment kèm theo)
## EF Configurations
ContractDetailsConfiguration.cs (1 file gộp 7 IEntityTypeConfiguration):
- ToTable + HasMaxLength + HasPrecision per type
- HasOne(Contract).WithMany(<TypeDetails>) cascade delete
- IX (ContractId, Order) cho load timeline
ContractChangelogConfiguration.cs:
- Cascade delete khi Contract xóa
- IX (ContractId, CreatedAt) timeline + IX (ContractId, EntityType) filter
## DbContext + IApplicationDbContext
+ 8 DbSet mới (7 Details + ContractChangelogs).
## Migration 9: AddContractDetailsAndChangelog
3-file rule (gotcha #17): .cs + .Designer.cs + ApplicationDbContextModel
Snapshot.cs đầy đủ. Applied LocalDB SolutionErp_Dev OK — 24 + 8 = 32 bảng
total.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| f216169039 |
[CLAUDE] FE-Admin+Domain+Infra+App: Workflows tab → sidebar menu items
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m37s
User request: 7 tab trong /system/workflows thành menu items riêng. Domain: - MenuKeys.WorkflowTypeLeaf(code) helper — `Wf_<TypeCode>` pattern Infrastructure (DbInitializer): - Seed 7 leaves dưới Workflows group (order 95..101), label matches ContractType (HĐ Thầu phụ / Giao khoán / NCC / Dịch vụ / Mua bán / Nguyên tắc NCC / Nguyên tắc Dịch vụ). Idempotent. Application (GetMyMenuTreeQuery): - Generalized inherit-perm logic: descendants of Contracts AND Workflows inherit parent CanRead flag. Single Workflows.Read grant → all 7 Wf_* leaves visible; no per-leaf permission rows needed. FE Layout (admin): - resolvePath: Wf_<Code> → /system/workflows/<code>. Ct_* still hidden on admin side. FE App.tsx: - New route /system/workflows/:typeCode? FE WorkflowsPage: - Removed horizontal tab bar; type selection now comes từ URL param. - Landing view (no param): 3-col grid card per type với active version badge — so admin có visual overview khi click top-level Workflows group without selecting a type. - TYPE_CODE_TO_INT map drives URL→int conversion. Result: click `Quy trình HĐ > HĐ Mua bán` trong sidebar → opens /system/workflows/MuaBan directly với designer scoped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| e7e5f2d066 |
[CLAUDE] Domain+Infra+App+Api+FE-Admin: versioned workflow per ContractType
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Failing after 1m32s
User yêu cầu: mỗi loại HĐ có quy trình riêng với admin add roles + users vào từng bước. Khi tạo version mới → HĐ tương lai chạy theo, HĐ cũ giữ version cũ. Domain: - WorkflowDefinition (Code + Version + ContractType + IsActive + Steps) - WorkflowStep (Order + Phase + Name + SlaDays + Approvers) - WorkflowStepApprover (Kind: Role/User + AssignmentValue) - Contract.WorkflowDefinitionId — pinned at creation - WorkflowPolicyRegistry.FromDefinition() — build runtime policy từ DB Infrastructure: - EF config + migration AddVersionedWorkflows (3 table mới) - DbInitializer.SeedWorkflowDefinitionsAsync: v01 per 7 ContractType, steps sinh từ hardcoded WorkflowPolicies (Role approvers). - ContractWorkflowService.TransitionAsync: load pinned WorkflowDefinition → FromDefinition(), fallback cho HĐ cũ không có pin. Application: - CreateContractCommand pin WorkflowDefinitionId = active version cho type - ContractFeatures.Get(id): load pinned def cho workflow summary - WorkflowAdminFeatures: GetWorkflowAdminOverviewQuery (7 types + active + history + ContractsUsingCount), CreateWorkflowDefinitionCommand (validate payload, auto-increment version, deactivate old). Api: - GET /api/workflows trả overview - POST /api/workflows tạo version mới (deactivate old) FE /system/workflows: - Tabs per 7 ContractType, mỗi tab hiện active version + lịch sử - DefinitionCard: steps với badge role/user + SLA + archived indicator hiện "N HĐ còn chạy" cho version cũ - WorkflowDesigner modal: form code/name/desc + danh sách steps (phase/name/SLA) + approvers (+ Role hoặc + User). Drop step ok. Clone từ version hiện tại để tạo v02 có điểm start sensible. - Amber banner: HĐ cũ không bị ảnh hưởng khi tạo version mới Invariants được giữ: - Unique (Code, Version) index - Chỉ 1 version IsActive per ContractType tại 1 thời điểm - Set default sẽ auto xóa override → respect legacy override table - Role-kind approvers drive transition guards; User-kind fallback DeptManager role cho v1 (user-level targeting = iteration 2) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 5e0f3801a1 |
[CLAUDE] Move nested-type menu → fe-user; Admin workflow config page
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m41s
User clarified: menu loại HĐ 3-level (Danh sách/Thao tác/Duyệt) thuộc
fe-user. Admin có page riêng để config quy trình per loại HĐ.
fe-admin Layout:
- filterForAdmin() drops Ct_* entries (hide nested type menu).
- Admin sidebar giờ về lại đơn giản: Dashboard / Master / Hợp đồng
(leaf) / Forms / Reports / System.
fe-user Layout:
- Dynamic menu tree từ /menus/me (thay fixed USER_MENU hardcoded).
- Recursive MenuNodeRenderer (top-level expanded, nested collapsed).
- resolvePath user-specific: Ct_*_List → /my-contracts?type=X,
Ct_*_Create → /contracts/new?type=X, Ct_*_Pending → /inbox?type=X.
- filterForUser drops admin-only entries (Master/System/Forms/Reports).
- Static USER_FIXED_TOP prepends "Hộp thư" leaf → /inbox.
- MyContractsPage + InboxPage đọc ?type=X param, filter client-side.
Workflow config (Admin side):
- Domain: WorkflowTypeAssignment entity (ContractType → PolicyName
override). Registry.ForContractWithOverrides() prefer DB override
else default.
- Infrastructure: EF config + migration AddWorkflowTypeAssignments,
unique index trên ContractType. ContractWorkflowService load
overrides dict mỗi transition. ContractFeatures load overrides khi
build WorkflowSummaryDto.
- Application: GetWorkflowAdminOverviewQuery returns 7 types × current
policy + available policies. SetWorkflowAssignmentCommand validate
policy name tồn tại; nếu = default thì delete override (no stale row).
- Api: GET /api/workflows + PUT /api/workflows/{contractType}
với policy "Workflows.Read" + "Workflows.Update".
- Menu: new key `Workflows` dưới System, label "Quy trình HĐ".
- FE /system/workflows: 7 card per type, dropdown Standard/SkipCcm +
'Đã override' badge khi khác default, phase sequence timeline,
explanation banner ở top. Iteration 2 note: admin-authored custom
policies.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 48e91fe7ca |
[CLAUDE] Domain+Infra+App+FE-Admin: per-ContractType nested sidebar menu
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m48s
User request: mỗi loại HĐ có menu riêng với 3 action Danh sách / Thao tác / Duyệt. Sidebar giờ 3-level under "Hợp đồng": Hợp đồng (group, expandable) ├── HĐ Thầu phụ (sub-group) │ ├── Danh sách → /contracts?type=1 │ ├── Thao tác → /contracts/new?type=1 │ └── Duyệt → /contracts?type=1&pendingMe=1 ├── HĐ Giao khoán (sub-group) ├── HĐ NCC / Dịch vụ / Mua bán / Nguyên tắc NCC / Nguyên tắc DV └── ... (7 types × 4 = 28 new menu items) BE: - MenuKeys.cs: ContractTypeCodes array + helpers ContractTypeGroup/ List/Create/Pending → key format Ct_<TypeCode>[_<Action>] - DbInitializer.SeedMenuTreeAsync: loop seeds 28 entries under Contracts - GetMyMenuTreeQuery.BuildChildren: descendants of `Contracts` inherit parent permission (avoid adding 28 rows to Permissions table per role) FE: - Layout.tsx recursive: MenuNodeRenderer dispatches group vs leaf by depth; nested groups collapsed by default (top-level expanded). Deeper levels get smaller padding/text + left border guide. - Pattern-based resolvePath: Ct_<Type>_<Action> → URL with query. - Contract type code → int map (matches Domain ContractType enum). - ContractsListPage reads ?type + ?pendingMe, filters client-side. Header title + description reflect active filter. "← Tất cả loại" quick-reset button. - ContractCreatePage new cho admin (copy từ fe-user), pre-select type từ ?type URL param. - App.tsx route /contracts/new → ContractCreatePage. Pure navigation UX; no new permissions needed. Admin + any role with Contracts.Read see full menu; leaves click-through to filtered views. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| cae4d84830 |
[CLAUDE] Domain+Infra+App+FE: dynamic workflow policy per ContractType
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m42s
Đọc QT-TP-NCC.docx: quy trình 9 bước chỉ áp dụng cho Thầu phụ/NCC/Tổ đội.
Dịch vụ/Mua bán/Nguyên tắc bypass CCM. Thay hardcoded dict bằng policy
registry.
Domain — WorkflowPolicy.cs:
- Record WorkflowPolicy { Name, Description, Transitions, PhaseSla,
ActivePhases } — pure data, testable.
- WorkflowPolicies.Standard: 9-phase full (Thầu phụ/Giao khoán/NCC)
- WorkflowPolicies.SkipCcm: 7-phase (Dịch vụ/Mua bán/Nguyên tắc)
- WorkflowPolicyRegistry.For(type) map ContractType → policy
- WorkflowPolicyRegistry.ForContract(c) override nếu BypassProcurement
AndCCM=true (instance-level escape hatch)
Infrastructure — ContractWorkflowService:
- Xóa hardcoded Transitions/PhaseSla dicts → load từ policy.ForContract
- TransitionAsync: validate qua policy.Transitions thay vì dict local
- Error message include policy.Name để debug dễ hơn
- GetPhaseSla trả SLA từ Standard policy (fallback — SLA hiện tại giống
nhau giữa 2 policy)
Application — ContractDetailDto:
- Field mới `Workflow: WorkflowSummaryDto { PolicyName, Description,
ActivePhases, NextPhases }` — FE dùng để render nút chuyển phase
dynamic + timeline card.
- BuildWorkflowSummary helper trong ContractFeatures.
FE (both apps):
- Type WorkflowSummary + ContractDetail.workflow
- ContractDetailPage xóa hardcoded NEXT_PHASES — dùng
c.workflow.nextPhases từ BE (single source of truth)
- WorkflowSummaryCard: timeline của ActivePhases với check/current/
future states + policy name/description ở header
- Card hiển thị trong sidebar, phía trên "Lịch sử duyệt"
Docs:
- gotchas.md #21 marked RESOLVED (NEXT_PHASES sync không còn cần)
Foundation: sau này admin có thể edit policy qua UI khi chuyển sang DB-
backed policy — nhưng API contract (WorkflowSummaryDto) đã stable.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 49c0ddc8f4 |
[CLAUDE] App+Domain+Infra+Api+FE: Notifications module end-to-end
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m43s
Domain: - Notification entity + NotificationType enum (stable ints) - Nullable RefId cho correlation (contract, user, ...) Infrastructure: - NotificationConfiguration: bảng Notifications, index theo (UserId, ReadAt) - NotificationService: ghi vào DbContext, không SaveChanges (để caller quyết định unit-of-work — đảm bảo atomic với domain mutation) - EF migration AddNotifications Application: - INotificationService (Notify + NotifyMany) - CQRS: ListMyNotifications / GetMyUnreadCount / MarkRead / MarkAllRead Api: - NotificationsController: GET /api/notifications + unread-count + mark-read Integration: - ContractWorkflowService emit notification tới Drafter khi HĐ chuyển phase (skip nếu actor chính là Drafter). Title + type theo phase đích: DaPhatHanh → ContractPublished, TuChoi → ContractRejected, khác → ContractPhaseTransition. FE: - Both NotificationBell (admin + user) dùng /api/notifications thật (thay cho derived-from-inbox MVP trước đó). 30s refetch, click mark-read, 'Đọc hết' bulk action. Foundation sẵn cho SignalR push + email outbox sau này — chỉ cần mở rộng NotificationService mà không đổi caller. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 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>
|
|||
| 5113e4c771 |
[CLAUDE] Phase2: Form Engine MVP + docs (gotchas, skill, handoff)
Backend Forms:
- Domain/Forms: ContractTemplate (FormCode, Name, ContractType, FileName, StoragePath, Format, FieldSpec JSON, IsActive) + ContractClause
- EF config voi unique FormCode + query filter IsDeleted
- DbSets + IApplicationDbContext update
- Migration AddForms (bang 14 total)
- Packages: DocumentFormat.OpenXml 3.x + ClosedXML 0.105+
- Application/Forms:
- IFormRenderer interface + RenderResult record
- FormFeatures.cs: List/Get/Render CQRS
- IWebHostEnvironmentLocator (abstract IWebHostEnvironment)
- Infrastructure/Forms:
- DocxRenderer: OpenXml-based placeholder {{field}} replace, handle split runs (gom text tat ca <w:t> trong paragraph, replace, gan lai text dau + clear rest)
- XlsxRenderer: ClosedXML cell value replace
- FormRenderer router theo format docx/xlsx
- Api:
- FormsController: GET /templates (filter type, onlyActive), GET /templates/{id}, POST /templates/{id}/render (return file)
- WebHostEnvironmentLocator impl
- DbInitializer SeedContractTemplatesAsync: seed 8 template metadata, IsActive=true chi khi file ton tai
Templates vat ly:
- Copy 5 .docx/.xlsx tu FORM/ sang wwwroot/templates/
- 3 .doc (FO-002.02/03/06) chua convert: IsActive=false (Word COM bi stuck luc test, can retry voi DisplayAlerts=0 hoac LibreOffice)
- scripts/convert-doc-to-docx.ps1 (Word COM automation)
Frontend fe-admin:
- types/forms.ts: ContractTemplate + ContractTypeLabel
- pages/forms/FormsPage.tsx: list templates + Render dialog (paste JSON data → download .docx/.xlsx)
- Route /forms them vao App.tsx
Bug fix:
- SpaceProcessingModeValues namespace: wrap EnumValue<> full path
- SaveAs2($path, 16) thay vi SaveAs([ref], [ref]) — PowerShell type issue
- Word COM stuck: kill process, skip .doc cho MVP
Docs (theo yeu cau user):
- docs/gotchas.md MOI: 17 pitfalls nhom theo tech stack / EF Core / OpenXml / JSON / dev workflow
- .claude/skills/form-engine/SKILL.md: placeholder → full spec (algorithm + code pointers + API + limitations)
- .claude/skills/permission-matrix/SKILL.md: placeholder → full spec (BE policy + FE guard + seed + pitfalls)
- docs/HANDOFF.md MOI: brief 5 phut cho session sau (run quickstart + where we are + next steps + file tree + gotchas ref)
- docs/STATUS.md: update cumulative stats + next up Phase 3
- docs/changelog/migration-todos.md: tick Phase 2 iteration 1 items + add iteration 2 list
- docs/changelog/sessions/2026-04-21-1200-phase2-form-engine.md: session log
- CLAUDE.md root: them reference den gotchas + HANDOFF
E2E verified:
- GET /api/forms/templates (onlyActive=false) → 8 templates
- POST /api/forms/templates/{FO-002.05}/render voi data dict → HTTP 200 + file .docx 482KB (Microsoft Word 2007+ OK)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 54d6c9ba52 |
[CLAUDE] Phase1.2: CRUD Master + Permission Matrix + FE admin pages
Backend:
- Domain/Master: Supplier (+ SupplierType 5 loai), Project, Department (AuditableEntity)
- Domain/Identity: MenuItem, Permission, MenuKeys const (12 menu)
- EF Configurations voi unique Code + query filter IsDeleted
- DbSets + IApplicationDbContext interface update
- Application: PagedResult + PagedRequest generic
- Application/Master CQRS CRUD 3 entity (Create/Update/Delete/Get/List voi paging search sort)
- Application/Permissions: GetMyMenuTree (union OR role, filter tree), ListMenuItems, ListPermissionsByRole, UpsertPermission (guard admin khong tu giam quyen), ListRoles
- Api/Authorization: MenuPermissionRequirement + Handler (Admin bypass, query DB)
- Program.cs: register 48 policy {menu}.{action} tu MenuKeys x Actions
- Api/Controllers: Suppliers, Projects, Departments, Menus, Roles, Permissions
- DbInitializer: seed 12 menu + admin full CRUD permissions
- Migration AddMasterData + AddPermissions
Frontend (fe-admin):
- Types: menuKeys.ts const, menu.ts (MenuNode/Role/Permission), master.ts (Supplier/Project/Department + SupplierType const-object)
- AuthContext: load menu from /menus/me, cache localStorage, refreshMenu()
- usePermission hook + PermissionGuard component (wrap button)
- UI kit them: Dialog (modal overlay), Textarea, Select
- Generic: DataTable (column config, sortable, loading, empty) + Pagination
- PageHeader component
- apiError helper extract message tu ProblemDetails
- Layout rewrite: render menu dong tu AuthContext.menu (MenuGroup collapsible + NavLink + lucide icon map)
- Pages: master/Suppliers, master/Projects, master/Departments (CRUD + search + sort + paging + Dialog form)
- Page system/Permissions: ma tran Role x MenuKey x CRUD checkbox (tick tu dong PUT upsert)
- App.tsx them 4 route moi
Bug fix:
- MenuPermissionHandler: EF expression tree khong support switch expression -> tach switch ra ngoai AnyAsync
- TS erasableSyntaxOnly khong cho enum -> SupplierType const-object pattern (typeof[keyof])
E2E verified via Vite proxy:
- GET /menus/me -> 6 root + 6 child nodes (12 menus)
- GET /roles -> 12 roles
- POST/GET/PUT/DELETE /suppliers -> full CRUD, soft delete OK
- tsc -b fe-admin pass
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
|||
| 702411fcc8 |
[CLAUDE] Phase1: foundation - BE Clean Arch + Identity + JWT + 2 FE React + login E2E
Backend (.NET 10): - Domain: BaseEntity/AuditableEntity, ContractType/Phase/ApprovalDecision enums, User/Role (Identity<Guid>), AppRoles (12 const) - Application: IApplicationDbContext/ICurrentUser/IDateTime/IJwtTokenService, custom exceptions, ValidationBehavior (MediatR pipeline), Auth CQRS (Login/Refresh/Me), DependencyInjection - Infrastructure: ApplicationDbContext (IdentityDbContext), AuditingInterceptor (auto audit + soft delete), DbInitializer (seed 12 role + admin), DesignTimeDbContextFactory, JwtTokenService, DateTimeService, DI - Api: CurrentUserService, GlobalExceptionMiddleware (ProblemDetails), AuthController, Program.cs rewrite (Serilog + JWT + CORS + Swagger), appsettings + launchSettings (port 5443) - Migration Init applied to SolutionErp_Dev LocalDB Frontend (React 19 + Vite 8 + Tailwind 4): - fe-admin (:8082 blue) + fe-user (:8080 emerald) - shared structure, khac menu + brand color - Tailwind 4 via @tailwindcss/vite plugin, theme brand colors - AuthContext (localStorage token), ProtectedRoute, Layout (sidebar + header) - UI kit: Button/Input/Label (CVA + Tailwind) - LoginPage voi toast error, DashboardPage/InboxPage placeholder - Axios interceptor: auto Bearer + 401 redirect - TanStack Query client, React Router 7, Sonner toast Package downgrades (do .NET 10 / TS 6 compat): - MediatR 14 -> 12.4.1 (v14 breaking changes) - Swashbuckle 10 -> 6.9.0 (v10 khong tuong thich OpenApi 2) - Removed Microsoft.AspNetCore.OpenApi (conflict voi Swashbuckle) E2E verified: POST /api/auth/login qua Vite proxy ca 2 FE -> JWT + user info Credentials seed: admin@solutionerp.local / Admin@123456 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
|||
| 25dad7f36f |
[CLAUDE] Scaffold: khoi tao SOLUTION_ERP Phase 0
- .NET 10 Clean Architecture: Domain/Application/Infrastructure/Api (4 project) - 2 React + Vite + TS app: fe-admin (:8082), fe-user (:8080) voi proxy /api - Node engines >=20, .nvmrc = 20 cho CI (bai hoc NamGroup) - SQL Server 2022 qua docker-compose (dev) - Parse 8 FORM -> docs/forms-spec.md (catalog + ma HD format RG-001) - Parse QUY_TRINH -> docs/workflow-contract.md (9 phase state machine + role matrix) - docs: CLAUDE.md, STATUS.md, PROJECT-MAP.md, migration-todos.md (roadmap 5 phase) - .claude/skills: 3 placeholder (contract-workflow, form-engine, permission-matrix) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |