Files
solution-erp/docs/HANDOFF.md
pqhuy1987 7ca6c914fa
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m55s
[CLAUDE] Docs: chốt session 2 — PE skeleton + G-084 + skill audit
User feedback: "phần Duyệt NCC chưa xong đâu đấy nhé, còn chỉnh nhiều"
→ mark PE module skeleton (not feature-complete), liệt kê chi tiết chức
năng/UX/edge-case còn missing cho session tiếp.

Update 7 file:
 - STATUS.md — phase = "PE skeleton + refinement WIP", In Progress liệt
   kê 4 nhóm: A Chức năng MISSING (9 item), B UX/Polish (6 item),
   C Edge case (4 item), D Deploy/Ops (1 item). +G-084 row Recently Done.
 - HANDOFF.md — TL;DR "PE skeleton, còn chỉnh nhiều" + Priority 0 section
   cho session tiếp (9 task PE refinement) + cảnh báo runner + G-084.
 - migration-todos.md — Phase 7 checklist (A/B/C/D nhóm) trước Phase 8
   post-launch. Pending migrations: PaymentTermFields + DepartmentOpinions
   + CodeSequences.
 - architecture.md — Section 9 PurchaseEvaluation module (ERD + workflow
   A/B + kế thừa HĐ flow).
 - CLAUDE.md (root) — 5 file đọc đầu (thêm HANDOFF), Modules table, 12
   migration 46 bảng, +PurchaseEvaluation commit scope.
 - .claude/skills/ — 4 skill cross-ref Phase 6:
   * README: trạng thái updated với Phase 6 note
   * contract-workflow: note PE workflow tách table riêng
   * permission-matrix: +Pe_*/PeWf_* menu keys + TODO grant non-admin
   * ef-core-migration: 12 migration history + Phase 7 pending
 - docs/changelog/sessions/2026-04-23-2359-chot-session-pe-skeleton.md —
   session log full commits + MD files updated + session tiếp priorities
   + notes (PE là skeleton, runner check, G-084 rule, MaPhieu format).
2026-04-23 17:46:41 +07:00

21 KiB
Raw Blame History

HANDOFF — Brief 5 phút cho session tiếp theo

Last updated: 2026-04-23 tối (Phase 6 — PE skeleton + G-084 hardening, PE còn chỉnh nhiều)

TL;DR

PE module skeleton E2E — 2 quy trình A/B config được admin, 10 bảng, 17 endpoint, 3 page × 2 app + kế thừa HĐ 1-click. BE + FE + migration đã push lên Gitea main (2c6f0ca..3990066, 6 commit). **CHƯA XONG — nhiều polish

  • feature thiếu cho session tiếp** (xem STATUS.md §🔥 In Progress đầy đủ).

G-084 hardening: localhost → 127.0.0.1 trong scripts + skill, doc gotcha #33 từ bài học VietReport (IPv4/IPv6 port hijack trên VPS shared).

Tổng: 46 DB tables, ~110 endpoints, 12 migrations, 33 gotchas. Blocker user/ops cũ vẫn còn: UAT thật + SMTP + rotate creds + runner apply.

⚠️ CẢNH BÁO session tiếp

  1. Runner có thể đang stopped sau VPS restart/api/purchase-evaluations vẫn 404. Kiểm tra + start gitea-runner service trước khi test PE endpoint.
  2. PE chỉ là skeleton — user nói "còn chỉnh nhiều". Nhóm A/B/C/D tasks đầy đủ ở STATUS.md §🔥 In Progress.
  3. Chú ý G-084: VPS shared với VietReport — mọi reverse proxy / backend service mới phải dùng 127.0.0.1 + bind loopback IPv4 explicit.

Skills (.claude/skills/) — PHẢI dùng khi task khớp

Domain (3) Ops (3)
contract-workflow — state machine + versioned WF dependency-audit-erp — npm/dotnet CVE scan
form-engine — render docx/xlsx + PDF ef-core-migration — EF migration + 3-file rule
permission-matrix — role × menu × CRUD iis-deploy-runbook — 3 site IIS + win-acme + runner

Audit cron: 0 9 1 * * (9:00 AM ngày 1 mỗi tháng). Workflow: docs/rules.md §9.4. Lần kế: 2026-05-01.

Quy tắc: KHÔNG bulk-clone repo skill 3rd party. Chỉ skill PROJECT-SPECIFIC. Đầy đủ: docs/rules.md §9.

Ở đâu rồi?

Phase Trạng thái
0 Draft Done
1 Alpha Core (foundation + đợt 2 CRUD + Permission) Done
2 Form Engine MVP + iter 2 (upload UI + .doc auto-convert + PDF export) Done
3 Workflow MVP (9 phase + code gen) + iter 2 (SLA job + attachment + notify) Done
4 Report MVP (Dashboard + Excel) + user-specific dashboard Done
5 Prep + 5.1 Security + Users Mgmt Done
5 Deploy prod (3 domain HTTPS live) Done
Tier 3 (Attach + Realtime + Form builder + PDF + Versioned WF + Nested menu + Permission 3-panel) Done
Skill governance (6 skill project-level + audit cron 1/tháng) Done
3-panel List/Inbox/Thao tác + sidebar accordion + UserDashboard Done
4-bảng data model (Header + 7 Details + Workflow + Changelog audit) Done
Mã HĐ gen tại Create + backfill legacy Done
4 master catalogs (Units/Materials/Services/WorkItems) + datalist autocomplete Done
Roles VN labels (ShortName) + Users dept/position + 13 demo users Done
RolesPage CRUD /system/roles + custom role admin Done
7 demo HĐ varied phases + details + comments + approvals workflow Done
User-kind approver runtime guard + Warning 20% SLA Done
Edit detail row inline (7 typed Update commands + EditRowDialog) Done
Master expand 15 NCC + 8 Project + backfill demo HĐ diverse Done
Deps audit script (scripts/deps-audit.ps1) Done
Module Duyệt NCC (tiền-HĐ) E2E — 10 bảng + 2 workflow + Kế thừa HĐ Done
6+ Post-launch (E-signature, Bravo/SAP, Mobile, AI) 📝 Future

Run nhanh

# Terminal 1 — API (auto seed 12 role + 9 dept + 5 supplier + 3 project + 8 template + 7 workflow definition + 28 ContractType menu + 7 workflow menu)
dotnet run --project src\Backend\SolutionErp.Api

# Terminal 2 — Admin FE
cd fe-admin && npm run dev  # → http://localhost:8082

# Terminal 3 — User FE
cd fe-user && npm run dev   # → http://localhost:8080

Login: admin@solutionerp.local / Admin@123456

Quick sanity-check

Admin (:8082):

  • /dashboard → "Của tôi" row 4 card + KPI cards + charts
  • /contracts → list toàn bộ, filter phase/supplier/project
  • /contracts/new?type=5 → tạo HĐ Mua bán, pre-select type từ URL
  • /contracts/{id} → timeline + action dialog + attachments drag-drop + WorkflowSummaryCard
  • /system/workflows → 7-card landing (Thầu phụ/Giao khoán/NCC/Dịch vụ/Mua bán/NguyenTacNcc/NguyenTacDv)
  • /system/workflows/MuaBan → DefinitionCard active + history + "Tạo phiên bản mới" modal với Steps + Approvers (+Role / +User)
  • /system/permissions → 3-panel layout (Role list | Menu×CRUD matrix | Granted stats)
  • /system/users → Users CRUD + assign roles
  • /forms → upload .docx/.xlsx + render dialog Form↔JSON + Tải PDF

User (:8080):

  • /inbox?type=5 → HĐ Mua bán chờ role mình
  • /my-contracts?type=2 → HĐ Thầu phụ của tôi
  • /contracts/new?type=3 → tạo HĐ NCC
  • Sidebar nested: 📄 Hợp đồng → expand 7 type → expand "HĐ Mua bán" → Danh sách / Thao tác / Duyệt

Realtime check:

  • Login 2 tab (admin + user) → user tạo comment / transition → admin nhận toast + bell +1

Cần làm kế tiếp

🔥 Priority 0 — PE module refinement (session tiếp)

Xem STATUS.md §🔥 In Progress đầy đủ (nhóm A/B/C/D). Tóm tắt nhanh:

  1. PE Workflow admin designer UI /system/pe-workflows/:typeCode — mirror pattern từ WorkflowsPage.tsx + WorkflowDesigner.tsx. BE cần PeWorkflowAdminFeatures.cs + PeWorkflowsController.cs. Framework backend đã sẵn, chỉ thiếu wire UI.
  2. PE Attachments upload — copy pattern ContractAttachmentFeatures.cs + ContractAttachmentsSection.tsx. Entity + enum có sẵn.
  3. Ý kiến 4 phòng ban (Phê duyệt / P.CCM / P.MuaHàng / SM-PM) — Excel form có, entity chưa map. Cần design: 4 text field + signoff date, hoặc dùng Approvals với role-kind.
  4. Payment terms tách field từ JSON blob → 6 field riêng (Tạm ứng / TT tạm / Quyết toán / Bảo hành / Hạn mức / Đánh giá) theo Excel section D.
  5. Seed demo PE data — 2-3 phiếu cho UAT + screenshot.
  6. Permission grant Pe_ cho non-admin role* — /system/permissions tick PurchaseEvaluations.Read + CRUD cho role Drafter/PRO/CCM/BOD.
  7. MaPhieu format chính thức — user confirm.
  8. Export phiếu PDF/Excel — tái dùng IDocumentConverter + template.
  9. Auto-map PE Details → Contract Details khi gen HĐ (optional — nâng cấp).

Deploy blocker hiện tại: commit 3990066 chưa apply prod. Check runner:

Get-Service *gitea-runner* ; Start-Service gitea-runner

A. Hard blockers (chờ user / ops)

  1. UAT thật 1 tuần với 2-3 user — hard requirement từ roadmap. Kiến nghị:
    • User A: Drafter (QS/NV.PB) — tạo 3 HĐ mỗi type, đi hết 9 phase
    • User B: CCM — duyệt phase 6
    • User C: BOD — duyệt phase 7
    • Ghi bug / friction / đề xuất → backlog iter 2
  2. SMTP config để bật Email outbox:
    "Email": {
      "Host": "smtp.gmail.com",
      "Port": 587,
      "Username": "...",
      "Password": "...",
      "From": "noreply@solutionerp.local"
    }
    
    Khi có → thêm MailKit, IEmailSender, hook vào NotificationService.CreateAsync ngay trước khi enqueue realtime push.
  3. Rotate credentials — SA SQL password, vrapp password, JWT secret prod, Gitea runner registration token
  4. Schedule SQL backupschtasks /create /tn "SolutionErp Backup" /tr "powershell -File C:\...\scripts\backup-sql.ps1" /sc DAILY /st 03:00

A1. Định kỳ — Skill audit

Cadence: Mỗi đầu tháng (4 tuần). Lần audit kế tiếp: 2026-05-01.

Workflow xem docs/rules.md §9.4. Tóm tắt:

  1. Cross-check 6 skill hiện có với STATUS / gotchas / migration-todos
  2. Check repo nguồn 3rd party (alirezarezvani/claude-skills) có gì mới
  3. Update / archive / add skill nếu cần
  4. Log vào docs/changelog/skill-audit-2026-05.md

Trigger: user nói "audit skill" hoặc tự chạy đầu Phase mới.

B. Polish iterations (optional — khi UAT phát sinh)

  • Roles CRUD — admin tạo custom role ngoài 12 hardcoded (Domain.Identity.AppRoles)
  • User-kind approver runtime — data model WorkflowStepApprover.Kind=User + AssignmentValue=userId đã có, chỉ cần:
    // ContractWorkflowService.TransitionAsync (bổ sung):
    var userApprovers = step.Approvers.Where(a => a.Kind == ApproverKind.User)
                                      .Select(a => Guid.Parse(a.AssignmentValue));
    if (userApprovers.Any() && !userApprovers.Contains(actorUserId))
        throw new ForbiddenException();
    
  • Grant Workflows.Read cho non-admin role trong PermissionsPage → menu Wf_* auto-visible (inheritance đã có)
  • Warning notification 20% SLA — job emit khi SlaDeadline - now < sla * 0.2 && !SlaWarningSent, set flag
  • Reject → DangSoanThao E2E test với 3 role khác nhau
  • Deps scan CIdotnet list package --vulnerable + npm audit --audit-level=high

C. Non-goals / parked

  • E-signature (VNPT CA / FPT CA) — Phase 6
  • Bravo/SAP import NCC — Phase 6
  • Mobile app — Phase 6
  • AI OCR scan HĐ — Phase 6+

Lưu ý kỹ thuật quan trọng

Đọc gotchas.md (26 bẫy) trước khi:

  • Thêm package mới → .NET 10 compat (MediatR 14 fail → dùng 12.4.1)
  • Debug TS enum error → dùng const-object pattern (erasableSyntaxOnly)
  • Expression tree lỗi → tách switch ra ngoài LINQ
  • Deploy Windows Feature (WebSockets, etc.) → unlock section ở applicationHost (gotcha #25)
  • Workflow transition 403 → check Contract.WorkflowDefinitionId pin đúng không
  • Migration lỗi → 3 file đầy đủ (Designer + Migration + Snapshot)

Versioned workflow — quick reference

Contract.WorkflowDefinitionId (nullable Guid FK)
  → pin tại `CreateContractCommandHandler` = WorkflowDefinitions.Single(d => d.ContractType == c.Type && d.IsActive)
  → ContractWorkflowService.LoadAsync(contractId):
      if contract.WorkflowDefinitionId != null:
        def = db.WorkflowDefinitions.Include(Steps.Approvers).First(wfId)
        return WorkflowPolicyRegistry.FromDefinition(def)
      else if admin override ở WorkflowTypeAssignments:
        return Registry.ByName(override.PolicyName)
      else:
        return Registry.For(contract.Type)  // hardcoded Standard/SkipCcm

Admin tạo version mới:
  POST /api/workflows
    body: { code, name, contractType, steps: [{ order, phase, name, slaDays, approvers: [{ kind, assignmentValue }] }] }
  → auto increment Version = max(Version where Code==code) + 1
  → deactivate old IsActive trong cùng ContractType (atomic)
  → HĐ cũ ĐÃ PIN WorkflowDefinitionId = old Id → vẫn chạy policy cũ ✓

Invariants:

  • UNIQUE (Code, Version) per WorkflowDefinitions
  • Chỉ 1 IsActive=true per ContractType tại 1 thời điểm
  • Contract.WorkflowDefinitionId KHÔNG cascade khi xóa WorkflowDefinition → protect history

File đang active (hiện trạng)

SOLUTION_ERP/
├── src/Backend/                    (Clean Arch, 4 project, .NET 10)
│   ├── SolutionErp.Domain/
│   │   ├── Common/                 BaseEntity, AuditableEntity
│   │   ├── Contracts/              ContractType, ContractPhase, ApprovalDecision,
│   │   │                           Contract (+WorkflowDefinitionId), ContractApproval,
│   │   │                           ContractComment, ContractAttachment, ContractCodeSequence,
│   │   │                           **WorkflowPolicy** (record + registry + FromDefinition),
│   │   │                           **WorkflowDefinition** (Code+Version+IsActive+ContractType),
│   │   │                           **WorkflowStep** (Order+Phase+Name+SlaDays),
│   │   │                           **WorkflowStepApprover** (Kind=Role|User, AssignmentValue),
│   │   │                           **WorkflowTypeAssignment** (admin override legacy)
│   │   ├── Forms/                  ContractTemplate (+FieldSpec JSON), ContractClause
│   │   ├── Identity/               User, Role, MenuItem, Permission, AppRoles,
│   │   │                           **MenuKeys** (+ContractTypeCodes, ContractTypeGroup/List/Create/Pending helpers, WorkflowTypeLeaf)
│   │   ├── Master/                 Supplier (+SupplierType), Project, Department
│   │   └── Notifications/          **Notification** (+NotificationType enum)
│   ├── SolutionErp.Application/
│   │   ├── Auth/                   Login, Refresh, Me
│   │   ├── Common/
│   │   │   └── Interfaces/         IApplicationDbContext, ICurrentUser, IDateTime,
│   │   │                           IJwtTokenService, **IFileStorage**, **IDocumentConverter**,
│   │   │                           **IRealtimeNotifier**, **INotificationService**
│   │   ├── Contracts/              ContractFeatures, IContractWorkflowService,
│   │   │                           **ContractAttachmentFeatures** (Upload/Download/Delete CQRS),
│   │   │                           **WorkflowAdminFeatures** (Overview + CreateNewVersion)
│   │   ├── Forms/                  FormFeatures (List/Get/Render/**Upload/Update/Delete/ExportPdf**)
│   │   ├── Master/                 Suppliers, Projects, Departments CQRS
│   │   ├── **Notifications/**      NotificationFeatures (List/UnreadCount/MarkRead/MarkAllRead)
│   │   ├── Permissions/            GetMyMenuTree (**+inherit Contracts/Workflows**)
│   │   └── Reports/                DashboardStats, ExportToExcel, **MyDashboard**
│   ├── SolutionErp.Infrastructure/
│   │   ├── Forms/                  DocxRenderer, XlsxRenderer, FormRenderer,
│   │   │                           **LibreOfficeDocumentConverter**
│   │   ├── Identity/               JwtSettings, JwtTokenService
│   │   ├── Persistence/
│   │   │   ├── Interceptors/       AuditingInterceptor, **NotificationPushInterceptor**
│   │   │   └── Migrations/         8 migrations
│   │   ├── Reports/                ContractExcelExporter
│   │   ├── **Storage/**            LocalFileStorage (path-traversal guard)
│   │   └── Services/               DateTimeService, **ContractWorkflowService (load pinned def)**,
│   │                               ContractCodeGenerator, **NotificationService**
│   └── SolutionErp.Api/
│       ├── Authorization/          MenuPermissionHandler + Requirement
│       ├── Controllers/            Auth, Suppliers, Projects, Departments, Menus,
│       │                           Roles, Permissions, Forms, Contracts, Reports,
│       │                           Users, **Notifications**, **Workflows**
│       ├── **Hubs/**                NotificationHub (/hubs/notifications)
│       ├── Middleware/             GlobalExceptionMiddleware
│       ├── **Realtime/**            SignalRNotifier
│       ├── Services/               CurrentUserService, WebHostEnvironmentLocator
│       └── wwwroot/templates/      .docx/.xlsx templates
├── fe-admin/                       (~18 page)
│   └── src/
│       ├── pages/
│       │   ├── LoginPage, DashboardPage (MyDashboardRow)
│       │   ├── master/              Suppliers, Projects, Departments
│       │   ├── system/              **PermissionsPage (3-panel)**, **WorkflowsPage (URL-driven)**, Users
│       │   ├── forms/               FormsPage (upload + Form/JSON + PDF)
│       │   ├── contracts/           List, Detail (+Attachments), **Create**
│       │   └── ReportsPage
│       ├── components/             Layout (recursive menu + filterForAdmin),
│       │                           TopBar, NotificationBell, UserMenu, SlaTimer,
│       │                           EmptyState, PhaseBadge, WorkflowSummaryCard,
│       │                           ContractAttachmentsSection, DynamicForm,
│       │                           **WorkflowDesigner** (Steps + Approvers modal)
│       └── lib/                    api.ts, realtime.ts, cn.ts
├── fe-user/                        (~10 page)
│   └── src/
│       ├── pages/                  Login, Inbox (+?type filter),
│       │                           contracts/{Create, Detail, MyContracts}
│       ├── components/             Layout (recursive + filterForUser + USER_FIXED_TOP),
│       │                           NotificationBell, ContractAttachmentsSection, SlaTimer
│       └── lib/                    realtime.ts (same singleton pattern)
├── docs/                           (~40 file)
│   ├── STATUS, HANDOFF, rules, architecture, CLAUDE, PROJECT-MAP (6)
│   ├── workflow-contract, forms-spec (2)
│   ├── database/{database-guide, schema-diagram} (2)
│   ├── flows/ (7 file — README + 6 flow)
│   ├── guides/ (4 file)
│   ├── changelog/migration-todos + sessions/ (8 session log)
│   └── gotchas (26 pitfall)
├── scripts/                        (5 PS + py)
│   ├── parse_forms, parse_workflow (Phase 0)
│   ├── convert-doc-to-docx (Phase 2)
│   ├── deploy-iis, backup-sql (Phase 5)
│   └── install-libreoffice (Tier 3)
├── .gitea/workflows/deploy.yml     CI/CD Windows self-hosted runner
└── .claude/skills/                 3 skill (contract-workflow, form-engine, permission-matrix)

Git state

HEAD → main
bcdc007 — Infra: Mở rộng seed master (15 NCC + 8 Project) + backfill demo HĐ (LATEST)
e53cd3a — App+Api+FE+Scripts: Edit detail row inline + deps audit helper
4edcd58 — Domain+Infra: User-kind approver runtime guard + Warning 20% SLA
8bc9565 — Infra: SeedDemoContractsAsync — 7 HĐ varied phases UAT-ready
072ad6d — App+Api+FE-Admin: RolesPage CRUD (/system/roles)
ff5e35f — Docs: chốt session 2026-04-23 chiều
ae59cfe — FE-Admin: UsersPage dept/position + RoleShortName VN
330d529 — Domain+App+Infra: Role ShortName + User Dept/Position + 13 demo users (migration 11)
39031ca — FE: ContractDetailsPreview cho create mode
16e24ed — FE: Admin CatalogsPage CRUD + Details datalist autocomplete
e27c547 — Domain+App+Api: 4 master catalogs cho Details (migration 10)
51449d6 — App+Infra: Mã HĐ gen ngay tại CreateContract + backfill legacy
7f26ff9 — Edit/Xóa luôn hiện, mờ khi != DangSoanThao
8c4b4da — 2-panel layout cho Thao tác
ad0652d — Bỏ tabs, Chi tiết+Lịch sử 7/3 grid
b3762af — Panel 2 tabs (Tổng quan/Chi tiết/Lịch sử)
e684455 — App+Api: 7 Details CRUD endpoints + Changelogs query
71c035d — App+Infra: IChangelogService
70810e1 — Domain+Infra: 7 Details + ContractChangelog (migration 9)
d326e80 — FE-User: tách Tổng quan thành /dashboard riêng
89c7e88 — FE-User: 3-panel InboxPage
b75448e — 3-panel layout cho danh sách HĐ
7ea3957 — Sidebar accordion menu loại HĐ
d43d2c0 — Docs: chốt session 2026-04-23 — skill governance

Branch: main (tracking origin/main)
Remote: https://git.baocaogiaoduc.vn/vietreport-admin/solution-erp.git

Credentials + URLs

admin@solutionerp.local / Admin@123456    ← Admin (QTV)

Demo users (User@123456):
  bod.huynh@solutionerp.local    Tổng GĐ (BOD)
  bod.le@solutionerp.local       Phó GĐ NĐUQ
  pm.nguyen@solutionerp.local    GĐ Dự án FLOCK 01 (PM)
  ccm.tran@solutionerp.local     TPB Kiểm soát chi phí (CCM + TPB)
  pro.pham@solutionerp.local     TPB Cung ứng (PRO + TPB)
  fin.do@solutionerp.local       TPB Tài chính (FIN + TPB)
  act.vu@solutionerp.local       Kế toán trưởng (ACT + TPB)
  equ.bui@solutionerp.local      TPB Thiết bị (EQU + TPB)
  hra.dang@solutionerp.local     TPB HRA (HRA + TPB)
  qs.hoang, qs.ngo               QS công trường (NV.PB)
  nv.cao, nv.dinh                NV Cung ứng/Tài chính (NV.PB)

⚠ Rotate ALL passwords trước UAT thật

Đánh giá nhanh

Tốt:

  • 3 domain HTTPS prod live, CI/CD xanh
  • Tier 3 feature-complete: attachment, realtime, form builder (upload + DynamicForm + PDF), versioned workflow (admin-configurable per ContractType, pin per contract), nested menu per type, 3-panel permissions
  • Clean-arch 3-project split đúng cho 2 cross-cutting service (realtime + document-converter)
  • 26 gotchas tích lũy, 8 session log, 40 docs — agent onboard nhanh
  • Invariant critical: "HĐ cũ giữ quy trình cũ" guaranteed by pinning (reference-based immutability, không snapshot copy)

Rủi ro còn:

  • UAT thật chưa chạy → có thể phát hiện edge case missing
  • SMTP chưa có → notification chỉ in-app (toast + bell), không email
  • User-kind approver chưa enable guard runtime (designer cho pick, nhưng transition dùng Role fall-back)
  • Credentials chưa rotate
  • SQL backup chưa schedule Task Scheduler