Files
solution-erp/docs/PROJECT-MAP.md
pqhuy1987 fbca83264c
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m33s
[CLAUDE] Docs: chốt session Tier 3 feature-complete + versioned workflow
- 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>
2026-04-22 10:25:02 +07:00

242 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PROJECT-MAP — Bản đồ toàn cảnh
> Đọ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 (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) ✅ ║
╠════════════════╣ ╠════════════════╣ ╠════════════════╣
║ 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) ✅ ║
╠════════════════╣ ╠════════════════╣ ╠════════════════╣
║ 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 (implemented)
```
User ────< UserRoles >──── Role ────< Permission (Role × MenuKey × CRUD)
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 (9 phòng từ QT docx)
Contract
├── 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)
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 (implemented)
```
/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/permissions — get matrix + bulk upsert
/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 (multipart) + download stream + delete
/api/forms — CRUD templates (upload/update/delete + render + PDF export)
/api/forms/templates/{id}/export-pdf — LibreOffice conversion
/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 (implemented)
### fe-admin (:8082) — cho Admin + Role quản lý
- `/login`
- `/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
Sidebar: nested menu + `filterForAdmin` hide `Ct_*`, keep `Wf_*` for admin
### fe-user (:8080) — cho Drafter, TBP, PD/PM, BOD, CCM, HRA, ...
- `/login`
- `/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
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) ← 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 ý → Notification push Drafter
Drafter
├─ [PATCH /api/contracts/{id}] revise
├─ [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 → [transitions] → DangKiemTraCCM
CCM → [transitions] → DangTrinhKy
BOD → [transitions] → DangDongDau
└─ BE: ContractCodeGenerator SERIALIZABLE → gen MaHopDong RG-001
HRA → [transitions] → DaPhatHanh (final)
```
## External dependencies (hiện trạng)
- **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 (React Native) — Phase 6+
- ❌ Multi-tenant (1 instance / 1 công ty)
- ❌ 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>`.