Files
solution-erp/docs/PROJECT-MAP.md
pqhuy1987 66c1a5c170
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m52s
[CLAUDE] Rebrand: 3 domain huypham.vn → solutions.com.vn + migrate script
User request: anh trỏ 3 subdomain mới về VPS IP 103.124.94.38:
  - api.huypham.vn        → api.solutions.com.vn
  - admin.huypham.vn      → admin.solutions.com.vn
  - user.huypham.vn       → eoffice.solutions.com.vn

Verified DNS: cả 3 resolve 103.124.94.38 ✓

Update 17 file repo:
FE (4): fe-admin/.env.production + fe-user/.env.production
        (VITE_API_BASE_URL → https://api.solutions.com.vn)
        fe-admin/src/lib/{api,realtime}.ts + fe-user equivalents (comment)
BE (1): appsettings.Production.json.example — CORS AllowedOrigins
CI/CD (1): .gitea/workflows/deploy.yml — smoke test URL
Scripts (3): setup-iis-sites (DomainApi/Admin/User), setup-ssl (3 host),
             deploy-all (verify curls)
Docs (5): STATUS, HANDOFF, PROJECT-MAP, vps-setup, gotchas
Skill (1): iis-deploy-runbook — 3 site table + description
Email admin@huypham.vn giữ nguyên (Let's Encrypt contact — không phải
domain serve).

Thêm scripts/migrate-domains.ps1 — 1-shot VPS migration:
  1. Pre-flight: resolve DNS 3 domain → verify IP VPS khớp
  2. Add HTTP binding mới cho 3 IIS site (giữ binding cũ làm fallback)
  3. Run win-acme xin 3 cert Let's Encrypt qua HTTP-01 challenge
     (auto add HTTPS binding + http→https redirect)
  4. Verify /health/live + /health/ready + 2 FE endpoint
  5. (Optional -RemoveOld) xóa binding huypham.vn sau verify OK
Rollback: nếu fail, binding cũ vẫn active → site serve qua huypham.vn.

Anh chạy trên VPS:
  cd C:\solution-erp\scripts  ;  .\migrate-domains.ps1
  # Sau 1-2 ngày verify stable:
  .\migrate-domains.ps1 -RemoveOld -SkipCert
2026-04-24 09:43:05 +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.solutions.com.vn / admin.solutions.com.vn / eoffice.solutions.com.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>`.