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

13 KiB
Raw Blame History

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.

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/permissions3-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
  • Giteahttps://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 notificationsNotificationPushInterceptor 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>.