[CLAUDE] Docs: chốt session Tier 3 feature-complete + versioned workflow
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m33s

- Session log 2026-04-22-0300 (A→K): attachment, SignalR, form builder,
  PDF, dynamic + versioned workflow, nested menu, 3-panel permissions,
  seed master, brand identity, content polish, Gitea fix
- STATUS: Tier 3 feature-complete snapshot + cumulative stats (24 tables,
  ~50 endpoints, 8 migrations); next-up = UAT + Email SMTP (blocked) +
  rotate creds + SQL backup schedule
- HANDOFF: rewrite brief cho session mới — phase 5 prod done, Tier 3
  đóng gói, quick sanity-check 2 app, versioned workflow quick ref,
  file active hiện trạng, git state
- migration-todos: tick Tier 3 items (attachment/realtime/form builder/
  PDF/dynamic+versioned workflow/nested menu) + thêm iter-3 versioned
  workflow section + post-launch list
- schema-diagram: +5 table (Notifications, WorkflowTypeAssignments,
  WorkflowDefinitions, WorkflowSteps, WorkflowStepApprovers); indexes
  mới, cardinality FK restrict cho pinned policy, truy vấn tiêu biểu
- workflow-contract: +section 7bis resolution order, 7ter admin
  designer flow, updated data model + code pointers Tier 3
- PROJECT-MAP: module map post-Tier-3 (3 box mới Notification/
  Attachment/Branding + Infra/DevOps box), API namespace đầy đủ,
  architectural wins 5 điểm
- contract-workflow skill: versioned workflow section, policy
  resolution code snippet, admin designer flow, code pointers Tier 3,
  tier 4+ backlog
- gotchas +7 bẫy mới (#26-32): SignalR WebSocket headers, interceptor
  2-phase pattern, LibreOffice mirror 404, PS 5.1 UTF-16 GITHUB_PATH,
  PS 5.1 diacritics parse, Dialog size TS, NavLink end query-params

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-04-22 10:25:02 +07:00
parent 91b2da147f
commit fbca83264c
9 changed files with 1363 additions and 479 deletions

View File

@ -2,153 +2,240 @@
> Đọc file này nếu cần deep context (~15 phút). Nếu chỉ cần snapshot → đọc [`STATUS.md`](STATUS.md).
## Module map
## Module map (hiện trạng post-Tier-3)
```
┌─────────────────────────────────────────────────────────────────┐
│ SOLUTION_ERP │
│ 🌐 Prod live: api/admin/user.huypham.vn (HTTPS Let's Encrypt) │
└─────────────────────────────────────────────────────────────────┘
╔════════════════╗ ╔════════════════╗ ╔════════════════╗
║ IDENTITY ║ ║ DANH MỤC ║ ║ QUẢN LÝ HĐ ║
║ (Phase 1) ║ ║ (Phase 1) ║ ║ (Phase 1-3)
║ (Phase 1) ║ ║ (Phase 1) ║ ║ (Phase 1-3)
╠════════════════╣ ╠════════════════╣ ╠════════════════╣
║ User ║ ║ Supplier ║ ║ Contract ║
║ Role ║ ║ Project ║ ║ ContractType
║ Permission ║ ║ Department ║ ║ ContractForm
MenuKey ║ ║ ContractClause ║ ║ Approval
AuditLog ║ ║ (điều kiện ║ ║ Comment
chung - 002.04)║ ║ Attachment
╚════════════════╝ ╚════════════════╝ ║ AuditTrail ║
╚════════════════╝
║ User (+Mgmt) ║ ║ Supplier ║ ║ Contract ║
║ Role (12 seed) ║ ║ Project ║ ║ + WorkflowDefId
║ Permission ║ ║ Department ║ ║ Approval
(3-panel UI) ║ + seed demo ║ ║ Comment
MenuKey ║ ║ ContractClause ║ ║ Attachment
+ nested tree ║ ║ (E2E upload)
╚════════════════╝ ╚════════════════╝ ╚════════════════╝
╔════════════════╗ ╔════════════════╗ ╔════════════════╗
║ FORM ENGINE ║ ║ WORKFLOW ║ ║ BÁO CÁO ║
║ (Phase 2) ║ ║ (Phase 3) ║ ║ (Phase 4)
║ (Phase 2) ║ ║ (Phase 3) ║ ║ (Phase 4)
╠════════════════╣ ╠════════════════╣ ╠════════════════╣
║ Template ║ ║ StateMachine ║ ║ Dashboard ║
Renderer ║ ║ Transition ║ ║ ExcelExport ║
║ (DOCX/XLSX) ║ ║ SlaTimer ║ ║ FilterQuery
║ Field mapping ║ ║ Notification ║ ║
║ PO gen (F.07) ║ ║ CodeGenerator ║ ║ ║
║ ║ (RG-001) ║ ║ ║
║ Template CRUD ║ ║ StateMachine ║ ║ Dashboard ║
DynamicForm ✅ ║ ║ Transition ║ ║ ExcelExport ║
║ (DOCX/XLSX) ║ ║ SlaTimer ║ ║ MyDashboard ✅
║ FieldSpec JSON ║ ║ SlaExpiryJob ✅ ║ ║ (role-aware)
║ PDF export ✅ ║ ║ CodeGen RG-001 ║ ║ ║
(LibreOffice) ║ **Versioned ✅**║ ║ ║
║ .doc auto-conv ║ ║ (admin design)║ ║ ║
╚════════════════╝ ╚════════════════╝ ╚════════════════╝
╔════════════════╗ ╔════════════════╗ ╔════════════════╗
║ NOTIFICATION ║ ║ ATTACHMENT ║ ║ BRANDING ║
║ (Tier 3) ✅ ║ ║ (Tier 3) ✅ ║ ║ (Tier 3) ✅ ║
╠════════════════╣ ╠════════════════╣ ╠════════════════╣
║ Notification ║ ║ IFileStorage ║ ║ #1F7DC1 palette║
║ SignalR Hub ║ ║ LocalFileStore ║ ║ Be Vietnam Pro ║
║ Auto-push ║ ║ Path traversal ║ ║ Solutions logo ║
║ interceptor ║ ║ guard ║ ║ ERP shell ║
║ Toast + Bell ║ ║ 3 endpoint ║ ║ (TopBar + Bell║
║ badge ║ ║ REST + FE ║ ║ + UserMenu) ║
║ Email (TODO) ║ ║ drag-drop ║ ║ ║
╚════════════════╝ ╚════════════════╝ ╚════════════════╝
╔════════════════════════════════════════════════════════════╗
║ INFRA / DEVOPS (Phase 5) ✅ ║
╠════════════════════════════════════════════════════════════╣
║ IIS 3 sites (Api/Admin/User) + URL Rewrite + ARR ║
║ win-acme 3 Let's Encrypt cert + auto-renew ║
║ Gitea Actions CI/CD (Windows self-hosted runner) ║
║ SQL Server 2019 SQLEXPRESS + scripts/backup-sql.ps1 ║
║ LibreOffice 25.8.6 headless (PDF/docx converter) ║
║ Health check /health/live + /health/ready ║
║ Serilog file rolling daily retention 30d ║
║ Security headers + HSTS + rate limit 300/min global ║
╚════════════════════════════════════════════════════════════╝
```
## Domain entities chính (dự kiến)
## Domain entities chính (implemented)
```
User ────< Role ────< Permission (Role × MenuKey × CRUD)
User ────< AuditLog
User ────< UserRoles >──── Role ────< Permission (Role × MenuKey × CRUD)
Supplier (NCC)
MenuItem ─┬─ Parent-child tree (Contracts → Ct_MuaBan_* → ...)
├─ 28 Ct_* leaves (7 type × 3 action + 7 group)
└─ 7 Wf_* leaves for workflow admin
Supplier (NCC / NTP / TD / DVDV / CDT)
Project (Dự án)
Department (Phòng ban)
Department (9 phòng từ QT docx)
Contract
├── Type: HĐTP | HĐGK | NCC | HĐDV | HĐ Mua bán | ...
├── Phase (9 state — xem workflow-contract.md)
├── Supplier, Project, Drafter
├── MaHopDong (gen theo RG-001)
├── Approvals[] (audit ai ký phase nào)
├── Comments[] (thread góp ý Phase 3 của workflow)
├── Attachments[] (scan bản gốc, file export)
── TemplateData (JSON — field đã điền khi render form)
├── Type: HĐTP | HĐGK | NCC | HĐDV | HĐ Mua bán | Nguyên tắc NCC | Nguyên tắc DV
├── Phase (9 state)
├── WorkflowDefinitionId (pinned policy at create-time)
├── Supplier, Project, Drafter, Template
├── MaHopDong (gen theo RG-001 khi DangDongDau)
├── SlaDeadline + SlaWarningSent flag
├── Approvals[] (history)
── Comments[] (thread)
└── Attachments[] (scan + upload)
ContractTemplate (ánh xạ Type → File mẫu FO-002.xx)
ContractClause (điều khoản chung FO-002.04 — rich text)
PurchaseOrder (có thể đính với Contract hoặc standalone)
WorkflowDefinition (versioned per ContractType)
├── Code (QT-MB, QT-TP, ...) + Version (v01, v02, ...)
├── IsActive (max 1 per ContractType)
└── Steps[]
├── Order + Phase + Name + SlaDays
└── Approvers[] (Kind=Role|User + AssignmentValue)
WorkflowTypeAssignment (legacy admin override — fall back khi chưa có WorkflowDefinition)
ContractTemplate (FormCode + ContractType + FieldSpec JSON + StoragePath)
ContractClause (điều khoản chung FO-002.04)
ContractCodeSequence (Prefix → LastSeq, atomic gen)
Notification (RecipientUserId + Type + Title + Body + Link + IsRead)
```
## API namespace dự kiến
## API namespace (implemented)
```
/api/auth — login, refresh, logout, register (admin gate)
/api/users — CRUD user, assign role, reset password
/api/roles — CRUD role, permission matrix
/api/menus — menu tree + permission resolution
/api/auth — login, refresh, me, logout
/api/users — CRUD + assign roles + reset password + unlock + toggle active
/api/roles — list (CRUD Create/Rename/Delete: TODO)
/api/menus /me tree với inherit Contracts/Workflows
/api/suppliers — CRUD NCC
/api/projects — CRUD dự án
/api/departments — CRUD phòng ban
/api/suppliers — CRUD NCC
/api/projects — CRUD dự án
/api/departments — CRUD phòng ban
/api/permissions — get matrix + bulk upsert
/api/contracts — CRUD + query by phase/project/supplier
/api/contracts/{id}/transitions — state machine action
/api/contracts — CRUD + query by phase/supplier/project/type + pendingMe
/api/contracts/inbox — HĐ chờ role tôi
/api/contracts/{id} — detail + pinned WorkflowDefinition policy
/api/contracts/{id}/transitions — state machine action (role guard + versioned policy)
/api/contracts/{id}/comments — thread góp ý
/api/contracts/{id}/attachments — upload/download
/api/contracts/{id}/attachments — upload (multipart) + download stream + delete
/api/forms — template catalog
/api/forms/{id}/render — render template → docx/xlsx (Phase 2)
/api/forms — CRUD templates (upload/update/delete + render + PDF export)
/api/forms/templates/{id}/export-pdf — LibreOffice conversion
/api/reports/dashboard — KPI tổng hợp
/api/reports/export — Excel download
/api/workflows — admin GET overview + POST create new version
/api/workflows/{type} — per-type definition + history
/api/notifications — list + unread count + mark-read + mark-all-read
/api/reports/dashboard — KPI tổng hợp
/api/reports/my-dashboard — role-aware user-specific stats
/api/reports/export — Excel download
/hubs/notifications — SignalR hub (JWT qua ?access_token=)
/health/live + /health/ready — health check
```
## FE screens dự kiến
## FE screens (implemented)
### fe-admin (:8082) — cho Admin + Role quản lý
- `/login`
- `/dashboard`KPI system
- `/master/users` + `/master/roles` + `/master/permissions`
- `/master/suppliers` + `/master/projects` + `/master/departments`
- `/master/contract-templates` + `/master/contract-clauses`
- `/contracts`danh sách toàn bộ, filter phase/dự án
- `/contracts/{id}` — detail + approval panel + audit log
- `/reports` + `/system/audit-log`
- `/dashboard`MyDashboard row (4 card) + KPI + charts
- `/master/suppliers|projects|departments` — CRUD
- `/system/users` — Users Mgmt (create/reset/unlock/assign-roles/toggle-active)
- `/system/permissions`**3-panel layout** (Role list | Menu×CRUD matrix | Granted stats)
- `/system/workflows`landing 7-card grid per ContractType
- `/system/workflows/:typeCode` — Definition card (active + history) + Designer modal
- `/forms` — list + upload + update + delete + render dialog (Form↔JSON toggle) + Tải PDF
- `/contracts` — list full + filter phase/supplier/project/type
- `/contracts/new` — Create (pre-select from `?type=X`)
- `/contracts/:id` — detail + timeline + action dialog + **Attachments section** + WorkflowSummaryCard
- `/reports` — filter + export Excel
### fe-user (:8080) — cho Drafter, TBP, PD/PM, BOD, CCM, ...
Sidebar: nested menu + `filterForAdmin` hide `Ct_*`, keep `Wf_*` for admin
### fe-user (:8080) — cho Drafter, TBP, PD/PM, BOD, CCM, HRA, ...
- `/login`
- `/inbox` — HĐ đang chờ tôi xử lý (filter theo role × phase)
- `/contracts/new`chọn template + điền form + submit
- `/contracts/{id}`detail, comment, approve/reject
- `/my-contracts`HĐ tôi đã tạo/tham gia
- `/inbox` — HĐ chờ role tôi xử lý (lọc theo `?type=X`)
- `/my-contracts`HĐ tôi đã tạo/tham gia (lọc theo `?type=X`)
- `/contracts/new`tạo HĐ draft (pre-select type)
- `/contracts/:id`detail + duyệt/comment + Attachments drag-drop
## Flow chính (Phase 3 — trình ký HĐ end-to-end)
Sidebar: nested 3-level, `filterForUser` hide admin items, hiển thị 7 ContractType × 3 action
## Flow chính (Phase 3 end-to-end, Tier 3 versioned)
```
Drafter (QS/NV.PB)
├─ [POST /api/contracts] tạo draft + chọn template
├─ [POST /api/forms/{id}/render] fill + preview
Drafter (QS/NV.PB) ← pin WorkflowDefinitionId = v02 active
├─ [POST /api/contracts] tạo draft Phase=DangSoanThao, pin v02
├─ [POST /api/forms/templates/{id}/render] fill FieldSpec + preview
├─ (upload scan đính kèm qua /attachments)
├─ [POST /api/contracts/{id}/transitions] DangSoanThao → DangGopY
│ BE: load wfDef v02 → FromDefinition → Registry policy → guard (role + from/to)
│ → Notification push tới all PD/PM/PRO/CCM/FIN/ACT + SignalR toast
PD/PM/PRO/CCM/FIN/ACT (song song)
└─ [POST /api/contracts/{id}/comments] góp ý
PD/PM/PRO/CCM/FIN/ACT (song song)
└─ [POST /api/contracts/{id}/comments] góp ý → Notification push Drafter
Drafter
├─ [PATCH /api/contracts/{id}] revise
├─ [POST /api/contracts/{id}/transitions] DangGopY → DangDamPhan → DangInKy
├─ [POST .../transitions] DangGopY → DangDamPhan → DangInKy
│ (BypassProcurementAndCCM=true → skip CCM → DangInKy → DangTrinhKy)
NTP/NCC/TĐ (external — Drafter update thay)
└─ upload scan có chữ ký đối tác
Drafter
└─ [POST /api/contracts/{id}/transitions] → DangKiemTraCCM
Drafter → [transitions] → DangKiemTraCCM
CCM → [transitions] → DangTrinhKy
BOD → [transitions] → DangDongDau
└─ BE: ContractCodeGenerator SERIALIZABLE → gen MaHopDong RG-001
CCM
└─ [POST /api/contracts/{id}/transitions] → DangTrinhKy
BOD/NĐUQ
└─ [POST /api/contracts/{id}/transitions] → DangDongDau (GEN mã HĐ ở đây!)
HRA
└─ [POST /api/contracts/{id}/transitions] → DaPhatHanh (upload scan có dấu)
HRA → [transitions] → DaPhatHanh (final)
```
## External dependencies
## External dependencies (hiện trạng)
- **SQL Server** — chính thức, dev có thể LocalDB hoặc Docker (`docker-compose.yml`)
- **IIS** — deploy target (Windows Server 2019+)
- **Gitea** — git remote (URL chờ user cấp)
- **Aspose.Words / DocumentFormat.OpenXml** — render .docx (Phase 2, quyết định khi đó)
- **EPPlus hoặc ClosedXML** — render .xlsx (Phase 2)
- **SQL Server** — prod SQLEXPRESS trên VPS, dev LocalDB hoặc Docker
- **IIS** — Windows Server (VPS shared VIETREPORT), URL Rewrite + ARR + WebSockets module
- **Gitea** — https://git.baocaogiaoduc.vn (self-hosted, shared runner)
- **win-acme** — Let's Encrypt auto-renew
- **LibreOffice 25.8.6** — PDF / docx / xlsx conversion (soffice headless)
- **DocumentFormat.OpenXml** — render .docx (Phase 2)
- **ClosedXML** — render .xlsx + Excel export (Phase 4)
- **MediatR 12.4.1** — CQRS mediator (pin, 14 breaking)
- **@microsoft/signalr 8.0.7** — FE realtime client
- **Be Vietnam Pro** — Google Fonts (Vietnamese diacritics)
## Non-goals (KHÔNG làm)
- ❌ Python AI service (user đã quyết gác vô thời hạn)
- ❌ Mobile app
- ❌ Mobile app (React Native) — Phase 6+
- ❌ Multi-tenant (1 instance / 1 công ty)
- ❌ Tích hợp e-signature (Phase 6+ nếu có)
- ❌ Tích hợp SAP/Bravo ERP (Phase 6+ nếu có)
- ❌ Tích hợp e-signature (VNPT/FPT CA) — Phase 6+
- ❌ Tích hợp SAP/Bravo ERP Phase 6+
- ❌ Public API / external webhooks
## Architectural wins (Tier 3)
1. **Versioned workflow via Contract.WorkflowDefinitionId pin** — zero-cost immutability guarantee.
HĐ cũ protected from policy changes by REFERENCE (FK restrict), không phải snapshot copy.
2. **Permission inheritance via menu ancestry** — Contracts + Workflows roots inherit CanRead xuống
descendant Ct_* / Wf_* nodes. Không cần per-leaf permission rows → Permissions table nhỏ gọn.
3. **3-project clean-arch split cho cross-cutting services** (SignalR realtime + LibreOffice converter):
- Abstraction ở Application (`IRealtimeNotifier`, `IDocumentConverter`)
- Implementation ở Api / Infrastructure
- Caller (Application handlers) KHÔNG depend transport / framework
4. **SaveChangesInterceptor auto-push notifications**`NotificationPushInterceptor` capture Added
Notifications ở SavingChanges, push via `IRealtimeNotifier` ở SavedChanges. Zero caller changes
khi CQRS handler chỉ `db.Notifications.Add(n)`.
5. **URL-driven admin UI (workflows per-type)** — thay tabs bằng sidebar menu items + URL param.
Linkable, bookmarkable, mỗi type có permission leaf riêng qua `Wf_<Code>`.